]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
[media] gscpa_m5602: Convert to the control framework
authorHans de Goede <hdegoede@redhat.com>
Tue, 19 Feb 2013 17:57:03 +0000 (14:57 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 5 Mar 2013 18:10:27 +0000 (15:10 -0300)
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
15 files changed:
drivers/media/usb/gspca/m5602/m5602_bridge.h
drivers/media/usb/gspca/m5602/m5602_core.c
drivers/media/usb/gspca/m5602/m5602_mt9m111.c
drivers/media/usb/gspca/m5602/m5602_mt9m111.h
drivers/media/usb/gspca/m5602/m5602_ov7660.c
drivers/media/usb/gspca/m5602/m5602_ov7660.h
drivers/media/usb/gspca/m5602/m5602_ov9650.c
drivers/media/usb/gspca/m5602/m5602_ov9650.h
drivers/media/usb/gspca/m5602/m5602_po1030.c
drivers/media/usb/gspca/m5602/m5602_po1030.h
drivers/media/usb/gspca/m5602/m5602_s5k4aa.c
drivers/media/usb/gspca/m5602/m5602_s5k4aa.h
drivers/media/usb/gspca/m5602/m5602_s5k83a.c
drivers/media/usb/gspca/m5602/m5602_s5k83a.h
drivers/media/usb/gspca/m5602/m5602_sensor.h

index 51af3ee3ab8550301a3bcb9b00c113a44b323c0a..19eb1a64f9d6e0058b121ff39d72fe02c275f270 100644 (file)
@@ -136,16 +136,33 @@ struct sd {
        /* A pointer to the currently connected sensor */
        const struct m5602_sensor *sensor;
 
-       struct sd_desc *desc;
-
-       /* Sensor private data */
-       void *sensor_priv;
-
        /* The current frame's id, used to detect frame boundaries */
        u8 frame_id;
 
        /* The current frame count */
        u32 frame_count;
+
+       /* Camera rotation polling thread for "flipable" cams */
+       struct task_struct *rotation_thread;
+
+       struct { /* auto-white-bal + green/red/blue balance control cluster */
+               struct v4l2_ctrl *auto_white_bal;
+               struct v4l2_ctrl *red_bal;
+               struct v4l2_ctrl *blue_bal;
+               struct v4l2_ctrl *green_bal;
+       };
+       struct { /* autoexpo / expo cluster */
+               struct v4l2_ctrl *autoexpo;
+               struct v4l2_ctrl *expo;
+       };
+       struct { /* autogain / gain cluster */
+               struct v4l2_ctrl *autogain;
+               struct v4l2_ctrl *gain;
+       };
+       struct { /* hflip/vflip cluster */
+               struct v4l2_ctrl *hflip;
+               struct v4l2_ctrl *vflip;
+       };
 };
 
 int m5602_read_bridge(
index ed22638978ce158f91b98155a7794b38bd770170..907a968f474d6e8d435560d242fc747ecc5d1e11 100644 (file)
@@ -252,6 +252,16 @@ static int m5602_init(struct gspca_dev *gspca_dev)
        return err;
 }
 
+static int m5602_init_controls(struct gspca_dev *gspca_dev)
+{
+       struct sd *sd = (struct sd *) gspca_dev;
+
+       if (!sd->sensor->init_controls)
+               return 0;
+
+       return sd->sensor->init_controls(sd);
+}
+
 static int m5602_start_transfer(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
@@ -336,11 +346,12 @@ static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
                sd->sensor->stop(sd);
 }
 
-/* sub-driver description, the ctrl and nctrl is filled at probe time */
-static struct sd_desc sd_desc = {
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
        .name           = MODULE_NAME,
        .config         = m5602_configure,
        .init           = m5602_init,
+       .init_controls  = m5602_init_controls,
        .start          = m5602_start_transfer,
        .stopN          = m5602_stop_transfer,
        .pkt_scan       = m5602_urb_complete
@@ -355,7 +366,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
        int err;
 
        cam = &gspca_dev->cam;
-       sd->desc = &sd_desc;
 
        if (dump_bridge)
                m5602_dump_bridge(sd);
index 6268aa24ec5d9989ec4003f598fde028950fec3b..b5f66921b3eb9d074143a4888786d939e9f6af01 100644 (file)
 
 #include "m5602_mt9m111.h"
 
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 val);
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                         __s32 *val);
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl);
+static void mt9m111_dump_registers(struct sd *sd);
 
 static struct v4l2_pix_format mt9m111_modes[] = {
        {
@@ -50,118 +36,26 @@ static struct v4l2_pix_format mt9m111_modes[] = {
        }
 };
 
-static const struct ctrl mt9m111_ctrls[] = {
-#define VFLIP_IDX 0
-       {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = mt9m111_set_vflip,
-               .get = mt9m111_get_vflip
-       },
-#define HFLIP_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = mt9m111_set_hflip,
-               .get = mt9m111_get_hflip
-       },
-#define GAIN_IDX 2
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0,
-                       .maximum        = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
-                       .step           = 1,
-                       .default_value  = MT9M111_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = mt9m111_set_gain,
-               .get = mt9m111_get_gain
-       },
-#define AUTO_WHITE_BALANCE_IDX 3
-       {
-               {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
-               },
-               .set = mt9m111_set_auto_white_balance,
-               .get = mt9m111_get_auto_white_balance
-       },
-#define GREEN_BALANCE_IDX 4
-       {
-               {
-                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "green balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_GREEN_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = mt9m111_set_green_balance,
-               .get = mt9m111_get_green_balance
-       },
-#define BLUE_BALANCE_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = mt9m111_set_blue_balance,
-               .get = mt9m111_get_blue_balance
-       },
-#define RED_BALANCE_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0x7ff,
-                       .step           = 0x1,
-                       .default_value  = MT9M111_RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = mt9m111_set_red_balance,
-               .get = mt9m111_get_red_balance
-       },
+static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
+       .s_ctrl = mt9m111_s_ctrl,
 };
 
-static void mt9m111_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = {
+       .ops    = &mt9m111_ctrl_ops,
+       .id     = M5602_V4L2_CID_GREEN_BALANCE,
+       .name   = "Green Balance",
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .min    = 0,
+       .max    = 0x7ff,
+       .step   = 1,
+       .def    = MT9M111_GREEN_GAIN_DEFAULT,
+       .flags  = V4L2_CTRL_FLAG_SLIDER,
+};
 
 int mt9m111_probe(struct sd *sd)
 {
        u8 data[2] = {0x00, 0x00};
        int i;
-       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == MT9M111_SENSOR) {
@@ -200,19 +94,8 @@ int mt9m111_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
-       sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
-                                 GFP_KERNEL);
-       if (!sensor_settings)
-               return -ENOMEM;
-
        sd->gspca_dev.cam.cam_mode = mt9m111_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
-       sd->desc->ctrls = mt9m111_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
-
-       for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
-               sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
-       sd->sensor_priv = sensor_settings;
 
        return 0;
 }
@@ -220,7 +103,6 @@ sensor_found:
 int mt9m111_init(struct sd *sd)
 {
        int i, err = 0;
-       s32 *sensor_settings = sd->sensor_priv;
 
        /* Init the sensor */
        for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -241,30 +123,45 @@ int mt9m111_init(struct sd *sd)
        if (dump_sensor)
                mt9m111_dump_registers(sd);
 
-       err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = mt9m111_set_green_balance(&sd->gspca_dev,
-                                        sensor_settings[GREEN_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+       return 0;
+}
 
-       err = mt9m111_set_blue_balance(&sd->gspca_dev,
-                                        sensor_settings[BLUE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+int mt9m111_init_controls(struct sd *sd)
+{
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 7);
+
+       sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+                                              V4L2_CID_AUTO_WHITE_BALANCE,
+                                              0, 1, 1, 0);
+       sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL);
+       sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+                                       V4L2_CID_RED_BALANCE, 0, 0x7ff, 1,
+                                       MT9M111_RED_GAIN_DEFAULT);
+       sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
+                                       V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1,
+                                       MT9M111_BLUE_GAIN_DEFAULT);
+
+       v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0,
+                         (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1,
+                         MT9M111_DEFAULT_GAIN);
+
+       sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
 
