V4L/DVB: gspca - zc3xx: Add back the brightness control
[deliverable/linux.git] / drivers / media / video / gspca / zc3xx.c
index 73c4ebbcbfb17affcff9a0a19b9a6df9713473e4..1420eb2a9d38b226212aeb9e3b3bd12b005a469c 100644 (file)
@@ -40,6 +40,7 @@ static int force_sensor = -1;
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
 
+       u8 brightness;
        u8 contrast;
        u8 gamma;
        u8 autogain;
@@ -79,6 +80,8 @@ 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_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
 static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
 static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
@@ -91,6 +94,20 @@ 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[] = {
+       {
+           {
+               .id      = V4L2_CID_BRIGHTNESS,
+               .type    = V4L2_CTRL_TYPE_INTEGER,
+               .name    = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step    = 1,
+#define BRIGHTNESS_DEF 128
+               .default_value = BRIGHTNESS_DEF,
+           },
+           .set = sd_setbrightness,
+           .get = sd_getbrightness,
+       },
        {
            {
                .id      = V4L2_CID_CONTRAST,
@@ -132,7 +149,7 @@ static const struct ctrl sd_ctrls[] = {
            .set = sd_setautogain,
            .get = sd_getautogain,
        },
-#define LIGHTFREQ_IDX 3
+#define LIGHTFREQ_IDX 4
        {
            {
                .id      = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -6011,9 +6028,12 @@ static void setcontrast(struct gspca_dev *gspca_dev)
        struct sd *sd = (struct sd *) gspca_dev;
        struct usb_device *dev = gspca_dev->dev;
        const u8 *Tgamma;
-       int g, i, k, adj, gp;
+       int g, i, brightness, contrast, adj, gp1, gp2;
        u8 gr[16];
-       static const u8 delta_tb[16] =          /* delta for contrast */
+       static const u8 delta_b[16] =           /* delta for brightness */
+               {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
+                0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18};
+       static const u8 delta_c[16] =           /* delta for contrast */
                {0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
                 0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
        static const u8 gamma_tb[6][16] = {
@@ -6033,30 +6053,30 @@ static void setcontrast(struct gspca_dev *gspca_dev)
 
        Tgamma = gamma_tb[sd->gamma - 1];
 
-       k = ((int) sd->contrast - 128);         /* -128 / 128 */
+       contrast = ((int) sd->contrast - 128);          /* -128 / 127 */
+       brightness = ((int) sd->brightness - 128);      /* -128 / 92 */
        adj = 0;
-       gp = 0;
+       gp1 = gp2 = 0;
        for (i = 0; i < 16; i++) {
-               g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
+               g = Tgamma[i] + delta_b[i] * brightness / 256
+                               - delta_c[i] * contrast / 256 - adj / 2;
                if (g > 0xff)
                        g = 0xff;
                else if (g < 0)
                        g = 0;
                reg_w(dev, g, 0x0120 + i);      /* gamma */
-               if (k > 0)
+               if (contrast > 0)
                        adj--;
-               else
+               else if (contrast < 0)
                        adj++;
-
-               if (i != 0) {
-                       if (gp == 0)
-                               gr[i - 1] = 0;
-                       else
-                               gr[i - 1] = g - gp;
-               }
-               gp = g;
+               if (i > 1)
+                       gr[i - 1] = (g - gp2) / 2;
+               else if (i != 0)
+                       gr[0] = gp1 == 0 ? 0 : (g - gp1);
+               gp2 = gp1;
+               gp1 = g;
        }
-       gr[15] = gr[14] / 2;
+       gr[15] = (0xff - gp2) / 2;
        for (i = 0; i < 16; i++)
                reg_w(dev, gr[i], 0x0130 + i);  /* gradient */
 }
@@ -6744,6 +6764,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
                cam->nmodes = ARRAY_SIZE(broken_vga_mode);
                break;
        }
+       sd->brightness = BRIGHTNESS_DEF;
        sd->contrast = CONTRAST_DEF;
        sd->gamma = gamma[sd->sensor];
        sd->autogain = AUTOGAIN_DEF;
@@ -6954,6 +6975,24 @@ 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)
+               setcontrast(gspca_dev);
+       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_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
This page took 0.026749 seconds and 5 git commands to generate.