in usb/em28xx/em28xx-video.c [2520:2914]
static int em28xx_v4l2_init(struct em28xx *dev)
{
u8 val;
int ret;
unsigned int maxw;
struct v4l2_ctrl_handler *hdl;
struct em28xx_v4l2 *v4l2;
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
return 0;
}
if (!dev->has_video) {
/* This device does not support the v4l2 extension */
return 0;
}
dev_info(&dev->intf->dev, "Registering V4L2 extension\n");
mutex_lock(&dev->lock);
v4l2 = kzalloc(sizeof(*v4l2), GFP_KERNEL);
if (!v4l2) {
mutex_unlock(&dev->lock);
return -ENOMEM;
}
kref_init(&v4l2->ref);
v4l2->dev = dev;
dev->v4l2 = v4l2;
#ifdef CONFIG_MEDIA_CONTROLLER
v4l2->v4l2_dev.mdev = dev->media_dev;
#endif
ret = v4l2_device_register(&dev->intf->dev, &v4l2->v4l2_dev);
if (ret < 0) {
dev_err(&dev->intf->dev,
"Call to v4l2_device_register() failed!\n");
goto err;
}
hdl = &v4l2->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 8);
v4l2->v4l2_dev.ctrl_handler = hdl;
if (dev->is_webcam)
v4l2->progressive = true;
/*
* Default format, used for tvp5150 or saa711x output formats
*/
v4l2->vinmode = EM28XX_VINMODE_YUV422_CbYCrY;
v4l2->vinctl = EM28XX_VINCTRL_INTERLACED |
EM28XX_VINCTRL_CCIR656_ENABLE;
/* request some modules */
if (dev->has_msp34xx)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tvp5150", 0, tvp5150_addrs);
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tvaudio", dev->board.tvaudio_addr, NULL);
/* Initialize tuner and camera */
if (dev->board.tuner_type != TUNER_ABSENT) {
unsigned short tuner_addr = dev->board.tuner_addr;
int has_demod = (dev->board.tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tuner", dev->board.radio_addr,
NULL);
if (has_demod)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tuner", 0,
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tuner", 0,
v4l2_i2c_tuner_addrs(type));
if (sd)
tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus],
"tuner", tuner_addr, NULL);
}
em28xx_tuner_setup(dev, tuner_addr);
}
if (dev->em28xx_sensor != EM28XX_NOSENSOR)
em28xx_init_camera(dev);
/* Configure audio */
ret = em28xx_audio_setup(dev);
if (ret < 0) {
dev_err(&dev->intf->dev,
"%s: Error while setting audio - error [%d]!\n",
__func__, ret);
goto unregister_dev;
}
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);
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vbiq.active);
if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
if (ret < 0) {
dev_err(&dev->intf->dev,
"%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
__func__, ret);
goto unregister_dev;
}
usleep_range(10000, 11000);
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
if (ret < 0) {
dev_err(&dev->intf->dev,
"%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
__func__, ret);
goto unregister_dev;
}
usleep_range(10000, 11000);
}
/* set default norm */
v4l2->norm = V4L2_STD_PAL;
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT;
/* Analog specific initialization */
v4l2->format = &format[0];
maxw = norm_maxw(dev);
/*
* MaxPacketSize for em2800 is too small to capture at full resolution
* use half of maxw as the scaler can only scale to 50%
*/
if (dev->board.is_em2800)
maxw /= 2;
em28xx_set_video_format(dev, format[0].fourcc,
maxw, norm_maxh(dev));
video_mux(dev, 0);
/* Audio defaults */
dev->mute = 1;
dev->volume = 0x1f;
/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
em28xx_write_reg(dev, EM28XX_R0F_XCLK,
(EM28XX_XCLK_AUDIO_UNMUTE | val));
em28xx_set_outfmt(dev);
/* Add image controls */
/*
* NOTE: at this point, the subdevices are already registered, so
* bridge controls are only added/enabled when no subdevice provides
* them
*/
if (!v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_CONTRAST,
0, 0x1f, 1, CONTRAST_DEFAULT);
if (!v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BRIGHTNESS,
-0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
if (!v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SATURATION,
0, 0x1f, 1, SATURATION_DEFAULT);
if (!v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BLUE_BALANCE,
-0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
if (!v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_RED_BALANCE,
-0x30, 0x30, 1, RED_BALANCE_DEFAULT);
if (!v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SHARPNESS,
0, 0x0f, 1, SHARPNESS_DEFAULT);
/* Reset image controls */
em28xx_colorlevels_set_default(dev);
v4l2_ctrl_handler_setup(hdl);
ret = hdl->error;
if (ret)
goto unregister_dev;
/* allocate and fill video video_device struct */
em28xx_vdev_init(dev, &v4l2->vdev, &em28xx_video_template, "video");
mutex_init(&v4l2->vb_queue_lock);
mutex_init(&v4l2->vb_vbi_queue_lock);
v4l2->vdev.queue = &v4l2->vb_vidq;
v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
v4l2->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
v4l2->vdev.device_caps |= V4L2_CAP_AUDIO;
if (dev->tuner_type != TUNER_ABSENT)
v4l2->vdev.device_caps |= V4L2_CAP_TUNER;
/* disable inapplicable ioctls */
if (dev->is_webcam) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD);
} else {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_PARM);
}
if (dev->tuner_type == TUNER_ABSENT) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_FREQUENCY);
}
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_AUDIO);
}
/* register v4l2 video video_device */
ret = video_register_device(&v4l2->vdev, VFL_TYPE_VIDEO,
video_nr[dev->devno]);
if (ret) {
dev_err(&dev->intf->dev,
"unable to register video device (error=%i).\n", ret);
goto unregister_dev;
}
/* Allocate and fill vbi video_device struct */
if (em28xx_vbi_supported(dev) == 1) {
em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template,
"vbi");
v4l2->vbi_dev.queue = &v4l2->vb_vbiq;
v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
v4l2->vbi_dev.device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
if (dev->tuner_type != TUNER_ABSENT)
v4l2->vbi_dev.device_caps |= V4L2_CAP_TUNER;
/* disable inapplicable ioctls */
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_TUNER);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
}
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_AUDIO);
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_AUDIO);
}
/* register v4l2 vbi video_device */
ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
dev_err(&dev->intf->dev,
"unable to register vbi device\n");
goto unregister_dev;
}
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template,
"radio");
v4l2->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
dev_err(&dev->intf->dev,
"can't register radio device\n");
goto unregister_dev;
}
dev_info(&dev->intf->dev,
"Registered radio device as %s\n",
video_device_node_name(&v4l2->radio_dev));
}
/* Init entities at the Media Controller */
em28xx_v4l2_create_entities(dev);
#ifdef CONFIG_MEDIA_CONTROLLER
ret = v4l2_mc_create_media_graph(dev->media_dev);
if (ret) {
dev_err(&dev->intf->dev,
"failed to create media graph\n");
em28xx_v4l2_media_release(dev);
goto unregister_dev;
}
#endif
dev_info(&dev->intf->dev,
"V4L2 video device registered as %s\n",
video_device_node_name(&v4l2->vdev));
if (video_is_registered(&v4l2->vbi_dev))
dev_info(&dev->intf->dev,
"V4L2 VBI device registered as %s\n",
video_device_node_name(&v4l2->vbi_dev));
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby);
/* initialize videobuf2 stuff */
em28xx_vb2_setup(dev);
dev_info(&dev->intf->dev,
"V4L2 extension successfully initialized\n");
kref_get(&dev->ref);
mutex_unlock(&dev->lock);
return 0;
unregister_dev:
if (video_is_registered(&v4l2->radio_dev)) {
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->radio_dev));
video_unregister_device(&v4l2->radio_dev);
}
if (video_is_registered(&v4l2->vbi_dev)) {
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vbi_dev));
video_unregister_device(&v4l2->vbi_dev);
}
if (video_is_registered(&v4l2->vdev)) {
dev_info(&dev->intf->dev,
"V4L2 device %s deregistered\n",
video_device_node_name(&v4l2->vdev));
video_unregister_device(&v4l2->vdev);
}
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
v4l2_device_unregister(&v4l2->v4l2_dev);
err:
dev->v4l2 = NULL;
kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
return ret;
}