--- drivers/media/video/uvc/uvc_video.c.orig	2010-04-02 01:02:33.000000000 +0200
+++ drivers/media/video/uvc/uvc_video.c	2010-04-17 15:00:45.000000000 +0200
@@ -450,23 +450,93 @@
 	return data[0];
 }
 
+/* This patched function allows to overturn video images from an upside-down
+ * orientation to a normal one with mirrored effect. The conversion consists in
+ * reversing the order of the rows of imagines.
+ * "data" stores a sequence of pixels coming from the video source.
+ * This sequence is not a full frame or a full row of pixel, but just an
+ * ordered vector of pixels (from top-left to bottom-right), whose
+ * represents just an area of the current frame and which size ("nbytes") is
+ * not constant. In fact this function has to be called hundreds of times
+ * before a frame is completed. Each time "data" contains the next part of the
+ * current frame (upside-down). At the end data stored in "mem" buffer will be
+ * used by the application who requested the video stream.
+ * No memory allocation is needed because pixel order is modified directly
+ * while copying from "data" into "mem" buffer (i.e. in each call of this
+ * function), and not just once when the frame is already completed.
+ * This patch should work with all YUV image formats.
+ */
 static void uvc_video_decode_data(struct uvc_streaming *stream,
 		struct uvc_buffer *buf, const __u8 *data, int len)
 {
 	struct uvc_video_queue *queue = &stream->queue;
 	unsigned int maxlen, nbytes;
 	void *mem;
+	/* Patch variables */
+	unsigned int row_size, to_be_copied, shift_right;
 
 	if (len <= 0)
 		return;
 
 	/* Copy the video data to the buffer. */
+	/* How many bytes are needed to complete the buffer? */
 	maxlen = buf->buf.length - buf->buf.bytesused;
+	/* Where do pixels stored in "data" have to be copied? */
 	mem = queue->mem + buf->buf.m.offset + buf->buf.bytesused;
+	/* How many bytes really can be copied into "mem"? */
 	nbytes = min((unsigned int)len, maxlen);
-	memcpy(mem, data, nbytes);
-	buf->buf.bytesused += nbytes;
+//	memcpy(mem, data, nbytes);
+//	buf->buf.bytesused += nbytes;
 
+	/* "row_size" is the number of bytes required to store a full row of
+	 * the frame.
+	 */
+	row_size = stream->cur_frame->wWidth *
+		   stream->format->bpp / 8;
+	/* Each loop "nbytes" is decremented of the number of bytes just copied.
+	 * So are there any other bytes to be copied?
+	 */
+	while (nbytes > 0) {
+		/* As the rows of modified frames have to be fulfilled from
+		 * bottom-left to top-right, each cycle tries to complete a
+		 * single row.
+		 * In this cycle where is it needed to start to store bytes
+		 * within the selected row? From the beginning or shifted
+		 * right? Because other bytes could have been already stored in
+		 * that row without completing it, so it could be needed a right
+		 * shift.
+		 */
+		shift_right = buf->buf.bytesused % row_size;
+		/* In this cycle how many byte can we copy in the selected row?
+		 */
+		if (nbytes > row_size - shift_right)
+			to_be_copied = row_size - shift_right ;
+		else
+			to_be_copied = nbytes;
+		/* "queue->mem + buf->buf.m.offset" is the base-address where to
+		 * start to store the current frame. This address refers to a
+		 * preallocated area (just for a sigle frame) taking part in a
+		 * circular buffer, where to store a fixed number of sequent
+		 * frames.
+		 */
+		memcpy(queue->mem + buf->buf.m.offset
+			/* Go to the end of this frame. */
+			+ row_size * stream->cur_frame->wHeight
+			/* Go back for the number of bytes corrisponding to the
+			 * already fully completed rows.
+			 */
+			- (buf->buf.bytesused - shift_right)
+			/* Go back at the starting point of the upper row. */
+			- row_size
+			/* Shift right on this row if it is needed. */
+			+ shift_right,
+			data,
+			to_be_copied );
+		/* Update "data", "byteused" and "nbytes" values. */
+		data += to_be_copied;
+		buf->buf.bytesused += to_be_copied ;
+		nbytes -= to_be_copied;
+	}
 	/* Complete the current frame if the buffer size was exceeded. */
 	if (len > maxlen) {
 		uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");

