18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 Mike Isely <isely@pobox.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "pvrusb2-io.h" 88c2ecf20Sopenharmony_ci#include "pvrusb2-debug.h" 98c2ecf20Sopenharmony_ci#include <linux/errno.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic const char *pvr2_buffer_state_decode(enum pvr2_buffer_state); 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define BUFFER_SIG 0x47653271 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci// #define SANITY_CHECK_BUFFERS 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#ifdef SANITY_CHECK_BUFFERS 228c2ecf20Sopenharmony_ci#define BUFFER_CHECK(bp) do { \ 238c2ecf20Sopenharmony_ci if ((bp)->signature != BUFFER_SIG) { \ 248c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_ERROR_LEGS, \ 258c2ecf20Sopenharmony_ci "Buffer %p is bad at %s:%d", \ 268c2ecf20Sopenharmony_ci (bp), __FILE__, __LINE__); \ 278c2ecf20Sopenharmony_ci pvr2_buffer_describe(bp, "BadSig"); \ 288c2ecf20Sopenharmony_ci BUG(); \ 298c2ecf20Sopenharmony_ci } \ 308c2ecf20Sopenharmony_ci} while (0) 318c2ecf20Sopenharmony_ci#else 328c2ecf20Sopenharmony_ci#define BUFFER_CHECK(bp) do {} while (0) 338c2ecf20Sopenharmony_ci#endif 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct pvr2_stream { 368c2ecf20Sopenharmony_ci /* Buffers queued for reading */ 378c2ecf20Sopenharmony_ci struct list_head queued_list; 388c2ecf20Sopenharmony_ci unsigned int q_count; 398c2ecf20Sopenharmony_ci unsigned int q_bcount; 408c2ecf20Sopenharmony_ci /* Buffers with retrieved data */ 418c2ecf20Sopenharmony_ci struct list_head ready_list; 428c2ecf20Sopenharmony_ci unsigned int r_count; 438c2ecf20Sopenharmony_ci unsigned int r_bcount; 448c2ecf20Sopenharmony_ci /* Buffers available for use */ 458c2ecf20Sopenharmony_ci struct list_head idle_list; 468c2ecf20Sopenharmony_ci unsigned int i_count; 478c2ecf20Sopenharmony_ci unsigned int i_bcount; 488c2ecf20Sopenharmony_ci /* Pointers to all buffers */ 498c2ecf20Sopenharmony_ci struct pvr2_buffer **buffers; 508c2ecf20Sopenharmony_ci /* Array size of buffers */ 518c2ecf20Sopenharmony_ci unsigned int buffer_slot_count; 528c2ecf20Sopenharmony_ci /* Total buffers actually in circulation */ 538c2ecf20Sopenharmony_ci unsigned int buffer_total_count; 548c2ecf20Sopenharmony_ci /* Designed number of buffers to be in circulation */ 558c2ecf20Sopenharmony_ci unsigned int buffer_target_count; 568c2ecf20Sopenharmony_ci /* Executed when ready list become non-empty */ 578c2ecf20Sopenharmony_ci pvr2_stream_callback callback_func; 588c2ecf20Sopenharmony_ci void *callback_data; 598c2ecf20Sopenharmony_ci /* Context for transfer endpoint */ 608c2ecf20Sopenharmony_ci struct usb_device *dev; 618c2ecf20Sopenharmony_ci int endpoint; 628c2ecf20Sopenharmony_ci /* Overhead for mutex enforcement */ 638c2ecf20Sopenharmony_ci spinlock_t list_lock; 648c2ecf20Sopenharmony_ci struct mutex mutex; 658c2ecf20Sopenharmony_ci /* Tracking state for tolerating errors */ 668c2ecf20Sopenharmony_ci unsigned int fail_count; 678c2ecf20Sopenharmony_ci unsigned int fail_tolerance; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci unsigned int buffers_processed; 708c2ecf20Sopenharmony_ci unsigned int buffers_failed; 718c2ecf20Sopenharmony_ci unsigned int bytes_processed; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistruct pvr2_buffer { 758c2ecf20Sopenharmony_ci int id; 768c2ecf20Sopenharmony_ci int signature; 778c2ecf20Sopenharmony_ci enum pvr2_buffer_state state; 788c2ecf20Sopenharmony_ci void *ptr; /* Pointer to storage area */ 798c2ecf20Sopenharmony_ci unsigned int max_count; /* Size of storage area */ 808c2ecf20Sopenharmony_ci unsigned int used_count; /* Amount of valid data in storage area */ 818c2ecf20Sopenharmony_ci int status; /* Transfer result status */ 828c2ecf20Sopenharmony_ci struct pvr2_stream *stream; 838c2ecf20Sopenharmony_ci struct list_head list_overhead; 848c2ecf20Sopenharmony_ci struct urb *purb; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci switch (st) { 908c2ecf20Sopenharmony_ci case pvr2_buffer_state_none: return "none"; 918c2ecf20Sopenharmony_ci case pvr2_buffer_state_idle: return "idle"; 928c2ecf20Sopenharmony_ci case pvr2_buffer_state_queued: return "queued"; 938c2ecf20Sopenharmony_ci case pvr2_buffer_state_ready: return "ready"; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci return "unknown"; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#ifdef SANITY_CHECK_BUFFERS 998c2ecf20Sopenharmony_cistatic void pvr2_buffer_describe(struct pvr2_buffer *bp, const char *msg) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INFO, 1028c2ecf20Sopenharmony_ci "buffer%s%s %p state=%s id=%d status=%d stream=%p purb=%p sig=0x%x", 1038c2ecf20Sopenharmony_ci (msg ? " " : ""), 1048c2ecf20Sopenharmony_ci (msg ? msg : ""), 1058c2ecf20Sopenharmony_ci bp, 1068c2ecf20Sopenharmony_ci (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"), 1078c2ecf20Sopenharmony_ci (bp ? bp->id : 0), 1088c2ecf20Sopenharmony_ci (bp ? bp->status : 0), 1098c2ecf20Sopenharmony_ci (bp ? bp->stream : NULL), 1108c2ecf20Sopenharmony_ci (bp ? bp->purb : NULL), 1118c2ecf20Sopenharmony_ci (bp ? bp->signature : 0)); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci#endif /* SANITY_CHECK_BUFFERS */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void pvr2_buffer_remove(struct pvr2_buffer *bp) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci unsigned int *cnt; 1188c2ecf20Sopenharmony_ci unsigned int *bcnt; 1198c2ecf20Sopenharmony_ci unsigned int ccnt; 1208c2ecf20Sopenharmony_ci struct pvr2_stream *sp = bp->stream; 1218c2ecf20Sopenharmony_ci switch (bp->state) { 1228c2ecf20Sopenharmony_ci case pvr2_buffer_state_idle: 1238c2ecf20Sopenharmony_ci cnt = &sp->i_count; 1248c2ecf20Sopenharmony_ci bcnt = &sp->i_bcount; 1258c2ecf20Sopenharmony_ci ccnt = bp->max_count; 1268c2ecf20Sopenharmony_ci break; 1278c2ecf20Sopenharmony_ci case pvr2_buffer_state_queued: 1288c2ecf20Sopenharmony_ci cnt = &sp->q_count; 1298c2ecf20Sopenharmony_ci bcnt = &sp->q_bcount; 1308c2ecf20Sopenharmony_ci ccnt = bp->max_count; 1318c2ecf20Sopenharmony_ci break; 1328c2ecf20Sopenharmony_ci case pvr2_buffer_state_ready: 1338c2ecf20Sopenharmony_ci cnt = &sp->r_count; 1348c2ecf20Sopenharmony_ci bcnt = &sp->r_bcount; 1358c2ecf20Sopenharmony_ci ccnt = bp->used_count; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci default: 1388c2ecf20Sopenharmony_ci return; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci list_del_init(&bp->list_overhead); 1418c2ecf20Sopenharmony_ci (*cnt)--; 1428c2ecf20Sopenharmony_ci (*bcnt) -= ccnt; 1438c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 1448c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferPool %8s dec cap=%07d cnt=%02d", 1458c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), *bcnt, *cnt); 1468c2ecf20Sopenharmony_ci bp->state = pvr2_buffer_state_none; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void pvr2_buffer_set_none(struct pvr2_buffer *bp) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci unsigned long irq_flags; 1528c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 1538c2ecf20Sopenharmony_ci BUFFER_CHECK(bp); 1548c2ecf20Sopenharmony_ci sp = bp->stream; 1558c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 1568c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 1578c2ecf20Sopenharmony_ci bp, 1588c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 1598c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(pvr2_buffer_state_none)); 1608c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 1618c2ecf20Sopenharmony_ci pvr2_buffer_remove(bp); 1628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int pvr2_buffer_set_ready(struct pvr2_buffer *bp) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci int fl; 1688c2ecf20Sopenharmony_ci unsigned long irq_flags; 1698c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 1708c2ecf20Sopenharmony_ci BUFFER_CHECK(bp); 1718c2ecf20Sopenharmony_ci sp = bp->stream; 1728c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 1738c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 1748c2ecf20Sopenharmony_ci bp, 1758c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 1768c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(pvr2_buffer_state_ready)); 1778c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 1788c2ecf20Sopenharmony_ci fl = (sp->r_count == 0); 1798c2ecf20Sopenharmony_ci pvr2_buffer_remove(bp); 1808c2ecf20Sopenharmony_ci list_add_tail(&bp->list_overhead, &sp->ready_list); 1818c2ecf20Sopenharmony_ci bp->state = pvr2_buffer_state_ready; 1828c2ecf20Sopenharmony_ci (sp->r_count)++; 1838c2ecf20Sopenharmony_ci sp->r_bcount += bp->used_count; 1848c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 1858c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", 1868c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 1878c2ecf20Sopenharmony_ci sp->r_bcount, sp->r_count); 1888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 1898c2ecf20Sopenharmony_ci return fl; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void pvr2_buffer_set_idle(struct pvr2_buffer *bp) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci unsigned long irq_flags; 1958c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 1968c2ecf20Sopenharmony_ci BUFFER_CHECK(bp); 1978c2ecf20Sopenharmony_ci sp = bp->stream; 1988c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 1998c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 2008c2ecf20Sopenharmony_ci bp, 2018c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 2028c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(pvr2_buffer_state_idle)); 2038c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 2048c2ecf20Sopenharmony_ci pvr2_buffer_remove(bp); 2058c2ecf20Sopenharmony_ci list_add_tail(&bp->list_overhead, &sp->idle_list); 2068c2ecf20Sopenharmony_ci bp->state = pvr2_buffer_state_idle; 2078c2ecf20Sopenharmony_ci (sp->i_count)++; 2088c2ecf20Sopenharmony_ci sp->i_bcount += bp->max_count; 2098c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 2108c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", 2118c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 2128c2ecf20Sopenharmony_ci sp->i_bcount, sp->i_count); 2138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void pvr2_buffer_set_queued(struct pvr2_buffer *bp) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci unsigned long irq_flags; 2198c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 2208c2ecf20Sopenharmony_ci BUFFER_CHECK(bp); 2218c2ecf20Sopenharmony_ci sp = bp->stream; 2228c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 2238c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s", 2248c2ecf20Sopenharmony_ci bp, 2258c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 2268c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(pvr2_buffer_state_queued)); 2278c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 2288c2ecf20Sopenharmony_ci pvr2_buffer_remove(bp); 2298c2ecf20Sopenharmony_ci list_add_tail(&bp->list_overhead, &sp->queued_list); 2308c2ecf20Sopenharmony_ci bp->state = pvr2_buffer_state_queued; 2318c2ecf20Sopenharmony_ci (sp->q_count)++; 2328c2ecf20Sopenharmony_ci sp->q_bcount += bp->max_count; 2338c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 2348c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", 2358c2ecf20Sopenharmony_ci pvr2_buffer_state_decode(bp->state), 2368c2ecf20Sopenharmony_ci sp->q_bcount, sp->q_count); 2378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic void pvr2_buffer_wipe(struct pvr2_buffer *bp) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci if (bp->state == pvr2_buffer_state_queued) { 2438c2ecf20Sopenharmony_ci usb_kill_urb(bp->purb); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int pvr2_buffer_init(struct pvr2_buffer *bp, 2488c2ecf20Sopenharmony_ci struct pvr2_stream *sp, 2498c2ecf20Sopenharmony_ci unsigned int id) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci memset(bp, 0, sizeof(*bp)); 2528c2ecf20Sopenharmony_ci bp->signature = BUFFER_SIG; 2538c2ecf20Sopenharmony_ci bp->id = id; 2548c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_POOL, 2558c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferInit %p stream=%p", bp, sp); 2568c2ecf20Sopenharmony_ci bp->stream = sp; 2578c2ecf20Sopenharmony_ci bp->state = pvr2_buffer_state_none; 2588c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bp->list_overhead); 2598c2ecf20Sopenharmony_ci bp->purb = usb_alloc_urb(0, GFP_KERNEL); 2608c2ecf20Sopenharmony_ci if (! bp->purb) return -ENOMEM; 2618c2ecf20Sopenharmony_ci#ifdef SANITY_CHECK_BUFFERS 2628c2ecf20Sopenharmony_ci pvr2_buffer_describe(bp, "create"); 2638c2ecf20Sopenharmony_ci#endif 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void pvr2_buffer_done(struct pvr2_buffer *bp) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci#ifdef SANITY_CHECK_BUFFERS 2708c2ecf20Sopenharmony_ci pvr2_buffer_describe(bp, "delete"); 2718c2ecf20Sopenharmony_ci#endif 2728c2ecf20Sopenharmony_ci pvr2_buffer_wipe(bp); 2738c2ecf20Sopenharmony_ci pvr2_buffer_set_none(bp); 2748c2ecf20Sopenharmony_ci bp->signature = 0; 2758c2ecf20Sopenharmony_ci bp->stream = NULL; 2768c2ecf20Sopenharmony_ci usb_free_urb(bp->purb); 2778c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_POOL, "/*---TRACE_FLOW---*/ bufferDone %p", 2788c2ecf20Sopenharmony_ci bp); 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci int ret; 2848c2ecf20Sopenharmony_ci unsigned int scnt; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Allocate buffers pointer array in multiples of 32 entries */ 2878c2ecf20Sopenharmony_ci if (cnt == sp->buffer_total_count) return 0; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_POOL, 2908c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ poolResize stream=%p cur=%d adj=%+d", 2918c2ecf20Sopenharmony_ci sp, 2928c2ecf20Sopenharmony_ci sp->buffer_total_count, 2938c2ecf20Sopenharmony_ci cnt-sp->buffer_total_count); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci scnt = cnt & ~0x1f; 2968c2ecf20Sopenharmony_ci if (cnt > scnt) scnt += 0x20; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (cnt > sp->buffer_total_count) { 2998c2ecf20Sopenharmony_ci if (scnt > sp->buffer_slot_count) { 3008c2ecf20Sopenharmony_ci struct pvr2_buffer **nb; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci nb = kmalloc_array(scnt, sizeof(*nb), GFP_KERNEL); 3038c2ecf20Sopenharmony_ci if (!nb) return -ENOMEM; 3048c2ecf20Sopenharmony_ci if (sp->buffer_slot_count) { 3058c2ecf20Sopenharmony_ci memcpy(nb, sp->buffers, 3068c2ecf20Sopenharmony_ci sp->buffer_slot_count * sizeof(*nb)); 3078c2ecf20Sopenharmony_ci kfree(sp->buffers); 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci sp->buffers = nb; 3108c2ecf20Sopenharmony_ci sp->buffer_slot_count = scnt; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci while (sp->buffer_total_count < cnt) { 3138c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 3148c2ecf20Sopenharmony_ci bp = kmalloc(sizeof(*bp), GFP_KERNEL); 3158c2ecf20Sopenharmony_ci if (!bp) return -ENOMEM; 3168c2ecf20Sopenharmony_ci ret = pvr2_buffer_init(bp, sp, sp->buffer_total_count); 3178c2ecf20Sopenharmony_ci if (ret) { 3188c2ecf20Sopenharmony_ci kfree(bp); 3198c2ecf20Sopenharmony_ci return -ENOMEM; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci sp->buffers[sp->buffer_total_count] = bp; 3228c2ecf20Sopenharmony_ci (sp->buffer_total_count)++; 3238c2ecf20Sopenharmony_ci pvr2_buffer_set_idle(bp); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci } else { 3268c2ecf20Sopenharmony_ci while (sp->buffer_total_count > cnt) { 3278c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 3288c2ecf20Sopenharmony_ci bp = sp->buffers[sp->buffer_total_count - 1]; 3298c2ecf20Sopenharmony_ci /* Paranoia */ 3308c2ecf20Sopenharmony_ci sp->buffers[sp->buffer_total_count - 1] = NULL; 3318c2ecf20Sopenharmony_ci (sp->buffer_total_count)--; 3328c2ecf20Sopenharmony_ci pvr2_buffer_done(bp); 3338c2ecf20Sopenharmony_ci kfree(bp); 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci if (scnt < sp->buffer_slot_count) { 3368c2ecf20Sopenharmony_ci struct pvr2_buffer **nb = NULL; 3378c2ecf20Sopenharmony_ci if (scnt) { 3388c2ecf20Sopenharmony_ci nb = kmemdup(sp->buffers, scnt * sizeof(*nb), 3398c2ecf20Sopenharmony_ci GFP_KERNEL); 3408c2ecf20Sopenharmony_ci if (!nb) return -ENOMEM; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci kfree(sp->buffers); 3438c2ecf20Sopenharmony_ci sp->buffers = nb; 3448c2ecf20Sopenharmony_ci sp->buffer_slot_count = scnt; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 3538c2ecf20Sopenharmony_ci unsigned int cnt; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (sp->buffer_total_count == sp->buffer_target_count) return 0; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_POOL, 3588c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ poolCheck stream=%p cur=%d tgt=%d", 3598c2ecf20Sopenharmony_ci sp, sp->buffer_total_count, sp->buffer_target_count); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (sp->buffer_total_count < sp->buffer_target_count) { 3628c2ecf20Sopenharmony_ci return pvr2_stream_buffer_count(sp, sp->buffer_target_count); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci cnt = 0; 3668c2ecf20Sopenharmony_ci while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) { 3678c2ecf20Sopenharmony_ci bp = sp->buffers[sp->buffer_total_count - (cnt + 1)]; 3688c2ecf20Sopenharmony_ci if (bp->state != pvr2_buffer_state_idle) break; 3698c2ecf20Sopenharmony_ci cnt++; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci if (cnt) { 3728c2ecf20Sopenharmony_ci pvr2_stream_buffer_count(sp, sp->buffer_total_count - cnt); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return 0; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic void pvr2_stream_internal_flush(struct pvr2_stream *sp) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci struct list_head *lp; 3818c2ecf20Sopenharmony_ci struct pvr2_buffer *bp1; 3828c2ecf20Sopenharmony_ci while ((lp = sp->queued_list.next) != &sp->queued_list) { 3838c2ecf20Sopenharmony_ci bp1 = list_entry(lp, struct pvr2_buffer, list_overhead); 3848c2ecf20Sopenharmony_ci pvr2_buffer_wipe(bp1); 3858c2ecf20Sopenharmony_ci /* At this point, we should be guaranteed that no 3868c2ecf20Sopenharmony_ci completion callback may happen on this buffer. But it's 3878c2ecf20Sopenharmony_ci possible that it might have completed after we noticed 3888c2ecf20Sopenharmony_ci it but before we wiped it. So double check its status 3898c2ecf20Sopenharmony_ci here first. */ 3908c2ecf20Sopenharmony_ci if (bp1->state != pvr2_buffer_state_queued) continue; 3918c2ecf20Sopenharmony_ci pvr2_buffer_set_idle(bp1); 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci if (sp->buffer_total_count != sp->buffer_target_count) { 3948c2ecf20Sopenharmony_ci pvr2_stream_achieve_buffer_count(sp); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void pvr2_stream_init(struct pvr2_stream *sp) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci spin_lock_init(&sp->list_lock); 4018c2ecf20Sopenharmony_ci mutex_init(&sp->mutex); 4028c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sp->queued_list); 4038c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sp->ready_list); 4048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sp->idle_list); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void pvr2_stream_done(struct pvr2_stream *sp) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); do { 4108c2ecf20Sopenharmony_ci pvr2_stream_internal_flush(sp); 4118c2ecf20Sopenharmony_ci pvr2_stream_buffer_count(sp, 0); 4128c2ecf20Sopenharmony_ci } while (0); mutex_unlock(&sp->mutex); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void buffer_complete(struct urb *urb) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct pvr2_buffer *bp = urb->context; 4188c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 4198c2ecf20Sopenharmony_ci unsigned long irq_flags; 4208c2ecf20Sopenharmony_ci BUFFER_CHECK(bp); 4218c2ecf20Sopenharmony_ci sp = bp->stream; 4228c2ecf20Sopenharmony_ci bp->used_count = 0; 4238c2ecf20Sopenharmony_ci bp->status = 0; 4248c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 4258c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d", 4268c2ecf20Sopenharmony_ci bp, urb->status, urb->actual_length); 4278c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 4288c2ecf20Sopenharmony_ci if ((!(urb->status)) || 4298c2ecf20Sopenharmony_ci (urb->status == -ENOENT) || 4308c2ecf20Sopenharmony_ci (urb->status == -ECONNRESET) || 4318c2ecf20Sopenharmony_ci (urb->status == -ESHUTDOWN)) { 4328c2ecf20Sopenharmony_ci (sp->buffers_processed)++; 4338c2ecf20Sopenharmony_ci sp->bytes_processed += urb->actual_length; 4348c2ecf20Sopenharmony_ci bp->used_count = urb->actual_length; 4358c2ecf20Sopenharmony_ci if (sp->fail_count) { 4368c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_TOLERANCE, 4378c2ecf20Sopenharmony_ci "stream %p transfer ok - fail count reset", 4388c2ecf20Sopenharmony_ci sp); 4398c2ecf20Sopenharmony_ci sp->fail_count = 0; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci } else if (sp->fail_count < sp->fail_tolerance) { 4428c2ecf20Sopenharmony_ci // We can tolerate this error, because we're below the 4438c2ecf20Sopenharmony_ci // threshold... 4448c2ecf20Sopenharmony_ci (sp->fail_count)++; 4458c2ecf20Sopenharmony_ci (sp->buffers_failed)++; 4468c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_TOLERANCE, 4478c2ecf20Sopenharmony_ci "stream %p ignoring error %d - fail count increased to %u", 4488c2ecf20Sopenharmony_ci sp, urb->status, sp->fail_count); 4498c2ecf20Sopenharmony_ci } else { 4508c2ecf20Sopenharmony_ci (sp->buffers_failed)++; 4518c2ecf20Sopenharmony_ci bp->status = urb->status; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 4548c2ecf20Sopenharmony_ci pvr2_buffer_set_ready(bp); 4558c2ecf20Sopenharmony_ci if (sp->callback_func) { 4568c2ecf20Sopenharmony_ci sp->callback_func(sp->callback_data); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistruct pvr2_stream *pvr2_stream_create(void) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 4638c2ecf20Sopenharmony_ci sp = kzalloc(sizeof(*sp), GFP_KERNEL); 4648c2ecf20Sopenharmony_ci if (!sp) return sp; 4658c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, "pvr2_stream_create: sp=%p", sp); 4668c2ecf20Sopenharmony_ci pvr2_stream_init(sp); 4678c2ecf20Sopenharmony_ci return sp; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_civoid pvr2_stream_destroy(struct pvr2_stream *sp) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci if (!sp) return; 4738c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_INIT, "pvr2_stream_destroy: sp=%p", sp); 4748c2ecf20Sopenharmony_ci pvr2_stream_done(sp); 4758c2ecf20Sopenharmony_ci kfree(sp); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_civoid pvr2_stream_setup(struct pvr2_stream *sp, 4798c2ecf20Sopenharmony_ci struct usb_device *dev, 4808c2ecf20Sopenharmony_ci int endpoint, 4818c2ecf20Sopenharmony_ci unsigned int tolerance) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); do { 4848c2ecf20Sopenharmony_ci pvr2_stream_internal_flush(sp); 4858c2ecf20Sopenharmony_ci sp->dev = dev; 4868c2ecf20Sopenharmony_ci sp->endpoint = endpoint; 4878c2ecf20Sopenharmony_ci sp->fail_tolerance = tolerance; 4888c2ecf20Sopenharmony_ci } while (0); mutex_unlock(&sp->mutex); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_civoid pvr2_stream_set_callback(struct pvr2_stream *sp, 4928c2ecf20Sopenharmony_ci pvr2_stream_callback func, 4938c2ecf20Sopenharmony_ci void *data) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci unsigned long irq_flags; 4968c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); 4978c2ecf20Sopenharmony_ci do { 4988c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 4998c2ecf20Sopenharmony_ci sp->callback_data = data; 5008c2ecf20Sopenharmony_ci sp->callback_func = func; 5018c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 5028c2ecf20Sopenharmony_ci } while (0); 5038c2ecf20Sopenharmony_ci mutex_unlock(&sp->mutex); 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_civoid pvr2_stream_get_stats(struct pvr2_stream *sp, 5078c2ecf20Sopenharmony_ci struct pvr2_stream_stats *stats, 5088c2ecf20Sopenharmony_ci int zero_counts) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci unsigned long irq_flags; 5118c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 5128c2ecf20Sopenharmony_ci if (stats) { 5138c2ecf20Sopenharmony_ci stats->buffers_in_queue = sp->q_count; 5148c2ecf20Sopenharmony_ci stats->buffers_in_idle = sp->i_count; 5158c2ecf20Sopenharmony_ci stats->buffers_in_ready = sp->r_count; 5168c2ecf20Sopenharmony_ci stats->buffers_processed = sp->buffers_processed; 5178c2ecf20Sopenharmony_ci stats->buffers_failed = sp->buffers_failed; 5188c2ecf20Sopenharmony_ci stats->bytes_processed = sp->bytes_processed; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci if (zero_counts) { 5218c2ecf20Sopenharmony_ci sp->buffers_processed = 0; 5228c2ecf20Sopenharmony_ci sp->buffers_failed = 0; 5238c2ecf20Sopenharmony_ci sp->bytes_processed = 0; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/* Query / set the nominal buffer count */ 5298c2ecf20Sopenharmony_ciint pvr2_stream_get_buffer_count(struct pvr2_stream *sp) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci return sp->buffer_target_count; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ciint pvr2_stream_set_buffer_count(struct pvr2_stream *sp, unsigned int cnt) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci int ret; 5378c2ecf20Sopenharmony_ci if (sp->buffer_target_count == cnt) return 0; 5388c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); 5398c2ecf20Sopenharmony_ci do { 5408c2ecf20Sopenharmony_ci sp->buffer_target_count = cnt; 5418c2ecf20Sopenharmony_ci ret = pvr2_stream_achieve_buffer_count(sp); 5428c2ecf20Sopenharmony_ci } while (0); 5438c2ecf20Sopenharmony_ci mutex_unlock(&sp->mutex); 5448c2ecf20Sopenharmony_ci return ret; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistruct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct list_head *lp = sp->idle_list.next; 5508c2ecf20Sopenharmony_ci if (lp == &sp->idle_list) return NULL; 5518c2ecf20Sopenharmony_ci return list_entry(lp, struct pvr2_buffer, list_overhead); 5528c2ecf20Sopenharmony_ci} 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cistruct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp) 5558c2ecf20Sopenharmony_ci{ 5568c2ecf20Sopenharmony_ci struct list_head *lp = sp->ready_list.next; 5578c2ecf20Sopenharmony_ci if (lp == &sp->ready_list) return NULL; 5588c2ecf20Sopenharmony_ci return list_entry(lp, struct pvr2_buffer, list_overhead); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_cistruct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp, int id) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci if (id < 0) return NULL; 5648c2ecf20Sopenharmony_ci if (id >= sp->buffer_total_count) return NULL; 5658c2ecf20Sopenharmony_ci return sp->buffers[id]; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ciint pvr2_stream_get_ready_count(struct pvr2_stream *sp) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci return sp->r_count; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_civoid pvr2_stream_kill(struct pvr2_stream *sp) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct pvr2_buffer *bp; 5768c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); 5778c2ecf20Sopenharmony_ci do { 5788c2ecf20Sopenharmony_ci pvr2_stream_internal_flush(sp); 5798c2ecf20Sopenharmony_ci while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) { 5808c2ecf20Sopenharmony_ci pvr2_buffer_set_idle(bp); 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci if (sp->buffer_total_count != sp->buffer_target_count) { 5838c2ecf20Sopenharmony_ci pvr2_stream_achieve_buffer_count(sp); 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci } while (0); 5868c2ecf20Sopenharmony_ci mutex_unlock(&sp->mutex); 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ciint pvr2_buffer_queue(struct pvr2_buffer *bp) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci#undef SEED_BUFFER 5928c2ecf20Sopenharmony_ci#ifdef SEED_BUFFER 5938c2ecf20Sopenharmony_ci unsigned int idx; 5948c2ecf20Sopenharmony_ci unsigned int val; 5958c2ecf20Sopenharmony_ci#endif 5968c2ecf20Sopenharmony_ci int ret = 0; 5978c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 5988c2ecf20Sopenharmony_ci if (!bp) return -EINVAL; 5998c2ecf20Sopenharmony_ci sp = bp->stream; 6008c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); 6018c2ecf20Sopenharmony_ci do { 6028c2ecf20Sopenharmony_ci pvr2_buffer_wipe(bp); 6038c2ecf20Sopenharmony_ci if (!sp->dev) { 6048c2ecf20Sopenharmony_ci ret = -EIO; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci pvr2_buffer_set_queued(bp); 6088c2ecf20Sopenharmony_ci#ifdef SEED_BUFFER 6098c2ecf20Sopenharmony_ci for (idx = 0; idx < (bp->max_count) / 4; idx++) { 6108c2ecf20Sopenharmony_ci val = bp->id << 24; 6118c2ecf20Sopenharmony_ci val |= idx; 6128c2ecf20Sopenharmony_ci ((unsigned int *)(bp->ptr))[idx] = val; 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci#endif 6158c2ecf20Sopenharmony_ci bp->status = -EINPROGRESS; 6168c2ecf20Sopenharmony_ci usb_fill_bulk_urb(bp->purb, // struct urb *urb 6178c2ecf20Sopenharmony_ci sp->dev, // struct usb_device *dev 6188c2ecf20Sopenharmony_ci // endpoint (below) 6198c2ecf20Sopenharmony_ci usb_rcvbulkpipe(sp->dev, sp->endpoint), 6208c2ecf20Sopenharmony_ci bp->ptr, // void *transfer_buffer 6218c2ecf20Sopenharmony_ci bp->max_count, // int buffer_length 6228c2ecf20Sopenharmony_ci buffer_complete, 6238c2ecf20Sopenharmony_ci bp); 6248c2ecf20Sopenharmony_ci usb_submit_urb(bp->purb, GFP_KERNEL); 6258c2ecf20Sopenharmony_ci } while (0); 6268c2ecf20Sopenharmony_ci mutex_unlock(&sp->mutex); 6278c2ecf20Sopenharmony_ci return ret; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ciint pvr2_buffer_set_buffer(struct pvr2_buffer *bp, void *ptr, unsigned int cnt) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci int ret = 0; 6338c2ecf20Sopenharmony_ci unsigned long irq_flags; 6348c2ecf20Sopenharmony_ci struct pvr2_stream *sp; 6358c2ecf20Sopenharmony_ci if (!bp) return -EINVAL; 6368c2ecf20Sopenharmony_ci sp = bp->stream; 6378c2ecf20Sopenharmony_ci mutex_lock(&sp->mutex); 6388c2ecf20Sopenharmony_ci do { 6398c2ecf20Sopenharmony_ci spin_lock_irqsave(&sp->list_lock, irq_flags); 6408c2ecf20Sopenharmony_ci if (bp->state != pvr2_buffer_state_idle) { 6418c2ecf20Sopenharmony_ci ret = -EPERM; 6428c2ecf20Sopenharmony_ci } else { 6438c2ecf20Sopenharmony_ci bp->ptr = ptr; 6448c2ecf20Sopenharmony_ci bp->stream->i_bcount -= bp->max_count; 6458c2ecf20Sopenharmony_ci bp->max_count = cnt; 6468c2ecf20Sopenharmony_ci bp->stream->i_bcount += bp->max_count; 6478c2ecf20Sopenharmony_ci pvr2_trace(PVR2_TRACE_BUF_FLOW, 6488c2ecf20Sopenharmony_ci "/*---TRACE_FLOW---*/ bufferPool %8s cap cap=%07d cnt=%02d", 6498c2ecf20Sopenharmony_ci pvr2_buffer_state_decode( 6508c2ecf20Sopenharmony_ci pvr2_buffer_state_idle), 6518c2ecf20Sopenharmony_ci bp->stream->i_bcount, bp->stream->i_count); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sp->list_lock, irq_flags); 6548c2ecf20Sopenharmony_ci } while (0); 6558c2ecf20Sopenharmony_ci mutex_unlock(&sp->mutex); 6568c2ecf20Sopenharmony_ci return ret; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ciunsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci return bp->used_count; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ciint pvr2_buffer_get_status(struct pvr2_buffer *bp) 6658c2ecf20Sopenharmony_ci{ 6668c2ecf20Sopenharmony_ci return bp->status; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ciint pvr2_buffer_get_id(struct pvr2_buffer *bp) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci return bp->id; 6728c2ecf20Sopenharmony_ci} 673