diff options
Diffstat (limited to 'drivers/media/usb/pvrusb2/pvrusb2-io.c')
| -rw-r--r-- | drivers/media/usb/pvrusb2/pvrusb2-io.c | 695 | 
1 files changed, 695 insertions, 0 deletions
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c new file mode 100644 index 00000000000..1e354747de3 --- /dev/null +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -0,0 +1,695 @@ +/* + * + * + *  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) +#endif + +struct 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; + +	unsigned int buffers_processed; +	unsigned int buffers_failed; +	unsigned int bytes_processed; +}; + +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_BUFFERS +static 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); +				return -ENOMEM; +			} +			sp->buffers[sp->buffer_total_count] = bp; +			(sp->buffer_total_count)++; +			pvr2_buffer_set_idle(bp); +		} +	} else { +		while (sp->buffer_total_count > cnt) { +			struct pvr2_buffer *bp; +			bp = sp->buffers[sp->buffer_total_count - 1]; +			/* Paranoia */ +			sp->buffers[sp->buffer_total_count - 1] = NULL; +			(sp->buffer_total_count)--; +			pvr2_buffer_done(bp); +			kfree(bp); +		} +		if (scnt < sp->buffer_slot_count) { +			struct pvr2_buffer **nb = NULL; +			if (scnt) { +				nb = kmemdup(sp->buffers, scnt * sizeof(*nb), +					     GFP_KERNEL); +				if (!nb) return -ENOMEM; +			} +			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->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->mutex); do { +		pvr2_stream_internal_flush(sp); +		pvr2_stream_buffer_count(sp,0); +	} while (0); mutex_unlock(&sp->mutex); +} + +static void buffer_complete(struct urb *urb) +{ +	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)) { +		(sp->buffers_processed)++; +		sp->bytes_processed += urb->actual_length; +		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)++; +		(sp->buffers_failed)++; +		pvr2_trace(PVR2_TRACE_TOLERANCE, +			   "stream %p ignoring error %d" +			   " - fail count increased to %u", +			   sp,urb->status,sp->fail_count); +	} else { +		(sp->buffers_failed)++; +		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 = kzalloc(sizeof(*sp),GFP_KERNEL); +	if (!sp) return 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->mutex); do { +		pvr2_stream_internal_flush(sp); +		sp->dev = dev; +		sp->endpoint = endpoint; +		sp->fail_tolerance = tolerance; +	} while(0); mutex_unlock(&sp->mutex); +} + +void pvr2_stream_set_callback(struct pvr2_stream *sp, +			      pvr2_stream_callback func, +			      void *data) +{ +	unsigned long irq_flags; +	mutex_lock(&sp->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->mutex); +} + +void pvr2_stream_get_stats(struct pvr2_stream *sp, +			   struct pvr2_stream_stats *stats, +			   int zero_counts) +{ +	unsigned long irq_flags; +	spin_lock_irqsave(&sp->list_lock,irq_flags); +	if (stats) { +		stats->buffers_in_queue = sp->q_count; +		stats->buffers_in_idle = sp->i_count; +		stats->buffers_in_ready = sp->r_count; +		stats->buffers_processed = sp->buffers_processed; +		stats->buffers_failed = sp->buffers_failed; +		stats->bytes_processed = sp->bytes_processed; +	} +	if (zero_counts) { +		sp->buffers_processed = 0; +		sp->buffers_failed = 0; +		sp->bytes_processed = 0; +	} +	spin_unlock_irqrestore(&sp->list_lock,irq_flags); +} + +/* 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->mutex); do { +		sp->buffer_target_count = cnt; +		ret = pvr2_stream_achieve_buffer_count(sp); +	} while(0); mutex_unlock(&sp->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 NULL; +	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 NULL; +	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 NULL; +	if (id >= sp->buffer_total_count) return NULL; +	return sp->buffers[id]; +} + +int pvr2_stream_get_ready_count(struct pvr2_stream *sp) +{ +	return sp->r_count; +} + +void pvr2_stream_kill(struct pvr2_stream *sp) +{ +	struct pvr2_buffer *bp; +	mutex_lock(&sp->mutex); do { +		pvr2_stream_internal_flush(sp); +		while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { +			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->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->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->mutex); +	return ret; +} + +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->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->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; +} + +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: *** +  */  | 