-       err = mt9m111_set_red_balance(&sd->gspca_dev,
-                                       sensor_settings[RED_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+       v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+       v4l2_ctrl_cluster(2, &sd->hflip);
 
-       return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+       return 0;
 }
 
 int mt9m111_start(struct sd *sd)
@@ -272,7 +169,6 @@ int mt9m111_start(struct sd *sd)
        int i, err = 0;
        u8 data[2];
        struct cam *cam = &sd->gspca_dev.cam;
-       s32 *sensor_settings = sd->sensor_priv;
 
        int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
        int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@@ -334,25 +230,10 @@ int mt9m111_start(struct sd *sd)
        switch (width) {
        case 640:
                PDEBUG(D_V4L2, "Configuring camera for VGA mode");
-               data[0] = MT9M111_RMB_OVER_SIZED;
-               data[1] = MT9M111_RMB_ROW_SKIP_2X |
-                         MT9M111_RMB_COLUMN_SKIP_2X |
-                         (sensor_settings[VFLIP_IDX] << 0) |
-                         (sensor_settings[HFLIP_IDX] << 1);
-
-               err = m5602_write_sensor(sd,
-                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
                break;
 
        case 320:
                PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
-               data[0] = MT9M111_RMB_OVER_SIZED;
-               data[1] = MT9M111_RMB_ROW_SKIP_4X |
-                               MT9M111_RMB_COLUMN_SKIP_4X |
-                               (sensor_settings[VFLIP_IDX] << 0) |
-                               (sensor_settings[HFLIP_IDX] << 1);
-               err = m5602_write_sensor(sd,
-                                        MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
                break;
        }
        return err;
@@ -361,105 +242,46 @@ int mt9m111_start(struct sd *sd)
 void mt9m111_disconnect(struct sd *sd)
 {
        sd->sensor = NULL;
-       kfree(sd->sensor_priv);
-}
-
-static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[VFLIP_IDX];
-       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
-       return 0;
-}
-
-static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       int err;
-       u8 data[2] = {0x00, 0x00};
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-
-       sensor_settings[VFLIP_IDX] = val;
-
-       /* The mt9m111 is flipped by default */
-       val = !val;
-
-       /* Set the correct page map */
-       err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
-       if (err < 0)
-               return err;
-
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
-       if (err < 0)
-               return err;
-
-       data[1] = (data[1] & 0xfe) | val;
-       err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
-                                  data, 2);
-       return err;
-}
-
-static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[HFLIP_IDX];
-       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
-       return 0;
 }
 
-static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
 {
        int err;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
+       int hflip;
+       int vflip;
 
-       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
-       sensor_settings[HFLIP_IDX] = val;
+       PDEBUG(D_V4L2, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val);
 
        /* The mt9m111 is flipped by default */
-       val = !val;
+       hflip = !sd->hflip->val;
+       vflip = !sd->vflip->val;
 
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
-       if (err < 0)
-               return err;
-
-       data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
+       data[0] = MT9M111_RMB_OVER_SIZED;
+       if (gspca_dev->width == 640) {
+               data[1] = MT9M111_RMB_ROW_SKIP_2X |
+                         MT9M111_RMB_COLUMN_SKIP_2X |
+                         (hflip << 1) | vflip;
+       } else {
+               data[1] = MT9M111_RMB_ROW_SKIP_4X |
+                         MT9M111_RMB_COLUMN_SKIP_4X |
+                         (hflip << 1) | vflip;
+       }
        err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
                                        data, 2);
        return err;
 }
 
-static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-
-       return 0;
-}
-
 static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
                                          __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        int err;
        u8 data[2];
 
@@ -467,7 +289,6 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
        if (err < 0)
                return err;
 
-       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
        data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
 
        err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
@@ -476,24 +297,11 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
        return err;
 }
 
-static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                         __s32 *val) {
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read auto white balance %d", *val);
-       return 0;
-}
-
 static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err, tmp;
        u8 data[2] = {0x00, 0x00};
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       sensor_settings[GAIN_IDX] = val;
 
        /* Set the correct page map */
        err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@@ -532,9 +340,7 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
-       sensor_settings[GREEN_BALANCE_IDX] = val;
        data[1] = (val & 0xff);
        data[0] = (val & 0xff00) >> 8;
 
@@ -548,23 +354,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
                                  data, 2);
 }
 
-static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GREEN_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read green balance %d", *val);
-       return 0;
-}
-
 static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
-       sensor_settings[BLUE_BALANCE_IDX] = val;
        data[1] = (val & 0xff);
        data[0] = (val & 0xff00) >> 8;
 
@@ -574,23 +368,11 @@ static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
                                  data, 2);
 }
 
-static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[BLUE_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read blue balance %d", *val);
-       return 0;
-}
-
 static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
-       sensor_settings[RED_BALANCE_IDX] = val;
        data[1] = (val & 0xff);
        data[0] = (val & 0xff00) >> 8;
 
@@ -600,14 +382,40 @@ static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
                                  data, 2);
 }
 
-static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
+       int err;
 
-       *val = sensor_settings[RED_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read red balance %d", *val);
-       return 0;
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val);
+               if (err || ctrl->val)
+                       return err;
+               err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val);
+               if (err)
+                       return err;
+               err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val);
+               if (err)
+                       return err;
+               err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val);
+               break;
+       case V4L2_CID_GAIN:
+               err = mt9m111_set_gain(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = mt9m111_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err;
 }
 
 static void mt9m111_dump_registers(struct sd *sd)
index 8c672b5c8c6a2797d659c29a0c644c5cced39a40..07448d35e3cd274392a81308907e2690b9e530d2 100644 (file)
@@ -110,6 +110,7 @@ extern bool dump_sensor;
 
 int mt9m111_probe(struct sd *sd);
 int mt9m111_init(struct sd *sd);
+int mt9m111_init_controls(struct sd *sd);
 int mt9m111_start(struct sd *sd);
 void mt9m111_disconnect(struct sd *sd);
 
@@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = {
 
        .probe = mt9m111_probe,
        .init = mt9m111_init,
+       .init_controls = mt9m111_init_controls,
        .disconnect = mt9m111_disconnect,
        .start = mt9m111_start,
 };
