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