V4L/DVB (10347): gspca - mars: Optimize, rewrite initialization and add controls.
authorJean-Francois Moine <moinejf@free.fr>
Thu, 8 Jan 2009 19:29:38 +0000 (16:29 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 30 Mar 2009 15:42:30 +0000 (12:42 -0300)
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/mars.c

index 54c68ea7e5468335902e13ac23def95dc59cfd02..e85ba1aa8bd3dc1a9ea7f14ea8b8b0f8a51b5de1 100644 (file)
@@ -32,16 +32,86 @@ MODULE_LICENSE("GPL");
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
+
+       u8 brightness;
+       u8 colors;
+       u8 gamma;
+       u8 sharpness;
 };
 
 /* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+
 static struct ctrl sd_ctrls[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 30,
+               .step    = 1,
+#define BRIGHTNESS_DEF 15
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
+       {
+           {
+               .id      = V4L2_CID_SATURATION,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Color",
+               .minimum = 0,
+               .maximum = 220,
+               .step    = 1,
+#define COLOR_DEF 190
+               .default_value = COLOR_DEF,
+           },
+           .set = sd_setcolors,
+           .get = sd_getcolors,
+       },
+       {
+           {
+               .id      = V4L2_CID_GAMMA,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Gamma",
+               .minimum = 0,
+               .maximum = 3,
+               .step    = 1,
+#define GAMMA_DEF 1
+               .default_value = GAMMA_DEF,
+           },
+           .set = sd_setgamma,
+           .get = sd_getgamma,
+       },
+       {
+           {
+               .id      = V4L2_CID_SHARPNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Sharpness",
+               .minimum = 0,
+               .maximum = 2,
+               .step    = 1,
+#define SHARPNESS_DEF 1
+               .default_value = SHARPNESS_DEF,
+           },
+           .set = sd_setsharpness,
+           .get = sd_getsharpness,
+       },
 };
 
 static const struct v4l2_pix_format vga_mode[] = {
        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
                .bytesperline = 320,
-               .sizeimage = 320 * 240 * 3 / 8 + 589,
+               .sizeimage = 320 * 240 * 3 / 8 + 590,
                .colorspace = V4L2_COLORSPACE_JPEG,
                .priv = 2},
        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
@@ -51,76 +121,62 @@ static const struct v4l2_pix_format vga_mode[] = {
                .priv = 1},
 };
 
-/* MI Register table //elvis */
-enum {
-       REG_HW_MI_0,
-       REG_HW_MI_1,
-       REG_HW_MI_2,
-       REG_HW_MI_3,
-       REG_HW_MI_4,
-       REG_HW_MI_5,
-       REG_HW_MI_6,
-       REG_HW_MI_7,
-       REG_HW_MI_9 = 0x09,
-       REG_HW_MI_B = 0x0B,
-       REG_HW_MI_C,
-       REG_HW_MI_D,
-       REG_HW_MI_1E = 0x1E,
-       REG_HW_MI_20 = 0x20,
-       REG_HW_MI_2B = 0x2B,
-       REG_HW_MI_2C,
-       REG_HW_MI_2D,
-       REG_HW_MI_2E,
-       REG_HW_MI_35 = 0x35,
-       REG_HW_MI_5F = 0x5f,
-       REG_HW_MI_60,
-       REG_HW_MI_61,
-       REG_HW_MI_62,
-       REG_HW_MI_63,
-       REG_HW_MI_64,
-       REG_HW_MI_F1 = 0xf1,
-       ATTR_TOTAL_MI_REG = 0xf2
+static const __u8 mi_data[0x20] = {
+/*      01    02   03     04    05    06    07    08 */
+       0x48, 0x22, 0x01, 0x47, 0x10, 0x00, 0x00, 0x00,
+/*      09    0a   0b     0c    0d    0e    0f    10 */
+       0x00, 0x01, 0x30, 0x01, 0x30, 0x01, 0x30, 0x01,
+/*      11    12   13     14    15    16    17    18 */
+       0x30, 0x00, 0x04, 0x00, 0x06, 0x01, 0xe2, 0x02,
+/*      19    1a   1b     1c    1d    1e    1f    20 */
+       0x82, 0x00, 0x20, 0x17, 0x80, 0x08, 0x0c, 0x00
 };
 
-/* the bytes to write are in gspca_dev->usb_buf */
+/* write <len> bytes from gspca_dev->usb_buf */
 static int reg_w(struct gspca_dev *gspca_dev,
-                __u16 index, int len)
+                int len)
 {
-       int rc;
-
-       rc = usb_control_msg(gspca_dev->dev,
-                        usb_sndbulkpipe(gspca_dev->dev, 4),
-                        0x12,
-                        0xc8,          /* ?? */
-                        0,             /* value */
-                        index, gspca_dev->usb_buf, len, 500);
-       if (rc < 0)
-               PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc);
-       return rc;
+       int alen, ret;
+
+       ret = usb_bulk_msg(gspca_dev->dev,
+                       usb_sndbulkpipe(gspca_dev->dev, 4),
+                       gspca_dev->usb_buf,
+                       len,
+                       &alen,
+                       500);   /* timeout in milliseconds */
+       if (ret < 0)
+               PDEBUG(D_ERR, "reg write [%02x] error %d",
+                       gspca_dev->usb_buf[0], ret);
+       return ret;
 }
 
-static void bulk_w(struct gspca_dev *gspca_dev,
-                  __u16 *pch,
-                  __u16 Address)
+static void mi_w(struct gspca_dev *gspca_dev,
+                u8 addr,
+                u8 value)
 {
        gspca_dev->usb_buf[0] = 0x1f;
        gspca_dev->usb_buf[1] = 0;                      /* control byte */
-       gspca_dev->usb_buf[2] = Address;
-       gspca_dev->usb_buf[3] = *pch >> 8;              /* high byte */
-       gspca_dev->usb_buf[4] = *pch;                   /* low byte */
+       gspca_dev->usb_buf[2] = addr;
+       gspca_dev->usb_buf[3] = value;
 
-       reg_w(gspca_dev, Address, 5);
+       reg_w(gspca_dev, 4);
 }
 
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
 
        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
+       sd->brightness = BRIGHTNESS_DEF;
+       sd->colors = COLOR_DEF;
+       sd->gamma = GAMMA_DEF;
+       sd->sharpness = SHARPNESS_DEF;
+       gspca_dev->iface = 9;           /* use the altsetting 08 */
        return 0;
 }
 
@@ -132,24 +188,16 @@ static int sd_init(struct gspca_dev *gspca_dev)
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
+       struct sd *sd = (struct sd *) gspca_dev;
        int err_code;
-       __u8 *data;
-       __u16 *MI_buf;
-       int h_size, v_size;
-       int intpipe;
-
-       PDEBUG(D_STREAM, "camera start, iface %d, alt 8", gspca_dev->iface);
-       err_code = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 8);
-       if (err_code < 0) {
-               PDEBUG(D_ERR|D_STREAM, "Set packet size: set interface error");
-               return err_code;
-       }
+       u8 *data;
+       int i, val;
 
        data = gspca_dev->usb_buf;
+
        data[0] = 0x01;         /* address */
        data[1] = 0x01;
-
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
@@ -159,30 +207,28 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;         /* address */
        data[1] = 0x0c | 0x01;  /* reg 0 */
        data[2] = 0x01;         /* reg 1 */
