# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.489   -> 1.490  
#	drivers/usb/media/usbvideo.h	1.12    -> 1.13   
#	drivers/usb/media/usbvideo.c	1.21    -> 1.22   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/08/17	spse@secret.org.uk	1.490
# [PATCH] cleanup RingQueue_* functions in usbvideo.c
# 
# This patch against 2.5.31 cleans up 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/media/usbvideo.c b/drivers/usb/media/usbvideo.c
--- a/drivers/usb/media/usbvideo.c	Sun Aug 18 20:48:36 2002
+++ b/drivers/usb/media/usbvideo.c	Sun Aug 18 20:48:36 2002
@@ -135,9 +135,21 @@
 
 static void RingQueue_Allocate(RingQueue_t *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);
 }
@@ -161,12 +173,32 @@
 
 int RingQueue_Dequeue(RingQueue_t *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;
 }
@@ -194,7 +226,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;
@@ -205,24 +237,6 @@
 
 EXPORT_SYMBOL(RingQueue_Enqueue);
 
-int RingQueue_GetLength(const RingQueue_t *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);
-}
-
-EXPORT_SYMBOL(RingQueue_GetLength);
-
 static void RingQueue_InterruptibleSleepOn(RingQueue_t *rq)
 {
 	assert(rq != NULL);
@@ -238,6 +252,16 @@
 
 EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
 
+void RingQueue_Flush(RingQueue_t *rq)
+{
+	assert(rq != NULL);
+	rq->ri = 0;
+	rq->wi = 0;
+}
+
+EXPORT_SYMBOL(RingQueue_Flush);
+
+
 /*
  * usbvideo_VideosizeToString()
  *
@@ -374,7 +398,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;
@@ -1256,7 +1280,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", proc);
diff -Nru a/drivers/usb/media/usbvideo.h b/drivers/usb/media/usbvideo.h
--- a/drivers/usb/media/usbvideo.h	Sun Aug 18 20:48:36 2002
+++ b/drivers/usb/media/usbvideo.h	Sun Aug 18 20:48:36 2002
@@ -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)])
 
 typedef struct {
 	unsigned char *queue;	/* Data from the Isoc data pump */
@@ -306,8 +307,18 @@
 
 int  RingQueue_Dequeue(RingQueue_t *rq, unsigned char *dst, int len);
 int  RingQueue_Enqueue(RingQueue_t *rq, const unsigned char *cdata, int n);
-int  RingQueue_GetLength(const RingQueue_t *rq);
 void RingQueue_WakeUpInterruptible(RingQueue_t *rq);
+void RingQueue_Flush(RingQueue_t *rq);
+
+static inline int RingQueue_GetLength(const RingQueue_t *rq)
+{
+	return (rq->wi - rq->ri + rq->length) & (rq->length-1);
+}
+
+static inline int RingQueue_GetFreeSpace(const RingQueue_t *rq)
+{
+	return rq->length - RingQueue_GetLength(rq);
+}
 
 void usbvideo_DrawLine(
 	usbvideo_frame_t *frame,
