📄 pvrusb2-io.c
字号:
/* Paranoia */ sp->buffers[sp->buffer_total_count - 1] = 0; (sp->buffer_total_count)--; pvr2_buffer_done(bp); kfree(bp); } if (scnt < sp->buffer_slot_count) { struct pvr2_buffer **nb = 0; if (scnt) { nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL); if (!nb) return -ENOMEM; memcpy(nb,sp->buffers,scnt * sizeof(*nb)); } kfree(sp->buffers); sp->buffers = nb; sp->buffer_slot_count = scnt; } } return 0;}static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp){ struct pvr2_buffer *bp; unsigned int cnt; if (sp->buffer_total_count == sp->buffer_target_count) return 0; pvr2_trace(PVR2_TRACE_BUF_POOL, "/*---TRACE_FLOW---*/" " poolCheck stream=%p cur=%d tgt=%d", sp,sp->buffer_total_count,sp->buffer_target_count); if (sp->buffer_total_count < sp->buffer_target_count) { return pvr2_stream_buffer_count(sp,sp->buffer_target_count); } cnt = 0; while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) { bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; if (bp->state != pvr2_buffer_state_idle) break; cnt++; } if (cnt) { pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt); } return 0;}static void pvr2_stream_internal_flush(struct pvr2_stream *sp){ struct list_head *lp; struct pvr2_buffer *bp1; while ((lp = sp->queued_list.next) != &sp->queued_list) { bp1 = list_entry(lp,struct pvr2_buffer,list_overhead); pvr2_buffer_wipe(bp1); /* At this point, we should be guaranteed that no completion callback may happen on this buffer. But it's possible that it might have completed after we noticed it but before we wiped it. So double check its status here first. */ if (bp1->state != pvr2_buffer_state_queued) continue; pvr2_buffer_set_idle(bp1); } if (sp->buffer_total_count != sp->buffer_target_count) { pvr2_stream_achieve_buffer_count(sp); }}static void pvr2_stream_init(struct pvr2_stream *sp){ spin_lock_init(&sp->list_lock); mutex_init(&sp->stream_mutex); INIT_LIST_HEAD(&sp->queued_list); INIT_LIST_HEAD(&sp->ready_list); INIT_LIST_HEAD(&sp->idle_list);}static void pvr2_stream_done(struct pvr2_stream *sp){ mutex_lock(&sp->stream_mutex); do { pvr2_stream_internal_flush(sp); pvr2_stream_buffer_count(sp,0); } while (0); mutex_unlock(&sp->stream_mutex);}static void buffer_complete(struct urb *urb, struct pt_regs *regs){ struct pvr2_buffer *bp = urb->context; struct pvr2_stream *sp; unsigned long irq_flags; BUFFER_CHECK(bp); sp = bp->stream; bp->used_count = 0; bp->status = 0; pvr2_trace(PVR2_TRACE_BUF_FLOW, "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d", bp,urb->status,urb->actual_length); spin_lock_irqsave(&sp->list_lock,irq_flags); if ((!(urb->status)) || (urb->status == -ENOENT) || (urb->status == -ECONNRESET) || (urb->status == -ESHUTDOWN)) { bp->used_count = urb->actual_length; if (sp->fail_count) { pvr2_trace(PVR2_TRACE_TOLERANCE, "stream %p transfer ok" " - fail count reset",sp); sp->fail_count = 0; } } else if (sp->fail_count < sp->fail_tolerance) { // We can tolerate this error, because we're below the // threshold... (sp->fail_count)++; pvr2_trace(PVR2_TRACE_TOLERANCE, "stream %p ignoring error %d" " - fail count increased to %u", sp,urb->status,sp->fail_count); } else { bp->status = urb->status; } spin_unlock_irqrestore(&sp->list_lock,irq_flags); pvr2_buffer_set_ready(bp); if (sp && sp->callback_func) { sp->callback_func(sp->callback_data); }}struct pvr2_stream *pvr2_stream_create(void){ struct pvr2_stream *sp; sp = kmalloc(sizeof(*sp),GFP_KERNEL); if (!sp) return sp; memset(sp,0,sizeof(*sp)); pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp); pvr2_stream_init(sp); return sp;}void pvr2_stream_destroy(struct pvr2_stream *sp){ if (!sp) return; pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp); pvr2_stream_done(sp); kfree(sp);}void pvr2_stream_setup(struct pvr2_stream *sp, struct usb_device *dev, int endpoint, unsigned int tolerance){ mutex_lock(&sp->stream_mutex); do { pvr2_stream_internal_flush(sp); sp->dev = dev; sp->endpoint = endpoint; sp->fail_tolerance = tolerance; } while(0); mutex_unlock(&sp->stream_mutex);}void pvr2_stream_set_callback(struct pvr2_stream *sp, pvr2_stream_callback func, void *data){ unsigned long irq_flags; mutex_lock(&sp->stream_mutex); do { spin_lock_irqsave(&sp->list_lock,irq_flags); sp->callback_data = data; sp->callback_func = func; spin_unlock_irqrestore(&sp->list_lock,irq_flags); } while(0); mutex_unlock(&sp->stream_mutex);}/* Query / set the nominal buffer count */int pvr2_stream_get_buffer_count(struct pvr2_stream *sp){ return sp->buffer_target_count;}int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt){ int ret; if (sp->buffer_target_count == cnt) return 0; mutex_lock(&sp->stream_mutex); do { sp->buffer_target_count = cnt; ret = pvr2_stream_achieve_buffer_count(sp); } while(0); mutex_unlock(&sp->stream_mutex); return ret;}struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp){ struct list_head *lp = sp->idle_list.next; if (lp == &sp->idle_list) return 0; return list_entry(lp,struct pvr2_buffer,list_overhead);}struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp){ struct list_head *lp = sp->ready_list.next; if (lp == &sp->ready_list) return 0; return list_entry(lp,struct pvr2_buffer,list_overhead);}struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id){ if (id < 0) return 0; if (id >= sp->buffer_total_count) return 0; return sp->buffers[id];}int pvr2_stream_get_ready_count(struct pvr2_stream *sp){ return sp->r_count;}int pvr2_stream_get_idle_count(struct pvr2_stream *sp){ return sp->i_count;}void pvr2_stream_flush(struct pvr2_stream *sp){ mutex_lock(&sp->stream_mutex); do { pvr2_stream_internal_flush(sp); } while(0); mutex_unlock(&sp->stream_mutex);}void pvr2_stream_kill(struct pvr2_stream *sp){ struct pvr2_buffer *bp; mutex_lock(&sp->stream_mutex); do { pvr2_stream_internal_flush(sp); while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) { pvr2_buffer_set_idle(bp); } if (sp->buffer_total_count != sp->buffer_target_count) { pvr2_stream_achieve_buffer_count(sp); } } while(0); mutex_unlock(&sp->stream_mutex);}int pvr2_buffer_queue(struct pvr2_buffer *bp){#undef SEED_BUFFER#ifdef SEED_BUFFER unsigned int idx; unsigned int val;#endif int ret = 0; struct pvr2_stream *sp; if (!bp) return -EINVAL; sp = bp->stream; mutex_lock(&sp->stream_mutex); do { pvr2_buffer_wipe(bp); if (!sp->dev) { ret = -EIO; break; } pvr2_buffer_set_queued(bp);#ifdef SEED_BUFFER for (idx = 0; idx < (bp->max_count) / 4; idx++) { val = bp->id << 24; val |= idx; ((unsigned int *)(bp->ptr))[idx] = val; }#endif bp->status = -EINPROGRESS; usb_fill_bulk_urb(bp->purb, // struct urb *urb sp->dev, // struct usb_device *dev // endpoint (below) usb_rcvbulkpipe(sp->dev,sp->endpoint), bp->ptr, // void *transfer_buffer bp->max_count, // int buffer_length buffer_complete, bp); usb_submit_urb(bp->purb,GFP_KERNEL); } while(0); mutex_unlock(&sp->stream_mutex); return ret;}int pvr2_buffer_idle(struct pvr2_buffer *bp){ struct pvr2_stream *sp; if (!bp) return -EINVAL; sp = bp->stream; mutex_lock(&sp->stream_mutex); do { pvr2_buffer_wipe(bp); pvr2_buffer_set_idle(bp); if (sp->buffer_total_count != sp->buffer_target_count) { pvr2_stream_achieve_buffer_count(sp); } } while(0); mutex_unlock(&sp->stream_mutex); return 0;}int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt){ int ret = 0; unsigned long irq_flags; struct pvr2_stream *sp; if (!bp) return -EINVAL; sp = bp->stream; mutex_lock(&sp->stream_mutex); do { spin_lock_irqsave(&sp->list_lock,irq_flags); if (bp->state != pvr2_buffer_state_idle) { ret = -EPERM; } else { bp->ptr = ptr; bp->stream->i_bcount -= bp->max_count; bp->max_count = cnt; bp->stream->i_bcount += bp->max_count; pvr2_trace(PVR2_TRACE_BUF_FLOW, "/*---TRACE_FLOW---*/ bufferPool " " %8s cap cap=%07d cnt=%02d", pvr2_buffer_state_decode( pvr2_buffer_state_idle), bp->stream->i_bcount,bp->stream->i_count); } spin_unlock_irqrestore(&sp->list_lock,irq_flags); } while(0); mutex_unlock(&sp->stream_mutex); return ret;}unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp){ return bp->used_count;}int pvr2_buffer_get_status(struct pvr2_buffer *bp){ return bp->status;}enum pvr2_buffer_state pvr2_buffer_get_state(struct pvr2_buffer *bp){ return bp->state;}int pvr2_buffer_get_id(struct pvr2_buffer *bp){ return bp->id;}/* Stuff for Emacs to see, in order to encourage consistent editing style: *** Local Variables: *** *** mode: c *** *** fill-column: 75 *** *** tab-width: 8 *** *** c-basic-offset: 8 *** *** End: *** */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -