1*0c0d06caSMauro Carvalho Chehab /* 2*0c0d06caSMauro Carvalho Chehab * 3*0c0d06caSMauro Carvalho Chehab * 4*0c0d06caSMauro Carvalho Chehab * Copyright (C) 2005 Mike Isely <isely@pobox.com> 5*0c0d06caSMauro Carvalho Chehab * 6*0c0d06caSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 7*0c0d06caSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 8*0c0d06caSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License 9*0c0d06caSMauro Carvalho Chehab * 10*0c0d06caSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 11*0c0d06caSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 12*0c0d06caSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*0c0d06caSMauro Carvalho Chehab * GNU General Public License for more details. 14*0c0d06caSMauro Carvalho Chehab * 15*0c0d06caSMauro Carvalho Chehab * You should have received a copy of the GNU General Public License 16*0c0d06caSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 17*0c0d06caSMauro Carvalho Chehab * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18*0c0d06caSMauro Carvalho Chehab * 19*0c0d06caSMauro Carvalho Chehab */ 20*0c0d06caSMauro Carvalho Chehab 21*0c0d06caSMauro Carvalho Chehab #include "pvrusb2-io.h" 22*0c0d06caSMauro Carvalho Chehab #include "pvrusb2-debug.h" 23*0c0d06caSMauro Carvalho Chehab #include <linux/errno.h> 24*0c0d06caSMauro Carvalho Chehab #include <linux/string.h> 25*0c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 26*0c0d06caSMauro Carvalho Chehab #include <linux/mutex.h> 27*0c0d06caSMauro Carvalho Chehab 28*0c0d06caSMauro Carvalho Chehab static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); 29*0c0d06caSMauro Carvalho Chehab 30*0c0d06caSMauro Carvalho Chehab #define BUFFER_SIG 0x47653271 31*0c0d06caSMauro Carvalho Chehab 32*0c0d06caSMauro Carvalho Chehab // #define SANITY_CHECK_BUFFERS 33*0c0d06caSMauro Carvalho Chehab 34*0c0d06caSMauro Carvalho Chehab 35*0c0d06caSMauro Carvalho Chehab #ifdef SANITY_CHECK_BUFFERS 36*0c0d06caSMauro Carvalho Chehab #define BUFFER_CHECK(bp) do { \ 37*0c0d06caSMauro Carvalho Chehab if ((bp)->signature != BUFFER_SIG) { \ 38*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ 39*0c0d06caSMauro Carvalho Chehab "Buffer %p is bad at %s:%d", \ 40*0c0d06caSMauro Carvalho Chehab (bp),__FILE__,__LINE__); \ 41*0c0d06caSMauro Carvalho Chehab pvr2_buffer_describe(bp,"BadSig"); \ 42*0c0d06caSMauro Carvalho Chehab BUG(); \ 43*0c0d06caSMauro Carvalho Chehab } \ 44*0c0d06caSMauro Carvalho Chehab } while (0) 45*0c0d06caSMauro Carvalho Chehab #else 46*0c0d06caSMauro Carvalho Chehab #define BUFFER_CHECK(bp) do {} while(0) 47*0c0d06caSMauro Carvalho Chehab #endif 48*0c0d06caSMauro Carvalho Chehab 49*0c0d06caSMauro Carvalho Chehab struct pvr2_stream { 50*0c0d06caSMauro Carvalho Chehab /* Buffers queued for reading */ 51*0c0d06caSMauro Carvalho Chehab struct list_head queued_list; 52*0c0d06caSMauro Carvalho Chehab unsigned int q_count; 53*0c0d06caSMauro Carvalho Chehab unsigned int q_bcount; 54*0c0d06caSMauro Carvalho Chehab /* Buffers with retrieved data */ 55*0c0d06caSMauro Carvalho Chehab struct list_head ready_list; 56*0c0d06caSMauro Carvalho Chehab unsigned int r_count; 57*0c0d06caSMauro Carvalho Chehab unsigned int r_bcount; 58*0c0d06caSMauro Carvalho Chehab /* Buffers available for use */ 59*0c0d06caSMauro Carvalho Chehab struct list_head idle_list; 60*0c0d06caSMauro Carvalho Chehab unsigned int i_count; 61*0c0d06caSMauro Carvalho Chehab unsigned int i_bcount; 62*0c0d06caSMauro Carvalho Chehab /* Pointers to all buffers */ 63*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer **buffers; 64*0c0d06caSMauro Carvalho Chehab /* Array size of buffers */ 65*0c0d06caSMauro Carvalho Chehab unsigned int buffer_slot_count; 66*0c0d06caSMauro Carvalho Chehab /* Total buffers actually in circulation */ 67*0c0d06caSMauro Carvalho Chehab unsigned int buffer_total_count; 68*0c0d06caSMauro Carvalho Chehab /* Designed number of buffers to be in circulation */ 69*0c0d06caSMauro Carvalho Chehab unsigned int buffer_target_count; 70*0c0d06caSMauro Carvalho Chehab /* Executed when ready list become non-empty */ 71*0c0d06caSMauro Carvalho Chehab pvr2_stream_callback callback_func; 72*0c0d06caSMauro Carvalho Chehab void *callback_data; 73*0c0d06caSMauro Carvalho Chehab /* Context for transfer endpoint */ 74*0c0d06caSMauro Carvalho Chehab struct usb_device *dev; 75*0c0d06caSMauro Carvalho Chehab int endpoint; 76*0c0d06caSMauro Carvalho Chehab /* Overhead for mutex enforcement */ 77*0c0d06caSMauro Carvalho Chehab spinlock_t list_lock; 78*0c0d06caSMauro Carvalho Chehab struct mutex mutex; 79*0c0d06caSMauro Carvalho Chehab /* Tracking state for tolerating errors */ 80*0c0d06caSMauro Carvalho Chehab unsigned int fail_count; 81*0c0d06caSMauro Carvalho Chehab unsigned int fail_tolerance; 82*0c0d06caSMauro Carvalho Chehab 83*0c0d06caSMauro Carvalho Chehab unsigned int buffers_processed; 84*0c0d06caSMauro Carvalho Chehab unsigned int buffers_failed; 85*0c0d06caSMauro Carvalho Chehab unsigned int bytes_processed; 86*0c0d06caSMauro Carvalho Chehab }; 87*0c0d06caSMauro Carvalho Chehab 88*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer { 89*0c0d06caSMauro Carvalho Chehab int id; 90*0c0d06caSMauro Carvalho Chehab int signature; 91*0c0d06caSMauro Carvalho Chehab enum pvr2_buffer_state state; 92*0c0d06caSMauro Carvalho Chehab void *ptr; /* Pointer to storage area */ 93*0c0d06caSMauro Carvalho Chehab unsigned int max_count; /* Size of storage area */ 94*0c0d06caSMauro Carvalho Chehab unsigned int used_count; /* Amount of valid data in storage area */ 95*0c0d06caSMauro Carvalho Chehab int status; /* Transfer result status */ 96*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *stream; 97*0c0d06caSMauro Carvalho Chehab struct list_head list_overhead; 98*0c0d06caSMauro Carvalho Chehab struct urb *purb; 99*0c0d06caSMauro Carvalho Chehab }; 100*0c0d06caSMauro Carvalho Chehab 101*0c0d06caSMauro Carvalho Chehab static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st) 102*0c0d06caSMauro Carvalho Chehab { 103*0c0d06caSMauro Carvalho Chehab switch (st) { 104*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_none: return "none"; 105*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_idle: return "idle"; 106*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_queued: return "queued"; 107*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_ready: return "ready"; 108*0c0d06caSMauro Carvalho Chehab } 109*0c0d06caSMauro Carvalho Chehab return "unknown"; 110*0c0d06caSMauro Carvalho Chehab } 111*0c0d06caSMauro Carvalho Chehab 112*0c0d06caSMauro Carvalho Chehab #ifdef SANITY_CHECK_BUFFERS 113*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg) 114*0c0d06caSMauro Carvalho Chehab { 115*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INFO, 116*0c0d06caSMauro Carvalho Chehab "buffer%s%s %p state=%s id=%d status=%d" 117*0c0d06caSMauro Carvalho Chehab " stream=%p purb=%p sig=0x%x", 118*0c0d06caSMauro Carvalho Chehab (msg ? " " : ""), 119*0c0d06caSMauro Carvalho Chehab (msg ? msg : ""), 120*0c0d06caSMauro Carvalho Chehab bp, 121*0c0d06caSMauro Carvalho Chehab (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"), 122*0c0d06caSMauro Carvalho Chehab (bp ? bp->id : 0), 123*0c0d06caSMauro Carvalho Chehab (bp ? bp->status : 0), 124*0c0d06caSMauro Carvalho Chehab (bp ? bp->stream : NULL), 125*0c0d06caSMauro Carvalho Chehab (bp ? bp->purb : NULL), 126*0c0d06caSMauro Carvalho Chehab (bp ? bp->signature : 0)); 127*0c0d06caSMauro Carvalho Chehab } 128*0c0d06caSMauro Carvalho Chehab #endif /* SANITY_CHECK_BUFFERS */ 129*0c0d06caSMauro Carvalho Chehab 130*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_remove(struct pvr2_buffer *bp) 131*0c0d06caSMauro Carvalho Chehab { 132*0c0d06caSMauro Carvalho Chehab unsigned int *cnt; 133*0c0d06caSMauro Carvalho Chehab unsigned int *bcnt; 134*0c0d06caSMauro Carvalho Chehab unsigned int ccnt; 135*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp = bp->stream; 136*0c0d06caSMauro Carvalho Chehab switch (bp->state) { 137*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_idle: 138*0c0d06caSMauro Carvalho Chehab cnt = &sp->i_count; 139*0c0d06caSMauro Carvalho Chehab bcnt = &sp->i_bcount; 140*0c0d06caSMauro Carvalho Chehab ccnt = bp->max_count; 141*0c0d06caSMauro Carvalho Chehab break; 142*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_queued: 143*0c0d06caSMauro Carvalho Chehab cnt = &sp->q_count; 144*0c0d06caSMauro Carvalho Chehab bcnt = &sp->q_bcount; 145*0c0d06caSMauro Carvalho Chehab ccnt = bp->max_count; 146*0c0d06caSMauro Carvalho Chehab break; 147*0c0d06caSMauro Carvalho Chehab case pvr2_buffer_state_ready: 148*0c0d06caSMauro Carvalho Chehab cnt = &sp->r_count; 149*0c0d06caSMauro Carvalho Chehab bcnt = &sp->r_bcount; 150*0c0d06caSMauro Carvalho Chehab ccnt = bp->used_count; 151*0c0d06caSMauro Carvalho Chehab break; 152*0c0d06caSMauro Carvalho Chehab default: 153*0c0d06caSMauro Carvalho Chehab return; 154*0c0d06caSMauro Carvalho Chehab } 155*0c0d06caSMauro Carvalho Chehab list_del_init(&bp->list_overhead); 156*0c0d06caSMauro Carvalho Chehab (*cnt)--; 157*0c0d06caSMauro Carvalho Chehab (*bcnt) -= ccnt; 158*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 159*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/" 160*0c0d06caSMauro Carvalho Chehab " bufferPool %8s dec cap=%07d cnt=%02d", 161*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state),*bcnt,*cnt); 162*0c0d06caSMauro Carvalho Chehab bp->state = pvr2_buffer_state_none; 163*0c0d06caSMauro Carvalho Chehab } 164*0c0d06caSMauro Carvalho Chehab 165*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_set_none(struct pvr2_buffer *bp) 166*0c0d06caSMauro Carvalho Chehab { 167*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 168*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 169*0c0d06caSMauro Carvalho Chehab BUFFER_CHECK(bp); 170*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 171*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 172*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 173*0c0d06caSMauro Carvalho Chehab bp, 174*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 175*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(pvr2_buffer_state_none)); 176*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 177*0c0d06caSMauro Carvalho Chehab pvr2_buffer_remove(bp); 178*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 179*0c0d06caSMauro Carvalho Chehab } 180*0c0d06caSMauro Carvalho Chehab 181*0c0d06caSMauro Carvalho Chehab static int pvr2_buffer_set_ready(struct pvr2_buffer *bp) 182*0c0d06caSMauro Carvalho Chehab { 183*0c0d06caSMauro Carvalho Chehab int fl; 184*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 185*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 186*0c0d06caSMauro Carvalho Chehab BUFFER_CHECK(bp); 187*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 188*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 189*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 190*0c0d06caSMauro Carvalho Chehab bp, 191*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 192*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(pvr2_buffer_state_ready)); 193*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 194*0c0d06caSMauro Carvalho Chehab fl = (sp->r_count == 0); 195*0c0d06caSMauro Carvalho Chehab pvr2_buffer_remove(bp); 196*0c0d06caSMauro Carvalho Chehab list_add_tail(&bp->list_overhead,&sp->ready_list); 197*0c0d06caSMauro Carvalho Chehab bp->state = pvr2_buffer_state_ready; 198*0c0d06caSMauro Carvalho Chehab (sp->r_count)++; 199*0c0d06caSMauro Carvalho Chehab sp->r_bcount += bp->used_count; 200*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 201*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/" 202*0c0d06caSMauro Carvalho Chehab " bufferPool %8s inc cap=%07d cnt=%02d", 203*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 204*0c0d06caSMauro Carvalho Chehab sp->r_bcount,sp->r_count); 205*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 206*0c0d06caSMauro Carvalho Chehab return fl; 207*0c0d06caSMauro Carvalho Chehab } 208*0c0d06caSMauro Carvalho Chehab 209*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_set_idle(struct pvr2_buffer *bp) 210*0c0d06caSMauro Carvalho Chehab { 211*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 212*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 213*0c0d06caSMauro Carvalho Chehab BUFFER_CHECK(bp); 214*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 215*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 216*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 217*0c0d06caSMauro Carvalho Chehab bp, 218*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 219*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(pvr2_buffer_state_idle)); 220*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 221*0c0d06caSMauro Carvalho Chehab pvr2_buffer_remove(bp); 222*0c0d06caSMauro Carvalho Chehab list_add_tail(&bp->list_overhead,&sp->idle_list); 223*0c0d06caSMauro Carvalho Chehab bp->state = pvr2_buffer_state_idle; 224*0c0d06caSMauro Carvalho Chehab (sp->i_count)++; 225*0c0d06caSMauro Carvalho Chehab sp->i_bcount += bp->max_count; 226*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 227*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/" 228*0c0d06caSMauro Carvalho Chehab " bufferPool %8s inc cap=%07d cnt=%02d", 229*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 230*0c0d06caSMauro Carvalho Chehab sp->i_bcount,sp->i_count); 231*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 232*0c0d06caSMauro Carvalho Chehab } 233*0c0d06caSMauro Carvalho Chehab 234*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_set_queued(struct pvr2_buffer *bp) 235*0c0d06caSMauro Carvalho Chehab { 236*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 237*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 238*0c0d06caSMauro Carvalho Chehab BUFFER_CHECK(bp); 239*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 240*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 241*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 242*0c0d06caSMauro Carvalho Chehab bp, 243*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 244*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(pvr2_buffer_state_queued)); 245*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 246*0c0d06caSMauro Carvalho Chehab pvr2_buffer_remove(bp); 247*0c0d06caSMauro Carvalho Chehab list_add_tail(&bp->list_overhead,&sp->queued_list); 248*0c0d06caSMauro Carvalho Chehab bp->state = pvr2_buffer_state_queued; 249*0c0d06caSMauro Carvalho Chehab (sp->q_count)++; 250*0c0d06caSMauro Carvalho Chehab sp->q_bcount += bp->max_count; 251*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 252*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/" 253*0c0d06caSMauro Carvalho Chehab " bufferPool %8s inc cap=%07d cnt=%02d", 254*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode(bp->state), 255*0c0d06caSMauro Carvalho Chehab sp->q_bcount,sp->q_count); 256*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 257*0c0d06caSMauro Carvalho Chehab } 258*0c0d06caSMauro Carvalho Chehab 259*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_wipe(struct pvr2_buffer *bp) 260*0c0d06caSMauro Carvalho Chehab { 261*0c0d06caSMauro Carvalho Chehab if (bp->state == pvr2_buffer_state_queued) { 262*0c0d06caSMauro Carvalho Chehab usb_kill_urb(bp->purb); 263*0c0d06caSMauro Carvalho Chehab } 264*0c0d06caSMauro Carvalho Chehab } 265*0c0d06caSMauro Carvalho Chehab 266*0c0d06caSMauro Carvalho Chehab static int pvr2_buffer_init(struct pvr2_buffer *bp, 267*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp, 268*0c0d06caSMauro Carvalho Chehab unsigned int id) 269*0c0d06caSMauro Carvalho Chehab { 270*0c0d06caSMauro Carvalho Chehab memset(bp,0,sizeof(*bp)); 271*0c0d06caSMauro Carvalho Chehab bp->signature = BUFFER_SIG; 272*0c0d06caSMauro Carvalho Chehab bp->id = id; 273*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_POOL, 274*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferInit %p stream=%p",bp,sp); 275*0c0d06caSMauro Carvalho Chehab bp->stream = sp; 276*0c0d06caSMauro Carvalho Chehab bp->state = pvr2_buffer_state_none; 277*0c0d06caSMauro Carvalho Chehab INIT_LIST_HEAD(&bp->list_overhead); 278*0c0d06caSMauro Carvalho Chehab bp->purb = usb_alloc_urb(0,GFP_KERNEL); 279*0c0d06caSMauro Carvalho Chehab if (! bp->purb) return -ENOMEM; 280*0c0d06caSMauro Carvalho Chehab #ifdef SANITY_CHECK_BUFFERS 281*0c0d06caSMauro Carvalho Chehab pvr2_buffer_describe(bp,"create"); 282*0c0d06caSMauro Carvalho Chehab #endif 283*0c0d06caSMauro Carvalho Chehab return 0; 284*0c0d06caSMauro Carvalho Chehab } 285*0c0d06caSMauro Carvalho Chehab 286*0c0d06caSMauro Carvalho Chehab static void pvr2_buffer_done(struct pvr2_buffer *bp) 287*0c0d06caSMauro Carvalho Chehab { 288*0c0d06caSMauro Carvalho Chehab #ifdef SANITY_CHECK_BUFFERS 289*0c0d06caSMauro Carvalho Chehab pvr2_buffer_describe(bp,"delete"); 290*0c0d06caSMauro Carvalho Chehab #endif 291*0c0d06caSMauro Carvalho Chehab pvr2_buffer_wipe(bp); 292*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_none(bp); 293*0c0d06caSMauro Carvalho Chehab bp->signature = 0; 294*0c0d06caSMauro Carvalho Chehab bp->stream = NULL; 295*0c0d06caSMauro Carvalho Chehab usb_free_urb(bp->purb); 296*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/" 297*0c0d06caSMauro Carvalho Chehab " bufferDone %p",bp); 298*0c0d06caSMauro Carvalho Chehab } 299*0c0d06caSMauro Carvalho Chehab 300*0c0d06caSMauro Carvalho Chehab static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt) 301*0c0d06caSMauro Carvalho Chehab { 302*0c0d06caSMauro Carvalho Chehab int ret; 303*0c0d06caSMauro Carvalho Chehab unsigned int scnt; 304*0c0d06caSMauro Carvalho Chehab 305*0c0d06caSMauro Carvalho Chehab /* Allocate buffers pointer array in multiples of 32 entries */ 306*0c0d06caSMauro Carvalho Chehab if (cnt == sp->buffer_total_count) return 0; 307*0c0d06caSMauro Carvalho Chehab 308*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_POOL, 309*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ poolResize " 310*0c0d06caSMauro Carvalho Chehab " stream=%p cur=%d adj=%+d", 311*0c0d06caSMauro Carvalho Chehab sp, 312*0c0d06caSMauro Carvalho Chehab sp->buffer_total_count, 313*0c0d06caSMauro Carvalho Chehab cnt-sp->buffer_total_count); 314*0c0d06caSMauro Carvalho Chehab 315*0c0d06caSMauro Carvalho Chehab scnt = cnt & ~0x1f; 316*0c0d06caSMauro Carvalho Chehab if (cnt > scnt) scnt += 0x20; 317*0c0d06caSMauro Carvalho Chehab 318*0c0d06caSMauro Carvalho Chehab if (cnt > sp->buffer_total_count) { 319*0c0d06caSMauro Carvalho Chehab if (scnt > sp->buffer_slot_count) { 320*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer **nb; 321*0c0d06caSMauro Carvalho Chehab nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); 322*0c0d06caSMauro Carvalho Chehab if (!nb) return -ENOMEM; 323*0c0d06caSMauro Carvalho Chehab if (sp->buffer_slot_count) { 324*0c0d06caSMauro Carvalho Chehab memcpy(nb,sp->buffers, 325*0c0d06caSMauro Carvalho Chehab sp->buffer_slot_count * sizeof(*nb)); 326*0c0d06caSMauro Carvalho Chehab kfree(sp->buffers); 327*0c0d06caSMauro Carvalho Chehab } 328*0c0d06caSMauro Carvalho Chehab sp->buffers = nb; 329*0c0d06caSMauro Carvalho Chehab sp->buffer_slot_count = scnt; 330*0c0d06caSMauro Carvalho Chehab } 331*0c0d06caSMauro Carvalho Chehab while (sp->buffer_total_count < cnt) { 332*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp; 333*0c0d06caSMauro Carvalho Chehab bp = kmalloc(sizeof(*bp),GFP_KERNEL); 334*0c0d06caSMauro Carvalho Chehab if (!bp) return -ENOMEM; 335*0c0d06caSMauro Carvalho Chehab ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count); 336*0c0d06caSMauro Carvalho Chehab if (ret) { 337*0c0d06caSMauro Carvalho Chehab kfree(bp); 338*0c0d06caSMauro Carvalho Chehab return -ENOMEM; 339*0c0d06caSMauro Carvalho Chehab } 340*0c0d06caSMauro Carvalho Chehab sp->buffers[sp->buffer_total_count] = bp; 341*0c0d06caSMauro Carvalho Chehab (sp->buffer_total_count)++; 342*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_idle(bp); 343*0c0d06caSMauro Carvalho Chehab } 344*0c0d06caSMauro Carvalho Chehab } else { 345*0c0d06caSMauro Carvalho Chehab while (sp->buffer_total_count > cnt) { 346*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp; 347*0c0d06caSMauro Carvalho Chehab bp = sp->buffers[sp->buffer_total_count - 1]; 348*0c0d06caSMauro Carvalho Chehab /* Paranoia */ 349*0c0d06caSMauro Carvalho Chehab sp->buffers[sp->buffer_total_count - 1] = NULL; 350*0c0d06caSMauro Carvalho Chehab (sp->buffer_total_count)--; 351*0c0d06caSMauro Carvalho Chehab pvr2_buffer_done(bp); 352*0c0d06caSMauro Carvalho Chehab kfree(bp); 353*0c0d06caSMauro Carvalho Chehab } 354*0c0d06caSMauro Carvalho Chehab if (scnt < sp->buffer_slot_count) { 355*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer **nb = NULL; 356*0c0d06caSMauro Carvalho Chehab if (scnt) { 357*0c0d06caSMauro Carvalho Chehab nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); 358*0c0d06caSMauro Carvalho Chehab if (!nb) return -ENOMEM; 359*0c0d06caSMauro Carvalho Chehab memcpy(nb,sp->buffers,scnt * sizeof(*nb)); 360*0c0d06caSMauro Carvalho Chehab } 361*0c0d06caSMauro Carvalho Chehab kfree(sp->buffers); 362*0c0d06caSMauro Carvalho Chehab sp->buffers = nb; 363*0c0d06caSMauro Carvalho Chehab sp->buffer_slot_count = scnt; 364*0c0d06caSMauro Carvalho Chehab } 365*0c0d06caSMauro Carvalho Chehab } 366*0c0d06caSMauro Carvalho Chehab return 0; 367*0c0d06caSMauro Carvalho Chehab } 368*0c0d06caSMauro Carvalho Chehab 369*0c0d06caSMauro Carvalho Chehab static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp) 370*0c0d06caSMauro Carvalho Chehab { 371*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp; 372*0c0d06caSMauro Carvalho Chehab unsigned int cnt; 373*0c0d06caSMauro Carvalho Chehab 374*0c0d06caSMauro Carvalho Chehab if (sp->buffer_total_count == sp->buffer_target_count) return 0; 375*0c0d06caSMauro Carvalho Chehab 376*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_POOL, 377*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/" 378*0c0d06caSMauro Carvalho Chehab " poolCheck stream=%p cur=%d tgt=%d", 379*0c0d06caSMauro Carvalho Chehab sp,sp->buffer_total_count,sp->buffer_target_count); 380*0c0d06caSMauro Carvalho Chehab 381*0c0d06caSMauro Carvalho Chehab if (sp->buffer_total_count < sp->buffer_target_count) { 382*0c0d06caSMauro Carvalho Chehab return pvr2_stream_buffer_count(sp,sp->buffer_target_count); 383*0c0d06caSMauro Carvalho Chehab } 384*0c0d06caSMauro Carvalho Chehab 385*0c0d06caSMauro Carvalho Chehab cnt = 0; 386*0c0d06caSMauro Carvalho Chehab while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) { 387*0c0d06caSMauro Carvalho Chehab bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; 388*0c0d06caSMauro Carvalho Chehab if (bp->state != pvr2_buffer_state_idle) break; 389*0c0d06caSMauro Carvalho Chehab cnt++; 390*0c0d06caSMauro Carvalho Chehab } 391*0c0d06caSMauro Carvalho Chehab if (cnt) { 392*0c0d06caSMauro Carvalho Chehab pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt); 393*0c0d06caSMauro Carvalho Chehab } 394*0c0d06caSMauro Carvalho Chehab 395*0c0d06caSMauro Carvalho Chehab return 0; 396*0c0d06caSMauro Carvalho Chehab } 397*0c0d06caSMauro Carvalho Chehab 398*0c0d06caSMauro Carvalho Chehab static void pvr2_stream_internal_flush(struct pvr2_stream *sp) 399*0c0d06caSMauro Carvalho Chehab { 400*0c0d06caSMauro Carvalho Chehab struct list_head *lp; 401*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp1; 402*0c0d06caSMauro Carvalho Chehab while ((lp = sp->queued_list.next) != &sp->queued_list) { 403*0c0d06caSMauro Carvalho Chehab bp1 = list_entry(lp,struct pvr2_buffer,list_overhead); 404*0c0d06caSMauro Carvalho Chehab pvr2_buffer_wipe(bp1); 405*0c0d06caSMauro Carvalho Chehab /* At this point, we should be guaranteed that no 406*0c0d06caSMauro Carvalho Chehab completion callback may happen on this buffer. But it's 407*0c0d06caSMauro Carvalho Chehab possible that it might have completed after we noticed 408*0c0d06caSMauro Carvalho Chehab it but before we wiped it. So double check its status 409*0c0d06caSMauro Carvalho Chehab here first. */ 410*0c0d06caSMauro Carvalho Chehab if (bp1->state != pvr2_buffer_state_queued) continue; 411*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_idle(bp1); 412*0c0d06caSMauro Carvalho Chehab } 413*0c0d06caSMauro Carvalho Chehab if (sp->buffer_total_count != sp->buffer_target_count) { 414*0c0d06caSMauro Carvalho Chehab pvr2_stream_achieve_buffer_count(sp); 415*0c0d06caSMauro Carvalho Chehab } 416*0c0d06caSMauro Carvalho Chehab } 417*0c0d06caSMauro Carvalho Chehab 418*0c0d06caSMauro Carvalho Chehab static void pvr2_stream_init(struct pvr2_stream *sp) 419*0c0d06caSMauro Carvalho Chehab { 420*0c0d06caSMauro Carvalho Chehab spin_lock_init(&sp->list_lock); 421*0c0d06caSMauro Carvalho Chehab mutex_init(&sp->mutex); 422*0c0d06caSMauro Carvalho Chehab INIT_LIST_HEAD(&sp->queued_list); 423*0c0d06caSMauro Carvalho Chehab INIT_LIST_HEAD(&sp->ready_list); 424*0c0d06caSMauro Carvalho Chehab INIT_LIST_HEAD(&sp->idle_list); 425*0c0d06caSMauro Carvalho Chehab } 426*0c0d06caSMauro Carvalho Chehab 427*0c0d06caSMauro Carvalho Chehab static void pvr2_stream_done(struct pvr2_stream *sp) 428*0c0d06caSMauro Carvalho Chehab { 429*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 430*0c0d06caSMauro Carvalho Chehab pvr2_stream_internal_flush(sp); 431*0c0d06caSMauro Carvalho Chehab pvr2_stream_buffer_count(sp,0); 432*0c0d06caSMauro Carvalho Chehab } while (0); mutex_unlock(&sp->mutex); 433*0c0d06caSMauro Carvalho Chehab } 434*0c0d06caSMauro Carvalho Chehab 435*0c0d06caSMauro Carvalho Chehab static void buffer_complete(struct urb *urb) 436*0c0d06caSMauro Carvalho Chehab { 437*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp = urb->context; 438*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 439*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 440*0c0d06caSMauro Carvalho Chehab BUFFER_CHECK(bp); 441*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 442*0c0d06caSMauro Carvalho Chehab bp->used_count = 0; 443*0c0d06caSMauro Carvalho Chehab bp->status = 0; 444*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 445*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d", 446*0c0d06caSMauro Carvalho Chehab bp,urb->status,urb->actual_length); 447*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 448*0c0d06caSMauro Carvalho Chehab if ((!(urb->status)) || 449*0c0d06caSMauro Carvalho Chehab (urb->status == -ENOENT) || 450*0c0d06caSMauro Carvalho Chehab (urb->status == -ECONNRESET) || 451*0c0d06caSMauro Carvalho Chehab (urb->status == -ESHUTDOWN)) { 452*0c0d06caSMauro Carvalho Chehab (sp->buffers_processed)++; 453*0c0d06caSMauro Carvalho Chehab sp->bytes_processed += urb->actual_length; 454*0c0d06caSMauro Carvalho Chehab bp->used_count = urb->actual_length; 455*0c0d06caSMauro Carvalho Chehab if (sp->fail_count) { 456*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_TOLERANCE, 457*0c0d06caSMauro Carvalho Chehab "stream %p transfer ok" 458*0c0d06caSMauro Carvalho Chehab " - fail count reset",sp); 459*0c0d06caSMauro Carvalho Chehab sp->fail_count = 0; 460*0c0d06caSMauro Carvalho Chehab } 461*0c0d06caSMauro Carvalho Chehab } else if (sp->fail_count < sp->fail_tolerance) { 462*0c0d06caSMauro Carvalho Chehab // We can tolerate this error, because we're below the 463*0c0d06caSMauro Carvalho Chehab // threshold... 464*0c0d06caSMauro Carvalho Chehab (sp->fail_count)++; 465*0c0d06caSMauro Carvalho Chehab (sp->buffers_failed)++; 466*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_TOLERANCE, 467*0c0d06caSMauro Carvalho Chehab "stream %p ignoring error %d" 468*0c0d06caSMauro Carvalho Chehab " - fail count increased to %u", 469*0c0d06caSMauro Carvalho Chehab sp,urb->status,sp->fail_count); 470*0c0d06caSMauro Carvalho Chehab } else { 471*0c0d06caSMauro Carvalho Chehab (sp->buffers_failed)++; 472*0c0d06caSMauro Carvalho Chehab bp->status = urb->status; 473*0c0d06caSMauro Carvalho Chehab } 474*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 475*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_ready(bp); 476*0c0d06caSMauro Carvalho Chehab if (sp && sp->callback_func) { 477*0c0d06caSMauro Carvalho Chehab sp->callback_func(sp->callback_data); 478*0c0d06caSMauro Carvalho Chehab } 479*0c0d06caSMauro Carvalho Chehab } 480*0c0d06caSMauro Carvalho Chehab 481*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *pvr2_stream_create(void) 482*0c0d06caSMauro Carvalho Chehab { 483*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 484*0c0d06caSMauro Carvalho Chehab sp = kzalloc(sizeof(*sp),GFP_KERNEL); 485*0c0d06caSMauro Carvalho Chehab if (!sp) return sp; 486*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp); 487*0c0d06caSMauro Carvalho Chehab pvr2_stream_init(sp); 488*0c0d06caSMauro Carvalho Chehab return sp; 489*0c0d06caSMauro Carvalho Chehab } 490*0c0d06caSMauro Carvalho Chehab 491*0c0d06caSMauro Carvalho Chehab void pvr2_stream_destroy(struct pvr2_stream *sp) 492*0c0d06caSMauro Carvalho Chehab { 493*0c0d06caSMauro Carvalho Chehab if (!sp) return; 494*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp); 495*0c0d06caSMauro Carvalho Chehab pvr2_stream_done(sp); 496*0c0d06caSMauro Carvalho Chehab kfree(sp); 497*0c0d06caSMauro Carvalho Chehab } 498*0c0d06caSMauro Carvalho Chehab 499*0c0d06caSMauro Carvalho Chehab void pvr2_stream_setup(struct pvr2_stream *sp, 500*0c0d06caSMauro Carvalho Chehab struct usb_device *dev, 501*0c0d06caSMauro Carvalho Chehab int endpoint, 502*0c0d06caSMauro Carvalho Chehab unsigned int tolerance) 503*0c0d06caSMauro Carvalho Chehab { 504*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 505*0c0d06caSMauro Carvalho Chehab pvr2_stream_internal_flush(sp); 506*0c0d06caSMauro Carvalho Chehab sp->dev = dev; 507*0c0d06caSMauro Carvalho Chehab sp->endpoint = endpoint; 508*0c0d06caSMauro Carvalho Chehab sp->fail_tolerance = tolerance; 509*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 510*0c0d06caSMauro Carvalho Chehab } 511*0c0d06caSMauro Carvalho Chehab 512*0c0d06caSMauro Carvalho Chehab void pvr2_stream_set_callback(struct pvr2_stream *sp, 513*0c0d06caSMauro Carvalho Chehab pvr2_stream_callback func, 514*0c0d06caSMauro Carvalho Chehab void *data) 515*0c0d06caSMauro Carvalho Chehab { 516*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 517*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 518*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 519*0c0d06caSMauro Carvalho Chehab sp->callback_data = data; 520*0c0d06caSMauro Carvalho Chehab sp->callback_func = func; 521*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 522*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 523*0c0d06caSMauro Carvalho Chehab } 524*0c0d06caSMauro Carvalho Chehab 525*0c0d06caSMauro Carvalho Chehab void pvr2_stream_get_stats(struct pvr2_stream *sp, 526*0c0d06caSMauro Carvalho Chehab struct pvr2_stream_stats *stats, 527*0c0d06caSMauro Carvalho Chehab int zero_counts) 528*0c0d06caSMauro Carvalho Chehab { 529*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 530*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 531*0c0d06caSMauro Carvalho Chehab if (stats) { 532*0c0d06caSMauro Carvalho Chehab stats->buffers_in_queue = sp->q_count; 533*0c0d06caSMauro Carvalho Chehab stats->buffers_in_idle = sp->i_count; 534*0c0d06caSMauro Carvalho Chehab stats->buffers_in_ready = sp->r_count; 535*0c0d06caSMauro Carvalho Chehab stats->buffers_processed = sp->buffers_processed; 536*0c0d06caSMauro Carvalho Chehab stats->buffers_failed = sp->buffers_failed; 537*0c0d06caSMauro Carvalho Chehab stats->bytes_processed = sp->bytes_processed; 538*0c0d06caSMauro Carvalho Chehab } 539*0c0d06caSMauro Carvalho Chehab if (zero_counts) { 540*0c0d06caSMauro Carvalho Chehab sp->buffers_processed = 0; 541*0c0d06caSMauro Carvalho Chehab sp->buffers_failed = 0; 542*0c0d06caSMauro Carvalho Chehab sp->bytes_processed = 0; 543*0c0d06caSMauro Carvalho Chehab } 544*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 545*0c0d06caSMauro Carvalho Chehab } 546*0c0d06caSMauro Carvalho Chehab 547*0c0d06caSMauro Carvalho Chehab /* Query / set the nominal buffer count */ 548*0c0d06caSMauro Carvalho Chehab int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) 549*0c0d06caSMauro Carvalho Chehab { 550*0c0d06caSMauro Carvalho Chehab return sp->buffer_target_count; 551*0c0d06caSMauro Carvalho Chehab } 552*0c0d06caSMauro Carvalho Chehab 553*0c0d06caSMauro Carvalho Chehab int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt) 554*0c0d06caSMauro Carvalho Chehab { 555*0c0d06caSMauro Carvalho Chehab int ret; 556*0c0d06caSMauro Carvalho Chehab if (sp->buffer_target_count == cnt) return 0; 557*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 558*0c0d06caSMauro Carvalho Chehab sp->buffer_target_count = cnt; 559*0c0d06caSMauro Carvalho Chehab ret = pvr2_stream_achieve_buffer_count(sp); 560*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 561*0c0d06caSMauro Carvalho Chehab return ret; 562*0c0d06caSMauro Carvalho Chehab } 563*0c0d06caSMauro Carvalho Chehab 564*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp) 565*0c0d06caSMauro Carvalho Chehab { 566*0c0d06caSMauro Carvalho Chehab struct list_head *lp = sp->idle_list.next; 567*0c0d06caSMauro Carvalho Chehab if (lp == &sp->idle_list) return NULL; 568*0c0d06caSMauro Carvalho Chehab return list_entry(lp,struct pvr2_buffer,list_overhead); 569*0c0d06caSMauro Carvalho Chehab } 570*0c0d06caSMauro Carvalho Chehab 571*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp) 572*0c0d06caSMauro Carvalho Chehab { 573*0c0d06caSMauro Carvalho Chehab struct list_head *lp = sp->ready_list.next; 574*0c0d06caSMauro Carvalho Chehab if (lp == &sp->ready_list) return NULL; 575*0c0d06caSMauro Carvalho Chehab return list_entry(lp,struct pvr2_buffer,list_overhead); 576*0c0d06caSMauro Carvalho Chehab } 577*0c0d06caSMauro Carvalho Chehab 578*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id) 579*0c0d06caSMauro Carvalho Chehab { 580*0c0d06caSMauro Carvalho Chehab if (id < 0) return NULL; 581*0c0d06caSMauro Carvalho Chehab if (id >= sp->buffer_total_count) return NULL; 582*0c0d06caSMauro Carvalho Chehab return sp->buffers[id]; 583*0c0d06caSMauro Carvalho Chehab } 584*0c0d06caSMauro Carvalho Chehab 585*0c0d06caSMauro Carvalho Chehab int pvr2_stream_get_ready_count(struct pvr2_stream *sp) 586*0c0d06caSMauro Carvalho Chehab { 587*0c0d06caSMauro Carvalho Chehab return sp->r_count; 588*0c0d06caSMauro Carvalho Chehab } 589*0c0d06caSMauro Carvalho Chehab 590*0c0d06caSMauro Carvalho Chehab void pvr2_stream_kill(struct pvr2_stream *sp) 591*0c0d06caSMauro Carvalho Chehab { 592*0c0d06caSMauro Carvalho Chehab struct pvr2_buffer *bp; 593*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 594*0c0d06caSMauro Carvalho Chehab pvr2_stream_internal_flush(sp); 595*0c0d06caSMauro Carvalho Chehab while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { 596*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_idle(bp); 597*0c0d06caSMauro Carvalho Chehab } 598*0c0d06caSMauro Carvalho Chehab if (sp->buffer_total_count != sp->buffer_target_count) { 599*0c0d06caSMauro Carvalho Chehab pvr2_stream_achieve_buffer_count(sp); 600*0c0d06caSMauro Carvalho Chehab } 601*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 602*0c0d06caSMauro Carvalho Chehab } 603*0c0d06caSMauro Carvalho Chehab 604*0c0d06caSMauro Carvalho Chehab int pvr2_buffer_queue(struct pvr2_buffer *bp) 605*0c0d06caSMauro Carvalho Chehab { 606*0c0d06caSMauro Carvalho Chehab #undef SEED_BUFFER 607*0c0d06caSMauro Carvalho Chehab #ifdef SEED_BUFFER 608*0c0d06caSMauro Carvalho Chehab unsigned int idx; 609*0c0d06caSMauro Carvalho Chehab unsigned int val; 610*0c0d06caSMauro Carvalho Chehab #endif 611*0c0d06caSMauro Carvalho Chehab int ret = 0; 612*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 613*0c0d06caSMauro Carvalho Chehab if (!bp) return -EINVAL; 614*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 615*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 616*0c0d06caSMauro Carvalho Chehab pvr2_buffer_wipe(bp); 617*0c0d06caSMauro Carvalho Chehab if (!sp->dev) { 618*0c0d06caSMauro Carvalho Chehab ret = -EIO; 619*0c0d06caSMauro Carvalho Chehab break; 620*0c0d06caSMauro Carvalho Chehab } 621*0c0d06caSMauro Carvalho Chehab pvr2_buffer_set_queued(bp); 622*0c0d06caSMauro Carvalho Chehab #ifdef SEED_BUFFER 623*0c0d06caSMauro Carvalho Chehab for (idx = 0; idx < (bp->max_count) / 4; idx++) { 624*0c0d06caSMauro Carvalho Chehab val = bp->id << 24; 625*0c0d06caSMauro Carvalho Chehab val |= idx; 626*0c0d06caSMauro Carvalho Chehab ((unsigned int *)(bp->ptr))[idx] = val; 627*0c0d06caSMauro Carvalho Chehab } 628*0c0d06caSMauro Carvalho Chehab #endif 629*0c0d06caSMauro Carvalho Chehab bp->status = -EINPROGRESS; 630*0c0d06caSMauro Carvalho Chehab usb_fill_bulk_urb(bp->purb, // struct urb *urb 631*0c0d06caSMauro Carvalho Chehab sp->dev, // struct usb_device *dev 632*0c0d06caSMauro Carvalho Chehab // endpoint (below) 633*0c0d06caSMauro Carvalho Chehab usb_rcvbulkpipe(sp->dev,sp->endpoint), 634*0c0d06caSMauro Carvalho Chehab bp->ptr, // void *transfer_buffer 635*0c0d06caSMauro Carvalho Chehab bp->max_count, // int buffer_length 636*0c0d06caSMauro Carvalho Chehab buffer_complete, 637*0c0d06caSMauro Carvalho Chehab bp); 638*0c0d06caSMauro Carvalho Chehab usb_submit_urb(bp->purb,GFP_KERNEL); 639*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 640*0c0d06caSMauro Carvalho Chehab return ret; 641*0c0d06caSMauro Carvalho Chehab } 642*0c0d06caSMauro Carvalho Chehab 643*0c0d06caSMauro Carvalho Chehab int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) 644*0c0d06caSMauro Carvalho Chehab { 645*0c0d06caSMauro Carvalho Chehab int ret = 0; 646*0c0d06caSMauro Carvalho Chehab unsigned long irq_flags; 647*0c0d06caSMauro Carvalho Chehab struct pvr2_stream *sp; 648*0c0d06caSMauro Carvalho Chehab if (!bp) return -EINVAL; 649*0c0d06caSMauro Carvalho Chehab sp = bp->stream; 650*0c0d06caSMauro Carvalho Chehab mutex_lock(&sp->mutex); do { 651*0c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&sp->list_lock,irq_flags); 652*0c0d06caSMauro Carvalho Chehab if (bp->state != pvr2_buffer_state_idle) { 653*0c0d06caSMauro Carvalho Chehab ret = -EPERM; 654*0c0d06caSMauro Carvalho Chehab } else { 655*0c0d06caSMauro Carvalho Chehab bp->ptr = ptr; 656*0c0d06caSMauro Carvalho Chehab bp->stream->i_bcount -= bp->max_count; 657*0c0d06caSMauro Carvalho Chehab bp->max_count = cnt; 658*0c0d06caSMauro Carvalho Chehab bp->stream->i_bcount += bp->max_count; 659*0c0d06caSMauro Carvalho Chehab pvr2_trace(PVR2_TRACE_BUF_FLOW, 660*0c0d06caSMauro Carvalho Chehab "/*---TRACE_FLOW---*/ bufferPool " 661*0c0d06caSMauro Carvalho Chehab " %8s cap cap=%07d cnt=%02d", 662*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_decode( 663*0c0d06caSMauro Carvalho Chehab pvr2_buffer_state_idle), 664*0c0d06caSMauro Carvalho Chehab bp->stream->i_bcount,bp->stream->i_count); 665*0c0d06caSMauro Carvalho Chehab } 666*0c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&sp->list_lock,irq_flags); 667*0c0d06caSMauro Carvalho Chehab } while(0); mutex_unlock(&sp->mutex); 668*0c0d06caSMauro Carvalho Chehab return ret; 669*0c0d06caSMauro Carvalho Chehab } 670*0c0d06caSMauro Carvalho Chehab 671*0c0d06caSMauro Carvalho Chehab unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp) 672*0c0d06caSMauro Carvalho Chehab { 673*0c0d06caSMauro Carvalho Chehab return bp->used_count; 674*0c0d06caSMauro Carvalho Chehab } 675*0c0d06caSMauro Carvalho Chehab 676*0c0d06caSMauro Carvalho Chehab int pvr2_buffer_get_status(struct pvr2_buffer *bp) 677*0c0d06caSMauro Carvalho Chehab { 678*0c0d06caSMauro Carvalho Chehab return bp->status; 679*0c0d06caSMauro Carvalho Chehab } 680*0c0d06caSMauro Carvalho Chehab 681*0c0d06caSMauro Carvalho Chehab int pvr2_buffer_get_id(struct pvr2_buffer *bp) 682*0c0d06caSMauro Carvalho Chehab { 683*0c0d06caSMauro Carvalho Chehab return bp->id; 684*0c0d06caSMauro Carvalho Chehab } 685*0c0d06caSMauro Carvalho Chehab 686*0c0d06caSMauro Carvalho Chehab 687*0c0d06caSMauro Carvalho Chehab /* 688*0c0d06caSMauro Carvalho Chehab Stuff for Emacs to see, in order to encourage consistent editing style: 689*0c0d06caSMauro Carvalho Chehab *** Local Variables: *** 690*0c0d06caSMauro Carvalho Chehab *** mode: c *** 691*0c0d06caSMauro Carvalho Chehab *** fill-column: 75 *** 692*0c0d06caSMauro Carvalho Chehab *** tab-width: 8 *** 693*0c0d06caSMauro Carvalho Chehab *** c-basic-offset: 8 *** 694*0c0d06caSMauro Carvalho Chehab *** End: *** 695*0c0d06caSMauro Carvalho Chehab */ 696