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