summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/gspca.c131
-rw-r--r--drivers/media/video/gspca/gspca.h12
2 files changed, 110 insertions, 33 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 90f058bda7da..68b58106e4c8 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -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;
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index b749c36d9f7e..d4d210b56b49 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -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 */