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