-       h_size = gspca_dev->width;
-       v_size = gspca_dev->height;
-       data[3] = h_size / 8;   /* h_size , reg 2 */
-       data[4] = v_size / 8;   /* v_size , reg 3 */
+       data[3] = gspca_dev->width / 8;         /* h_size , reg 2 */
+       data[4] = gspca_dev->height / 8;        /* v_size , reg 3 */
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
-       data[6] = 4;            /* reg 5, H start */
-       data[7] = 0xc0;         /* reg 6, gamma 1.5 */
-       data[8] = 3;            /* reg 7, V start */
+       data[6] = 0x02;         /* reg 5, H start - was 0x04 */
+       data[7] = sd->gamma * 0x40;     /* reg 0x06: gamma */
+       data[8] = 0x01;         /* reg 7, V start - was 0x03 */
 /*     if (h_size == 320 ) */
 /*             data[9]= 0x56;   * reg 8, 24MHz, 2:1 scale down */
 /*     else */
        data[9] = 0x52;         /* reg 8, 24MHz, no scale down */
-       data[10] = 0x5d;        /* reg 9, I2C device address
-                                *      [for PAS5101 (0x40)] [for MI (0x5d)] */
+/*jfm: from win trace*/
+       data[10] = 0x18;
 
-       err_code = reg_w(gspca_dev, data[0], 11);
+       err_code = reg_w(gspca_dev, 11);
        if (err_code < 0)
                return err_code;
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
@@ -193,137 +239,55 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*     else */
        data[1] = 50;           /* 50 reg 60, pc-cam frame size
                                 *      (unit: 4KB) 200KB */
-       err_code = reg_w(gspca_dev, data[0], 2);
+       err_code = reg_w(gspca_dev, 2);
        if (err_code < 0)
                return err_code;
 
-       if (0) {                        /* fixed dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (1.75) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x3f;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               data[4] = 0;            /* reg 97, set fixed dark level */
-               data[5] = 0;            /* reg 98, don't care */
-       } else {                        /* auto dark-gain */
-               data[1] = 0;            /* reg 94, Y Gain (auto) */
-               data[2] = 0;            /* reg 95, UV Gain (1.75) */
-               data[3] = 0x78;         /* reg 96, Y Gain/UV Gain/disable
-                                        *      auto dark-gain */
-               switch (gspca_dev->width) {
-/*             case 1280: */
-/*                     data[4] = 154;
-                                * reg 97, %3 shadow point (unit: 256 pixel) */
-/*                     data[5] = 51;
-                                * reg 98, %1 highlight point
-                                *      (uint: 256 pixel) */
-/*                     break; */
-               default:
-/*             case 640: */
-                       data[4] = 36;   /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 12;   /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               case 320:
-                       data[4] = 9;    /* reg 97, %3 shadow point
-                                        *      (unit: 256 pixel) */
-                       data[5] = 3;    /* reg 98, %1 highlight point
-                                        *      (uint: 256 pixel) */
-                       break;
-               }
-       }
        /* auto dark-gain */
        data[0] = 0x5e;         /* address */
-
-       err_code = reg_w(gspca_dev, data[0], 6);
+       data[1] = 0;            /* reg 94, Y Gain (auto) */
+/*jfm: from win trace*/
+       val = sd->colors * 0x40 + 0x400;
+       data[2] = val;          /* reg 0x5f/0x60 (LE) = saturation */
+       data[3] = val >> 8;
+       data[4] = sd->brightness; /* reg 0x61 = brightness */
+       data[5] = 0x00;
+
+       err_code = reg_w(gspca_dev, 6);
        if (err_code < 0)
                return err_code;
 
        data[0] = 0x67;
-       data[1] = 0x13;         /* reg 103, first pixel B, disable sharpness */
-       err_code = reg_w(gspca_dev, data[0], 2);
+/*jfm: from win trace*/
+       data[1] = sd->sharpness * 4 + 3;
+       data[2] = 0x14;
+       err_code = reg_w(gspca_dev, 3);
        if (err_code < 0)
                return err_code;
 
-       /*
-        * initialize the value of MI sensor...
-        */
-       MI_buf = kzalloc(ATTR_TOTAL_MI_REG * sizeof *MI_buf, GFP_KERNEL);
-       MI_buf[REG_HW_MI_1] = 0x000a;
-       MI_buf[REG_HW_MI_2] = 0x000c;
-       MI_buf[REG_HW_MI_3] = 0x0405;
-       MI_buf[REG_HW_MI_4] = 0x0507;
-       /* mi_Attr_Reg_[REG_HW_MI_5]     = 0x01ff;//13 */
-       MI_buf[REG_HW_MI_5] = 0x0013;   /* 13 */
-       MI_buf[REG_HW_MI_6] = 0x001f;   /* vertical blanking */
-       /* mi_Attr_Reg_[REG_HW_MI_6]     = 0x0400;  // vertical blanking */
-       MI_buf[REG_HW_MI_7] = 0x0002;
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x015f; */
-       /* mi_Attr_Reg_[REG_HW_MI_9]     = 0x030f; */
-       MI_buf[REG_HW_MI_9] = 0x0374;
-       MI_buf[REG_HW_MI_B] = 0x0000;
-       MI_buf[REG_HW_MI_C] = 0x0000;
-       MI_buf[REG_HW_MI_D] = 0x0000;
-       MI_buf[REG_HW_MI_1E] = 0x8000;
-/* mi_Attr_Reg_[REG_HW_MI_20]    = 0x1104; */
-       MI_buf[REG_HW_MI_20] = 0x1104;  /* 0x111c; */
-       MI_buf[REG_HW_MI_2B] = 0x0008;
-/* mi_Attr_Reg_[REG_HW_MI_2C]    = 0x000f; */
-       MI_buf[REG_HW_MI_2C] = 0x001f;  /* lita suggest */
-       MI_buf[REG_HW_MI_2D] = 0x0008;
-       MI_buf[REG_HW_MI_2E] = 0x0008;
-       MI_buf[REG_HW_MI_35] = 0x0051;
-       MI_buf[REG_HW_MI_5F] = 0x0904;  /* fail to write */
-       MI_buf[REG_HW_MI_60] = 0x0000;
-       MI_buf[REG_HW_MI_61] = 0x0000;
-       MI_buf[REG_HW_MI_62] = 0x0498;
-       MI_buf[REG_HW_MI_63] = 0x0000;
-       MI_buf[REG_HW_MI_64] = 0x0000;
-       MI_buf[REG_HW_MI_F1] = 0x0001;
-       /* changing while setting up the different value of dx/dy */
-
-       if (gspca_dev->width != 1280) {
-               MI_buf[0x01] = 0x010a;
-               MI_buf[0x02] = 0x014c;
-               MI_buf[0x03] = 0x01e5;
-               MI_buf[0x04] = 0x0287;
-       }
-       MI_buf[0x20] = 0x1104;
-
-       bulk_w(gspca_dev, MI_buf + 1, 1);
-       bulk_w(gspca_dev, MI_buf + 2, 2);
-       bulk_w(gspca_dev, MI_buf + 3, 3);
-       bulk_w(gspca_dev, MI_buf + 4, 4);
-       bulk_w(gspca_dev, MI_buf + 5, 5);
-       bulk_w(gspca_dev, MI_buf + 6, 6);
-       bulk_w(gspca_dev, MI_buf + 7, 7);
-       bulk_w(gspca_dev, MI_buf + 9, 9);
-       bulk_w(gspca_dev, MI_buf + 0x0b, 0x0b);
-       bulk_w(gspca_dev, MI_buf + 0x0c, 0x0c);
-       bulk_w(gspca_dev, MI_buf + 0x0d, 0x0d);
-       bulk_w(gspca_dev, MI_buf + 0x1e, 0x1e);
-       bulk_w(gspca_dev, MI_buf + 0x20, 0x20);
-       bulk_w(gspca_dev, MI_buf + 0x2b, 0x2b);
-       bulk_w(gspca_dev, MI_buf + 0x2c, 0x2c);
-       bulk_w(gspca_dev, MI_buf + 0x2d, 0x2d);
-       bulk_w(gspca_dev, MI_buf + 0x2e, 0x2e);
-       bulk_w(gspca_dev, MI_buf + 0x35, 0x35);
-       bulk_w(gspca_dev, MI_buf + 0x5f, 0x5f);
-       bulk_w(gspca_dev, MI_buf + 0x60, 0x60);
-       bulk_w(gspca_dev, MI_buf + 0x61, 0x61);
-       bulk_w(gspca_dev, MI_buf + 0x62, 0x62);
-       bulk_w(gspca_dev, MI_buf + 0x63, 0x63);
-       bulk_w(gspca_dev, MI_buf + 0x64, 0x64);
-       bulk_w(gspca_dev, MI_buf + 0xf1, 0xf1);
-       kfree(MI_buf);
-
-       intpipe = usb_sndintpipe(gspca_dev->dev, 0);
-       err_code = usb_clear_halt(gspca_dev->dev, intpipe);
+       data[0] = 0x69;
+       data[1] = 0x2f;
+       data[2] = 0x28;
+       data[3] = 0x42;
+       err_code = reg_w(gspca_dev, 4);
+       if (err_code < 0)
+               return err_code;
+
+       data[0] = 0x63;
+       data[1] = 0x07;
+       err_code = reg_w(gspca_dev, 2);
+/*jfm: win trace - many writes here to reg 0x64*/
+       if (err_code < 0)
+               return err_code;
+
+       /* initialize the MI sensor */
+       for (i = 0; i < sizeof mi_data; i++)
+               mi_w(gspca_dev, i + 1, mi_data[i]);
 
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
-       reg_w(gspca_dev, data[0], 2);
-       return err_code;
+       reg_w(gspca_dev, 2);
+       return 0;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -332,7 +296,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
 
        gspca_dev->usb_buf[0] = 1;
        gspca_dev->usb_buf[1] = 0;
