V4L/DVB (8660): gspca: Simplify the scan of URB packets in pac7311.

Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 815bea6..caa3329 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -40,7 +40,8 @@
 	unsigned char colors;
 	unsigned char autogain;
 
-	char ffseq;
+	char ffnb;	/* number of 'ff' in the previous frame */
+	char tosof;	/* number of bytes before next start of frame */
 	signed char ag_cnt;
 #define AG_CNT_START 13
 };
@@ -335,6 +336,10 @@
 
 static void sd_start(struct gspca_dev *gspca_dev)
 {
+	struct sd *sd = (struct sd *) gspca_dev;
+
+	sd->ffnb = 0;
+	sd->tosof = 0;
 	reg_w(gspca_dev, 0xff, 0x01);
 	reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8);
 	reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8);
@@ -511,114 +516,123 @@
 	}
 }
 
+/* output the jpeg header */
+static void put_jpeg_head(struct gspca_dev *gspca_dev,
+			struct gspca_frame *frame)
+{
+	unsigned char tmpbuf[4];
+
+	gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+			(__u8 *) pac7311_jpeg_header,
+			12);
+	tmpbuf[0] = gspca_dev->height >> 8;
+	tmpbuf[1] = gspca_dev->height & 0xff;
+	tmpbuf[2] = gspca_dev->width >> 8;
+	tmpbuf[3] = gspca_dev->width & 0xff;
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+			tmpbuf, 4);
+	gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+		(__u8 *) &pac7311_jpeg_header[16],
+		PAC7311_JPEG_HEADER_SIZE - 16);
+}
+
+/* this function is run at interrupt level */
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 			struct gspca_frame *frame,	/* target */
 			__u8 *data,			/* isoc packet */
 			int len)			/* iso packet length */
 {
 	struct sd *sd = (struct sd *) gspca_dev;
-	unsigned char tmpbuf[4];
-	int i, p, ffseq;
+	int i;
 
-/*	if (len < 5) { */
-	if (len < 6) {
-/*		gspca_dev->last_packet_type = DISCARD_PACKET; */
-		return;
+#define INTER_FRAME 0x53
+#define LUM_OFFSET 0x1e		/* reverse offset / start of frame */
+
+	/*
+	 * inside a frame, there may be:
+	 *	escaped ff ('ff 00')
+	 *	sequences'ff ff ff xx' to remove
+	 *	end of frame ('ff d9')
+	 * at the end of frame, there are:
+	 *	ff d9			end of frame
+	 *	0x33 bytes
+	 *	one byte luminosity
+	 *	0x16 bytes
+	 *	ff ff 00 ff 96 62 44	start of frame header
+	 */
+
+	if (sd->tosof == 0) {	/* if inside a frame */
+
+		/* check for 'ff ff ff xx' at start and at end of packet */
+		/* (len is always >= 3) */
+		switch (sd->ffnb) {
+		case 1:
+			if (data[0] != 0xff)
+				break;		/* keep 'ff 00' */
+			/* fall thru */
+		case 2:
+		case 3:
+			data += 4 - sd->ffnb;
+			len -= 4 - sd->ffnb;
+			sd->ffnb = 0;
+			break;
+		}
+		if (data[len - 1] == 0xff) {
+			if (data[len - 2] == 0xff) {
+				if (data[len - 3] == 0xff) {
+					sd->ffnb = 3;
+					len -= 3;
+				} else {
+					sd->ffnb = 2;
+					len -= 2;
+				}
+			} else {
+				sd->ffnb = 1;
+				len--;
+			}
+		}
+	} else {		/* outside a frame */
+
+		/*
+		 * get the luminosity
+		 * and go to the start of frame
+		 */
+		data += sd->tosof;
+		len -= sd->tosof;
+		if (sd->tosof > LUM_OFFSET)
+			sd->lum_sum += data[-LUM_OFFSET];
+		put_jpeg_head(gspca_dev, frame);
+		sd->tosof = 0;
 	}
 
-	ffseq = sd->ffseq;
-
-	for (p = 0; p < len - 6; p++) {
-		if ((data[0 + p] == 0xff)
-		    && (data[1 + p] == 0xff)
-		    && (data[2 + p] == 0x00)
-		    && (data[3 + p] == 0xff)
-		    && (data[4 + p] == 0x96)) {
-
-			/* start of frame */
-			if (sd->ag_cnt >= 0 && p > 28) {
-				sd->lum_sum += data[p - 23];
-				if (--sd->ag_cnt < 0) {
-					sd->ag_cnt = AG_CNT_START;
-					atomic_set(&sd->avg_lum,
-						sd->lum_sum / AG_CNT_START);
-					sd->lum_sum = 0;
-					atomic_set(&sd->do_gain, 1);
-				}
+	for (i = 0; i < len; i++) {
+		if (data[i] != 0xff)
+			continue;
+		switch (data[i + 1]) {
+		case 0xd9:		/* end of frame */
+			frame = gspca_frame_add(gspca_dev,
+						LAST_PACKET,
+						frame, data, i + 1);
+			data += INTER_FRAME;
+			len -= INTER_FRAME;
+			i = 0;
+			if (len > LUM_OFFSET)
+				sd->lum_sum += data[-LUM_OFFSET];
+			if (len < 0) {
+				sd->tosof = -len;
+				break;
 			}
-
-			/* copy the end of data to the current frame */
-			frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
-						data, p);
-
-			/* put the JPEG header in the new frame */
-			gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
-					(unsigned char *) pac7311_jpeg_header,
-					12);
-			tmpbuf[0] = gspca_dev->height >> 8;
-			tmpbuf[1] = gspca_dev->height & 0xff;
-			tmpbuf[2] = gspca_dev->width >> 8;
-			tmpbuf[3] = gspca_dev->width & 0xff;
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-					tmpbuf, 4);
-			gspca_frame_add(gspca_dev, INTER_PACKET, frame,
-				(unsigned char *) &pac7311_jpeg_header[16],
-				PAC7311_JPEG_HEADER_SIZE - 16);
-
-			data += p + 7;
-			len -= p + 7;
-			ffseq = 0;
+			put_jpeg_head(gspca_dev, frame);
+			break;
+		case 0xff:		/* 'ff ff ff xx' */
+			gspca_frame_add(gspca_dev, INTER_PACKET,
+					frame, data, i);
+			data += i + 4;
+			len -= i + 4;
+			i = 0;
 			break;
 		}
 	}
-
-	/* remove the 'ff ff ff xx' sequences */
-	switch (ffseq) {
-	case 3:
-		data += 1;
-		len -= 1;
-		break;
-	case 2:
-		if (data[0] == 0xff) {
-			data += 2;
-			len -= 2;
-			frame->data_end -= 2;
-		}
-		break;
-	case 1:
-		if (data[0] == 0xff
-		    && data[1] == 0xff) {
-			data += 3;
-			len -= 3;
-			frame->data_end -= 1;
-		}
-		break;
-	}
-	for (i = 0; i < len - 4; i++) {
-		if (data[i] == 0xff
-		    && data[i + 1] == 0xff
-		    && data[i + 2] == 0xff) {
-			memmove(&data[i], &data[i + 4], len - i - 4);
-			len -= 4;
-		}
-	}
-	ffseq = 0;
-	if (data[len - 4] == 0xff) {
-		if (data[len - 3] == 0xff
-		    && data[len - 2] == 0xff) {
-			len -= 4;
-		}
-	} else if (data[len - 3] == 0xff) {
-		if (data[len - 2] == 0xff
-		    && data[len - 1] == 0xff)
-			ffseq = 3;
-	} else if (data[len - 2] == 0xff) {
-		if (data[len - 1] == 0xff)
-			ffseq = 2;
-	} else if (data[len - 1] == 0xff)
-		ffseq = 1;
-	sd->ffseq = ffseq;
-	gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
 static void getbrightness(struct gspca_dev *gspca_dev)