static int em28xx_v4l2_init()

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;
}