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