⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pvrusb2-io.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * *  $Id$ * *  Copyright (C) 2005 Mike Isely <isely@pobox.com> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include "pvrusb2-io.h"#include "pvrusb2-debug.h"#include <linux/errno.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/mutex.h>static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);#define BUFFER_SIG 0x47653271// #define SANITY_CHECK_BUFFERS#ifdef SANITY_CHECK_BUFFERS#define BUFFER_CHECK(bp) do { \	if ((bp)->signature != BUFFER_SIG) { \		pvr2_trace(PVR2_TRACE_ERROR_LEGS, \		"Buffer %p is bad at %s:%d", \		(bp),__FILE__,__LINE__); \		pvr2_buffer_describe(bp,"BadSig"); \		BUG(); \	} \} while (0)#else#define BUFFER_CHECK(bp) do {} while(0)#endifstruct pvr2_stream {	/* Buffers queued for reading */	struct list_head queued_list;	unsigned int q_count;	unsigned int q_bcount;	/* Buffers with retrieved data */	struct list_head ready_list;	unsigned int r_count;	unsigned int r_bcount;	/* Buffers available for use */	struct list_head idle_list;	unsigned int i_count;	unsigned int i_bcount;	/* Pointers to all buffers */	struct pvr2_buffer **buffers;	/* Array size of buffers */	unsigned int buffer_slot_count;	/* Total buffers actually in circulation */	unsigned int buffer_total_count;	/* Designed number of buffers to be in circulation */	unsigned int buffer_target_count;	/* Executed when ready list become non-empty */	pvr2_stream_callback callback_func;	void *callback_data;	/* Context for transfer endpoint */	struct usb_device *dev;	int endpoint;	/* Overhead for mutex enforcement */	spinlock_t list_lock;	struct mutex mutex;	/* Tracking state for tolerating errors */	unsigned int fail_count;	unsigned int fail_tolerance;};struct pvr2_buffer {	int id;	int signature;	enum pvr2_buffer_state state;	void *ptr;               /* Pointer to storage area */	unsigned int max_count;  /* Size of storage area */	unsigned int used_count; /* Amount of valid data in storage area */	int status;              /* Transfer result status */	struct pvr2_stream *stream;	struct list_head list_overhead;	struct urb *purb;};static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st){	switch (st) {	case pvr2_buffer_state_none: return "none";	case pvr2_buffer_state_idle: return "idle";	case pvr2_buffer_state_queued: return "queued";	case pvr2_buffer_state_ready: return "ready";	}	return "unknown";}#ifdef SANITY_CHECK_BUFFERSstatic void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg){	pvr2_trace(PVR2_TRACE_INFO,		   "buffer%s%s %p state=%s id=%d status=%d"		   " stream=%p purb=%p sig=0x%x",		   (msg ? " " : ""),		   (msg ? msg : ""),		   bp,		   (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"),		   (bp ? bp->id : 0),		   (bp ? bp->status : 0),		   (bp ? bp->stream : NULL),		   (bp ? bp->purb : NULL),		   (bp ? bp->signature : 0));}#endif  /*  SANITY_CHECK_BUFFERS  */static void pvr2_buffer_remove(struct pvr2_buffer *bp){	unsigned int *cnt;	unsigned int *bcnt;	unsigned int ccnt;	struct pvr2_stream *sp = bp->stream;	switch (bp->state) {	case pvr2_buffer_state_idle:		cnt = &sp->i_count;		bcnt = &sp->i_bcount;		ccnt = bp->max_count;		break;	case pvr2_buffer_state_queued:		cnt = &sp->q_count;		bcnt = &sp->q_bcount;		ccnt = bp->max_count;		break;	case pvr2_buffer_state_ready:		cnt = &sp->r_count;		bcnt = &sp->r_bcount;		ccnt = bp->used_count;		break;	default:		return;	}	list_del_init(&bp->list_overhead);	(*cnt)--;	(*bcnt) -= ccnt;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/"		   " bufferPool     %8s dec cap=%07d cnt=%02d",		   pvr2_buffer_state_decode(bp->state),*bcnt,*cnt);	bp->state = pvr2_buffer_state_none;}static void pvr2_buffer_set_none(struct pvr2_buffer *bp){	unsigned long irq_flags;	struct pvr2_stream *sp;	BUFFER_CHECK(bp);	sp = bp->stream;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",		   bp,		   pvr2_buffer_state_decode(bp->state),		   pvr2_buffer_state_decode(pvr2_buffer_state_none));	spin_lock_irqsave(&sp->list_lock,irq_flags);	pvr2_buffer_remove(bp);	spin_unlock_irqrestore(&sp->list_lock,irq_flags);}static int pvr2_buffer_set_ready(struct pvr2_buffer *bp){	int fl;	unsigned long irq_flags;	struct pvr2_stream *sp;	BUFFER_CHECK(bp);	sp = bp->stream;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",		   bp,		   pvr2_buffer_state_decode(bp->state),		   pvr2_buffer_state_decode(pvr2_buffer_state_ready));	spin_lock_irqsave(&sp->list_lock,irq_flags);	fl = (sp->r_count == 0);	pvr2_buffer_remove(bp);	list_add_tail(&bp->list_overhead,&sp->ready_list);	bp->state = pvr2_buffer_state_ready;	(sp->r_count)++;	sp->r_bcount += bp->used_count;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/"		   " bufferPool     %8s inc cap=%07d cnt=%02d",		   pvr2_buffer_state_decode(bp->state),		   sp->r_bcount,sp->r_count);	spin_unlock_irqrestore(&sp->list_lock,irq_flags);	return fl;}static void pvr2_buffer_set_idle(struct pvr2_buffer *bp){	unsigned long irq_flags;	struct pvr2_stream *sp;	BUFFER_CHECK(bp);	sp = bp->stream;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",		   bp,		   pvr2_buffer_state_decode(bp->state),		   pvr2_buffer_state_decode(pvr2_buffer_state_idle));	spin_lock_irqsave(&sp->list_lock,irq_flags);	pvr2_buffer_remove(bp);	list_add_tail(&bp->list_overhead,&sp->idle_list);	bp->state = pvr2_buffer_state_idle;	(sp->i_count)++;	sp->i_bcount += bp->max_count;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/"		   " bufferPool     %8s inc cap=%07d cnt=%02d",		   pvr2_buffer_state_decode(bp->state),		   sp->i_bcount,sp->i_count);	spin_unlock_irqrestore(&sp->list_lock,irq_flags);}static void pvr2_buffer_set_queued(struct pvr2_buffer *bp){	unsigned long irq_flags;	struct pvr2_stream *sp;	BUFFER_CHECK(bp);	sp = bp->stream;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/ bufferState    %p %6s --> %6s",		   bp,		   pvr2_buffer_state_decode(bp->state),		   pvr2_buffer_state_decode(pvr2_buffer_state_queued));	spin_lock_irqsave(&sp->list_lock,irq_flags);	pvr2_buffer_remove(bp);	list_add_tail(&bp->list_overhead,&sp->queued_list);	bp->state = pvr2_buffer_state_queued;	(sp->q_count)++;	sp->q_bcount += bp->max_count;	pvr2_trace(PVR2_TRACE_BUF_FLOW,		   "/*---TRACE_FLOW---*/"		   " bufferPool     %8s inc cap=%07d cnt=%02d",		   pvr2_buffer_state_decode(bp->state),		   sp->q_bcount,sp->q_count);	spin_unlock_irqrestore(&sp->list_lock,irq_flags);}static void pvr2_buffer_wipe(struct pvr2_buffer *bp){	if (bp->state == pvr2_buffer_state_queued) {		usb_kill_urb(bp->purb);	}}static int pvr2_buffer_init(struct pvr2_buffer *bp,			    struct pvr2_stream *sp,			    unsigned int id){	memset(bp,0,sizeof(*bp));	bp->signature = BUFFER_SIG;	bp->id = id;	pvr2_trace(PVR2_TRACE_BUF_POOL,		   "/*---TRACE_FLOW---*/ bufferInit     %p stream=%p",bp,sp);	bp->stream = sp;	bp->state = pvr2_buffer_state_none;	INIT_LIST_HEAD(&bp->list_overhead);	bp->purb = usb_alloc_urb(0,GFP_KERNEL);	if (! bp->purb) return -ENOMEM;#ifdef SANITY_CHECK_BUFFERS	pvr2_buffer_describe(bp,"create");#endif	return 0;}static void pvr2_buffer_done(struct pvr2_buffer *bp){#ifdef SANITY_CHECK_BUFFERS	pvr2_buffer_describe(bp,"delete");#endif	pvr2_buffer_wipe(bp);	pvr2_buffer_set_none(bp);	bp->signature = 0;	bp->stream = NULL;	usb_free_urb(bp->purb);	pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/"		   " bufferDone     %p",bp);}static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt){	int ret;	unsigned int scnt;	/* Allocate buffers pointer array in multiples of 32 entries */	if (cnt == sp->buffer_total_count) return 0;	pvr2_trace(PVR2_TRACE_BUF_POOL,		   "/*---TRACE_FLOW---*/ poolResize    "		   " stream=%p cur=%d adj=%+d",		   sp,		   sp->buffer_total_count,		   cnt-sp->buffer_total_count);	scnt = cnt & ~0x1f;	if (cnt > scnt) scnt += 0x20;	if (cnt > sp->buffer_total_count) {		if (scnt > sp->buffer_slot_count) {			struct pvr2_buffer **nb;			nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);			if (!nb) return -ENOMEM;			if (sp->buffer_slot_count) {				memcpy(nb,sp->buffers,				       sp->buffer_slot_count * sizeof(*nb));				kfree(sp->buffers);			}			sp->buffers = nb;			sp->buffer_slot_count = scnt;		}		while (sp->buffer_total_count < cnt) {			struct pvr2_buffer *bp;			bp = kmalloc(sizeof(*bp),GFP_KERNEL);			if (!bp) return -ENOMEM;			ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count);			if (ret) {				kfree(bp);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -