[media] gspca - main: New video control mechanism
authorJean-François Moine <moinejf@free.fr>
Sat, 2 Oct 2010 07:12:25 +0000 (04:12 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Oct 2010 03:18:27 +0000 (01:18 -0200)
The new control mechanism uses dynamic control values in the subdriver
descriptor. It simplifies standard control handling.

Signed-off-by: Jean-François Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h

index 90f058bda7da423a507be7eb000fbffe710a6f0a..68b58106e4c8ca28c9c803daefdc531a507183c6 100644 (file)
@@ -878,6 +878,7 @@ out:
 
 static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
 {
+       struct gspca_ctrl *ctrl;
        int i;
 
        i = gspca_dev->cam.nmodes - 1;  /* take the highest mode */
@@ -885,6 +886,16 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
        gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
        gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
        gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+
+       /* set the current control values to their default values
+        * which may have changed in sd_init() */
+       ctrl = gspca_dev->cam.ctrls;
+       if (ctrl != NULL) {
+               for (i = 0;
+                    i < gspca_dev->sd_desc->nctrls;
+                    i++, ctrl++)
+                       ctrl->val = ctrl->def;
+       }
 }
 
 static int wxh_to_mode(struct gspca_dev *gspca_dev,
@@ -1308,7 +1319,7 @@ out:
        return ret;
 }
 
-static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+static int get_ctrl(struct gspca_dev *gspca_dev,
                                   int id)
 {
        const struct ctrl *ctrls;
@@ -1320,9 +1331,9 @@ static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
                if (gspca_dev->ctrl_dis & (1 << i))
                        continue;
                if (id == ctrls->qctrl.id)
-                       return ctrls;
+                       return i;
        }
-       return NULL;
+       return -1;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
@@ -1330,34 +1341,40 @@ static int vidioc_queryctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int i;
+       struct gspca_ctrl *gspca_ctrl;
+       int i, idx;
        u32 id;
 
-       ctrls = NULL;
        id = q_ctrl->id;
        if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
                id &= V4L2_CTRL_ID_MASK;
                id++;
+               idx = -1;
                for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
                        if (gspca_dev->ctrl_dis & (1 << i))
                                continue;
                        if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
                                continue;
-                       if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id
-                                           > ctrls->qctrl.id)
+                       if (idx >= 0
+                        && gspca_dev->sd_desc->ctrls[i].qctrl.id
+                                       > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
                                continue;
-                       ctrls = &gspca_dev->sd_desc->ctrls[i];
+                       idx = i;
                }
-               if (ctrls == NULL)
-                       return -EINVAL;
        } else {
-               ctrls = get_ctrl(gspca_dev, id);
-               if (ctrls == NULL)
-                       return -EINVAL;
-               i = ctrls - gspca_dev->sd_desc->ctrls;
+               idx = get_ctrl(gspca_dev, id);
        }
-       memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
-       if (gspca_dev->ctrl_inac & (1 << i))
+       if (idx < 0)
+               return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
+       memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
+       if (gspca_dev->cam.ctrls != NULL) {
+               gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+               q_ctrl->default_value = gspca_ctrl->def;
+               q_ctrl->minimum = gspca_ctrl->min;
+               q_ctrl->maximum = gspca_ctrl->max;
+       }
+       if (gspca_dev->ctrl_inac & (1 << idx))
                q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
        return 0;
 }
@@ -1367,23 +1384,46 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int ret;
+       struct gspca_ctrl *gspca_ctrl;
+       int idx, ret;
 
-       ctrls = get_ctrl(gspca_dev, ctrl->id);
-       if (ctrls == NULL)
+       idx = get_ctrl(gspca_dev, ctrl->id);
+       if (idx < 0)
                return -EINVAL;
-
-       if (ctrl->value < ctrls->qctrl.minimum
-           || ctrl->value > ctrls->qctrl.maximum)
-               return -ERANGE;
+       if (gspca_dev->ctrl_inac & (1 << idx))
+               return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
+       if (gspca_dev->cam.ctrls != NULL) {
+               gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+               if (ctrl->value < gspca_ctrl->min
+                   || ctrl->value > gspca_ctrl->max)
+                       return -ERANGE;
+       } else {
+               gspca_ctrl = NULL;
+               if (ctrl->value < ctrls->qctrl.minimum
+                   || ctrl->value > ctrls->qctrl.maximum)
+                       return -ERANGE;
+       }
        PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
        gspca_dev->usb_err = 0;
-       if (gspca_dev->present)
+       if (ctrls->set != NULL) {
                ret = ctrls->set(gspca_dev, ctrl->value);
-       else
-               ret = -ENODEV;
+               goto out;
+       }
+       if (gspca_ctrl != NULL) {
+               gspca_ctrl->val = ctrl->value;
+               if (ctrls->set_control != NULL
+                && gspca_dev->streaming)
+                       ctrls->set_control(gspca_dev);
+       }
+       ret = gspca_dev->usb_err;
+out:
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -1393,19 +1433,28 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
 {
        struct gspca_dev *gspca_dev = priv;
        const struct ctrl *ctrls;
-       int ret;
+       int idx, ret;
 
-       ctrls = get_ctrl(gspca_dev, ctrl->id);
-       if (ctrls == NULL)
+       idx = get_ctrl(gspca_dev, ctrl->id);
+       if (idx < 0)
                return -EINVAL;
+       ctrls = &gspca_dev->sd_desc->ctrls[idx];
 
        if (mutex_lock_interruptible(&gspca_dev->usb_lock))
                return -ERESTARTSYS;
+       if (!gspca_dev->present) {
+               ret = -ENODEV;
+               goto out;
+       }
        gspca_dev->usb_err = 0;
-       if (gspca_dev->present)
+       if (ctrls->get != NULL) {
                ret = ctrls->get(gspca_dev, &ctrl->value);
-       else
-               ret = -ENODEV;
+               goto out;
+       }
+       if (gspca_dev->cam.ctrls != NULL)
+               ctrl->value = gspca_dev->cam.ctrls[idx].val;
+       ret = 0;
+out:
        mutex_unlock(&gspca_dev->usb_lock);
        return ret;
 }
@@ -2125,6 +2174,22 @@ static struct video_device gspca_template = {
        .release = gspca_release,
 };
 
+/* initialize the controls */
+static void ctrls_init(struct gspca_dev *gspca_dev)
+{
+       struct gspca_ctrl *ctrl;
+       int i;
+
+       for (i = 0, ctrl = gspca_dev->cam.ctrls;
+            i < gspca_dev->sd_desc->nctrls;
+            i++, ctrl++) {
+               ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
+               ctrl->val = ctrl->def;
+               ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
+               ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
+       }
+}
+
 /*
  * probe and create a new gspca device
  *
@@ -2186,6 +2251,8 @@ int gspca_dev_probe2(struct usb_interface *intf,
        ret = sd_desc->config(gspca_dev, id);
        if (ret < 0)
                goto out;
+       if (gspca_dev->cam.ctrls != NULL)
+               ctrls_init(gspca_dev);
        ret = sd_desc->init(gspca_dev);
        if (ret < 0)
                goto out;
index b749c36d9f7eacf263efbdc222b8fed9603dc672..d4d210b56b499d6ee4248b3c80cafc399bb45190 100644 (file)
@@ -52,11 +52,20 @@ struct framerates {
        int nrates;
 };
 
+/* control definition */
+struct gspca_ctrl {
+       s16 val;        /* current value */
+       s16 def;        /* default value */
+       s16 min, max;   /* minimum and maximum values */
+};
+
 /* device information - set at probe time */
 struct cam {
        const struct v4l2_pix_format *cam_mode; /* size nmodes */
        const struct framerates *mode_framerates; /* must have size nmode,
                                                   * just like cam_mode */
+       struct gspca_ctrl *ctrls;       /* control table - size nctrls */
+                                       /* may be NULL */
        u32 bulk_size;          /* buffer size when image transfer by bulk */
        u32 input_flags;        /* value for ENUM_INPUT status flags */
        u8 nmodes;              /* size of cam_mode */
@@ -99,6 +108,7 @@ struct ctrl {
        struct v4l2_queryctrl qctrl;
        int (*set)(struct gspca_dev *, __s32);
        int (*get)(struct gspca_dev *, __s32 *);
+       cam_v_op set_control;
 };
 
 /* subdriver description */
@@ -106,7 +116,7 @@ struct sd_desc {
 /* information */
        const char *name;       /* sub-driver name */
 /* controls */
-       const struct ctrl *ctrls;
+       const struct ctrl *ctrls;       /* static control definition */
        int nctrls;
 /* mandatory operations */
        cam_cf_op config;       /* called on probe */