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 | |
14 | static 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 | |
35 | struct 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 | |
74 | struct 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 | |
87 | static 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 |
99 | static 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 | |
115 | static 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(entry: &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 | |
149 | static 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(lock: &sp->list_lock, flags: irq_flags); |
163 | } |
164 | |
165 | static 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(new: &bp->list_overhead, head: &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(lock: &sp->list_lock, flags: irq_flags); |
189 | return fl; |
190 | } |
191 | |
192 | static 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(new: &bp->list_overhead, head: &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(lock: &sp->list_lock, flags: irq_flags); |
214 | } |
215 | |
216 | static 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(new: &bp->list_overhead, head: &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(lock: &sp->list_lock, flags: irq_flags); |
238 | } |
239 | |
240 | static void pvr2_buffer_wipe(struct pvr2_buffer *bp) |
241 | { |
242 | if (bp->state == pvr2_buffer_state_queued) { |
243 | usb_kill_urb(urb: bp->purb); |
244 | } |
245 | } |
246 | |
247 | static 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(list: &bp->list_overhead); |
259 | bp->purb = usb_alloc_urb(iso_packets: 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 | |
267 | static 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(urb: bp->purb); |
277 | pvr2_trace(PVR2_TRACE_BUF_POOL, "/*---TRACE_FLOW---*/ bufferDone %p" , |
278 | bp); |
279 | } |
280 | |
281 | static 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(n: scnt, size: 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(objp: 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(size: sizeof(*bp), GFP_KERNEL); |
315 | if (!bp) return -ENOMEM; |
316 | ret = pvr2_buffer_init(bp, sp, id: sp->buffer_total_count); |
317 | if (ret) { |
318 | kfree(objp: 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(objp: bp); |
334 | } |
335 | if (scnt < sp->buffer_slot_count) { |
336 | struct pvr2_buffer **nb = NULL; |
337 | if (scnt) { |
338 | nb = kmemdup(p: sp->buffers, size: scnt * sizeof(*nb), |
339 | GFP_KERNEL); |
340 | if (!nb) return -ENOMEM; |
341 | } |
342 | kfree(objp: sp->buffers); |
343 | sp->buffers = nb; |
344 | sp->buffer_slot_count = scnt; |
345 | } |
346 | } |
347 | return 0; |
348 | } |
349 | |
350 | static 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, cnt: 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, cnt: sp->buffer_total_count - cnt); |
373 | } |
374 | |
375 | return 0; |
376 | } |
377 | |
378 | static 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(bp: 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(bp: bp1); |
392 | } |
393 | if (sp->buffer_total_count != sp->buffer_target_count) { |
394 | pvr2_stream_achieve_buffer_count(sp); |
395 | } |
396 | } |
397 | |
398 | static 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(list: &sp->queued_list); |
403 | INIT_LIST_HEAD(list: &sp->ready_list); |
404 | INIT_LIST_HEAD(list: &sp->idle_list); |
405 | } |
406 | |
407 | static 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, cnt: 0); |
412 | } while (0); mutex_unlock(lock: &sp->mutex); |
413 | } |
414 | |
415 | static 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(lock: &sp->list_lock, flags: irq_flags); |
454 | pvr2_buffer_set_ready(bp); |
455 | if (sp->callback_func) { |
456 | sp->callback_func(sp->callback_data); |
457 | } |
458 | } |
459 | |
460 | struct pvr2_stream *pvr2_stream_create(void) |
461 | { |
462 | struct pvr2_stream *sp; |
463 | sp = kzalloc(size: 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 | |
470 | void 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(objp: sp); |
476 | } |
477 | |
478 | void 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(lock: &sp->mutex); |
489 | } |
490 | |
491 | void 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(lock: &sp->list_lock, flags: irq_flags); |
502 | } while (0); |
503 | mutex_unlock(lock: &sp->mutex); |
504 | } |
505 | |
506 | void 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(lock: &sp->list_lock, flags: irq_flags); |
526 | } |
527 | |
528 | /* Query / set the nominal buffer count */ |
529 | int pvr2_stream_get_buffer_count(struct pvr2_stream *sp) |
530 | { |
531 | return sp->buffer_target_count; |
532 | } |
533 | |
534 | int 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(lock: &sp->mutex); |
544 | return ret; |
545 | } |
546 | |
547 | struct 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 | |
554 | struct 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 | |
561 | struct 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 | |
568 | int pvr2_stream_get_ready_count(struct pvr2_stream *sp) |
569 | { |
570 | return sp->r_count; |
571 | } |
572 | |
573 | void 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(lock: &sp->mutex); |
587 | } |
588 | |
589 | int 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(urb: bp->purb, // struct urb *urb |
617 | dev: sp->dev, // struct usb_device *dev |
618 | // endpoint (below) |
619 | usb_rcvbulkpipe(sp->dev, sp->endpoint), |
620 | transfer_buffer: bp->ptr, // void *transfer_buffer |
621 | buffer_length: bp->max_count, // int buffer_length |
622 | complete_fn: buffer_complete, |
623 | context: bp); |
624 | usb_submit_urb(urb: bp->purb, GFP_KERNEL); |
625 | } while (0); |
626 | mutex_unlock(lock: &sp->mutex); |
627 | return ret; |
628 | } |
629 | |
630 | int 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(lock: &sp->list_lock, flags: irq_flags); |
654 | } while (0); |
655 | mutex_unlock(lock: &sp->mutex); |
656 | return ret; |
657 | } |
658 | |
659 | unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp) |
660 | { |
661 | return bp->used_count; |
662 | } |
663 | |
664 | int pvr2_buffer_get_status(struct pvr2_buffer *bp) |
665 | { |
666 | return bp->status; |
667 | } |
668 | |
669 | int pvr2_buffer_get_id(struct pvr2_buffer *bp) |
670 | { |
671 | return bp->id; |
672 | } |
673 | |