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(
