xref: /OK3568_Linux_fs/kernel/drivers/media/usb/pvrusb2/pvrusb2-ioread.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include "pvrusb2-ioread.h"
8*4882a593Smuzhiyun #include "pvrusb2-debug.h"
9*4882a593Smuzhiyun #include <linux/errno.h>
10*4882a593Smuzhiyun #include <linux/string.h>
11*4882a593Smuzhiyun #include <linux/mm.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include <linux/mutex.h>
14*4882a593Smuzhiyun #include <linux/uaccess.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define BUFFER_COUNT 32
17*4882a593Smuzhiyun #define BUFFER_SIZE PAGE_ALIGN(0x4000)
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun struct pvr2_ioread {
20*4882a593Smuzhiyun 	struct pvr2_stream *stream;
21*4882a593Smuzhiyun 	char *buffer_storage[BUFFER_COUNT];
22*4882a593Smuzhiyun 	char *sync_key_ptr;
23*4882a593Smuzhiyun 	unsigned int sync_key_len;
24*4882a593Smuzhiyun 	unsigned int sync_buf_offs;
25*4882a593Smuzhiyun 	unsigned int sync_state;
26*4882a593Smuzhiyun 	unsigned int sync_trashed_count;
27*4882a593Smuzhiyun 	int enabled;         // Streaming is on
28*4882a593Smuzhiyun 	int spigot_open;     // OK to pass data to client
29*4882a593Smuzhiyun 	int stream_running;  // Passing data to client now
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	/* State relevant to current buffer being read */
32*4882a593Smuzhiyun 	struct pvr2_buffer *c_buf;
33*4882a593Smuzhiyun 	char *c_data_ptr;
34*4882a593Smuzhiyun 	unsigned int c_data_len;
35*4882a593Smuzhiyun 	unsigned int c_data_offs;
36*4882a593Smuzhiyun 	struct mutex mutex;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun 
pvr2_ioread_init(struct pvr2_ioread * cp)39*4882a593Smuzhiyun static int pvr2_ioread_init(struct pvr2_ioread *cp)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	unsigned int idx;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	cp->stream = NULL;
44*4882a593Smuzhiyun 	mutex_init(&cp->mutex);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	for (idx = 0; idx < BUFFER_COUNT; idx++) {
47*4882a593Smuzhiyun 		cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
48*4882a593Smuzhiyun 		if (!(cp->buffer_storage[idx])) break;
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (idx < BUFFER_COUNT) {
52*4882a593Smuzhiyun 		// An allocation appears to have failed
53*4882a593Smuzhiyun 		for (idx = 0; idx < BUFFER_COUNT; idx++) {
54*4882a593Smuzhiyun 			if (!(cp->buffer_storage[idx])) continue;
55*4882a593Smuzhiyun 			kfree(cp->buffer_storage[idx]);
56*4882a593Smuzhiyun 		}
57*4882a593Smuzhiyun 		return -ENOMEM;
58*4882a593Smuzhiyun 	}
59*4882a593Smuzhiyun 	return 0;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
pvr2_ioread_done(struct pvr2_ioread * cp)62*4882a593Smuzhiyun static void pvr2_ioread_done(struct pvr2_ioread *cp)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun 	unsigned int idx;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	pvr2_ioread_setup(cp,NULL);
67*4882a593Smuzhiyun 	for (idx = 0; idx < BUFFER_COUNT; idx++) {
68*4882a593Smuzhiyun 		if (!(cp->buffer_storage[idx])) continue;
69*4882a593Smuzhiyun 		kfree(cp->buffer_storage[idx]);
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
pvr2_ioread_create(void)73*4882a593Smuzhiyun struct pvr2_ioread *pvr2_ioread_create(void)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct pvr2_ioread *cp;
76*4882a593Smuzhiyun 	cp = kzalloc(sizeof(*cp),GFP_KERNEL);
77*4882a593Smuzhiyun 	if (!cp) return NULL;
78*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
79*4882a593Smuzhiyun 	if (pvr2_ioread_init(cp) < 0) {
80*4882a593Smuzhiyun 		kfree(cp);
81*4882a593Smuzhiyun 		return NULL;
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 	return cp;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
pvr2_ioread_destroy(struct pvr2_ioread * cp)86*4882a593Smuzhiyun void pvr2_ioread_destroy(struct pvr2_ioread *cp)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun 	if (!cp) return;
89*4882a593Smuzhiyun 	pvr2_ioread_done(cp);
90*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
91*4882a593Smuzhiyun 	if (cp->sync_key_ptr) {
92*4882a593Smuzhiyun 		kfree(cp->sync_key_ptr);
93*4882a593Smuzhiyun 		cp->sync_key_ptr = NULL;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 	kfree(cp);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
pvr2_ioread_set_sync_key(struct pvr2_ioread * cp,const char * sync_key_ptr,unsigned int sync_key_len)98*4882a593Smuzhiyun void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
99*4882a593Smuzhiyun 			      const char *sync_key_ptr,
100*4882a593Smuzhiyun 			      unsigned int sync_key_len)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	if (!cp) return;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (!sync_key_ptr) sync_key_len = 0;
105*4882a593Smuzhiyun 	if ((sync_key_len == cp->sync_key_len) &&
106*4882a593Smuzhiyun 	    ((!sync_key_len) ||
107*4882a593Smuzhiyun 	     (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if (sync_key_len != cp->sync_key_len) {
110*4882a593Smuzhiyun 		if (cp->sync_key_ptr) {
111*4882a593Smuzhiyun 			kfree(cp->sync_key_ptr);
112*4882a593Smuzhiyun 			cp->sync_key_ptr = NULL;
113*4882a593Smuzhiyun 		}
114*4882a593Smuzhiyun 		cp->sync_key_len = 0;
115*4882a593Smuzhiyun 		if (sync_key_len) {
116*4882a593Smuzhiyun 			cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
117*4882a593Smuzhiyun 			if (cp->sync_key_ptr) {
118*4882a593Smuzhiyun 				cp->sync_key_len = sync_key_len;
119*4882a593Smuzhiyun 			}
120*4882a593Smuzhiyun 		}
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 	if (!cp->sync_key_len) return;
123*4882a593Smuzhiyun 	memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
pvr2_ioread_stop(struct pvr2_ioread * cp)126*4882a593Smuzhiyun static void pvr2_ioread_stop(struct pvr2_ioread *cp)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	if (!(cp->enabled)) return;
129*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_START_STOP,
130*4882a593Smuzhiyun 		   "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
131*4882a593Smuzhiyun 	pvr2_stream_kill(cp->stream);
132*4882a593Smuzhiyun 	cp->c_buf = NULL;
133*4882a593Smuzhiyun 	cp->c_data_ptr = NULL;
134*4882a593Smuzhiyun 	cp->c_data_len = 0;
135*4882a593Smuzhiyun 	cp->c_data_offs = 0;
136*4882a593Smuzhiyun 	cp->enabled = 0;
137*4882a593Smuzhiyun 	cp->stream_running = 0;
138*4882a593Smuzhiyun 	cp->spigot_open = 0;
139*4882a593Smuzhiyun 	if (cp->sync_state) {
140*4882a593Smuzhiyun 		pvr2_trace(PVR2_TRACE_DATA_FLOW,
141*4882a593Smuzhiyun 			   "/*---TRACE_READ---*/ sync_state <== 0");
142*4882a593Smuzhiyun 		cp->sync_state = 0;
143*4882a593Smuzhiyun 	}
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
pvr2_ioread_start(struct pvr2_ioread * cp)146*4882a593Smuzhiyun static int pvr2_ioread_start(struct pvr2_ioread *cp)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	int stat;
149*4882a593Smuzhiyun 	struct pvr2_buffer *bp;
150*4882a593Smuzhiyun 	if (cp->enabled) return 0;
151*4882a593Smuzhiyun 	if (!(cp->stream)) return 0;
152*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_START_STOP,
153*4882a593Smuzhiyun 		   "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
154*4882a593Smuzhiyun 	while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
155*4882a593Smuzhiyun 		stat = pvr2_buffer_queue(bp);
156*4882a593Smuzhiyun 		if (stat < 0) {
157*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_DATA_FLOW,
158*4882a593Smuzhiyun 				   "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
159*4882a593Smuzhiyun 				   cp,stat);
160*4882a593Smuzhiyun 			pvr2_ioread_stop(cp);
161*4882a593Smuzhiyun 			return stat;
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 	}
164*4882a593Smuzhiyun 	cp->enabled = !0;
165*4882a593Smuzhiyun 	cp->c_buf = NULL;
166*4882a593Smuzhiyun 	cp->c_data_ptr = NULL;
167*4882a593Smuzhiyun 	cp->c_data_len = 0;
168*4882a593Smuzhiyun 	cp->c_data_offs = 0;
169*4882a593Smuzhiyun 	cp->stream_running = 0;
170*4882a593Smuzhiyun 	if (cp->sync_key_len) {
171*4882a593Smuzhiyun 		pvr2_trace(PVR2_TRACE_DATA_FLOW,
172*4882a593Smuzhiyun 			   "/*---TRACE_READ---*/ sync_state <== 1");
173*4882a593Smuzhiyun 		cp->sync_state = 1;
174*4882a593Smuzhiyun 		cp->sync_trashed_count = 0;
175*4882a593Smuzhiyun 		cp->sync_buf_offs = 0;
176*4882a593Smuzhiyun 	}
177*4882a593Smuzhiyun 	cp->spigot_open = 0;
178*4882a593Smuzhiyun 	return 0;
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
pvr2_ioread_get_stream(struct pvr2_ioread * cp)181*4882a593Smuzhiyun struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	return cp->stream;
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun 
pvr2_ioread_setup(struct pvr2_ioread * cp,struct pvr2_stream * sp)186*4882a593Smuzhiyun int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun 	int ret;
189*4882a593Smuzhiyun 	unsigned int idx;
190*4882a593Smuzhiyun 	struct pvr2_buffer *bp;
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	mutex_lock(&cp->mutex);
193*4882a593Smuzhiyun 	do {
194*4882a593Smuzhiyun 		if (cp->stream) {
195*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_START_STOP,
196*4882a593Smuzhiyun 				   "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
197*4882a593Smuzhiyun 				   cp);
198*4882a593Smuzhiyun 			pvr2_ioread_stop(cp);
199*4882a593Smuzhiyun 			pvr2_stream_kill(cp->stream);
200*4882a593Smuzhiyun 			if (pvr2_stream_get_buffer_count(cp->stream)) {
201*4882a593Smuzhiyun 				pvr2_stream_set_buffer_count(cp->stream,0);
202*4882a593Smuzhiyun 			}
203*4882a593Smuzhiyun 			cp->stream = NULL;
204*4882a593Smuzhiyun 		}
205*4882a593Smuzhiyun 		if (sp) {
206*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_START_STOP,
207*4882a593Smuzhiyun 				   "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
208*4882a593Smuzhiyun 				   cp);
209*4882a593Smuzhiyun 			pvr2_stream_kill(sp);
210*4882a593Smuzhiyun 			ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
211*4882a593Smuzhiyun 			if (ret < 0) {
212*4882a593Smuzhiyun 				mutex_unlock(&cp->mutex);
213*4882a593Smuzhiyun 				return ret;
214*4882a593Smuzhiyun 			}
215*4882a593Smuzhiyun 			for (idx = 0; idx < BUFFER_COUNT; idx++) {
216*4882a593Smuzhiyun 				bp = pvr2_stream_get_buffer(sp,idx);
217*4882a593Smuzhiyun 				pvr2_buffer_set_buffer(bp,
218*4882a593Smuzhiyun 						       cp->buffer_storage[idx],
219*4882a593Smuzhiyun 						       BUFFER_SIZE);
220*4882a593Smuzhiyun 			}
221*4882a593Smuzhiyun 			cp->stream = sp;
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 	} while (0);
224*4882a593Smuzhiyun 	mutex_unlock(&cp->mutex);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	return 0;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun 
pvr2_ioread_set_enabled(struct pvr2_ioread * cp,int fl)229*4882a593Smuzhiyun int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun 	int ret = 0;
232*4882a593Smuzhiyun 	if ((!fl) == (!(cp->enabled))) return ret;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	mutex_lock(&cp->mutex);
235*4882a593Smuzhiyun 	do {
236*4882a593Smuzhiyun 		if (fl) {
237*4882a593Smuzhiyun 			ret = pvr2_ioread_start(cp);
238*4882a593Smuzhiyun 		} else {
239*4882a593Smuzhiyun 			pvr2_ioread_stop(cp);
240*4882a593Smuzhiyun 		}
241*4882a593Smuzhiyun 	} while (0);
242*4882a593Smuzhiyun 	mutex_unlock(&cp->mutex);
243*4882a593Smuzhiyun 	return ret;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
pvr2_ioread_get_buffer(struct pvr2_ioread * cp)246*4882a593Smuzhiyun static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	int stat;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	while (cp->c_data_len <= cp->c_data_offs) {
251*4882a593Smuzhiyun 		if (cp->c_buf) {
252*4882a593Smuzhiyun 			// Flush out current buffer first.
253*4882a593Smuzhiyun 			stat = pvr2_buffer_queue(cp->c_buf);
254*4882a593Smuzhiyun 			if (stat < 0) {
255*4882a593Smuzhiyun 				// Streaming error...
256*4882a593Smuzhiyun 				pvr2_trace(PVR2_TRACE_DATA_FLOW,
257*4882a593Smuzhiyun 					   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
258*4882a593Smuzhiyun 					   cp,stat);
259*4882a593Smuzhiyun 				pvr2_ioread_stop(cp);
260*4882a593Smuzhiyun 				return 0;
261*4882a593Smuzhiyun 			}
262*4882a593Smuzhiyun 			cp->c_buf = NULL;
263*4882a593Smuzhiyun 			cp->c_data_ptr = NULL;
264*4882a593Smuzhiyun 			cp->c_data_len = 0;
265*4882a593Smuzhiyun 			cp->c_data_offs = 0;
266*4882a593Smuzhiyun 		}
267*4882a593Smuzhiyun 		// Now get a freshly filled buffer.
268*4882a593Smuzhiyun 		cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
269*4882a593Smuzhiyun 		if (!cp->c_buf) break; // Nothing ready; done.
270*4882a593Smuzhiyun 		cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
271*4882a593Smuzhiyun 		if (!cp->c_data_len) {
272*4882a593Smuzhiyun 			// Nothing transferred.  Was there an error?
273*4882a593Smuzhiyun 			stat = pvr2_buffer_get_status(cp->c_buf);
274*4882a593Smuzhiyun 			if (stat < 0) {
275*4882a593Smuzhiyun 				// Streaming error...
276*4882a593Smuzhiyun 				pvr2_trace(PVR2_TRACE_DATA_FLOW,
277*4882a593Smuzhiyun 					   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
278*4882a593Smuzhiyun 					   cp,stat);
279*4882a593Smuzhiyun 				pvr2_ioread_stop(cp);
280*4882a593Smuzhiyun 				// Give up.
281*4882a593Smuzhiyun 				return 0;
282*4882a593Smuzhiyun 			}
283*4882a593Smuzhiyun 			// Start over...
284*4882a593Smuzhiyun 			continue;
285*4882a593Smuzhiyun 		}
286*4882a593Smuzhiyun 		cp->c_data_offs = 0;
287*4882a593Smuzhiyun 		cp->c_data_ptr = cp->buffer_storage[
288*4882a593Smuzhiyun 			pvr2_buffer_get_id(cp->c_buf)];
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	return !0;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun 
pvr2_ioread_filter(struct pvr2_ioread * cp)293*4882a593Smuzhiyun static void pvr2_ioread_filter(struct pvr2_ioread *cp)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	unsigned int idx;
296*4882a593Smuzhiyun 	if (!cp->enabled) return;
297*4882a593Smuzhiyun 	if (cp->sync_state != 1) return;
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	// Search the stream for our synchronization key.  This is made
300*4882a593Smuzhiyun 	// complicated by the fact that in order to be honest with
301*4882a593Smuzhiyun 	// ourselves here we must search across buffer boundaries...
302*4882a593Smuzhiyun 	mutex_lock(&cp->mutex);
303*4882a593Smuzhiyun 	while (1) {
304*4882a593Smuzhiyun 		// Ensure we have a buffer
305*4882a593Smuzhiyun 		if (!pvr2_ioread_get_buffer(cp)) break;
306*4882a593Smuzhiyun 		if (!cp->c_data_len) break;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		// Now walk the buffer contents until we match the key or
309*4882a593Smuzhiyun 		// run out of buffer data.
310*4882a593Smuzhiyun 		for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
311*4882a593Smuzhiyun 			if (cp->sync_buf_offs >= cp->sync_key_len) break;
312*4882a593Smuzhiyun 			if (cp->c_data_ptr[idx] ==
313*4882a593Smuzhiyun 			    cp->sync_key_ptr[cp->sync_buf_offs]) {
314*4882a593Smuzhiyun 				// Found the next key byte
315*4882a593Smuzhiyun 				(cp->sync_buf_offs)++;
316*4882a593Smuzhiyun 			} else {
317*4882a593Smuzhiyun 				// Whoops, mismatched.  Start key over...
318*4882a593Smuzhiyun 				cp->sync_buf_offs = 0;
319*4882a593Smuzhiyun 			}
320*4882a593Smuzhiyun 		}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		// Consume what we've walked through
323*4882a593Smuzhiyun 		cp->c_data_offs += idx;
324*4882a593Smuzhiyun 		cp->sync_trashed_count += idx;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 		// If we've found the key, then update state and get out.
327*4882a593Smuzhiyun 		if (cp->sync_buf_offs >= cp->sync_key_len) {
328*4882a593Smuzhiyun 			cp->sync_trashed_count -= cp->sync_key_len;
329*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_DATA_FLOW,
330*4882a593Smuzhiyun 				   "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
331*4882a593Smuzhiyun 				   cp->sync_trashed_count);
332*4882a593Smuzhiyun 			cp->sync_state = 2;
333*4882a593Smuzhiyun 			cp->sync_buf_offs = 0;
334*4882a593Smuzhiyun 			break;
335*4882a593Smuzhiyun 		}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		if (cp->c_data_offs < cp->c_data_len) {
338*4882a593Smuzhiyun 			// Sanity check - should NEVER get here
339*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
340*4882a593Smuzhiyun 				   "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
341*4882a593Smuzhiyun 				   cp->c_data_len,cp->c_data_offs);
342*4882a593Smuzhiyun 			// Get out so we don't get stuck in an infinite
343*4882a593Smuzhiyun 			// loop.
344*4882a593Smuzhiyun 			break;
345*4882a593Smuzhiyun 		}
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 		continue; // (for clarity)
348*4882a593Smuzhiyun 	}
349*4882a593Smuzhiyun 	mutex_unlock(&cp->mutex);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
pvr2_ioread_avail(struct pvr2_ioread * cp)352*4882a593Smuzhiyun int pvr2_ioread_avail(struct pvr2_ioread *cp)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun 	int ret;
355*4882a593Smuzhiyun 	if (!(cp->enabled)) {
356*4882a593Smuzhiyun 		// Stream is not enabled; so this is an I/O error
357*4882a593Smuzhiyun 		return -EIO;
358*4882a593Smuzhiyun 	}
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (cp->sync_state == 1) {
361*4882a593Smuzhiyun 		pvr2_ioread_filter(cp);
362*4882a593Smuzhiyun 		if (cp->sync_state == 1) return -EAGAIN;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	ret = 0;
366*4882a593Smuzhiyun 	if (cp->stream_running) {
367*4882a593Smuzhiyun 		if (!pvr2_stream_get_ready_count(cp->stream)) {
368*4882a593Smuzhiyun 			// No data available at all right now.
369*4882a593Smuzhiyun 			ret = -EAGAIN;
370*4882a593Smuzhiyun 		}
371*4882a593Smuzhiyun 	} else {
372*4882a593Smuzhiyun 		if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
373*4882a593Smuzhiyun 			// Haven't buffered up enough yet; try again later
374*4882a593Smuzhiyun 			ret = -EAGAIN;
375*4882a593Smuzhiyun 		}
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if ((!(cp->spigot_open)) != (!(ret == 0))) {
379*4882a593Smuzhiyun 		cp->spigot_open = (ret == 0);
380*4882a593Smuzhiyun 		pvr2_trace(PVR2_TRACE_DATA_FLOW,
381*4882a593Smuzhiyun 			   "/*---TRACE_READ---*/ data is %s",
382*4882a593Smuzhiyun 			   cp->spigot_open ? "available" : "pending");
383*4882a593Smuzhiyun 	}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 	return ret;
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun 
pvr2_ioread_read(struct pvr2_ioread * cp,void __user * buf,unsigned int cnt)388*4882a593Smuzhiyun int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun 	unsigned int copied_cnt;
391*4882a593Smuzhiyun 	unsigned int bcnt;
392*4882a593Smuzhiyun 	const char *src;
393*4882a593Smuzhiyun 	int stat;
394*4882a593Smuzhiyun 	int ret = 0;
395*4882a593Smuzhiyun 	unsigned int req_cnt = cnt;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (!cnt) {
398*4882a593Smuzhiyun 		pvr2_trace(PVR2_TRACE_TRAP,
399*4882a593Smuzhiyun 			   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
400*4882a593Smuzhiyun cp);
401*4882a593Smuzhiyun 		return 0;
402*4882a593Smuzhiyun 	}
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	stat = pvr2_ioread_avail(cp);
405*4882a593Smuzhiyun 	if (stat < 0) return stat;
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	cp->stream_running = !0;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	mutex_lock(&cp->mutex);
410*4882a593Smuzhiyun 	do {
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 		// Suck data out of the buffers and copy to the user
413*4882a593Smuzhiyun 		copied_cnt = 0;
414*4882a593Smuzhiyun 		if (!buf) cnt = 0;
415*4882a593Smuzhiyun 		while (1) {
416*4882a593Smuzhiyun 			if (!pvr2_ioread_get_buffer(cp)) {
417*4882a593Smuzhiyun 				ret = -EIO;
418*4882a593Smuzhiyun 				break;
419*4882a593Smuzhiyun 			}
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 			if (!cnt) break;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 			if (cp->sync_state == 2) {
424*4882a593Smuzhiyun 				// We're repeating the sync key data into
425*4882a593Smuzhiyun 				// the stream.
426*4882a593Smuzhiyun 				src = cp->sync_key_ptr + cp->sync_buf_offs;
427*4882a593Smuzhiyun 				bcnt = cp->sync_key_len - cp->sync_buf_offs;
428*4882a593Smuzhiyun 			} else {
429*4882a593Smuzhiyun 				// Normal buffer copy
430*4882a593Smuzhiyun 				src = cp->c_data_ptr + cp->c_data_offs;
431*4882a593Smuzhiyun 				bcnt = cp->c_data_len - cp->c_data_offs;
432*4882a593Smuzhiyun 			}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 			if (!bcnt) break;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 			// Don't run past user's buffer
437*4882a593Smuzhiyun 			if (bcnt > cnt) bcnt = cnt;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 			if (copy_to_user(buf,src,bcnt)) {
440*4882a593Smuzhiyun 				// User supplied a bad pointer?
441*4882a593Smuzhiyun 				// Give up - this *will* cause data
442*4882a593Smuzhiyun 				// to be lost.
443*4882a593Smuzhiyun 				ret = -EFAULT;
444*4882a593Smuzhiyun 				break;
445*4882a593Smuzhiyun 			}
446*4882a593Smuzhiyun 			cnt -= bcnt;
447*4882a593Smuzhiyun 			buf += bcnt;
448*4882a593Smuzhiyun 			copied_cnt += bcnt;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 			if (cp->sync_state == 2) {
451*4882a593Smuzhiyun 				// Update offset inside sync key that we're
452*4882a593Smuzhiyun 				// repeating back out.
453*4882a593Smuzhiyun 				cp->sync_buf_offs += bcnt;
454*4882a593Smuzhiyun 				if (cp->sync_buf_offs >= cp->sync_key_len) {
455*4882a593Smuzhiyun 					// Consumed entire key; switch mode
456*4882a593Smuzhiyun 					// to normal.
457*4882a593Smuzhiyun 					pvr2_trace(PVR2_TRACE_DATA_FLOW,
458*4882a593Smuzhiyun 						   "/*---TRACE_READ---*/ sync_state <== 0");
459*4882a593Smuzhiyun 					cp->sync_state = 0;
460*4882a593Smuzhiyun 				}
461*4882a593Smuzhiyun 			} else {
462*4882a593Smuzhiyun 				// Update buffer offset.
463*4882a593Smuzhiyun 				cp->c_data_offs += bcnt;
464*4882a593Smuzhiyun 			}
465*4882a593Smuzhiyun 		}
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	} while (0);
468*4882a593Smuzhiyun 	mutex_unlock(&cp->mutex);
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	if (!ret) {
471*4882a593Smuzhiyun 		if (copied_cnt) {
472*4882a593Smuzhiyun 			// If anything was copied, return that count
473*4882a593Smuzhiyun 			ret = copied_cnt;
474*4882a593Smuzhiyun 		} else {
475*4882a593Smuzhiyun 			// Nothing copied; suggest to caller that another
476*4882a593Smuzhiyun 			// attempt should be tried again later
477*4882a593Smuzhiyun 			ret = -EAGAIN;
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_DATA_FLOW,
482*4882a593Smuzhiyun 		   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
483*4882a593Smuzhiyun 		   cp,req_cnt,ret);
484*4882a593Smuzhiyun 	return ret;
485*4882a593Smuzhiyun }
486