[media] em28xx: convert to the control framework
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
8ac7a9493a
commit
081b945ed7
|
@ -2941,6 +2941,8 @@ void em28xx_release_resources(struct em28xx *dev)
|
|||
|
||||
em28xx_i2c_unregister(dev);
|
||||
|
||||
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
||||
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
|
@ -2957,6 +2959,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
|
|||
struct usb_interface *interface,
|
||||
int minor)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
|
||||
int retval;
|
||||
static const char *default_chip_name = "em28xx";
|
||||
const char *chip_name = default_chip_name;
|
||||
|
@ -3084,6 +3087,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
|
|||
return retval;
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_init(hdl, 4);
|
||||
dev->v4l2_dev.ctrl_handler = hdl;
|
||||
|
||||
/* register i2c bus */
|
||||
retval = em28xx_i2c_register(dev);
|
||||
if (retval < 0) {
|
||||
|
@ -3109,6 +3115,18 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
|
|||
__func__, retval);
|
||||
goto fail;
|
||||
}
|
||||
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
|
||||
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
||||
V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
|
||||
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
||||
V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
|
||||
} else {
|
||||
/* install the em28xx notify callback */
|
||||
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
|
||||
em28xx_ctrl_notify, dev);
|
||||
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
|
||||
em28xx_ctrl_notify, dev);
|
||||
}
|
||||
|
||||
/* wake i2c devices */
|
||||
em28xx_wake_i2c(dev);
|
||||
|
@ -3138,6 +3156,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
|
|||
msleep(3);
|
||||
}
|
||||
|
||||
v4l2_ctrl_handler_setup(&dev->ctrl_handler);
|
||||
retval = dev->ctrl_handler.error;
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
retval = em28xx_register_analog_devices(dev);
|
||||
if (retval < 0) {
|
||||
goto fail;
|
||||
|
@ -3150,6 +3173,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
|
|||
|
||||
fail:
|
||||
em28xx_i2c_unregister(dev);
|
||||
v4l2_ctrl_handler_free(&dev->ctrl_handler);
|
||||
|
||||
unregister_dev:
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
|
|
|
@ -125,30 +125,6 @@ static struct em28xx_fmt format[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* supported controls */
|
||||
/* Common to all boards */
|
||||
static struct v4l2_queryctrl ac97_qctrl[] = {
|
||||
{
|
||||
.id = V4L2_CID_AUDIO_VOLUME,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "Volume",
|
||||
.minimum = 0x0,
|
||||
.maximum = 0x1f,
|
||||
.step = 0x1,
|
||||
.default_value = 0x1f,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER,
|
||||
}, {
|
||||
.id = V4L2_CID_AUDIO_MUTE,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
.name = "Mute",
|
||||
.minimum = 0,
|
||||
.maximum = 1,
|
||||
.step = 1,
|
||||
.default_value = 1,
|
||||
.flags = 0,
|
||||
}
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
DMA and thread functions
|
||||
------------------------------------------------------------------*/
|
||||
|
@ -718,76 +694,48 @@ static int get_ressource(struct em28xx_fh *fh)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ac97_queryctrl()
|
||||
* return the ac97 supported controls
|
||||
*/
|
||||
static int ac97_queryctrl(struct v4l2_queryctrl *qc)
|
||||
void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
|
||||
{
|
||||
int i;
|
||||
struct em28xx *dev = priv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
|
||||
if (qc->id && qc->id == ac97_qctrl[i].id) {
|
||||
memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Control is not ac97 related */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ac97_get_ctrl()
|
||||
* return the current values for ac97 mute and volume
|
||||
*/
|
||||
static int ac97_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
|
||||
{
|
||||
/*
|
||||
* In the case of non-AC97 volume controls, we still need
|
||||
* to do some setups at em28xx, in order to mute/unmute
|
||||
* and to adjust audio volume. However, the value ranges
|
||||
* should be checked by the corresponding V4L subdriver.
|
||||
*/
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value = dev->mute;
|
||||
return 0;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value = dev->volume;
|
||||
return 0;
|
||||
default:
|
||||
/* Control is not ac97 related */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ac97_set_ctrl()
|
||||
* set values for ac97 mute and volume
|
||||
*/
|
||||
static int ac97_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++)
|
||||
if (ctrl->id == ac97_qctrl[i].id)
|
||||
goto handle;
|
||||
|
||||
/* Announce that hasn't handle it */
|
||||
return 1;
|
||||
|
||||
handle:
|
||||
if (ctrl->value < ac97_qctrl[i].minimum ||
|
||||
ctrl->value > ac97_qctrl[i].maximum)
|
||||
return -ERANGE;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
dev->mute = ctrl->value;
|
||||
dev->mute = ctrl->val;
|
||||
em28xx_audio_analog_set(dev);
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
dev->volume = ctrl->value;
|
||||
dev->volume = ctrl->val;
|
||||
em28xx_audio_analog_set(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
dev->mute = ctrl->val;
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
dev->volume = ctrl->val;
|
||||
break;
|
||||
}
|
||||
|
||||
return em28xx_audio_analog_set(dev);
|
||||
}
|
||||
|
||||
const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
|
||||
.s_ctrl = em28xx_s_ctrl,
|
||||
};
|
||||
|
||||
static int check_dev(struct em28xx *dev)
|
||||
{
|
||||
if (dev->state & DEV_DISCONNECTED) {
|
||||
|
@ -1182,131 +1130,6 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
struct em28xx *dev = fh->dev;
|
||||
int id = qc->id;
|
||||
int rc;
|
||||
|
||||
rc = check_dev(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
memset(qc, 0, sizeof(*qc));
|
||||
|
||||
qc->id = id;
|
||||
|
||||
/* enumerate AC97 controls */
|
||||
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
|
||||
rc = ac97_queryctrl(qc);
|
||||
if (!rc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* enumerate V4L2 device controls */
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
|
||||
|
||||
if (qc->type)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: This is an indirect way to check if a control exists at a
|
||||
* subdev. Instead of that hack, maybe the better would be to change all
|
||||
* subdevs to return -ENOIOCTLCMD, if an ioctl is not supported.
|
||||
*/
|
||||
static int check_subdev_ctrl(struct em28xx *dev, int id)
|
||||
{
|
||||
struct v4l2_queryctrl qc;
|
||||
|
||||
memset(&qc, 0, sizeof(qc));
|
||||
qc.id = id;
|
||||
|
||||
/* enumerate V4L2 device controls */
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, &qc);
|
||||
|
||||
if (qc.type)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
struct em28xx *dev = fh->dev;
|
||||
int rc;
|
||||
|
||||
rc = check_dev(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
rc = 0;
|
||||
|
||||
/* Set an AC97 control */
|
||||
if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
|
||||
rc = ac97_get_ctrl(dev, ctrl);
|
||||
else
|
||||
rc = 1;
|
||||
|
||||
/* It were not an AC97 control. Sends it to the v4l2 dev interface */
|
||||
if (rc == 1) {
|
||||
if (check_subdev_ctrl(dev, ctrl->id))
|
||||
return -EINVAL;
|
||||
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_ctrl, ctrl);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl(struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct em28xx_fh *fh = priv;
|
||||
struct em28xx *dev = fh->dev;
|
||||
int rc;
|
||||
|
||||
rc = check_dev(dev);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Set an AC97 control */
|
||||
if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
|
||||
rc = ac97_set_ctrl(dev, ctrl);
|
||||
else
|
||||
rc = 1;
|
||||
|
||||
/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
|
||||
if (rc == 1) {
|
||||
rc = check_subdev_ctrl(dev, ctrl->id);
|
||||
if (!rc)
|
||||
v4l2_device_call_all(&dev->v4l2_dev, 0,
|
||||
core, s_ctrl, ctrl);
|
||||
/*
|
||||
* In the case of non-AC97 volume controls, we still need
|
||||
* to do some setups at em28xx, in order to mute/unmute
|
||||
* and to adjust audio volume. However, the value ranges
|
||||
* should be checked by the corresponding V4L subdriver.
|
||||
*/
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
dev->mute = ctrl->value;
|
||||
rc = em28xx_audio_analog_set(dev);
|
||||
break;
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
dev->volume = ctrl->value;
|
||||
rc = em28xx_audio_analog_set(dev);
|
||||
}
|
||||
}
|
||||
return (rc < 0) ? rc : 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner(struct file *file, void *priv,
|
||||
struct v4l2_tuner *t)
|
||||
{
|
||||
|
@ -1874,25 +1697,6 @@ static int radio_s_tuner(struct file *file, void *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int radio_queryctrl(struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (qc->id < V4L2_CID_BASE ||
|
||||
qc->id >= V4L2_CID_LASTP1)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ac97_qctrl); i++) {
|
||||
if (qc->id && qc->id == ac97_qctrl[i].id) {
|
||||
memcpy(qc, &(ac97_qctrl[i]), sizeof(*qc));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* em28xx_v4l2_open()
|
||||
* inits the device and starts isoc transfer
|
||||
|
@ -2218,9 +2022,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|||
.vidioc_enum_input = vidioc_enum_input,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_streamon = vidioc_streamon,
|
||||
.vidioc_streamoff = vidioc_streamoff,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
|
@ -2254,9 +2055,6 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
|
|||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = radio_g_tuner,
|
||||
.vidioc_s_tuner = radio_s_tuner,
|
||||
.vidioc_queryctrl = radio_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
|
@ -2300,7 +2098,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
|
|||
|
||||
int em28xx_register_analog_devices(struct em28xx *dev)
|
||||
{
|
||||
u8 val;
|
||||
u8 val;
|
||||
int ret;
|
||||
unsigned int maxw;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <media/videobuf-vmalloc.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/ir-kbd-i2c.h>
|
||||
#include <media/rc-core.h>
|
||||
#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
|
||||
|
@ -497,6 +498,9 @@ struct em28xx {
|
|||
int audio_ifnum;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
/* provides ac97 mute and volume overrides */
|
||||
struct v4l2_ctrl_handler ac97_ctrl_handler;
|
||||
struct em28xx_board board;
|
||||
|
||||
/* Webcam specific fields */
|
||||
|
@ -705,6 +709,8 @@ void em28xx_close_extension(struct em28xx *dev);
|
|||
/* Provided by em28xx-video.c */
|
||||
int em28xx_register_analog_devices(struct em28xx *dev);
|
||||
void em28xx_release_analog_resources(struct em28xx *dev);
|
||||
void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
|
||||
extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
|
||||
|
||||
/* Provided by em28xx-cards.c */
|
||||
extern int em2800_variant_detect(struct usb_device *udev, int model);
|
||||
|
|
Loading…
Reference in New Issue