18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "pvrusb2-ioread.h" 88c2ecf20Sopenharmony_ci#include "pvrusb2-debug.h" 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/mm.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/mutex.h> 148c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define BUFFER_COUNT 32 178c2ecf20Sopenharmony_ci#define BUFFER_SIZE PAGE_ALIGN(0x4000) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistruct pvr2_ioread { 208c2ecf20Sopenharmony_ci struct pvr2_stream *stream; 218c2ecf20Sopenharmony_ci char *buffer_storage[BUFFER_COUNT]; 228c2ecf20Sopenharmony_ci char *sync_key_ptr; 238c2ecf20Sopenharmony_ci unsigned int sync_key_len; 248c2ecf20Sopenharmony_ci unsigned int sync_buf_offs; 258c2ecf20Sopenharmony_ci unsigned int sync_state; 268c2ecf20Sopenharmony_ci unsigned int sync_trashed_count; 278c2ecf20Sopenharmony_ci int enabled; // Streaming is on 288c2ecf20Sopenharmony_ci int spigot_open; // OK to pass data to client 298c2ecf20Sopenharmony_ci int stream_running; // Passing data to client now 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* State relevant to current buffer being read */ 328c2ecf20Sopenharmony_ci struct pvr2_buffer *c_buf; 338c2ecf20Sopenharmony_ci char *c_data_ptr; 348c2ecf20Sopenharmony_ci unsigned int c_data_len; 358c2ecf20Sopenharmony_ci unsigned int c_data_offs; 368c2ecf20Sopenharmony_ci struct mutex mutex; 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int pvr2_ioread_init(struct pvr2_ioread *cp) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci unsigned int idx; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci cp->stream = NULL; 448c2ecf20Sopenharmony_ci mutex_init(&cp->mutex); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci for (idx = 0; idx < BUFFER_COUNT; idx++) { 478c2ecf20Sopenharmony_ci cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL); 488c2ecf20Sopenharmony_ci if (!(cp->buffer_storage[idx])) break; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (idx < BUFFER_COUNT) { 528c2ecf20Sopenharmony_ci // An allocation appears to have failed 538c2ecf20Sopenharmony_ci for (idx = 0; idx < BUFFER_COUNT; idx++) { 548c2ecf20Sopenharmony_ci if (!(cp->buffer_storage[idx])) continue; 558c2ecf20Sopenharmony_ci kfree(cp->buffer_storage[idx]); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci return -ENOMEM; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void pvr2_ioread_done(struct pvr2_ioread *cp) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned int idx; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci pvr2_ioread_setup(cp,NULL); 678c2ecf20Sopenharmony_ci for (idx = 0; idx < BUFFER_COUNT; idx++) { 688c2ecf20Sopenharmony_ci if (!(cp->buffer_storage[idx])) continue; 698c2ecf20Sopenharmony_ci kfree(cp->buffer_storage[idx]); 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistruct pvr2_ioread *pvr2_ioread_create(void) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct pvr2_ioread *cp; 768c2ecf20Sopenharmony_ci cp = kzalloc(sizeof(*cp),GFP_KERNEL); 778c2ecf20Sopenharmony_ci if (!cp) return NULL; 788c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp); 798c2ecf20Sopenharmony_ci if (pvr2_ioread_init(cp) < 0) { 808c2ecf20Sopenharmony_ci kfree(cp); 818c2ecf20Sopenharmony_ci return NULL; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci return cp; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_civoid pvr2_ioread_destroy(struct pvr2_ioread *cp) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (!cp) return; 898c2ecf20Sopenharmony_ci pvr2_ioread_done(cp); 908c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp); 918c2ecf20Sopenharmony_ci if (cp->sync_key_ptr) { 928c2ecf20Sopenharmony_ci kfree(cp->sync_key_ptr); 938c2ecf20Sopenharmony_ci cp->sync_key_ptr = NULL; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci kfree(cp); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_civoid pvr2_ioread_set_sync_key(struct pvr2_ioread *cp, 998c2ecf20Sopenharmony_ci const char *sync_key_ptr, 1008c2ecf20Sopenharmony_ci unsigned int sync_key_len) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci if (!cp) return; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!sync_key_ptr) sync_key_len = 0; 1058c2ecf20Sopenharmony_ci if ((sync_key_len == cp->sync_key_len) && 1068c2ecf20Sopenharmony_ci ((!sync_key_len) || 1078c2ecf20Sopenharmony_ci (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (sync_key_len != cp->sync_key_len) { 1108c2ecf20Sopenharmony_ci if (cp->sync_key_ptr) { 1118c2ecf20Sopenharmony_ci kfree(cp->sync_key_ptr); 1128c2ecf20Sopenharmony_ci cp->sync_key_ptr = NULL; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci cp->sync_key_len = 0; 1158c2ecf20Sopenharmony_ci if (sync_key_len) { 1168c2ecf20Sopenharmony_ci cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL); 1178c2ecf20Sopenharmony_ci if (cp->sync_key_ptr) { 1188c2ecf20Sopenharmony_ci cp->sync_key_len = sync_key_len; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci if (!cp->sync_key_len) return; 1238c2ecf20Sopenharmony_ci memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic void pvr2_ioread_stop(struct pvr2_ioread *cp) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (!(cp->enabled)) return; 1298c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 1308c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp); 1318c2ecf20Sopenharmony_ci pvr2_stream_kill(cp->stream); 1328c2ecf20Sopenharmony_ci cp->c_buf = NULL; 1338c2ecf20Sopenharmony_ci cp->c_data_ptr = NULL; 1348c2ecf20Sopenharmony_ci cp->c_data_len = 0; 1358c2ecf20Sopenharmony_ci cp->c_data_offs = 0; 1368c2ecf20Sopenharmony_ci cp->enabled = 0; 1378c2ecf20Sopenharmony_ci cp->stream_running = 0; 1388c2ecf20Sopenharmony_ci cp->spigot_open = 0; 1398c2ecf20Sopenharmony_ci if (cp->sync_state) { 1408c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 1418c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ sync_state <== 0"); 1428c2ecf20Sopenharmony_ci cp->sync_state = 0; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int pvr2_ioread_start(struct pvr2_ioread *cp) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int stat; 1498c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 1508c2ecf20Sopenharmony_ci if (cp->enabled) return 0; 1518c2ecf20Sopenharmony_ci if (!(cp->stream)) return 0; 1528c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 1538c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp); 1548c2ecf20Sopenharmony_ci while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) { 1558c2ecf20Sopenharmony_ci stat = pvr2_buffer_queue(bp); 1568c2ecf20Sopenharmony_ci if (stat < 0) { 1578c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 1588c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d", 1598c2ecf20Sopenharmony_ci cp,stat); 1608c2ecf20Sopenharmony_ci pvr2_ioread_stop(cp); 1618c2ecf20Sopenharmony_ci return stat; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci cp->enabled = !0; 1658c2ecf20Sopenharmony_ci cp->c_buf = NULL; 1668c2ecf20Sopenharmony_ci cp->c_data_ptr = NULL; 1678c2ecf20Sopenharmony_ci cp->c_data_len = 0; 1688c2ecf20Sopenharmony_ci cp->c_data_offs = 0; 1698c2ecf20Sopenharmony_ci cp->stream_running = 0; 1708c2ecf20Sopenharmony_ci if (cp->sync_key_len) { 1718c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 1728c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ sync_state <== 1"); 1738c2ecf20Sopenharmony_ci cp->sync_state = 1; 1748c2ecf20Sopenharmony_ci cp->sync_trashed_count = 0; 1758c2ecf20Sopenharmony_ci cp->sync_buf_offs = 0; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci cp->spigot_open = 0; 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci return cp->stream; 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciint pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci int ret; 1898c2ecf20Sopenharmony_ci unsigned int idx; 1908c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci mutex_lock(&cp->mutex); 1938c2ecf20Sopenharmony_ci do { 1948c2ecf20Sopenharmony_ci if (cp->stream) { 1958c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 1968c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p", 1978c2ecf20Sopenharmony_ci cp); 1988c2ecf20Sopenharmony_ci pvr2_ioread_stop(cp); 1998c2ecf20Sopenharmony_ci pvr2_stream_kill(cp->stream); 2008c2ecf20Sopenharmony_ci if (pvr2_stream_get_buffer_count(cp->stream)) { 2018c2ecf20Sopenharmony_ci pvr2_stream_set_buffer_count(cp->stream,0); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci cp->stream = NULL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci if (sp) { 2068c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_START_STOP, 2078c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p", 2088c2ecf20Sopenharmony_ci cp); 2098c2ecf20Sopenharmony_ci pvr2_stream_kill(sp); 2108c2ecf20Sopenharmony_ci ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); 2118c2ecf20Sopenharmony_ci if (ret < 0) { 2128c2ecf20Sopenharmony_ci mutex_unlock(&cp->mutex); 2138c2ecf20Sopenharmony_ci return ret; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci for (idx = 0; idx < BUFFER_COUNT; idx++) { 2168c2ecf20Sopenharmony_ci bp = pvr2_stream_get_buffer(sp,idx); 2178c2ecf20Sopenharmony_ci pvr2_buffer_set_buffer(bp, 2188c2ecf20Sopenharmony_ci cp->buffer_storage[idx], 2198c2ecf20Sopenharmony_ci BUFFER_SIZE); 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci cp->stream = sp; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } while (0); 2248c2ecf20Sopenharmony_ci mutex_unlock(&cp->mutex); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciint pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int ret = 0; 2328c2ecf20Sopenharmony_ci if ((!fl) == (!(cp->enabled))) return ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci mutex_lock(&cp->mutex); 2358c2ecf20Sopenharmony_ci do { 2368c2ecf20Sopenharmony_ci if (fl) { 2378c2ecf20Sopenharmony_ci ret = pvr2_ioread_start(cp); 2388c2ecf20Sopenharmony_ci } else { 2398c2ecf20Sopenharmony_ci pvr2_ioread_stop(cp); 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci } while (0); 2428c2ecf20Sopenharmony_ci mutex_unlock(&cp->mutex); 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci int stat; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci while (cp->c_data_len <= cp->c_data_offs) { 2518c2ecf20Sopenharmony_ci if (cp->c_buf) { 2528c2ecf20Sopenharmony_ci // Flush out current buffer first. 2538c2ecf20Sopenharmony_ci stat = pvr2_buffer_queue(cp->c_buf); 2548c2ecf20Sopenharmony_ci if (stat < 0) { 2558c2ecf20Sopenharmony_ci // Streaming error... 2568c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 2578c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d", 2588c2ecf20Sopenharmony_ci cp,stat); 2598c2ecf20Sopenharmony_ci pvr2_ioread_stop(cp); 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci cp->c_buf = NULL; 2638c2ecf20Sopenharmony_ci cp->c_data_ptr = NULL; 2648c2ecf20Sopenharmony_ci cp->c_data_len = 0; 2658c2ecf20Sopenharmony_ci cp->c_data_offs = 0; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci // Now get a freshly filled buffer. 2688c2ecf20Sopenharmony_ci cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream); 2698c2ecf20Sopenharmony_ci if (!cp->c_buf) break; // Nothing ready; done. 2708c2ecf20Sopenharmony_ci cp->c_data_len = pvr2_buffer_get_count(cp->c_buf); 2718c2ecf20Sopenharmony_ci if (!cp->c_data_len) { 2728c2ecf20Sopenharmony_ci // Nothing transferred. Was there an error? 2738c2ecf20Sopenharmony_ci stat = pvr2_buffer_get_status(cp->c_buf); 2748c2ecf20Sopenharmony_ci if (stat < 0) { 2758c2ecf20Sopenharmony_ci // Streaming error... 2768c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 2778c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d", 2788c2ecf20Sopenharmony_ci cp,stat); 2798c2ecf20Sopenharmony_ci pvr2_ioread_stop(cp); 2808c2ecf20Sopenharmony_ci // Give up. 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci // Start over... 2848c2ecf20Sopenharmony_ci continue; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci cp->c_data_offs = 0; 2878c2ecf20Sopenharmony_ci cp->c_data_ptr = cp->buffer_storage[ 2888c2ecf20Sopenharmony_ci pvr2_buffer_get_id(cp->c_buf)]; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci return !0; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void pvr2_ioread_filter(struct pvr2_ioread *cp) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci unsigned int idx; 2968c2ecf20Sopenharmony_ci if (!cp->enabled) return; 2978c2ecf20Sopenharmony_ci if (cp->sync_state != 1) return; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci // Search the stream for our synchronization key. This is made 3008c2ecf20Sopenharmony_ci // complicated by the fact that in order to be honest with 3018c2ecf20Sopenharmony_ci // ourselves here we must search across buffer boundaries... 3028c2ecf20Sopenharmony_ci mutex_lock(&cp->mutex); 3038c2ecf20Sopenharmony_ci while (1) { 3048c2ecf20Sopenharmony_ci // Ensure we have a buffer 3058c2ecf20Sopenharmony_ci if (!pvr2_ioread_get_buffer(cp)) break; 3068c2ecf20Sopenharmony_ci if (!cp->c_data_len) break; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci // Now walk the buffer contents until we match the key or 3098c2ecf20Sopenharmony_ci // run out of buffer data. 3108c2ecf20Sopenharmony_ci for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) { 3118c2ecf20Sopenharmony_ci if (cp->sync_buf_offs >= cp->sync_key_len) break; 3128c2ecf20Sopenharmony_ci if (cp->c_data_ptr[idx] == 3138c2ecf20Sopenharmony_ci cp->sync_key_ptr[cp->sync_buf_offs]) { 3148c2ecf20Sopenharmony_ci // Found the next key byte 3158c2ecf20Sopenharmony_ci (cp->sync_buf_offs)++; 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci // Whoops, mismatched. Start key over... 3188c2ecf20Sopenharmony_ci cp->sync_buf_offs = 0; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci // Consume what we've walked through 3238c2ecf20Sopenharmony_ci cp->c_data_offs += idx; 3248c2ecf20Sopenharmony_ci cp->sync_trashed_count += idx; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci // If we've found the key, then update state and get out. 3278c2ecf20Sopenharmony_ci if (cp->sync_buf_offs >= cp->sync_key_len) { 3288c2ecf20Sopenharmony_ci cp->sync_trashed_count -= cp->sync_key_len; 3298c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 3308c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)", 3318c2ecf20Sopenharmony_ci cp->sync_trashed_count); 3328c2ecf20Sopenharmony_ci cp->sync_state = 2; 3338c2ecf20Sopenharmony_ci cp->sync_buf_offs = 0; 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (cp->c_data_offs < cp->c_data_len) { 3388c2ecf20Sopenharmony_ci // Sanity check - should NEVER get here 3398c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, 3408c2ecf20Sopenharmony_ci "ERROR: pvr2_ioread filter sync problem len=%u offs=%u", 3418c2ecf20Sopenharmony_ci cp->c_data_len,cp->c_data_offs); 3428c2ecf20Sopenharmony_ci // Get out so we don't get stuck in an infinite 3438c2ecf20Sopenharmony_ci // loop. 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci continue; // (for clarity) 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci mutex_unlock(&cp->mutex); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciint pvr2_ioread_avail(struct pvr2_ioread *cp) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci int ret; 3558c2ecf20Sopenharmony_ci if (!(cp->enabled)) { 3568c2ecf20Sopenharmony_ci // Stream is not enabled; so this is an I/O error 3578c2ecf20Sopenharmony_ci return -EIO; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (cp->sync_state == 1) { 3618c2ecf20Sopenharmony_ci pvr2_ioread_filter(cp); 3628c2ecf20Sopenharmony_ci if (cp->sync_state == 1) return -EAGAIN; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci ret = 0; 3668c2ecf20Sopenharmony_ci if (cp->stream_running) { 3678c2ecf20Sopenharmony_ci if (!pvr2_stream_get_ready_count(cp->stream)) { 3688c2ecf20Sopenharmony_ci // No data available at all right now. 3698c2ecf20Sopenharmony_ci ret = -EAGAIN; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci } else { 3728c2ecf20Sopenharmony_ci if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) { 3738c2ecf20Sopenharmony_ci // Haven't buffered up enough yet; try again later 3748c2ecf20Sopenharmony_ci ret = -EAGAIN; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci if ((!(cp->spigot_open)) != (!(ret == 0))) { 3798c2ecf20Sopenharmony_ci cp->spigot_open = (ret == 0); 3808c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 3818c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ data is %s", 3828c2ecf20Sopenharmony_ci cp->spigot_open ? "available" : "pending"); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci return ret; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciint pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned int copied_cnt; 3918c2ecf20Sopenharmony_ci unsigned int bcnt; 3928c2ecf20Sopenharmony_ci const char *src; 3938c2ecf20Sopenharmony_ci int stat; 3948c2ecf20Sopenharmony_ci int ret = 0; 3958c2ecf20Sopenharmony_ci unsigned int req_cnt = cnt; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!cnt) { 3988c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_TRAP, 3998c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.", 4008c2ecf20Sopenharmony_cicp); 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci stat = pvr2_ioread_avail(cp); 4058c2ecf20Sopenharmony_ci if (stat < 0) return stat; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci cp->stream_running = !0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci mutex_lock(&cp->mutex); 4108c2ecf20Sopenharmony_ci do { 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci // Suck data out of the buffers and copy to the user 4138c2ecf20Sopenharmony_ci copied_cnt = 0; 4148c2ecf20Sopenharmony_ci if (!buf) cnt = 0; 4158c2ecf20Sopenharmony_ci while (1) { 4168c2ecf20Sopenharmony_ci if (!pvr2_ioread_get_buffer(cp)) { 4178c2ecf20Sopenharmony_ci ret = -EIO; 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!cnt) break; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (cp->sync_state == 2) { 4248c2ecf20Sopenharmony_ci // We're repeating the sync key data into 4258c2ecf20Sopenharmony_ci // the stream. 4268c2ecf20Sopenharmony_ci src = cp->sync_key_ptr + cp->sync_buf_offs; 4278c2ecf20Sopenharmony_ci bcnt = cp->sync_key_len - cp->sync_buf_offs; 4288c2ecf20Sopenharmony_ci } else { 4298c2ecf20Sopenharmony_ci // Normal buffer copy 4308c2ecf20Sopenharmony_ci src = cp->c_data_ptr + cp->c_data_offs; 4318c2ecf20Sopenharmony_ci bcnt = cp->c_data_len - cp->c_data_offs; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (!bcnt) break; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci // Don't run past user's buffer 4378c2ecf20Sopenharmony_ci if (bcnt > cnt) bcnt = cnt; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci if (copy_to_user(buf,src,bcnt)) { 4408c2ecf20Sopenharmony_ci // User supplied a bad pointer? 4418c2ecf20Sopenharmony_ci // Give up - this *will* cause data 4428c2ecf20Sopenharmony_ci // to be lost. 4438c2ecf20Sopenharmony_ci ret = -EFAULT; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci cnt -= bcnt; 4478c2ecf20Sopenharmony_ci buf += bcnt; 4488c2ecf20Sopenharmony_ci copied_cnt += bcnt; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (cp->sync_state == 2) { 4518c2ecf20Sopenharmony_ci // Update offset inside sync key that we're 4528c2ecf20Sopenharmony_ci // repeating back out. 4538c2ecf20Sopenharmony_ci cp->sync_buf_offs += bcnt; 4548c2ecf20Sopenharmony_ci if (cp->sync_buf_offs >= cp->sync_key_len) { 4558c2ecf20Sopenharmony_ci // Consumed entire key; switch mode 4568c2ecf20Sopenharmony_ci // to normal. 4578c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 4588c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ sync_state <== 0"); 4598c2ecf20Sopenharmony_ci cp->sync_state = 0; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci // Update buffer offset. 4638c2ecf20Sopenharmony_ci cp->c_data_offs += bcnt; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci } while (0); 4688c2ecf20Sopenharmony_ci mutex_unlock(&cp->mutex); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (!ret) { 4718c2ecf20Sopenharmony_ci if (copied_cnt) { 4728c2ecf20Sopenharmony_ci // If anything was copied, return that count 4738c2ecf20Sopenharmony_ci ret = copied_cnt; 4748c2ecf20Sopenharmony_ci } else { 4758c2ecf20Sopenharmony_ci // Nothing copied; suggest to caller that another 4768c2ecf20Sopenharmony_ci // attempt should be tried again later 4778c2ecf20Sopenharmony_ci ret = -EAGAIN; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_DATA_FLOW, 4828c2ecf20Sopenharmony_ci "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d", 4838c2ecf20Sopenharmony_ci cp,req_cnt,ret); 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci} 486