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