ChangeSet 1.893.2.16, 2002/12/26 18:53:13-08:00, spse@secret.org.uk [PATCH] 2.4.20 usbvideo fixes from 2.5 1/5 This patch backports some fixes from 2.5 for the RingQueue_* functions Make the buffer length be a power of 2 to speed up index manipulation Make RingQueue_Dequeue use memcpy() rather than a byte by byte copy Make RingQueue_Enqueue use memcpy() instead of memmove() as the memory regions do not overlap Add RingQueue_Flush() and RingQueue_GetFreeSpace() Make RingQueue_GetLength() an inline diff -Nru a/drivers/usb/usbvideo.c b/drivers/usb/usbvideo.c --- a/drivers/usb/usbvideo.c Mon Jan 6 11:30:42 2003 +++ b/drivers/usb/usbvideo.c Mon Jan 6 11:30:42 2003 @@ -109,29 +109,41 @@ vfree(mem); } -void RingQueue_Initialize(struct RingQueue *rq) +static void RingQueue_Initialize(struct RingQueue *rq) { assert(rq != NULL); init_waitqueue_head(&rq->wqh); } -void RingQueue_Allocate(struct RingQueue *rq, int rqLen) +static void RingQueue_Allocate(struct RingQueue *rq, int rqLen) { + /* Make sure the requested size is a power of 2 and + round up if necessary. This allows index wrapping + using masks rather than modulo */ + + int i = 1; assert(rq != NULL); assert(rqLen > 0); + + while(rqLen >> i) + i++; + if(rqLen != 1 << (i-1)) + rqLen = 1 << i; + rq->length = rqLen; + rq->ri = rq->wi = 0; rq->queue = usbvideo_rvmalloc(rq->length); assert(rq->queue != NULL); } -int RingQueue_IsAllocated(const struct RingQueue *rq) +static int RingQueue_IsAllocated(const struct RingQueue *rq) { if (rq == NULL) return 0; return (rq->queue != NULL) && (rq->length > 0); } -void RingQueue_Free(struct RingQueue *rq) +static void RingQueue_Free(struct RingQueue *rq) { assert(rq != NULL); if (RingQueue_IsAllocated(rq)) { @@ -143,12 +155,32 @@ int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len) { - int i; + int rql, toread; + assert(rq != NULL); assert(dst != NULL); - for (i=0; i < len; i++) { - dst[i] = rq->queue[rq->ri]; - RING_QUEUE_DEQUEUE_BYTES(rq,1); + + rql = RingQueue_GetLength(rq); + if(!rql) + return 0; + + /* Clip requested length to available data */ + if(len > rql) + len = rql; + + toread = len; + if(rq->ri > rq->wi) { + /* Read data from tail */ + int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri; + memcpy(dst, rq->queue + rq->ri, read); + toread -= read; + dst += read; + rq->ri = (rq->ri + read) & (rq->length-1); + } + if(toread) { + /* Read data from head */ + memcpy(dst, rq->queue + rq->ri, toread); + rq->ri = (rq->ri + toread) & (rq->length-1); } return len; } @@ -174,7 +206,7 @@ if (m > q_avail) m = q_avail; - memmove(rq->queue + rq->wi, cdata, m); + memcpy(rq->queue + rq->wi, cdata, m); RING_QUEUE_ADVANCE_INDEX(rq, wi, m); cdata += m; enqueued += m; @@ -183,23 +215,7 @@ return enqueued; } -int RingQueue_GetLength(const struct RingQueue *rq) -{ - int ri, wi; - - assert(rq != NULL); - - ri = rq->ri; - wi = rq->wi; - if (ri == wi) - return 0; - else if (ri < wi) - return wi - ri; - else - return wi + (rq->length - ri); -} - -void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) +static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq) { assert(rq != NULL); interruptible_sleep_on(&rq->wqh); @@ -212,6 +228,14 @@ wake_up_interruptible(&rq->wqh); } +void RingQueue_Flush(struct RingQueue *rq) +{ + assert(rq != NULL); + rq->ri = 0; + rq->wi = 0; +} + + /* * usbvideo_VideosizeToString() * @@ -348,7 +372,7 @@ q_used = RingQueue_GetLength(&uvd->dp); if ((uvd->dp.ri + q_used) >= uvd->dp.length) { u_hi = uvd->dp.length; - u_lo = (q_used + uvd->dp.ri) % uvd->dp.length; + u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1); } else { u_hi = (q_used + uvd->dp.ri); u_lo = -1; @@ -1203,7 +1227,7 @@ /* Allocate memory for the frame buffers */ uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size; uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size); - RingQueue_Allocate(&uvd->dp, 128*1024); /* FIXME #define */ + RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE); if ((uvd->fbuf == NULL) || (!RingQueue_IsAllocated(&uvd->dp))) { err("%s: Failed to allocate fbuf or dp", __FUNCTION__); diff -Nru a/drivers/usb/usbvideo.h b/drivers/usb/usbvideo.h --- a/drivers/usb/usbvideo.h Mon Jan 6 11:30:42 2003 +++ b/drivers/usb/usbvideo.h Mon Jan 6 11:30:42 2003 @@ -113,9 +113,10 @@ mr = LIMIT_RGB(mm_r); \ } -#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) % (rq)->length +#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */ +#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1) #define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n) -#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) % (rq)->length]) +#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)]) struct RingQueue { unsigned char *queue; /* Data from the Isoc data pump */ @@ -300,15 +301,20 @@ #define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \ ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL) -void RingQueue_Initialize(struct RingQueue *rq); -void RingQueue_Allocate(struct RingQueue *rq, int rqLen); -int RingQueue_IsAllocated(const struct RingQueue *rq); -void RingQueue_Free(struct RingQueue *rq); int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len); int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n); -int RingQueue_GetLength(const struct RingQueue *rq); -void RingQueue_InterruptibleSleepOn(struct RingQueue *rq); void RingQueue_WakeUpInterruptible(struct RingQueue *rq); +void RingQueue_Flush(struct RingQueue *rq); + +static inline int RingQueue_GetLength(const struct RingQueue *rq) +{ + return (rq->wi - rq->ri + rq->length) & (rq->length-1); +} + +static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq) +{ + return rq->length - RingQueue_GetLength(rq); +} void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame); void usbvideo_DrawLine(