index 9a14835c128fb9b8047d91b05ef0927aeeee65ec..3bbe3ad5d4a9998544ec948e583eeb39aaef0ced 100644 (file)
 
 #include "m5602_ov7660.h"
 
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val);
-static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 val);
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-
-static const struct ctrl ov7660_ctrls[] = {
-#define GAIN_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = OV7660_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = ov7660_set_gain,
-               .get = ov7660_get_gain
-       },
-#define BLUE_BALANCE_IDX 2
-#define RED_BALANCE_IDX 3
-#define AUTO_WHITE_BALANCE_IDX 4
-       {
-               {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov7660_set_auto_white_balance,
-               .get = ov7660_get_auto_white_balance
-       },
-#define AUTO_GAIN_CTRL_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_AUTOGAIN,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto gain control",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov7660_set_auto_gain,
-               .get = ov7660_get_auto_gain
-       },
-#define AUTO_EXPOSURE_IDX 6
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov7660_set_auto_exposure,
-               .get = ov7660_get_auto_exposure
-       },
-#define HFLIP_IDX 7
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = ov7660_set_hflip,
-               .get = ov7660_get_hflip
-       },
-#define VFLIP_IDX 8
-       {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = ov7660_set_vflip,
-               .get = ov7660_get_vflip
-       },
-
-};
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov7660_dump_registers(struct sd *sd);
 
 static struct v4l2_pix_format ov7660_modes[] = {
        {
@@ -140,15 +37,15 @@ static struct v4l2_pix_format ov7660_modes[] = {
        }
 };
 
-static void ov7660_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov7660_ctrl_ops = {
+       .s_ctrl = ov7660_s_ctrl,
+};
 
 int ov7660_probe(struct sd *sd)
 {
        int err = 0, i;
        u8 prod_id = 0, ver_id = 0;
 
-       s32 *sensor_settings;
-
        if (force_sensor) {
                if (force_sensor == OV7660_SENSOR) {
                        pr_info("Forcing an %s sensor\n", ov7660.name);
@@ -191,19 +88,8 @@ int ov7660_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
-       sensor_settings = kmalloc(
-               ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
-       if (!sensor_settings)
-               return -ENOMEM;
-
        sd->gspca_dev.cam.cam_mode = ov7660_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
-       sd->desc->ctrls = ov7660_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
-
-       for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
-               sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
-       sd->sensor_priv = sensor_settings;
 
        return 0;
 }
@@ -211,7 +97,6 @@ sensor_found:
 int ov7660_init(struct sd *sd)
 {
        int i, err = 0;
-       s32 *sensor_settings = sd->sensor_priv;
 
        /* Init the sensor */
        for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
@@ -231,33 +116,40 @@ int ov7660_init(struct sd *sd)
        if (dump_sensor)
                ov7660_dump_registers(sd);
 
-       err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-       if (err < 0)
-               return err;
+       return 0;
+}
 
-       err = ov7660_set_auto_white_balance(&sd->gspca_dev,
-               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+int ov7660_init_controls(struct sd *sd)
+{
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 
-       err = ov7660_set_auto_gain(&sd->gspca_dev,
-               sensor_settings[AUTO_GAIN_CTRL_IDX]);
-       if (err < 0)
-               return err;
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 6);
 
-       err = ov7660_set_auto_exposure(&sd->gspca_dev,
-               sensor_settings[AUTO_EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
-       err = ov7660_set_hflip(&sd->gspca_dev,
-               sensor_settings[HFLIP_IDX]);
-       if (err < 0)
-               return err;
+       v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+                         0, 1, 1, 1);
+       v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
+                         V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
 
-       err = ov7660_set_vflip(&sd->gspca_dev,
-               sensor_settings[VFLIP_IDX]);
+       sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
+                                        V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0,
+                                    255, 1, OV7660_DEFAULT_GAIN);
 
-       return err;
+       sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
+
+       v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+       v4l2_ctrl_cluster(2, &sd->hflip);
+
+       return 0;
 }
 
 int ov7660_start(struct sd *sd)
@@ -275,56 +167,29 @@ void ov7660_disconnect(struct sd *sd)
        ov7660_stop(sd);
 
        sd->sensor = NULL;
-       kfree(sd->sensor_priv);
-}
-
-static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-       return 0;
 }
 
 static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
-       u8 i2c_data;
+       u8 i2c_data = val;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Setting gain to %d", val);
 
-       sensor_settings[GAIN_IDX] = val;
-
        err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
        return err;
 }
 
-
-static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
-       return 0;
-}
-
 static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
                                         __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto white balance to %d", val);
 
-       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -335,26 +200,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
        return err;
 }
 
-static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
-       PDEBUG(D_V4L2, "Read auto gain control %d", *val);
-       return 0;
-}
-
 static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto gain control to %d", val);
 
-       sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -364,94 +217,69 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
        return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
 }
 
-static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
-       return 0;
-}
-
 static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
                                    __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
 
-       sensor_settings[AUTO_EXPOSURE_IDX] = val;
        err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
 
+       val = (val == V4L2_EXPOSURE_AUTO);
        i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
 
        return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
 }
 
-static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[HFLIP_IDX];
-       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-       return 0;
-}
-
-static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
-       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+       PDEBUG(D_V4L2, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val);
 
-       sensor_settings[HFLIP_IDX] = val;
-
-       i2c_data = ((val & 0x01) << 5) |
-               (sensor_settings[VFLIP_IDX] << 4);
+       i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
 
        err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
 
        return err;
 }
 
-static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[VFLIP_IDX];
-       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
-       return 0;
-}
-
-static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
        int err;
-       u8 i2c_data;
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-       sensor_settings[VFLIP_IDX] = val;
 
-       i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
-       err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
-       if (err < 0)
-               return err;
-
-       /* When vflip is toggled we need to readjust the bridge hsync/vsync */
-       if (gspca_dev->streaming)
-               err = ov7660_start(sd);
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               err = ov7660_set_auto_gain(gspca_dev, ctrl->val);
+               if (err || ctrl->val)
+                       return err;
+               err = ov7660_set_gain(gspca_dev, sd->gain->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = ov7660_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
+       }
 
        return err;
 }
index 2b6a13b508f7331518acb30099fa2f885ab426d1..6fece1ce1232c697bca9fa4c55b451a52259c200 100644 (file)
@@ -90,6 +90,8 @@ extern bool dump_sensor;
 
 int ov7660_probe(struct sd *sd);
 int ov7660_init(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_init_controls(struct sd *sd);
 int ov7660_start(struct sd *sd);
 int ov7660_stop(struct sd *sd);
 void ov7660_disconnect(struct sd *sd);
@@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = {
        .i2c_regW = 1,
        .probe = ov7660_probe,
        .init = ov7660_init,
+       .init_controls = ov7660_init_controls,
        .start = ov7660_start,
        .stop = ov7660_stop,
        .disconnect = ov7660_disconnect,
index 2114a8b90ec98d53b16be0ef8a05367c09e5ea99..e2fe2f942fe648e1ae9cecf1e5f59e00dab4f5c3 100644 (file)
 
 #include "m5602_ov9650.h"
 
-static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val);
-static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 val);
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
+static void ov9650_dump_registers(struct sd *sd);
 
 /* Vertically and horizontally flips the image if matched, needed for machines
    where the sensor is mounted upside down */
@@ -113,140 +95,6 @@ static
        {}
 };
 
-static const struct ctrl ov9650_ctrls[] = {
-#define EXPOSURE_IDX 0
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "exposure",
-                       .minimum        = 0x00,
-                       .maximum        = 0x1ff,
-                       .step           = 0x4,
-                       .default_value  = EXPOSURE_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = ov9650_set_exposure,
-               .get = ov9650_get_exposure
-       },
-#define GAIN_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0x00,
-                       .maximum        = 0x3ff,
-                       .step           = 0x1,
-                       .default_value  = GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = ov9650_set_gain,
-               .get = ov9650_get_gain
-       },
-#define RED_BALANCE_IDX 2
-       {
-               {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = ov9650_set_red_balance,
-               .get = ov9650_get_red_balance
-       },
-#define BLUE_BALANCE_IDX 3
-       {
-               {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = ov9650_set_blue_balance,
-               .get = ov9650_get_blue_balance
-       },
-#define HFLIP_IDX 4
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = ov9650_set_hflip,
-               .get = ov9650_get_hflip
-       },
-#define VFLIP_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = ov9650_set_vflip,
-               .get = ov9650_get_vflip
-       },
-#define AUTO_WHITE_BALANCE_IDX 6
-       {
-               {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov9650_set_auto_white_balance,
-               .get = ov9650_get_auto_white_balance
-       },
-#define AUTO_GAIN_CTRL_IDX 7
-       {
-               {
-                       .id             = V4L2_CID_AUTOGAIN,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto gain control",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov9650_set_auto_gain,
-               .get = ov9650_get_auto_gain
-       },
-#define AUTO_EXPOSURE_IDX 8
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1
-               },
-               .set = ov9650_set_auto_exposure,
-               .get = ov9650_get_auto_exposure
-       }
-
-};
-
 static struct v4l2_pix_format ov9650_modes[] = {
        {
                176,
@@ -291,13 +139,14 @@ static struct v4l2_pix_format ov9650_modes[] = {
        }
 };
 
-static void ov9650_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_ops ov9650_ctrl_ops = {
+       .s_ctrl = ov9650_s_ctrl,
+};
 
 int ov9650_probe(struct sd *sd)
 {
        int err = 0;
        u8 prod_id = 0, ver_id = 0, i;
-       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == OV9650_SENSOR) {
@@ -338,19 +187,9 @@ int ov9650_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
-       sensor_settings = kmalloc(
-               ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
-       if (!sensor_settings)
-               return -ENOMEM;
-
        sd->gspca_dev.cam.cam_mode = ov9650_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
-       sd->desc->ctrls = ov9650_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
 
-       for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
-               sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
-       sd->sensor_priv = sensor_settings;
        return 0;
 }
 
@@ -358,7 +197,6 @@ int ov9650_init(struct sd *sd)
 {
        int i, err = 0;
        u8 data;
-       s32 *sensor_settings = sd->sensor_priv;
 
        if (dump_sensor)
                ov9650_dump_registers(sd);
@@ -372,46 +210,52 @@ int ov9650_init(struct sd *sd)
                        err = m5602_write_bridge(sd, init_ov9650[i][1], data);
        }
 
-       err = ov9650_set_exposure(&sd->gspca_dev,
-                                  sensor_settings[EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-       if (err < 0)
-               return err;
-
-       err = ov9650_set_red_balance(&sd->gspca_dev,
-                                     sensor_settings[RED_BALANCE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = ov9650_set_blue_balance(&sd->gspca_dev,
-                                      sensor_settings[BLUE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
-       if (err < 0)
-               return err;
+       return 0;
+}
 
-       err = ov9650_set_auto_exposure(&sd->gspca_dev,
-                               sensor_settings[AUTO_EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
+int ov9650_init_controls(struct sd *sd)
+{
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 9);
+
+       sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+                                              V4L2_CID_AUTO_WHITE_BALANCE,
+                                              0, 1, 1, 1);
+       sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+                                       V4L2_CID_RED_BALANCE, 0, 255, 1,
+                                       RED_GAIN_DEFAULT);
+       sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+                                       V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+                                       BLUE_GAIN_DEFAULT);
+
+       sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
+                         V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
+       sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE,
+                         0, 0x1ff, 4, EXPOSURE_DEFAULT);
+
+       sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
+                                        V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0,
+                                    0x3ff, 1, GAIN_DEFAULT);
+
+       sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
 
-       err = ov9650_set_auto_white_balance(&sd->gspca_dev,
-                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+       v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
+       v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+       v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
+       v4l2_ctrl_cluster(2, &sd->hflip);
 
-       err = ov9650_set_auto_gain(&sd->gspca_dev,
-                               sensor_settings[AUTO_GAIN_CTRL_IDX]);
-       return err;
+       return 0;
 }
 
 int ov9650_start(struct sd *sd)
@@ -419,7 +263,6 @@ int ov9650_start(struct sd *sd)
        u8 data;
        int i, err = 0;
        struct cam *cam = &sd->gspca_dev.cam;
-       s32 *sensor_settings = sd->sensor_priv;
 
        int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
        int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@@ -427,9 +270,9 @@ int ov9650_start(struct sd *sd)
        int hor_offs = OV9650_LEFT_OFFSET;
 
        if ((!dmi_check_system(ov9650_flip_dmi_table) &&
-               sensor_settings[VFLIP_IDX]) ||
+               sd->vflip->val) ||
                (dmi_check_system(ov9650_flip_dmi_table) &&
-               !sensor_settings[VFLIP_IDX]))
+               !sd->vflip->val))
                ver_offs--;
 
        if (width <= 320)
@@ -553,29 +396,16 @@ void ov9650_disconnect(struct sd *sd)
        ov9650_stop(sd);
 
        sd->sensor = NULL;
-       kfree(sd->sensor_priv);
-}
-
-static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Read exposure %d", *val);
-       return 0;
 }
 
 static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
        PDEBUG(D_V4L2, "Set exposure to %d", val);
 
-       sensor_settings[EXPOSURE_IDX] = val;
        /* The 6 MSBs */
        i2c_data = (val >> 10) & 0x3f;
        err = m5602_write_sensor(sd, OV9650_AECHM,
@@ -596,27 +426,14 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
-       return 0;
-}
-
 static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Setting gain to %d", val);
 
-       sensor_settings[GAIN_IDX] = val;
-
        /* The 2 MSB */
        /* Read the OV9650_VREF register first to avoid
           corrupting the VREF high and low bits */
@@ -637,117 +454,46 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[RED_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read red gain %d", *val);
-       return 0;
-}
-
 static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set red gain to %d", val);
 
-       sensor_settings[RED_BALANCE_IDX] = val;
-
        i2c_data = val & 0xff;
        err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
        return err;
 }
 
-static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[BLUE_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
-       return 0;
-}
-
 static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set blue gain to %d", val);
 
-       sensor_settings[BLUE_BALANCE_IDX] = val;
-
        i2c_data = val & 0xff;
        err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
        return err;
 }
 
-static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[HFLIP_IDX];
-       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-       return 0;
-}
-
-static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
+       int hflip = sd->hflip->val;
+       int vflip = sd->vflip->val;
 
-       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-
-       sensor_settings[HFLIP_IDX] = val;
-
-       if (!dmi_check_system(ov9650_flip_dmi_table))
-               i2c_data = ((val & 0x01) << 5) |
-                               (sensor_settings[VFLIP_IDX] << 4);
-       else
-               i2c_data = ((val & 0x01) << 5) |
-                               (!sensor_settings[VFLIP_IDX] << 4);
-
-       err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-
-       return err;
-}
-
-static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[VFLIP_IDX];
-       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
-       return 0;
-}
-
-static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       int err;
-       u8 i2c_data;
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
-       sensor_settings[VFLIP_IDX] = val;
+       PDEBUG(D_V4L2, "Set hvflip to %d %d", hflip, vflip);
 
        if (dmi_check_system(ov9650_flip_dmi_table))
-               val = !val;
+               vflip = !vflip;
 
-       i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
+       i2c_data = (hflip << 5) | (vflip << 4);
        err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -759,57 +505,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
-       return 0;
-}
-
 static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
                                    __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
 
-       sensor_settings[AUTO_EXPOSURE_IDX] = val;
        err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
 
+       val = (val == V4L2_EXPOSURE_AUTO);
        i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
 
        return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
-static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
-       return 0;
-}
-
 static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
                                         __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto white balance to %d", val);
 
-       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
        err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -820,26 +543,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
        return err;
 }
 
-static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
-       PDEBUG(D_V4L2, "Read auto gain control %d", *val);
-       return 0;
-}
-
 static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 i2c_data;
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
 
        PDEBUG(D_V4L2, "Set auto gain control to %d", val);
 
-       sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
        err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -849,6 +560,48 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
        return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
 }
 
+static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val);
+               if (err || ctrl->val)
+                       return err;
+               err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val);
+               if (err)
+                       return err;
+               err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               err = ov9650_set_auto_exposure(gspca_dev, ctrl->val);
+               if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+                       return err;
+               err = ov9650_set_exposure(gspca_dev, sd->expo->val);
+               break;
+       case V4L2_CID_AUTOGAIN:
+               err = ov9650_set_auto_gain(gspca_dev, ctrl->val);
+               if (err || ctrl->val)
+                       return err;
+               err = ov9650_set_gain(gspca_dev, sd->gain->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = ov9650_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err;
+}
+
 static void ov9650_dump_registers(struct sd *sd)
 {
        int address;
index f7aa5bf68983d3d4245b6fc914a433adc9b6d161..f9f5870da60f3d916dabfa92afee1274c3f6f3d6 100644 (file)
@@ -139,6 +139,7 @@ extern bool dump_sensor;
 
 int ov9650_probe(struct sd *sd);
 int ov9650_init(struct sd *sd);
+int ov9650_init_controls(struct sd *sd);
 int ov9650_start(struct sd *sd);
 int ov9650_stop(struct sd *sd);
 void ov9650_disconnect(struct sd *sd);
@@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = {
        .i2c_regW = 1,
        .probe = ov9650_probe,
        .init = ov9650_init,
+       .init_controls = ov9650_init_controls,
        .start = ov9650_start,
        .stop = ov9650_stop,
        .disconnect = ov9650_disconnect,
index b8771698cbcb1b8260654adc8d9cba84504139e5..1890862913034120a44ff8b4c22a09dea0a47c06 100644 (file)
 
 #include "m5602_po1030.h"
 
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 val);
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val);
-static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
-                                        __s32 val);
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
-                                        __s32 *val);
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
+static void po1030_dump_registers(struct sd *sd);
 
 static struct v4l2_pix_format po1030_modes[] = {
        {
@@ -56,146 +36,25 @@ static struct v4l2_pix_format po1030_modes[] = {
        }
 };
 
-static const struct ctrl po1030_ctrls[] = {
-#define GAIN_IDX 0
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "gain",
-                       .minimum        = 0x00,
-                       .maximum        = 0x4f,
-                       .step           = 0x1,
-                       .default_value  = PO1030_GLOBAL_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = po1030_set_gain,
-               .get = po1030_get_gain
-       },
-#define EXPOSURE_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "exposure",
-                       .minimum        = 0x00,
-                       .maximum        = 0x02ff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_EXPOSURE_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = po1030_set_exposure,
-               .get = po1030_get_exposure
-       },
-#define RED_BALANCE_IDX 2
-       {
-               {
-                       .id             = V4L2_CID_RED_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "red balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_RED_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = po1030_set_red_balance,
-               .get = po1030_get_red_balance
-       },
-#define BLUE_BALANCE_IDX 3
-       {
-               {
-                       .id             = V4L2_CID_BLUE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "blue balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_BLUE_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = po1030_set_blue_balance,
-               .get = po1030_get_blue_balance
-       },
-#define HFLIP_IDX 4
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
-               },
-               .set = po1030_set_hflip,
-               .get = po1030_get_hflip
-       },
-#define VFLIP_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
-               },
-               .set = po1030_set_vflip,
-               .get = po1030_get_vflip
-       },
-#define AUTO_WHITE_BALANCE_IDX 6
-       {
-               {
-                       .id             = V4L2_CID_AUTO_WHITE_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto white balance",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
-               },
-               .set = po1030_set_auto_white_balance,
-               .get = po1030_get_auto_white_balance
-       },
-#define AUTO_EXPOSURE_IDX 7
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE_AUTO,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "auto exposure",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0,
-               },
-               .set = po1030_set_auto_exposure,
-               .get = po1030_get_auto_exposure
-       },
-#define GREEN_BALANCE_IDX 8
-       {
-               {
-                       .id             = M5602_V4L2_CID_GREEN_BALANCE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "green balance",
-                       .minimum        = 0x00,
-                       .maximum        = 0xff,
-                       .step           = 0x1,
-                       .default_value  = PO1030_GREEN_GAIN_DEFAULT,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = po1030_set_green_balance,
-               .get = po1030_get_green_balance
-       },
+static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
+       .s_ctrl = po1030_s_ctrl,
 };
 
-static void po1030_dump_registers(struct sd *sd);
+static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
+       .ops    = &po1030_ctrl_ops,
+       .id     = M5602_V4L2_CID_GREEN_BALANCE,
+       .name   = "Green Balance",
+       .type   = V4L2_CTRL_TYPE_INTEGER,
+       .min    = 0,
+       .max    = 255,
+       .step   = 1,
+       .def    = PO1030_GREEN_GAIN_DEFAULT,
+       .flags  = V4L2_CTRL_FLAG_SLIDER,
+};
 
 int po1030_probe(struct sd *sd)
 {
        u8 dev_id_h = 0, i;
-       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == PO1030_SENSOR) {
@@ -229,26 +88,14 @@ int po1030_probe(struct sd *sd)
        return -ENODEV;
 
 sensor_found:
-       sensor_settings = kmalloc(
-               ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
-       if (!sensor_settings)
-               return -ENOMEM;
-
        sd->gspca_dev.cam.cam_mode = po1030_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
-       sd->desc->ctrls = po1030_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
-
-       for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
-               sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
-       sd->sensor_priv = sensor_settings;
 
        return 0;
 }
 
 int po1030_init(struct sd *sd)
 {
-       s32 *sensor_settings = sd->sensor_priv;
        int i, err = 0;
 
        /* Init the sensor */
@@ -279,46 +126,50 @@ int po1030_init(struct sd *sd)
        if (dump_sensor)
                po1030_dump_registers(sd);
 
-       err = po1030_set_exposure(&sd->gspca_dev,
-                                  sensor_settings[EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-       if (err < 0)
-               return err;
-
-       err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = po1030_set_red_balance(&sd->gspca_dev,
-                                     sensor_settings[RED_BALANCE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = po1030_set_blue_balance(&sd->gspca_dev,
-                                     sensor_settings[BLUE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+       return 0;
+}
 
-       err = po1030_set_green_balance(&sd->gspca_dev,
-                                      sensor_settings[GREEN_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+int po1030_init_controls(struct sd *sd)
+{
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 9);
+
+       sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+                                              V4L2_CID_AUTO_WHITE_BALANCE,
+                                              0, 1, 1, 0);
+       sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
+       sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+                                       V4L2_CID_RED_BALANCE, 0, 255, 1,
+                                       PO1030_RED_GAIN_DEFAULT);
+       sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
+                                       V4L2_CID_BLUE_BALANCE, 0, 255, 1,
+                                       PO1030_BLUE_GAIN_DEFAULT);
+
+       sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
+                         V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
+       sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
+                         0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
+
+       sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
+                                    0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
+
+       sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
 
-       err = po1030_set_auto_white_balance(&sd->gspca_dev,
-                               sensor_settings[AUTO_WHITE_BALANCE_IDX]);
-       if (err < 0)
-               return err;
+       v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
+       v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
+       v4l2_ctrl_cluster(2, &sd->hflip);
 
-       err = po1030_set_auto_exposure(&sd->gspca_dev,
-                               sensor_settings[AUTO_EXPOSURE_IDX]);
-       return err;
+       return 0;
 }
 
 int po1030_start(struct sd *sd)
@@ -448,24 +299,12 @@ int po1030_start(struct sd *sd)
        return err;
 }
 
-static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Exposure read as %d", *val);
-       return 0;
-}
-
 static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
 
        i2c_data = ((val & 0xff00) >> 8);
@@ -486,25 +325,12 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read global gain %d", *val);
-       return 0;
-}
-
 static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[GAIN_IDX] = val;
-
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
        err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
@@ -512,65 +338,19 @@ static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[HFLIP_IDX];
-       PDEBUG(D_V4L2, "Read hflip %d", *val);
-
-       return 0;
-}
-
-static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-       u8 i2c_data;
-       int err;
-
-       sensor_settings[HFLIP_IDX] = val;
-
-       PDEBUG(D_V4L2, "Set hflip %d", val);
-       err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
-       if (err < 0)
-               return err;
-
-       i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
-
-       err = m5602_write_sensor(sd, PO1030_CONTROL2,
-                                &i2c_data, 1);
-
-       return err;
-}
-
-static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[VFLIP_IDX];
-       PDEBUG(D_V4L2, "Read vflip %d", *val);
-
-       return 0;
-}
-
-static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[VFLIP_IDX] = val;
-
-       PDEBUG(D_V4L2, "Set vflip %d", val);
+       PDEBUG(D_V4L2, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
        err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
        if (err < 0)
                return err;
 
-       i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
+       i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
+                  (sd->vflip->val << 6);
 
        err = m5602_write_sensor(sd, PO1030_CONTROL2,
                                 &i2c_data, 1);
@@ -578,25 +358,12 @@ static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[RED_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read red gain %d", *val);
-       return 0;
-}
-
 static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[RED_BALANCE_IDX] = val;
-
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
        err = m5602_write_sensor(sd, PO1030_RED_GAIN,
@@ -604,26 +371,12 @@ static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[BLUE_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read blue gain %d", *val);
-
-       return 0;
-}
-
 static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[BLUE_BALANCE_IDX] = val;
-
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
        err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
@@ -632,25 +385,12 @@ static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[GREEN_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Read green gain %d", *val);
-
-       return 0;
-}
-
 static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[GREEN_BALANCE_IDX] = val;
        i2c_data = val & 0xff;
        PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
 
@@ -663,28 +403,13 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
                                 &i2c_data, 1);
 }
 
-static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
-                                        __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
-       PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
-
-       return 0;
-}
-
 static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
                                         __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
-
        err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
        if (err < 0)
                return err;
@@ -695,31 +420,19 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
        return err;
 }
 
-static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
-                                   __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[AUTO_EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Auto exposure is %d", *val);
-       return 0;
-}
-
 static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
                                    __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 i2c_data;
        int err;
 
-       sensor_settings[AUTO_EXPOSURE_IDX] = val;
        err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
        if (err < 0)
                return err;
 
        PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+       val = (val == V4L2_EXPOSURE_AUTO);
        i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
        return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
 }
@@ -727,7 +440,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
 void po1030_disconnect(struct sd *sd)
 {
        sd->sensor = NULL;
-       kfree(sd->sensor_priv);
+}
+
+static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+       struct sd *sd = (struct sd *) gspca_dev;
+       int err;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
+               if (err || ctrl->val)
+                       return err;
+               err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
+               if (err)
+                       return err;
+               err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
+               if (err)
+                       return err;
+               err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
+               break;
+       case V4L2_CID_EXPOSURE_AUTO:
+               err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
+               if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
+                       return err;
+               err = po1030_set_exposure(gspca_dev, sd->expo->val);
+               break;
+       case V4L2_CID_GAIN:
+               err = po1030_set_gain(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = po1030_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err;
 }
 
 static void po1030_dump_registers(struct sd *sd)
index 81a2bcb88fe3c3ac61e2e3b8d442346d9acc5a32..a6ab76149bd0e07d895de1e390323e54a4d1c3e8 100644 (file)
@@ -151,6 +151,7 @@ extern bool dump_sensor;
 
 int po1030_probe(struct sd *sd);
 int po1030_init(struct sd *sd);
+int po1030_init_controls(struct sd *sd);
 int po1030_start(struct sd *sd);
 void po1030_disconnect(struct sd *sd);
 
@@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = {
 
        .probe = po1030_probe,
        .init = po1030_init,
+       .init_controls = po1030_init_controls,
        .start = po1030_start,
        .disconnect = po1030_disconnect,
 };
index c8e1572eb5024cba1f12af7ece1f4ca24bf8a8d5..42ffaf04771c2144cc1b622a0b7baaa45eebc493 100644 (file)
 
 #include "m5602_s5k4aa.h"
 
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
+static void s5k4aa_dump_registers(struct sd *sd);
+
+static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
+       .s_ctrl = s5k4aa_s_ctrl,
+};
 
 static
     const
@@ -147,104 +141,11 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
        }
 };
 
-static const struct ctrl s5k4aa_ctrls[] = {
-#define VFLIP_IDX 0
-       {
-               {
-                       .id             = V4L2_CID_VFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "vertical flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = s5k4aa_set_vflip,
-               .get = s5k4aa_get_vflip
-       },
-#define HFLIP_IDX 1
-       {
-               {
-                       .id             = V4L2_CID_HFLIP,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "horizontal flip",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 0
-               },
-               .set = s5k4aa_set_hflip,
-               .get = s5k4aa_get_hflip
-       },
-#define GAIN_IDX 2
-       {
-               {
-                       .id             = V4L2_CID_GAIN,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Gain",
-                       .minimum        = 0,
-                       .maximum        = 127,
-                       .step           = 1,
-                       .default_value  = S5K4AA_DEFAULT_GAIN,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = s5k4aa_set_gain,
-               .get = s5k4aa_get_gain
-       },
-#define EXPOSURE_IDX 3
-       {
-               {
-                       .id             = V4L2_CID_EXPOSURE,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Exposure",
-                       .minimum        = 13,
-                       .maximum        = 0xfff,
-                       .step           = 1,
-                       .default_value  = 0x100,
-                       .flags          = V4L2_CTRL_FLAG_SLIDER
-               },
-               .set = s5k4aa_set_exposure,
-               .get = s5k4aa_get_exposure
-       },
-#define NOISE_SUPP_IDX 4
-       {
-               {
-                       .id             = V4L2_CID_PRIVATE_BASE,
-                       .type           = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name           = "Noise suppression (smoothing)",
-                       .minimum        = 0,
-                       .maximum        = 1,
-                       .step           = 1,
-                       .default_value  = 1,
-               },
-                       .set = s5k4aa_set_noise,
-                       .get = s5k4aa_get_noise
-       },
-#define BRIGHTNESS_IDX 5
-       {
-               {
-                       .id             = V4L2_CID_BRIGHTNESS,
-                       .type           = V4L2_CTRL_TYPE_INTEGER,
-                       .name           = "Brightness",
-                       .minimum        = 0,
-                       .maximum        = 0x1f,
-                       .step           = 1,
-                       .default_value  = S5K4AA_DEFAULT_BRIGHTNESS,
-               },
-                       .set = s5k4aa_set_brightness,
-                       .get = s5k4aa_get_brightness
-       },
-
-};
-
-static void s5k4aa_dump_registers(struct sd *sd);
-
 int s5k4aa_probe(struct sd *sd)
 {
        u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
        const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
        int i, err = 0;
-       s32 *sensor_settings;
 
        if (force_sensor) {
                if (force_sensor == S5K4AA_SENSOR) {
@@ -303,19 +204,8 @@ int s5k4aa_probe(struct sd *sd)
                pr_info("Detected a s5k4aa sensor\n");
 
 sensor_found:
-       sensor_settings = kmalloc(
-               ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
-       if (!sensor_settings)
-               return -ENOMEM;
-
        sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
-       sd->desc->ctrls = s5k4aa_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
-
-       for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
-               sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
-       sd->sensor_priv = sensor_settings;
 
        return 0;
 }
@@ -325,7 +215,6 @@ int s5k4aa_start(struct sd *sd)
        int i, err = 0;
        u8 data[2];
        struct cam *cam = &sd->gspca_dev.cam;
-       s32 *sensor_settings = sd->sensor_priv;
 
        switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
        case 1280:
@@ -359,9 +248,6 @@ int s5k4aa_start(struct sd *sd)
                                return -EINVAL;
                        }
                }
-               err = s5k4aa_set_noise(&sd->gspca_dev, 0);
-               if (err < 0)
-                       return err;
                break;
 
        case 640:
@@ -395,37 +281,12 @@ int s5k4aa_start(struct sd *sd)
                                return -EINVAL;
                        }
                }
-               err = s5k4aa_set_noise(&sd->gspca_dev, 1);
-               if (err < 0)
-                       return err;
                break;
        }
        if (err < 0)
                return err;
 
-       err = s5k4aa_set_exposure(&sd->gspca_dev,
-                                  sensor_settings[EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
-
-       err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-       if (err < 0)
-               return err;
-
-       err = s5k4aa_set_brightness(&sd->gspca_dev,
-                                    sensor_settings[BRIGHTNESS_IDX]);
-       if (err < 0)
-               return err;
-
-       err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
-       if (err < 0)
-               return err;
-
-       err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
-       if (err < 0)
-               return err;
-
-       return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+       return 0;
 }
 
 int s5k4aa_init(struct sd *sd)
@@ -466,13 +327,36 @@ int s5k4aa_init(struct sd *sd)
        return err;
 }
 
-static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int s5k4aa_init_controls(struct sd *sd)
 {
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
+
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 6);
 
-       *val = sensor_settings[EXPOSURE_IDX];
-       PDEBUG(D_V4L2, "Read exposure %d", *val);
+       v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
+                         0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
+
+       v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
+                         13, 0xfff, 1, 0x100);
+
+       v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
+                         0, 127, 1, S5K4AA_DEFAULT_GAIN);
+
+       v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
+                         0, 1, 1, 1);
+
+       sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
+
+       v4l2_ctrl_cluster(2, &sd->hflip);
 
        return 0;
 }
@@ -480,11 +364,9 @@ static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
 static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       sensor_settings[EXPOSURE_IDX] = val;
        PDEBUG(D_V4L2, "Set exposure to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -499,27 +381,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[VFLIP_IDX];
-       PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-
-       return 0;
-}
-
-static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
+       int hflip = sd->hflip->val;
+       int vflip = sd->vflip->val;
 
-       sensor_settings[VFLIP_IDX] = val;
-
-       PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+       PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
                return err;
@@ -528,92 +398,47 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
        if (err < 0)
                return err;
 
-       if (dmi_check_system(s5k4aa_vflip_dmi_table))
-               val = !val;
+       if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
+               hflip = !hflip;
+               vflip = !vflip;
+       }
 
-       data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+       data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
        err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
        if (err < 0)
                return err;
-       if (val)
+       if (hflip)
                data &= 0xfe;
        else
                data |= 0x01;
-       err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
-       return err;
-}
-
-static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[HFLIP_IDX];
-       PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
-       return 0;
-}
-
-static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-       u8 data = S5K4AA_PAGE_MAP_2;
-       int err;
-
-       sensor_settings[HFLIP_IDX] = val;
-
-       PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
-       err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
-       if (err < 0)
-               return err;
-
-       err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-       if (err < 0)
-               return err;
-
-       if (dmi_check_system(s5k4aa_vflip_dmi_table))
-               val = !val;
-
-       data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
-       err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+       err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
        if (err < 0)
                return err;
 
-       err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+       err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
        if (err < 0)
                return err;
-       if (val)
+       if (vflip)
                data &= 0xfe;
        else
                data |= 0x01;
-       err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-       return err;
-}
-
-static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
+       err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+       if (err < 0)
+               return err;
 
-       *val = sensor_settings[GAIN_IDX];
-       PDEBUG(D_V4L2, "Read gain %d", *val);
        return 0;
 }
 
 static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       sensor_settings[GAIN_IDX] = val;
-
        PDEBUG(D_V4L2, "Set gain to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -625,25 +450,12 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[BRIGHTNESS_IDX];
-       PDEBUG(D_V4L2, "Read brightness %d", *val);
-       return 0;
-}
-
 static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       sensor_settings[BRIGHTNESS_IDX] = val;
-
        PDEBUG(D_V4L2, "Set brightness to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -653,25 +465,12 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
        return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
 }
 
-static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
-
-       *val = sensor_settings[NOISE_SUPP_IDX];
-       PDEBUG(D_V4L2, "Read noise %d", *val);
-       return 0;
-}
-
 static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
 {
        struct sd *sd = (struct sd *) gspca_dev;
-       s32 *sensor_settings = sd->sensor_priv;
        u8 data = S5K4AA_PAGE_MAP_2;
        int err;
 
-       sensor_settings[NOISE_SUPP_IDX] = val;
-
        PDEBUG(D_V4L2, "Set noise to %d", val);
        err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
        if (err < 0)
@@ -681,10 +480,41 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
        return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
 }
 
+static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+       int err;
+
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_GAIN:
+               err = s5k4aa_set_gain(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_SHARPNESS:
+               err = s5k4aa_set_noise(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = s5k4aa_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return err;
+}
+
 void s5k4aa_disconnect(struct sd *sd)
 {
        sd->sensor = NULL;
-       kfree(sd->sensor_priv);
 }
 
 static void s5k4aa_dump_registers(struct sd *sd)
index 8e0035e731c777c95b15b15971b61722e7915090..9953e976695442142a77f9935f7e7d96e232bb65 100644 (file)
@@ -69,6 +69,7 @@ extern bool dump_sensor;
 
 int s5k4aa_probe(struct sd *sd);
 int s5k4aa_init(struct sd *sd);
+int s5k4aa_init_controls(struct sd *sd);
 int s5k4aa_start(struct sd *sd);
 void s5k4aa_disconnect(struct sd *sd);
 
@@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = {
 
        .probe = s5k4aa_probe,
        .init = s5k4aa_init,
+       .init_controls = s5k4aa_init_controls,
        .start = s5k4aa_start,
        .disconnect = s5k4aa_disconnect,
 };
index 1de743a02b02521e8effe86129c287046a4f1566..69ee6e26b8ea64e219eec68023a3e1441315274c 100644 (file)
 #include <linux/kthread.h>
 #include "m5602_s5k83a.h"
 
-static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
+
+static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
+       .s_ctrl = s5k83a_s_ctrl,
+};
 
 static struct v4l2_pix_format s5k83a_modes[] = {
        {
@@ -46,83 +41,6 @@ static struct v4l2_pix_format s5k83a_modes[] = {
        }
 };
 
-static const struct ctrl s5k83a_ctrls[] = {
-#define GAIN_IDX 0
-       {
-               {
-                       .id = V4L2_CID_GAIN,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "gain",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_GAIN,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-                       .set = s5k83a_set_gain,
-                       .get = s5k83a_get_gain
-
-       },
-#define BRIGHTNESS_IDX 1
-       {
-               {
-                       .id = V4L2_CID_BRIGHTNESS,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "brightness",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_BRIGHTNESS,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-                       .set = s5k83a_set_brightness,
-                       .get = s5k83a_get_brightness,
-       },
-#define EXPOSURE_IDX 2
-       {
-               {
-                       .id = V4L2_CID_EXPOSURE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "exposure",
-                       .minimum = 0x00,
-                       .maximum = S5K83A_MAXIMUM_EXPOSURE,
-                       .step = 0x01,
-                       .default_value = S5K83A_DEFAULT_EXPOSURE,
-                       .flags = V4L2_CTRL_FLAG_SLIDER
-               },
-                       .set = s5k83a_set_exposure,
-                       .get = s5k83a_get_exposure
-       },
-#define HFLIP_IDX 3
-       {
-               {
-                       .id = V4L2_CID_HFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "horizontal flip",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0
-               },
-                       .set = s5k83a_set_hflip,
-                       .get = s5k83a_get_hflip
-       },
-#define VFLIP_IDX 4
-       {
-               {
-                       .id = V4L2_CID_VFLIP,
-                       .type = V4L2_CTRL_TYPE_BOOLEAN,
-                       .name = "vertical flip",
-                       .minimum = 0,
-                       .maximum = 1,
-                       .step = 1,
-                       .default_value = 0
-               },
-               .set = s5k83a_set_vflip,
-               .get = s5k83a_get_vflip
-       }
-};
-
 static void s5k83a_dump_registers(struct sd *sd);
 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
 static int s5k83a_set_led_indication(struct sd *sd, u8 val);
@@ -131,7 +49,6 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
 
 int s5k83a_probe(struct sd *sd)
 {
-       struct s5k83a_priv *sens_priv;
        u8 prod_id = 0, ver_id = 0;
        int i, err = 0;
 
@@ -173,38 +90,18 @@ int s5k83a_probe(struct sd *sd)
                pr_info("Detected a s5k83a sensor\n");
 
 sensor_found:
-       sens_priv = kmalloc(
-               sizeof(struct s5k83a_priv), GFP_KERNEL);
-       if (!sens_priv)
-               return -ENOMEM;
-
-       sens_priv->settings =
-       kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
-       if (!sens_priv->settings) {
-               kfree(sens_priv);
-               return -ENOMEM;
-       }
-
        sd->gspca_dev.cam.cam_mode = s5k83a_modes;
        sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
-       sd->desc->ctrls = s5k83a_ctrls;
-       sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
 
        /* null the pointer! thread is't running now */
-       sens_priv->rotation_thread = NULL;
-
-       for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
-               sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+       sd->rotation_thread = NULL;
 
-       sd->sensor_priv = sens_priv;
        return 0;
 }
 
 int s5k83a_init(struct sd *sd)
 {
        int i, err = 0;
-       s32 *sensor_settings =
-                       ((struct s5k83a_priv *) sd->sensor_priv)->settings;
 
        for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
                u8 data[2] = {0x00, 0x00};
@@ -237,33 +134,44 @@ int s5k83a_init(struct sd *sd)
        if (dump_sensor)
                s5k83a_dump_registers(sd);
 
-       err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
-       if (err < 0)
-               return err;
+       return err;
+}
 
-       err = s5k83a_set_brightness(&sd->gspca_dev,
-                                    sensor_settings[BRIGHTNESS_IDX]);
-       if (err < 0)
-               return err;
+int s5k83a_init_controls(struct sd *sd)
+{
+       struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
 
-       err = s5k83a_set_exposure(&sd->gspca_dev,
-                                  sensor_settings[EXPOSURE_IDX]);
-       if (err < 0)
-               return err;
+       sd->gspca_dev.vdev.ctrl_handler = hdl;
+       v4l2_ctrl_handler_init(hdl, 6);
 
-       err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
-       if (err < 0)
-               return err;
+       v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
+                         0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
 
-       err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+       v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
+                         0, S5K83A_MAXIMUM_EXPOSURE, 1,
+                         S5K83A_DEFAULT_EXPOSURE);
 
-       return err;
+       v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
+                         0, 255, 1, S5K83A_DEFAULT_GAIN);
+
+       sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
+                                     0, 1, 1, 0);
+       sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
+                                     0, 1, 1, 0);
+
+       if (hdl->error) {
+               pr_err("Could not initialize controls\n");
+               return hdl->error;
+       }
+
+       v4l2_ctrl_cluster(2, &sd->hflip);
+
+       return 0;
 }
 
 static int rotation_thread_function(void *data)
 {
        struct sd *sd = (struct sd *) data;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
        u8 reg, previous_rotation = 0;
        __s32 vflip, hflip;
 
@@ -277,8 +185,8 @@ static int rotation_thread_function(void *data)
                        previous_rotation = reg;
                        pr_info("Camera was flipped\n");
 
-                       s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
-                       s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+                       hflip = sd->hflip->val;
+                       vflip = sd->vflip->val;
 
                        if (reg) {
                                vflip = !vflip;
@@ -294,26 +202,25 @@ static int rotation_thread_function(void *data)
 
        /* return to "front" flip */
        if (previous_rotation) {
-               s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
-               s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+               hflip = sd->hflip->val;
+               vflip = sd->vflip->val;
                s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
        }
 
-       sens_priv->rotation_thread = NULL;
+       sd->rotation_thread = NULL;
        return 0;
 }
 
 int s5k83a_start(struct sd *sd)
 {
        int i, err = 0;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
        /* Create another thread, polling the GPIO ports of the camera to check
           if it got rotated. This is how the windows driver does it so we have
           to assume that there is no better way of accomplishing this */
-       sens_priv->rotation_thread = kthread_create(rotation_thread_function,
-                                                   sd, "rotation thread");
-       wake_up_process(sens_priv->rotation_thread);
+       sd->rotation_thread = kthread_create(rotation_thread_function,
+                                            sd, "rotation thread");
+       wake_up_process(sd->rotation_thread);
 
        /* Preinit the sensor */
        for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
@@ -333,32 +240,17 @@ int s5k83a_start(struct sd *sd)
 
 int s5k83a_stop(struct sd *sd)
 {
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       if (sens_priv->rotation_thread)
-               kthread_stop(sens_priv->rotation_thread);
+       if (sd->rotation_thread)
+               kthread_stop(sd->rotation_thread);
 
        return s5k83a_set_led_indication(sd, 0);
 }
 
 void s5k83a_disconnect(struct sd *sd)
 {
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
        s5k83a_stop(sd);
 
        sd->sensor = NULL;
-       kfree(sens_priv->settings);
-       kfree(sens_priv);
-}
-
-static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       *val = sens_priv->settings[GAIN_IDX];
-       return 0;
 }
 
 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@@ -366,9 +258,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       sens_priv->settings[GAIN_IDX] = val;
 
        data[0] = 0x00;
        data[1] = 0x20;
@@ -391,60 +280,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
        return err;
 }
 
-static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       *val = sens_priv->settings[BRIGHTNESS_IDX];
-       return 0;
-}
-
 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[1];
        struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       sens_priv->settings[BRIGHTNESS_IDX] = val;
        data[0] = val;
        err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
        return err;
 }
 
-static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       *val = sens_priv->settings[EXPOSURE_IDX];
-       return 0;
-}
-
 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
 {
        int err;
        u8 data[2];
        struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
 
-       sens_priv->settings[EXPOSURE_IDX] = val;
        data[0] = 0;
        data[1] = val;
        err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
        return err;
 }
 
-static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       *val = sens_priv->settings[VFLIP_IDX];
-       return 0;
-}
-
 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
                                __s32 vflip, __s32 hflip)
 {
@@ -476,60 +334,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
        return err;
 }
 
-static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
 {
        int err;
        u8 reg;
-       __s32 hflip;
        struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       sens_priv->settings[VFLIP_IDX] = val;
-
-       s5k83a_get_hflip(gspca_dev, &hflip);
+       int hflip = sd->hflip->val;
+       int vflip = sd->vflip->val;
 
        err = s5k83a_get_rotation(sd, &reg);
        if (err < 0)
                return err;
        if (reg) {
-               val = !val;
                hflip = !hflip;
+               vflip = !vflip;
        }
 
-       err = s5k83a_set_flip_real(gspca_dev, val, hflip);
+       err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
        return err;
 }
 
-static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       *val = sens_priv->settings[HFLIP_IDX];
-       return 0;
-}
-
-static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+       struct gspca_dev *gspca_dev =
+               container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
        int err;
-       u8 reg;
-       __s32 vflip;
-       struct sd *sd = (struct sd *) gspca_dev;
-       struct s5k83a_priv *sens_priv = sd->sensor_priv;
-
-       sens_priv->settings[HFLIP_IDX] = val;
 
-       s5k83a_get_vflip(gspca_dev, &vflip);
-
-       err = s5k83a_get_rotation(sd, &reg);
-       if (err < 0)
-               return err;
-       if (reg) {
-               val = !val;
-               vflip = !vflip;
+       if (!gspca_dev->streaming)
+               return 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+               err = s5k83a_set_brightness(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE:
+               err = s5k83a_set_exposure(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_GAIN:
+               err = s5k83a_set_gain(gspca_dev, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               err = s5k83a_set_hvflip(gspca_dev);
+               break;
+       default:
+               return -EINVAL;
        }
 
-       err = s5k83a_set_flip_real(gspca_dev, vflip, val);
        return err;
 }
 
index 79952247b534e029569a8d6c8eab4f7afe4590d9..d61b918228dfbede87aa28e64154d4b7605e03df 100644 (file)
@@ -45,6 +45,7 @@ extern bool dump_sensor;
 
 int s5k83a_probe(struct sd *sd);
 int s5k83a_init(struct sd *sd);
+int s5k83a_init_controls(struct sd *sd);
 int s5k83a_start(struct sd *sd);
 int s5k83a_stop(struct sd *sd);
 void s5k83a_disconnect(struct sd *sd);
@@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = {
        .name = "S5K83A",
        .probe = s5k83a_probe,
        .init = s5k83a_init,
+       .init_controls = s5k83a_init_controls,
        .start = s5k83a_start,
        .stop = s5k83a_stop,
        .disconnect = s5k83a_disconnect,
@@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = {
        .i2c_regW = 2,
 };
 
-struct s5k83a_priv {
-       /* We use another thread periodically
-          probing the orientation of the camera */
-       struct task_struct *rotation_thread;
-       s32 *settings;
-};
-
 static const unsigned char preinit_s5k83a[][4] = {
        {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
        {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
index edff4f1f586fdcef4c463834ca8523e6e2297241..48341b4d607bfe1045ddf3f3bd6d0c9627e4e4fd 100644 (file)
@@ -57,6 +57,9 @@ struct m5602_sensor {
        /* Performs a initialization sequence */
        int (*init)(struct sd *sd);
 
+       /* Controls initialization, maybe NULL */
+       int (*init_controls)(struct sd *sd);
+
        /* Executed when the camera starts to send data */
        int (*start)(struct sd *sd);