-       result = reg_w(gspca_dev, gspca_dev->usb_buf[0], 2);
+       result = reg_w(gspca_dev, 2);
        if (result < 0)
                PDEBUG(D_ERR, "Camera Stop failed");
 }
@@ -358,7 +322,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                            || data[5 + p] == 0x65
                            || data[5 + p] == 0x66
                            || data[5 + p] == 0x67) {
-                               PDEBUG(D_PACK, "sof offset: %d leng: %d",
+                               PDEBUG(D_PACK, "sof offset: %d len: %d",
                                        p, len);
                                frame = gspca_frame_add(gspca_dev, LAST_PACKET,
                                                        frame, data, 0);
@@ -374,6 +338,92 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
 }
 
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->brightness = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x61;
+               gspca_dev->usb_buf[1] = val;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->brightness;
+       return 0;
+}
+
+static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->colors = val;
+       if (gspca_dev->streaming) {
+               val = val * 0x40 + 0x400;
+               gspca_dev->usb_buf[0] = 0x5f;
+               gspca_dev->usb_buf[1] = val;
+               gspca_dev->usb_buf[2] = val >> 8;
+               reg_w(gspca_dev, 3);
+       }
+       return 0;
+}
+
+static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->colors;
+       return 0;
+}
+
+static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->gamma = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x06;
+               gspca_dev->usb_buf[1] = val * 0x40;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->gamma;
+       return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       sd->sharpness = val;
+       if (gspca_dev->streaming) {
+               gspca_dev->usb_buf[0] = 0x67;
+               gspca_dev->usb_buf[1] = val * 4 + 3;
+               reg_w(gspca_dev, 2);
+       }
+       return 0;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       *val = sd->sharpness;
+       return 0;
+}
+
 /* sub-driver description */
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
@@ -416,6 +466,7 @@ static struct usb_driver sd_driver = {
 static int __init sd_mod_init(void)
 {
        int ret;
+
        ret = usb_register(&sd_driver);
        if (ret < 0)
                return ret;