1*2504ba9fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20c0d06caSMauro Carvalho Chehab /*
30c0d06caSMauro Carvalho Chehab *
40c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 Mike Isely <isely@pobox.com>
50c0d06caSMauro Carvalho Chehab */
60c0d06caSMauro Carvalho Chehab
70c0d06caSMauro Carvalho Chehab #include "pvrusb2-ioread.h"
80c0d06caSMauro Carvalho Chehab #include "pvrusb2-debug.h"
90c0d06caSMauro Carvalho Chehab #include <linux/errno.h>
100c0d06caSMauro Carvalho Chehab #include <linux/string.h>
110c0d06caSMauro Carvalho Chehab #include <linux/mm.h>
120c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
130c0d06caSMauro Carvalho Chehab #include <linux/mutex.h>
147c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
150c0d06caSMauro Carvalho Chehab
160c0d06caSMauro Carvalho Chehab #define BUFFER_COUNT 32
170c0d06caSMauro Carvalho Chehab #define BUFFER_SIZE PAGE_ALIGN(0x4000)
180c0d06caSMauro Carvalho Chehab
190c0d06caSMauro Carvalho Chehab struct pvr2_ioread {
200c0d06caSMauro Carvalho Chehab struct pvr2_stream *stream;
210c0d06caSMauro Carvalho Chehab char *buffer_storage[BUFFER_COUNT];
220c0d06caSMauro Carvalho Chehab char *sync_key_ptr;
230c0d06caSMauro Carvalho Chehab unsigned int sync_key_len;
240c0d06caSMauro Carvalho Chehab unsigned int sync_buf_offs;
250c0d06caSMauro Carvalho Chehab unsigned int sync_state;
260c0d06caSMauro Carvalho Chehab unsigned int sync_trashed_count;
270c0d06caSMauro Carvalho Chehab int enabled; // Streaming is on
280c0d06caSMauro Carvalho Chehab int spigot_open; // OK to pass data to client
290c0d06caSMauro Carvalho Chehab int stream_running; // Passing data to client now
300c0d06caSMauro Carvalho Chehab
310c0d06caSMauro Carvalho Chehab /* State relevant to current buffer being read */
320c0d06caSMauro Carvalho Chehab struct pvr2_buffer *c_buf;
330c0d06caSMauro Carvalho Chehab char *c_data_ptr;
340c0d06caSMauro Carvalho Chehab unsigned int c_data_len;
350c0d06caSMauro Carvalho Chehab unsigned int c_data_offs;
360c0d06caSMauro Carvalho Chehab struct mutex mutex;
370c0d06caSMauro Carvalho Chehab };
380c0d06caSMauro Carvalho Chehab
pvr2_ioread_init(struct pvr2_ioread * cp)390c0d06caSMauro Carvalho Chehab static int pvr2_ioread_init(struct pvr2_ioread *cp)
400c0d06caSMauro Carvalho Chehab {
410c0d06caSMauro Carvalho Chehab unsigned int idx;
420c0d06caSMauro Carvalho Chehab
430c0d06caSMauro Carvalho Chehab cp->stream = NULL;
440c0d06caSMauro Carvalho Chehab mutex_init(&cp->mutex);
450c0d06caSMauro Carvalho Chehab
460c0d06caSMauro Carvalho Chehab for (idx = 0; idx < BUFFER_COUNT; idx++) {
470c0d06caSMauro Carvalho Chehab cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
480c0d06caSMauro Carvalho Chehab if (!(cp->buffer_storage[idx])) break;
490c0d06caSMauro Carvalho Chehab }
500c0d06caSMauro Carvalho Chehab
510c0d06caSMauro Carvalho Chehab if (idx < BUFFER_COUNT) {
520c0d06caSMauro Carvalho Chehab // An allocation appears to have failed
530c0d06caSMauro Carvalho Chehab for (idx = 0; idx < BUFFER_COUNT; idx++) {
540c0d06caSMauro Carvalho Chehab if (!(cp->buffer_storage[idx])) continue;
550c0d06caSMauro Carvalho Chehab kfree(cp->buffer_storage[idx]);
560c0d06caSMauro Carvalho Chehab }
570c0d06caSMauro Carvalho Chehab return -ENOMEM;
580c0d06caSMauro Carvalho Chehab }
590c0d06caSMauro Carvalho Chehab return 0;
600c0d06caSMauro Carvalho Chehab }
610c0d06caSMauro Carvalho Chehab
pvr2_ioread_done(struct pvr2_ioread * cp)620c0d06caSMauro Carvalho Chehab static void pvr2_ioread_done(struct pvr2_ioread *cp)
630c0d06caSMauro Carvalho Chehab {
640c0d06caSMauro Carvalho Chehab unsigned int idx;
650c0d06caSMauro Carvalho Chehab
660c0d06caSMauro Carvalho Chehab pvr2_ioread_setup(cp,NULL);
670c0d06caSMauro Carvalho Chehab for (idx = 0; idx < BUFFER_COUNT; idx++) {
680c0d06caSMauro Carvalho Chehab if (!(cp->buffer_storage[idx])) continue;
690c0d06caSMauro Carvalho Chehab kfree(cp->buffer_storage[idx]);
700c0d06caSMauro Carvalho Chehab }
710c0d06caSMauro Carvalho Chehab }
720c0d06caSMauro Carvalho Chehab
pvr2_ioread_create(void)730c0d06caSMauro Carvalho Chehab struct pvr2_ioread *pvr2_ioread_create(void)
740c0d06caSMauro Carvalho Chehab {
750c0d06caSMauro Carvalho Chehab struct pvr2_ioread *cp;
760c0d06caSMauro Carvalho Chehab cp = kzalloc(sizeof(*cp),GFP_KERNEL);
770c0d06caSMauro Carvalho Chehab if (!cp) return NULL;
780c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
790c0d06caSMauro Carvalho Chehab if (pvr2_ioread_init(cp) < 0) {
800c0d06caSMauro Carvalho Chehab kfree(cp);
810c0d06caSMauro Carvalho Chehab return NULL;
820c0d06caSMauro Carvalho Chehab }
830c0d06caSMauro Carvalho Chehab return cp;
840c0d06caSMauro Carvalho Chehab }
850c0d06caSMauro Carvalho Chehab
pvr2_ioread_destroy(struct pvr2_ioread * cp)860c0d06caSMauro Carvalho Chehab void pvr2_ioread_destroy(struct pvr2_ioread *cp)
870c0d06caSMauro Carvalho Chehab {
880c0d06caSMauro Carvalho Chehab if (!cp) return;
890c0d06caSMauro Carvalho Chehab pvr2_ioread_done(cp);
900c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
910c0d06caSMauro Carvalho Chehab if (cp->sync_key_ptr) {
920c0d06caSMauro Carvalho Chehab kfree(cp->sync_key_ptr);
930c0d06caSMauro Carvalho Chehab cp->sync_key_ptr = NULL;
940c0d06caSMauro Carvalho Chehab }
950c0d06caSMauro Carvalho Chehab kfree(cp);
960c0d06caSMauro Carvalho Chehab }
970c0d06caSMauro Carvalho Chehab
pvr2_ioread_set_sync_key(struct pvr2_ioread * cp,const char * sync_key_ptr,unsigned int sync_key_len)980c0d06caSMauro Carvalho Chehab void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
990c0d06caSMauro Carvalho Chehab const char *sync_key_ptr,
1000c0d06caSMauro Carvalho Chehab unsigned int sync_key_len)
1010c0d06caSMauro Carvalho Chehab {
1020c0d06caSMauro Carvalho Chehab if (!cp) return;
1030c0d06caSMauro Carvalho Chehab
1040c0d06caSMauro Carvalho Chehab if (!sync_key_ptr) sync_key_len = 0;
1050c0d06caSMauro Carvalho Chehab if ((sync_key_len == cp->sync_key_len) &&
1060c0d06caSMauro Carvalho Chehab ((!sync_key_len) ||
1070c0d06caSMauro Carvalho Chehab (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
1080c0d06caSMauro Carvalho Chehab
1090c0d06caSMauro Carvalho Chehab if (sync_key_len != cp->sync_key_len) {
1100c0d06caSMauro Carvalho Chehab if (cp->sync_key_ptr) {
1110c0d06caSMauro Carvalho Chehab kfree(cp->sync_key_ptr);
1120c0d06caSMauro Carvalho Chehab cp->sync_key_ptr = NULL;
1130c0d06caSMauro Carvalho Chehab }
1140c0d06caSMauro Carvalho Chehab cp->sync_key_len = 0;
1150c0d06caSMauro Carvalho Chehab if (sync_key_len) {
1160c0d06caSMauro Carvalho Chehab cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
1170c0d06caSMauro Carvalho Chehab if (cp->sync_key_ptr) {
1180c0d06caSMauro Carvalho Chehab cp->sync_key_len = sync_key_len;
1190c0d06caSMauro Carvalho Chehab }
1200c0d06caSMauro Carvalho Chehab }
1210c0d06caSMauro Carvalho Chehab }
1220c0d06caSMauro Carvalho Chehab if (!cp->sync_key_len) return;
1230c0d06caSMauro Carvalho Chehab memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
1240c0d06caSMauro Carvalho Chehab }
1250c0d06caSMauro Carvalho Chehab
pvr2_ioread_stop(struct pvr2_ioread * cp)1260c0d06caSMauro Carvalho Chehab static void pvr2_ioread_stop(struct pvr2_ioread *cp)
1270c0d06caSMauro Carvalho Chehab {
1280c0d06caSMauro Carvalho Chehab if (!(cp->enabled)) return;
1290c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_START_STOP,
1300c0d06caSMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
1310c0d06caSMauro Carvalho Chehab pvr2_stream_kill(cp->stream);
1320c0d06caSMauro Carvalho Chehab cp->c_buf = NULL;
1330c0d06caSMauro Carvalho Chehab cp->c_data_ptr = NULL;
1340c0d06caSMauro Carvalho Chehab cp->c_data_len = 0;
1350c0d06caSMauro Carvalho Chehab cp->c_data_offs = 0;
1360c0d06caSMauro Carvalho Chehab cp->enabled = 0;
1370c0d06caSMauro Carvalho Chehab cp->stream_running = 0;
1380c0d06caSMauro Carvalho Chehab cp->spigot_open = 0;
1390c0d06caSMauro Carvalho Chehab if (cp->sync_state) {
1400c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
1410c0d06caSMauro Carvalho Chehab "/*---TRACE_READ---*/ sync_state <== 0");
1420c0d06caSMauro Carvalho Chehab cp->sync_state = 0;
1430c0d06caSMauro Carvalho Chehab }
1440c0d06caSMauro Carvalho Chehab }
1450c0d06caSMauro Carvalho Chehab
pvr2_ioread_start(struct pvr2_ioread * cp)1460c0d06caSMauro Carvalho Chehab static int pvr2_ioread_start(struct pvr2_ioread *cp)
1470c0d06caSMauro Carvalho Chehab {
1480c0d06caSMauro Carvalho Chehab int stat;
1490c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp;
1500c0d06caSMauro Carvalho Chehab if (cp->enabled) return 0;
1510c0d06caSMauro Carvalho Chehab if (!(cp->stream)) return 0;
1520c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_START_STOP,
1530c0d06caSMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
1540c0d06caSMauro Carvalho Chehab while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
1550c0d06caSMauro Carvalho Chehab stat = pvr2_buffer_queue(bp);
1560c0d06caSMauro Carvalho Chehab if (stat < 0) {
1570c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
15896292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
1590c0d06caSMauro Carvalho Chehab cp,stat);
1600c0d06caSMauro Carvalho Chehab pvr2_ioread_stop(cp);
1610c0d06caSMauro Carvalho Chehab return stat;
1620c0d06caSMauro Carvalho Chehab }
1630c0d06caSMauro Carvalho Chehab }
1640c0d06caSMauro Carvalho Chehab cp->enabled = !0;
1650c0d06caSMauro Carvalho Chehab cp->c_buf = NULL;
1660c0d06caSMauro Carvalho Chehab cp->c_data_ptr = NULL;
1670c0d06caSMauro Carvalho Chehab cp->c_data_len = 0;
1680c0d06caSMauro Carvalho Chehab cp->c_data_offs = 0;
1690c0d06caSMauro Carvalho Chehab cp->stream_running = 0;
1700c0d06caSMauro Carvalho Chehab if (cp->sync_key_len) {
1710c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
1720c0d06caSMauro Carvalho Chehab "/*---TRACE_READ---*/ sync_state <== 1");
1730c0d06caSMauro Carvalho Chehab cp->sync_state = 1;
1740c0d06caSMauro Carvalho Chehab cp->sync_trashed_count = 0;
1750c0d06caSMauro Carvalho Chehab cp->sync_buf_offs = 0;
1760c0d06caSMauro Carvalho Chehab }
1770c0d06caSMauro Carvalho Chehab cp->spigot_open = 0;
1780c0d06caSMauro Carvalho Chehab return 0;
1790c0d06caSMauro Carvalho Chehab }
1800c0d06caSMauro Carvalho Chehab
pvr2_ioread_get_stream(struct pvr2_ioread * cp)1810c0d06caSMauro Carvalho Chehab struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
1820c0d06caSMauro Carvalho Chehab {
1830c0d06caSMauro Carvalho Chehab return cp->stream;
1840c0d06caSMauro Carvalho Chehab }
1850c0d06caSMauro Carvalho Chehab
pvr2_ioread_setup(struct pvr2_ioread * cp,struct pvr2_stream * sp)1860c0d06caSMauro Carvalho Chehab int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
1870c0d06caSMauro Carvalho Chehab {
1880c0d06caSMauro Carvalho Chehab int ret;
1890c0d06caSMauro Carvalho Chehab unsigned int idx;
1900c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp;
1910c0d06caSMauro Carvalho Chehab
192f419edd4SMauro Carvalho Chehab mutex_lock(&cp->mutex);
193f419edd4SMauro Carvalho Chehab do {
1940c0d06caSMauro Carvalho Chehab if (cp->stream) {
1950c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_START_STOP,
19696292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
19796292c89SMauro Carvalho Chehab cp);
1980c0d06caSMauro Carvalho Chehab pvr2_ioread_stop(cp);
1990c0d06caSMauro Carvalho Chehab pvr2_stream_kill(cp->stream);
2000c0d06caSMauro Carvalho Chehab if (pvr2_stream_get_buffer_count(cp->stream)) {
2010c0d06caSMauro Carvalho Chehab pvr2_stream_set_buffer_count(cp->stream,0);
2020c0d06caSMauro Carvalho Chehab }
2030c0d06caSMauro Carvalho Chehab cp->stream = NULL;
2040c0d06caSMauro Carvalho Chehab }
2050c0d06caSMauro Carvalho Chehab if (sp) {
2060c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_START_STOP,
20796292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
20896292c89SMauro Carvalho Chehab cp);
2090c0d06caSMauro Carvalho Chehab pvr2_stream_kill(sp);
2100c0d06caSMauro Carvalho Chehab ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
2110c0d06caSMauro Carvalho Chehab if (ret < 0) {
2120c0d06caSMauro Carvalho Chehab mutex_unlock(&cp->mutex);
2130c0d06caSMauro Carvalho Chehab return ret;
2140c0d06caSMauro Carvalho Chehab }
2150c0d06caSMauro Carvalho Chehab for (idx = 0; idx < BUFFER_COUNT; idx++) {
2160c0d06caSMauro Carvalho Chehab bp = pvr2_stream_get_buffer(sp,idx);
2170c0d06caSMauro Carvalho Chehab pvr2_buffer_set_buffer(bp,
2180c0d06caSMauro Carvalho Chehab cp->buffer_storage[idx],
2190c0d06caSMauro Carvalho Chehab BUFFER_SIZE);
2200c0d06caSMauro Carvalho Chehab }
2210c0d06caSMauro Carvalho Chehab cp->stream = sp;
2220c0d06caSMauro Carvalho Chehab }
223f419edd4SMauro Carvalho Chehab } while (0);
224f419edd4SMauro Carvalho Chehab mutex_unlock(&cp->mutex);
2250c0d06caSMauro Carvalho Chehab
2260c0d06caSMauro Carvalho Chehab return 0;
2270c0d06caSMauro Carvalho Chehab }
2280c0d06caSMauro Carvalho Chehab
pvr2_ioread_set_enabled(struct pvr2_ioread * cp,int fl)2290c0d06caSMauro Carvalho Chehab int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
2300c0d06caSMauro Carvalho Chehab {
2310c0d06caSMauro Carvalho Chehab int ret = 0;
2320c0d06caSMauro Carvalho Chehab if ((!fl) == (!(cp->enabled))) return ret;
2330c0d06caSMauro Carvalho Chehab
234f419edd4SMauro Carvalho Chehab mutex_lock(&cp->mutex);
235f419edd4SMauro Carvalho Chehab do {
2360c0d06caSMauro Carvalho Chehab if (fl) {
2370c0d06caSMauro Carvalho Chehab ret = pvr2_ioread_start(cp);
2380c0d06caSMauro Carvalho Chehab } else {
2390c0d06caSMauro Carvalho Chehab pvr2_ioread_stop(cp);
2400c0d06caSMauro Carvalho Chehab }
241f419edd4SMauro Carvalho Chehab } while (0);
242f419edd4SMauro Carvalho Chehab mutex_unlock(&cp->mutex);
2430c0d06caSMauro Carvalho Chehab return ret;
2440c0d06caSMauro Carvalho Chehab }
2450c0d06caSMauro Carvalho Chehab
pvr2_ioread_get_buffer(struct pvr2_ioread * cp)2460c0d06caSMauro Carvalho Chehab static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
2470c0d06caSMauro Carvalho Chehab {
2480c0d06caSMauro Carvalho Chehab int stat;
2490c0d06caSMauro Carvalho Chehab
2500c0d06caSMauro Carvalho Chehab while (cp->c_data_len <= cp->c_data_offs) {
2510c0d06caSMauro Carvalho Chehab if (cp->c_buf) {
2520c0d06caSMauro Carvalho Chehab // Flush out current buffer first.
2530c0d06caSMauro Carvalho Chehab stat = pvr2_buffer_queue(cp->c_buf);
2540c0d06caSMauro Carvalho Chehab if (stat < 0) {
2550c0d06caSMauro Carvalho Chehab // Streaming error...
2560c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
25796292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
2580c0d06caSMauro Carvalho Chehab cp,stat);
2590c0d06caSMauro Carvalho Chehab pvr2_ioread_stop(cp);
2600c0d06caSMauro Carvalho Chehab return 0;
2610c0d06caSMauro Carvalho Chehab }
2620c0d06caSMauro Carvalho Chehab cp->c_buf = NULL;
2630c0d06caSMauro Carvalho Chehab cp->c_data_ptr = NULL;
2640c0d06caSMauro Carvalho Chehab cp->c_data_len = 0;
2650c0d06caSMauro Carvalho Chehab cp->c_data_offs = 0;
2660c0d06caSMauro Carvalho Chehab }
2670c0d06caSMauro Carvalho Chehab // Now get a freshly filled buffer.
2680c0d06caSMauro Carvalho Chehab cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
2690c0d06caSMauro Carvalho Chehab if (!cp->c_buf) break; // Nothing ready; done.
2700c0d06caSMauro Carvalho Chehab cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
2710c0d06caSMauro Carvalho Chehab if (!cp->c_data_len) {
2720c0d06caSMauro Carvalho Chehab // Nothing transferred. Was there an error?
2730c0d06caSMauro Carvalho Chehab stat = pvr2_buffer_get_status(cp->c_buf);
2740c0d06caSMauro Carvalho Chehab if (stat < 0) {
2750c0d06caSMauro Carvalho Chehab // Streaming error...
2760c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
27796292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
2780c0d06caSMauro Carvalho Chehab cp,stat);
2790c0d06caSMauro Carvalho Chehab pvr2_ioread_stop(cp);
2800c0d06caSMauro Carvalho Chehab // Give up.
2810c0d06caSMauro Carvalho Chehab return 0;
2820c0d06caSMauro Carvalho Chehab }
2830c0d06caSMauro Carvalho Chehab // Start over...
2840c0d06caSMauro Carvalho Chehab continue;
2850c0d06caSMauro Carvalho Chehab }
2860c0d06caSMauro Carvalho Chehab cp->c_data_offs = 0;
2870c0d06caSMauro Carvalho Chehab cp->c_data_ptr = cp->buffer_storage[
2880c0d06caSMauro Carvalho Chehab pvr2_buffer_get_id(cp->c_buf)];
2890c0d06caSMauro Carvalho Chehab }
2900c0d06caSMauro Carvalho Chehab return !0;
2910c0d06caSMauro Carvalho Chehab }
2920c0d06caSMauro Carvalho Chehab
pvr2_ioread_filter(struct pvr2_ioread * cp)2930c0d06caSMauro Carvalho Chehab static void pvr2_ioread_filter(struct pvr2_ioread *cp)
2940c0d06caSMauro Carvalho Chehab {
2950c0d06caSMauro Carvalho Chehab unsigned int idx;
2960c0d06caSMauro Carvalho Chehab if (!cp->enabled) return;
2970c0d06caSMauro Carvalho Chehab if (cp->sync_state != 1) return;
2980c0d06caSMauro Carvalho Chehab
2990c0d06caSMauro Carvalho Chehab // Search the stream for our synchronization key. This is made
3000c0d06caSMauro Carvalho Chehab // complicated by the fact that in order to be honest with
3010c0d06caSMauro Carvalho Chehab // ourselves here we must search across buffer boundaries...
302f419edd4SMauro Carvalho Chehab mutex_lock(&cp->mutex);
303f419edd4SMauro Carvalho Chehab while (1) {
3040c0d06caSMauro Carvalho Chehab // Ensure we have a buffer
3050c0d06caSMauro Carvalho Chehab if (!pvr2_ioread_get_buffer(cp)) break;
3060c0d06caSMauro Carvalho Chehab if (!cp->c_data_len) break;
3070c0d06caSMauro Carvalho Chehab
3080c0d06caSMauro Carvalho Chehab // Now walk the buffer contents until we match the key or
3090c0d06caSMauro Carvalho Chehab // run out of buffer data.
3100c0d06caSMauro Carvalho Chehab for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
3110c0d06caSMauro Carvalho Chehab if (cp->sync_buf_offs >= cp->sync_key_len) break;
3120c0d06caSMauro Carvalho Chehab if (cp->c_data_ptr[idx] ==
3130c0d06caSMauro Carvalho Chehab cp->sync_key_ptr[cp->sync_buf_offs]) {
3140c0d06caSMauro Carvalho Chehab // Found the next key byte
3150c0d06caSMauro Carvalho Chehab (cp->sync_buf_offs)++;
3160c0d06caSMauro Carvalho Chehab } else {
3170c0d06caSMauro Carvalho Chehab // Whoops, mismatched. Start key over...
3180c0d06caSMauro Carvalho Chehab cp->sync_buf_offs = 0;
3190c0d06caSMauro Carvalho Chehab }
3200c0d06caSMauro Carvalho Chehab }
3210c0d06caSMauro Carvalho Chehab
3220c0d06caSMauro Carvalho Chehab // Consume what we've walked through
3230c0d06caSMauro Carvalho Chehab cp->c_data_offs += idx;
3240c0d06caSMauro Carvalho Chehab cp->sync_trashed_count += idx;
3250c0d06caSMauro Carvalho Chehab
3260c0d06caSMauro Carvalho Chehab // If we've found the key, then update state and get out.
3270c0d06caSMauro Carvalho Chehab if (cp->sync_buf_offs >= cp->sync_key_len) {
3280c0d06caSMauro Carvalho Chehab cp->sync_trashed_count -= cp->sync_key_len;
3290c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
33096292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
3310c0d06caSMauro Carvalho Chehab cp->sync_trashed_count);
3320c0d06caSMauro Carvalho Chehab cp->sync_state = 2;
3330c0d06caSMauro Carvalho Chehab cp->sync_buf_offs = 0;
3340c0d06caSMauro Carvalho Chehab break;
3350c0d06caSMauro Carvalho Chehab }
3360c0d06caSMauro Carvalho Chehab
3370c0d06caSMauro Carvalho Chehab if (cp->c_data_offs < cp->c_data_len) {
3380c0d06caSMauro Carvalho Chehab // Sanity check - should NEVER get here
3390c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS,
34096292c89SMauro Carvalho Chehab "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
3410c0d06caSMauro Carvalho Chehab cp->c_data_len,cp->c_data_offs);
3420c0d06caSMauro Carvalho Chehab // Get out so we don't get stuck in an infinite
3430c0d06caSMauro Carvalho Chehab // loop.
3440c0d06caSMauro Carvalho Chehab break;
3450c0d06caSMauro Carvalho Chehab }
3460c0d06caSMauro Carvalho Chehab
3470c0d06caSMauro Carvalho Chehab continue; // (for clarity)
348f419edd4SMauro Carvalho Chehab }
349f419edd4SMauro Carvalho Chehab mutex_unlock(&cp->mutex);
3500c0d06caSMauro Carvalho Chehab }
3510c0d06caSMauro Carvalho Chehab
pvr2_ioread_avail(struct pvr2_ioread * cp)3520c0d06caSMauro Carvalho Chehab int pvr2_ioread_avail(struct pvr2_ioread *cp)
3530c0d06caSMauro Carvalho Chehab {
3540c0d06caSMauro Carvalho Chehab int ret;
3550c0d06caSMauro Carvalho Chehab if (!(cp->enabled)) {
3560c0d06caSMauro Carvalho Chehab // Stream is not enabled; so this is an I/O error
3570c0d06caSMauro Carvalho Chehab return -EIO;
3580c0d06caSMauro Carvalho Chehab }
3590c0d06caSMauro Carvalho Chehab
3600c0d06caSMauro Carvalho Chehab if (cp->sync_state == 1) {
3610c0d06caSMauro Carvalho Chehab pvr2_ioread_filter(cp);
3620c0d06caSMauro Carvalho Chehab if (cp->sync_state == 1) return -EAGAIN;
3630c0d06caSMauro Carvalho Chehab }
3640c0d06caSMauro Carvalho Chehab
3650c0d06caSMauro Carvalho Chehab ret = 0;
3660c0d06caSMauro Carvalho Chehab if (cp->stream_running) {
3670c0d06caSMauro Carvalho Chehab if (!pvr2_stream_get_ready_count(cp->stream)) {
3680c0d06caSMauro Carvalho Chehab // No data available at all right now.
3690c0d06caSMauro Carvalho Chehab ret = -EAGAIN;
3700c0d06caSMauro Carvalho Chehab }
3710c0d06caSMauro Carvalho Chehab } else {
3720c0d06caSMauro Carvalho Chehab if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
3730c0d06caSMauro Carvalho Chehab // Haven't buffered up enough yet; try again later
3740c0d06caSMauro Carvalho Chehab ret = -EAGAIN;
3750c0d06caSMauro Carvalho Chehab }
3760c0d06caSMauro Carvalho Chehab }
3770c0d06caSMauro Carvalho Chehab
3780c0d06caSMauro Carvalho Chehab if ((!(cp->spigot_open)) != (!(ret == 0))) {
3790c0d06caSMauro Carvalho Chehab cp->spigot_open = (ret == 0);
3800c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
3810c0d06caSMauro Carvalho Chehab "/*---TRACE_READ---*/ data is %s",
3820c0d06caSMauro Carvalho Chehab cp->spigot_open ? "available" : "pending");
3830c0d06caSMauro Carvalho Chehab }
3840c0d06caSMauro Carvalho Chehab
3850c0d06caSMauro Carvalho Chehab return ret;
3860c0d06caSMauro Carvalho Chehab }
3870c0d06caSMauro Carvalho Chehab
pvr2_ioread_read(struct pvr2_ioread * cp,void __user * buf,unsigned int cnt)3880c0d06caSMauro Carvalho Chehab int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
3890c0d06caSMauro Carvalho Chehab {
3900c0d06caSMauro Carvalho Chehab unsigned int copied_cnt;
3910c0d06caSMauro Carvalho Chehab unsigned int bcnt;
3920c0d06caSMauro Carvalho Chehab const char *src;
3930c0d06caSMauro Carvalho Chehab int stat;
3940c0d06caSMauro Carvalho Chehab int ret = 0;
3950c0d06caSMauro Carvalho Chehab unsigned int req_cnt = cnt;
3960c0d06caSMauro Carvalho Chehab
3970c0d06caSMauro Carvalho Chehab if (!cnt) {
3980c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_TRAP,
39996292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
40096292c89SMauro Carvalho Chehab cp);
4010c0d06caSMauro Carvalho Chehab return 0;
4020c0d06caSMauro Carvalho Chehab }
4030c0d06caSMauro Carvalho Chehab
4040c0d06caSMauro Carvalho Chehab stat = pvr2_ioread_avail(cp);
4050c0d06caSMauro Carvalho Chehab if (stat < 0) return stat;
4060c0d06caSMauro Carvalho Chehab
4070c0d06caSMauro Carvalho Chehab cp->stream_running = !0;
4080c0d06caSMauro Carvalho Chehab
409f419edd4SMauro Carvalho Chehab mutex_lock(&cp->mutex);
410f419edd4SMauro Carvalho Chehab do {
4110c0d06caSMauro Carvalho Chehab
4120c0d06caSMauro Carvalho Chehab // Suck data out of the buffers and copy to the user
4130c0d06caSMauro Carvalho Chehab copied_cnt = 0;
4140c0d06caSMauro Carvalho Chehab if (!buf) cnt = 0;
4150c0d06caSMauro Carvalho Chehab while (1) {
4160c0d06caSMauro Carvalho Chehab if (!pvr2_ioread_get_buffer(cp)) {
4170c0d06caSMauro Carvalho Chehab ret = -EIO;
4180c0d06caSMauro Carvalho Chehab break;
4190c0d06caSMauro Carvalho Chehab }
4200c0d06caSMauro Carvalho Chehab
4210c0d06caSMauro Carvalho Chehab if (!cnt) break;
4220c0d06caSMauro Carvalho Chehab
4230c0d06caSMauro Carvalho Chehab if (cp->sync_state == 2) {
4240c0d06caSMauro Carvalho Chehab // We're repeating the sync key data into
4250c0d06caSMauro Carvalho Chehab // the stream.
4260c0d06caSMauro Carvalho Chehab src = cp->sync_key_ptr + cp->sync_buf_offs;
4270c0d06caSMauro Carvalho Chehab bcnt = cp->sync_key_len - cp->sync_buf_offs;
4280c0d06caSMauro Carvalho Chehab } else {
4290c0d06caSMauro Carvalho Chehab // Normal buffer copy
4300c0d06caSMauro Carvalho Chehab src = cp->c_data_ptr + cp->c_data_offs;
4310c0d06caSMauro Carvalho Chehab bcnt = cp->c_data_len - cp->c_data_offs;
4320c0d06caSMauro Carvalho Chehab }
4330c0d06caSMauro Carvalho Chehab
4340c0d06caSMauro Carvalho Chehab if (!bcnt) break;
4350c0d06caSMauro Carvalho Chehab
4360c0d06caSMauro Carvalho Chehab // Don't run past user's buffer
4370c0d06caSMauro Carvalho Chehab if (bcnt > cnt) bcnt = cnt;
4380c0d06caSMauro Carvalho Chehab
4390c0d06caSMauro Carvalho Chehab if (copy_to_user(buf,src,bcnt)) {
4400c0d06caSMauro Carvalho Chehab // User supplied a bad pointer?
4410c0d06caSMauro Carvalho Chehab // Give up - this *will* cause data
4420c0d06caSMauro Carvalho Chehab // to be lost.
4430c0d06caSMauro Carvalho Chehab ret = -EFAULT;
4440c0d06caSMauro Carvalho Chehab break;
4450c0d06caSMauro Carvalho Chehab }
4460c0d06caSMauro Carvalho Chehab cnt -= bcnt;
4470c0d06caSMauro Carvalho Chehab buf += bcnt;
4480c0d06caSMauro Carvalho Chehab copied_cnt += bcnt;
4490c0d06caSMauro Carvalho Chehab
4500c0d06caSMauro Carvalho Chehab if (cp->sync_state == 2) {
4510c0d06caSMauro Carvalho Chehab // Update offset inside sync key that we're
4520c0d06caSMauro Carvalho Chehab // repeating back out.
4530c0d06caSMauro Carvalho Chehab cp->sync_buf_offs += bcnt;
4540c0d06caSMauro Carvalho Chehab if (cp->sync_buf_offs >= cp->sync_key_len) {
4550c0d06caSMauro Carvalho Chehab // Consumed entire key; switch mode
4560c0d06caSMauro Carvalho Chehab // to normal.
4570c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
45896292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ sync_state <== 0");
4590c0d06caSMauro Carvalho Chehab cp->sync_state = 0;
4600c0d06caSMauro Carvalho Chehab }
4610c0d06caSMauro Carvalho Chehab } else {
4620c0d06caSMauro Carvalho Chehab // Update buffer offset.
4630c0d06caSMauro Carvalho Chehab cp->c_data_offs += bcnt;
4640c0d06caSMauro Carvalho Chehab }
4650c0d06caSMauro Carvalho Chehab }
4660c0d06caSMauro Carvalho Chehab
467f419edd4SMauro Carvalho Chehab } while (0);
468f419edd4SMauro Carvalho Chehab mutex_unlock(&cp->mutex);
4690c0d06caSMauro Carvalho Chehab
4700c0d06caSMauro Carvalho Chehab if (!ret) {
4710c0d06caSMauro Carvalho Chehab if (copied_cnt) {
4720c0d06caSMauro Carvalho Chehab // If anything was copied, return that count
4730c0d06caSMauro Carvalho Chehab ret = copied_cnt;
4740c0d06caSMauro Carvalho Chehab } else {
4750c0d06caSMauro Carvalho Chehab // Nothing copied; suggest to caller that another
4760c0d06caSMauro Carvalho Chehab // attempt should be tried again later
4770c0d06caSMauro Carvalho Chehab ret = -EAGAIN;
4780c0d06caSMauro Carvalho Chehab }
4790c0d06caSMauro Carvalho Chehab }
4800c0d06caSMauro Carvalho Chehab
4810c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_DATA_FLOW,
48296292c89SMauro Carvalho Chehab "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
4830c0d06caSMauro Carvalho Chehab cp,req_cnt,ret);
4840c0d06caSMauro Carvalho Chehab return ret;
4850c0d06caSMauro Carvalho Chehab }
486