Skip to content

Commit

Permalink
[media] gspca - main: New video control mechanism
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jean-François Moine authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent 27a61c1 commit 6a33091
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 33 deletions.
131 changes: 99 additions & 32 deletions drivers/media/video/gspca/gspca.c
Original file line number Diff line number Diff line change
Expand Up @@ -878,13 +878,24 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)

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 */
gspca_dev->curr_mode = i;
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,
Expand Down Expand Up @@ -1308,7 +1319,7 @@ static int vidioc_querycap(struct file *file, void *priv,
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;
Expand All @@ -1320,44 +1331,50 @@ 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,
struct v4l2_queryctrl *q_ctrl)
{
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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
*
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 11 additions & 1 deletion drivers/media/video/gspca/gspca.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -99,14 +108,15 @@ 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 */
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 */
Expand Down

0 comments on commit 6a33091

Please sign in to comment.