V4L/DVB (8660): gspca: Simplify the scan of URB packets in pac7311.
authorJean-Francois Moine <moinejf@free.fr>
Wed, 3 Sep 2008 19:47:21 +0000 (16:47 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 3 Sep 2008 21:36:26 +0000 (18:36 -0300)
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/gspca/pac7311.c

index 815bea6edc448f989ac9a8f4df41ea7067b1dc29..caa33292a08a90f899bd2952341154c2f87bff3a 100644 (file)
@@ -40,7 +40,8 @@ struct sd {
        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 int sd_open(struct gspca_dev *gspca_dev)
 
 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 @@ static void do_autogain(struct gspca_dev *gspca_dev)
        }
 }
 
+/* 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;
-
-/*     if (len < 5) { */
-       if (len < 6) {
-/*             gspca_dev->last_packet_type = DISCARD_PACKET; */
-               return;
-       }
-
-       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);
+       int i;
+
+#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--;
                        }
-
-                       /* 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;
-                       break;
                }
+       } 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;
        }
 
-       /* 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;
+       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;
+                       }
+                       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;
                }
        }
-       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)