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