Merge branch 'bugfixes' of git://git.linux-nfs.org/projects/trondmy/nfs-2.6
[pandora-kernel.git] / drivers / media / video / gspca / mars.c
index 031f719..a81536e 100644 (file)
@@ -28,14 +28,23 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
 MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
 MODULE_LICENSE("GPL");
 
+/* controls */
+enum e_ctrl {
+       BRIGHTNESS,
+       COLORS,
+       GAMMA,
+       SHARPNESS,
+       ILLUM_TOP,
+       ILLUM_BOT,
+       NCTRLS          /* number of controls */
+};
+
 /* specific webcam descriptor */
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
-       u8 brightness;
-       u8 colors;
-       u8 gamma;
-       u8 sharpness;
+       struct gspca_ctrl ctrls[NCTRLS];
+
        u8 quality;
 #define QUALITY_MIN 40
 #define QUALITY_MAX 70
@@ -45,17 +54,15 @@ struct sd {
 };
 
 /* 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 const struct ctrl sd_ctrls[] = {
-       {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setgamma(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
            {
                .id      = V4L2_CID_BRIGHTNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -63,13 +70,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 30,
                .step    = 1,
-#define BRIGHTNESS_DEF 15
-               .default_value = BRIGHTNESS_DEF,
+               .default_value = 15,
            },
-           .set = sd_setbrightness,
-           .get = sd_getbrightness,
+           .set_control = setbrightness
        },
-       {
+[COLORS] = {
            {
                .id      = V4L2_CID_SATURATION,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -77,13 +82,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 1,
                .maximum = 255,
                .step    = 1,
-#define COLOR_DEF 200
-               .default_value = COLOR_DEF,
+               .default_value = 200,
            },
-           .set = sd_setcolors,
-           .get = sd_getcolors,
+           .set_control = setcolors
        },
-       {
+[GAMMA] = {
            {
                .id      = V4L2_CID_GAMMA,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -91,13 +94,11 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 3,
                .step    = 1,
-#define GAMMA_DEF 1
-               .default_value = GAMMA_DEF,
+               .default_value = 1,
            },
-           .set = sd_setgamma,
-           .get = sd_getgamma,
+           .set_control = setgamma
        },
-       {
+[SHARPNESS] = {
            {
                .id      = V4L2_CID_SHARPNESS,
                .type    = V4L2_CTRL_TYPE_INTEGER,
@@ -105,11 +106,35 @@ static const struct ctrl sd_ctrls[] = {
                .minimum = 0,
                .maximum = 2,
                .step    = 1,
-#define SHARPNESS_DEF 1
-               .default_value = SHARPNESS_DEF,
+               .default_value = 1,
+           },
+           .set_control = setsharpness
+       },
+[ILLUM_TOP] = {
+           {
+               .id      = V4L2_CID_ILLUMINATORS_1,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Top illuminator",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 0,
+               .flags = V4L2_CTRL_FLAG_UPDATE,
+           },
+           .set = sd_setilluminator1
+       },
+[ILLUM_BOT] = {
+           {
+               .id      = V4L2_CID_ILLUMINATORS_2,
+               .type    = V4L2_CTRL_TYPE_BOOLEAN,
+               .name    = "Bottom illuminator",
+               .minimum = 0,
+               .maximum = 1,
+               .step    = 1,
+               .default_value = 0,
+               .flags = V4L2_CTRL_FLAG_UPDATE,
            },
-           .set = sd_setsharpness,
-           .get = sd_getsharpness,
+           .set = sd_setilluminator2
        },
 };
 
@@ -138,21 +163,25 @@ static const __u8 mi_data[0x20] = {
 };
 
 /* write <len> bytes from gspca_dev->usb_buf */
-static int reg_w(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
                 int len)
 {
        int alen, ret;
 
+       if (gspca_dev->usb_err < 0)
+               return;
+
        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",
+       if (ret < 0) {
+               err("reg write [%02x] error %d",
                        gspca_dev->usb_buf[0], ret);
-       return ret;
+               gspca_dev->usb_err = ret;
+       }
 }
 
 static void mi_w(struct gspca_dev *gspca_dev,
@@ -167,6 +196,59 @@ static void mi_w(struct gspca_dev *gspca_dev,
        reg_w(gspca_dev, 4);
 }
 
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x61;
+       gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
+       reg_w(gspca_dev, 2);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+       s16 val;
+
+       val = sd->ctrls[COLORS].val;
+       gspca_dev->usb_buf[0] = 0x5f;
+       gspca_dev->usb_buf[1] = val << 3;
+       gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
+       reg_w(gspca_dev, 3);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x06;
+       gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
+       reg_w(gspca_dev, 2);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x67;
+       gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+       reg_w(gspca_dev, 2);
+}
+
+static void setilluminators(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->usb_buf[0] = 0x22;
+       if (sd->ctrls[ILLUM_TOP].val)
+               gspca_dev->usb_buf[1] = 0x76;
+       else if (sd->ctrls[ILLUM_BOT].val)
+               gspca_dev->usb_buf[1] = 0x7a;
+       else
+               gspca_dev->usb_buf[1] = 0x7e;
+       reg_w(gspca_dev, 2);
+}
+
 /* this function is called at probe time */
 static int sd_config(struct gspca_dev *gspca_dev,
                        const struct usb_device_id *id)
@@ -177,10 +259,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
        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;
+       cam->ctrls = sd->ctrls;
        sd->quality = QUALITY_DEF;
        gspca_dev->nbalt = 9;           /* use the altsetting 08 */
        return 0;
@@ -189,13 +268,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
 /* this function is called at probe and resume time */
 static int sd_init(struct gspca_dev *gspca_dev)
 {
+       gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
        return 0;
 }
 
 static int sd_start(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       int err_code;
        u8 *data;
        int i;
 
@@ -208,9 +287,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
 
        data[0] = 0x01;         /* address */
        data[1] = 0x01;
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        /*
           Initialize the MR97113 chip register
@@ -223,7 +300,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[5] = 0x30;         /* reg 4, MI, PAS5101 :
                                 *      0x30 for 24mhz , 0x28 for 12mhz */
        data[6] = 0x02;         /* reg 5, H start - was 0x04 */
-       data[7] = sd->gamma * 0x40;     /* reg 0x06: gamma */
+       data[7] = sd->ctrls[GAMMA].val * 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 */
@@ -232,16 +309,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
 /*jfm: from win trace*/
        data[10] = 0x18;
 
-       err_code = reg_w(gspca_dev, 11);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 11);
 
        data[0] = 0x23;         /* address */
        data[1] = 0x09;         /* reg 35, append frame header */
 
-       err_code = reg_w(gspca_dev, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        data[0] = 0x3c;         /* address */
 /*     if (gspca_dev->width == 1280) */
@@ -250,9 +323,7 @@ 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, 2);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 2);
 
        /* auto dark-gain */
        data[0] = 0x5e;         /* address */
@@ -261,37 +332,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
                                /* reg 0x5f/0x60 (LE) = saturation */
                                /* h (60): xxxx x100
                                 * l (5f): xxxx x000 */
-       data[2] = sd->colors << 3;
-       data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
-       data[4] = sd->brightness; /* reg 0x61 = brightness */
+       data[2] = sd->ctrls[COLORS].val << 3;
+       data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
+       data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
        data[5] = 0x00;
 
-       err_code = reg_w(gspca_dev, 6);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 6);
 
        data[0] = 0x67;
 /*jfm: from win trace*/
-       data[1] = sd->sharpness * 4 + 3;
+       data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
        data[2] = 0x14;
-       err_code = reg_w(gspca_dev, 3);
-       if (err_code < 0)
-               return err_code;
+       reg_w(gspca_dev, 3);
 
        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;
+       reg_w(gspca_dev, 4);
 
        data[0] = 0x63;
        data[1] = 0x07;
-       err_code = reg_w(gspca_dev, 2);
+       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++)
@@ -300,18 +363,26 @@ static int sd_start(struct gspca_dev *gspca_dev)
        data[0] = 0x00;
        data[1] = 0x4d;         /* ISOC transfering enable... */
        reg_w(gspca_dev, 2);
-       return 0;
+
+       gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
+       return gspca_dev->usb_err;
 }
 
 static void sd_stopN(struct gspca_dev *gspca_dev)
 {
-       int result;
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
+       if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
+               sd->ctrls[ILLUM_TOP].val = 0;
+               sd->ctrls[ILLUM_BOT].val = 0;
+               setilluminators(gspca_dev);
+               msleep(20);
+       }
 
        gspca_dev->usb_buf[0] = 1;
        gspca_dev->usb_buf[1] = 0;
-       result = reg_w(gspca_dev, 2);
-       if (result < 0)
-               PDEBUG(D_ERR, "Camera Stop failed");
+       reg_w(gspca_dev, 2);
 }
 
 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -352,91 +423,28 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
        gspca_frame_add(gspca_dev, INTER_PACKET, 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)
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       *val = sd->brightness;
-       return 0;
+       /* only one illuminator may be on */
+       sd->ctrls[ILLUM_TOP].val = val;
+       if (val)
+               sd->ctrls[ILLUM_BOT].val = 0;
+       setilluminators(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
 
-       sd->colors = val;
-       if (gspca_dev->streaming) {
-
-               /* see sd_start */
-               gspca_dev->usb_buf[0] = 0x5f;
-               gspca_dev->usb_buf[1] = sd->colors << 3;
-               gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
-               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;
+       /* only one illuminator may be on */
+       sd->ctrls[ILLUM_BOT].val = val;
+       if (val)
+               sd->ctrls[ILLUM_TOP].val = 0;
+       setilluminators(gspca_dev);
+       return gspca_dev->usb_err;
 }
 
 static int sd_set_jcomp(struct gspca_dev *gspca_dev,
@@ -471,7 +479,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
 static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .ctrls = sd_ctrls,
-       .nctrls = ARRAY_SIZE(sd_ctrls),
+       .nctrls = NCTRLS,
        .config = sd_config,
        .init = sd_init,
        .start = sd_start,
@@ -510,18 +518,11 @@ static struct usb_driver sd_driver = {
 /* -- module insert / remove -- */
 static int __init sd_mod_init(void)
 {
-       int ret;
-
-       ret = usb_register(&sd_driver);
-       if (ret < 0)
-               return ret;
-       PDEBUG(D_PROBE, "registered");
-       return 0;
+       return usb_register(&sd_driver);
 }
 static void __exit sd_mod_exit(void)
 {
        usb_deregister(&sd_driver);
-       PDEBUG(D_PROBE, "deregistered");
 }
 
 module_init(sd_mod_init);