示例#1
0
static int vivid_create_instance(struct platform_device *pdev, int inst)
{
	static const struct v4l2_dv_timings def_dv_timings =
					V4L2_DV_BT_CEA_1280X720P60;
	unsigned in_type_counter[4] = { 0, 0, 0, 0 };
	unsigned out_type_counter[4] = { 0, 0, 0, 0 };
	int ccs_cap = ccs_cap_mode[inst];
	int ccs_out = ccs_out_mode[inst];
	bool has_tuner;
	bool has_modulator;
	struct vivid_dev *dev;
	struct video_device *vfd;
	struct vb2_queue *q;
	unsigned node_type = node_types[inst];
	v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
	int ret;
	int i;

	/* allocate main vivid state structure */
	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
	if (!dev)
		return -ENOMEM;

	dev->inst = inst;

	/* register v4l2_device */
	snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
			"%s-%03d", VIVID_MODULE_NAME, inst);
	ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
	if (ret) {
		kfree(dev);
		return ret;
	}
	dev->v4l2_dev.release = vivid_dev_release;

	/* start detecting feature set */

	/* do we use single- or multi-planar? */
	dev->multiplanar = multiplanar[inst] > 1;
	v4l2_info(&dev->v4l2_dev, "using %splanar format API\n",
			dev->multiplanar ? "multi" : "single ");

	/* how many inputs do we have and of what type? */
	dev->num_inputs = num_inputs[inst];
	if (dev->num_inputs < 1)
		dev->num_inputs = 1;
	if (dev->num_inputs >= MAX_INPUTS)
		dev->num_inputs = MAX_INPUTS;
	for (i = 0; i < dev->num_inputs; i++) {
		dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3;
		dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
	}
	dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];

	/* how many outputs do we have and of what type? */
	dev->num_outputs = num_outputs[inst];
	if (dev->num_outputs < 1)
		dev->num_outputs = 1;
	if (dev->num_outputs >= MAX_OUTPUTS)
		dev->num_outputs = MAX_OUTPUTS;
	for (i = 0; i < dev->num_outputs; i++) {
		dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
		dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
	}
	dev->has_audio_outputs = out_type_counter[SVID];

	/* do we create a video capture device? */
	dev->has_vid_cap = node_type & 0x0001;

	/* do we create a vbi capture device? */
	if (in_type_counter[TV] || in_type_counter[SVID]) {
		dev->has_raw_vbi_cap = node_type & 0x0004;
		dev->has_sliced_vbi_cap = node_type & 0x0008;
		dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap;
	}

	/* do we create a video output device? */
	dev->has_vid_out = node_type & 0x0100;

	/* do we create a vbi output device? */
	if (out_type_counter[SVID]) {
		dev->has_raw_vbi_out = node_type & 0x0400;
		dev->has_sliced_vbi_out = node_type & 0x0800;
		dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out;
	}

	/* do we create a radio receiver device? */
	dev->has_radio_rx = node_type & 0x0010;

	/* do we create a radio transmitter device? */
	dev->has_radio_tx = node_type & 0x1000;

	/* do we create a software defined radio capture device? */
	dev->has_sdr_cap = node_type & 0x0020;

	/* do we have a tuner? */
	has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
		    dev->has_radio_rx || dev->has_sdr_cap;

	/* do we have a modulator? */
	has_modulator = dev->has_radio_tx;

	if (dev->has_vid_cap)
		/* do we have a framebuffer for overlay testing? */
		dev->has_fb = node_type & 0x10000;

	/* can we do crop/compose/scaling while capturing? */
	if (no_error_inj && ccs_cap == -1)
		ccs_cap = 7;

	/* if ccs_cap == -1, then the use can select it using controls */
	if (ccs_cap != -1) {
		dev->has_crop_cap = ccs_cap & 1;
		dev->has_compose_cap = ccs_cap & 2;
		dev->has_scaler_cap = ccs_cap & 4;
		v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n",
			dev->has_crop_cap ? 'Y' : 'N',
			dev->has_compose_cap ? 'Y' : 'N',
			dev->has_scaler_cap ? 'Y' : 'N');
	}

	/* can we do crop/compose/scaling with video output? */
	if (no_error_inj && ccs_out == -1)
		ccs_out = 7;

	/* if ccs_out == -1, then the use can select it using controls */
	if (ccs_out != -1) {
		dev->has_crop_out = ccs_out & 1;
		dev->has_compose_out = ccs_out & 2;
		dev->has_scaler_out = ccs_out & 4;
		v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n",
			dev->has_crop_out ? 'Y' : 'N',
			dev->has_compose_out ? 'Y' : 'N',
			dev->has_scaler_out ? 'Y' : 'N');
	}

	/* end detecting feature set */

	if (dev->has_vid_cap) {
		/* set up the capabilities of the video capture device */
		dev->vid_cap_caps = dev->multiplanar ?
			V4L2_CAP_VIDEO_CAPTURE_MPLANE :
			V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY;
		dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
		if (dev->has_audio_inputs)
			dev->vid_cap_caps |= V4L2_CAP_AUDIO;
		if (in_type_counter[TV])
			dev->vid_cap_caps |= V4L2_CAP_TUNER;
	}
	if (dev->has_vid_out) {
		/* set up the capabilities of the video output device */
		dev->vid_out_caps = dev->multiplanar ?
			V4L2_CAP_VIDEO_OUTPUT_MPLANE :
			V4L2_CAP_VIDEO_OUTPUT;
		if (dev->has_fb)
			dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
		dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
		if (dev->has_audio_outputs)
			dev->vid_out_caps |= V4L2_CAP_AUDIO;
	}
	if (dev->has_vbi_cap) {
		/* set up the capabilities of the vbi capture device */
		dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) |
				    (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0);
		dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
		if (dev->has_audio_inputs)
			dev->vbi_cap_caps |= V4L2_CAP_AUDIO;
		if (in_type_counter[TV])
			dev->vbi_cap_caps |= V4L2_CAP_TUNER;
	}
	if (dev->has_vbi_out) {
		/* set up the capabilities of the vbi output device */
		dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) |
				    (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0);
		dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
		if (dev->has_audio_outputs)
			dev->vbi_out_caps |= V4L2_CAP_AUDIO;
	}
	if (dev->has_sdr_cap) {
		/* set up the capabilities of the sdr capture device */
		dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
		dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
	}
	/* set up the capabilities of the radio receiver device */
	if (dev->has_radio_rx)
		dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE |
				     V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
				     V4L2_CAP_READWRITE;
	/* set up the capabilities of the radio transmitter device */
	if (dev->has_radio_tx)
		dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR |
				     V4L2_CAP_READWRITE;

	/* initialize the test pattern generator */
	tpg_init(&dev->tpg, 640, 360);
	if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH))
		goto free_dev;
	dev->scaled_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
	if (!dev->scaled_line)
		goto free_dev;
	dev->blended_line = vzalloc(MAX_ZOOM * MAX_WIDTH);
	if (!dev->blended_line)
		goto free_dev;

	/* load the edid */
	dev->edid = vmalloc(256 * 128);
	if (!dev->edid)
		goto free_dev;

	/* create a string array containing the names of all the preset timings */
	while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
		dev->query_dv_timings_size++;
	dev->query_dv_timings_qmenu = kmalloc(dev->query_dv_timings_size *
					   (sizeof(void *) + 32), GFP_KERNEL);
	if (dev->query_dv_timings_qmenu == NULL)
		goto free_dev;
	for (i = 0; i < dev->query_dv_timings_size; i++) {
		const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
		char *p = (char *)&dev->query_dv_timings_qmenu[dev->query_dv_timings_size];
		u32 htot, vtot;

		p += i * 32;
		dev->query_dv_timings_qmenu[i] = p;

		htot = V4L2_DV_BT_FRAME_WIDTH(bt);
		vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
		snprintf(p, 32, "%ux%u%s%u",
			bt->width, bt->height, bt->interlaced ? "i" : "p",
			(u32)bt->pixelclock / (htot * vtot));
	}

	/* disable invalid ioctls based on the feature set */
	if (!dev->has_audio_inputs) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO);
	}
	if (!dev->has_audio_outputs) {
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT);
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT);
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT);
		v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT);
	}
	if (!in_type_counter[TV] && !in_type_counter[SVID]) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD);
	}
	if (!out_type_counter[SVID]) {
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD);
	}
	if (!has_tuner && !has_modulator) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY);
	}
	if (!has_tuner) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER);
		v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER);
	}
	if (in_type_counter[HDMI] == 0) {
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS);
		v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS);
	}
	if (out_type_counter[HDMI] == 0) {
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS);
	}
	if (!dev->has_fb) {
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF);
		v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY);
	}
	v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
	v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
	v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK);
	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY);
	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY);
	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES);
	v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS);
	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY);
	v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY);

	/* configure internal data */
	dev->fmt_cap = &vivid_formats[0];
	dev->fmt_out = &vivid_formats[0];
	if (!dev->multiplanar)
		vivid_formats[0].data_offset[0] = 0;
	dev->webcam_size_idx = 1;
	dev->webcam_ival_idx = 3;
	tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
	dev->std_cap = V4L2_STD_PAL;
	dev->std_out = V4L2_STD_PAL;
	if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
		tvnorms_cap = V4L2_STD_ALL;
	if (dev->output_type[0] == SVID)
		tvnorms_out = V4L2_STD_ALL;
	dev->dv_timings_cap = def_dv_timings;
	dev->dv_timings_out = def_dv_timings;
	dev->tv_freq = 2804 /* 175.25 * 16 */;
	dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
	dev->tv_field_cap = V4L2_FIELD_INTERLACED;
	dev->tv_field_out = V4L2_FIELD_INTERLACED;
	dev->radio_rx_freq = 95000 * 16;
	dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
	if (dev->has_radio_tx) {
		dev->radio_tx_freq = 95500 * 16;
		dev->radio_rds_loop = false;
	}
	dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
	dev->sdr_adc_freq = 300000;
	dev->sdr_fm_freq = 50000000;
	dev->edid_max_blocks = dev->edid_blocks = 2;
	memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
	ktime_get_ts(&dev->radio_rds_init_ts);

	/* create all controls */
	ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
			in_type_counter[TV] || in_type_counter[SVID] ||
			out_type_counter[SVID],
			in_type_counter[HDMI] || out_type_counter[HDMI]);
	if (ret)
		goto unreg_dev;

	/*
	 * update the capture and output formats to do a proper initial
	 * configuration.
	 */
	vivid_update_format_cap(dev, false);
	vivid_update_format_out(dev);

	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
	v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);

	/* initialize overlay */
	dev->fb_cap.fmt.width = dev->src_rect.width;
	dev->fb_cap.fmt.height = dev->src_rect.height;
	dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
	dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
	dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;

	/* initialize locks */
	spin_lock_init(&dev->slock);
	mutex_init(&dev->mutex);

	/* init dma queues */
	INIT_LIST_HEAD(&dev->vid_cap_active);
	INIT_LIST_HEAD(&dev->vid_out_active);
	INIT_LIST_HEAD(&dev->vbi_cap_active);
	INIT_LIST_HEAD(&dev->vbi_out_active);
	INIT_LIST_HEAD(&dev->sdr_cap_active);

	/* start creating the vb2 queues */
	if (dev->has_vid_cap) {
		/* initialize vid_cap queue */
		q = &dev->vb_vid_cap_q;
		q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE :
			V4L2_BUF_TYPE_VIDEO_CAPTURE;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_vid_cap_qops;
		q->mem_ops = &vb2_vmalloc_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 2;
		q->lock = &dev->mutex;

		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

	if (dev->has_vid_out) {
		/* initialize vid_out queue */
		q = &dev->vb_vid_out_q;
		q->type = dev->multiplanar ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE :
			V4L2_BUF_TYPE_VIDEO_OUTPUT;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_vid_out_qops;
		q->mem_ops = &vb2_vmalloc_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 2;
		q->lock = &dev->mutex;

		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

	if (dev->has_vbi_cap) {
		/* initialize vbi_cap queue */
		q = &dev->vb_vbi_cap_q;
		q->type = dev->has_raw_vbi_cap ? V4L2_BUF_TYPE_VBI_CAPTURE :
					      V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_vbi_cap_qops;
		q->mem_ops = &vb2_vmalloc_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 2;
		q->lock = &dev->mutex;

		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

	if (dev->has_vbi_out) {
		/* initialize vbi_out queue */
		q = &dev->vb_vbi_out_q;
		q->type = dev->has_raw_vbi_out ? V4L2_BUF_TYPE_VBI_OUTPUT :
					      V4L2_BUF_TYPE_SLICED_VBI_OUTPUT;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_vbi_out_qops;
		q->mem_ops = &vb2_vmalloc_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 2;
		q->lock = &dev->mutex;

		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

	if (dev->has_sdr_cap) {
		/* initialize sdr_cap queue */
		q = &dev->vb_sdr_cap_q;
		q->type = V4L2_BUF_TYPE_SDR_CAPTURE;
		q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
		q->drv_priv = dev;
		q->buf_struct_size = sizeof(struct vivid_buffer);
		q->ops = &vivid_sdr_cap_qops;
		q->mem_ops = &vb2_vmalloc_memops;
		q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
		q->min_buffers_needed = 8;
		q->lock = &dev->mutex;

		ret = vb2_queue_init(q);
		if (ret)
			goto unreg_dev;
	}

	if (dev->has_fb) {
		/* Create framebuffer for testing capture/output overlay */
		ret = vivid_fb_init(dev);
		if (ret)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
				dev->fb_info.node);
	}

	/* finally start creating the device nodes */
	if (dev->has_vid_cap) {
		vfd = &dev->vid_cap_dev;
		strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_vid_cap_q;
		vfd->tvnorms = tvnorms_cap;

		/*
		 * Provide a mutex to v4l2 core. It will be used to protect
		 * all fops and v4l2 ioctls.
		 */
		vfd->lock = &dev->mutex;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
					  video_device_node_name(vfd));
	}

	if (dev->has_vid_out) {
		vfd = &dev->vid_out_dev;
		strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
		vfd->vfl_dir = VFL_DIR_TX;
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_vid_out_q;
		vfd->tvnorms = tvnorms_out;

		/*
		 * Provide a mutex to v4l2 core. It will be used to protect
		 * all fops and v4l2 ioctls.
		 */
		vfd->lock = &dev->mutex;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
					  video_device_node_name(vfd));
	}

	if (dev->has_vbi_cap) {
		vfd = &dev->vbi_cap_dev;
		strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_vbi_cap_q;
		vfd->lock = &dev->mutex;
		vfd->tvnorms = tvnorms_cap;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n",
					  video_device_node_name(vfd),
					  (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ?
					  "raw and sliced" :
					  (dev->has_raw_vbi_cap ? "raw" : "sliced"));
	}

	if (dev->has_vbi_out) {
		vfd = &dev->vbi_out_dev;
		strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
		vfd->vfl_dir = VFL_DIR_TX;
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_vbi_out_q;
		vfd->lock = &dev->mutex;
		vfd->tvnorms = tvnorms_out;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n",
					  video_device_node_name(vfd),
					  (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ?
					  "raw and sliced" :
					  (dev->has_raw_vbi_out ? "raw" : "sliced"));
	}

	if (dev->has_sdr_cap) {
		vfd = &dev->sdr_cap_dev;
		strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
		vfd->fops = &vivid_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->queue = &dev->vb_sdr_cap_q;
		vfd->lock = &dev->mutex;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
					  video_device_node_name(vfd));
	}

	if (dev->has_radio_rx) {
		vfd = &dev->radio_rx_dev;
		strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
		vfd->fops = &vivid_radio_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->lock = &dev->mutex;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n",
					  video_device_node_name(vfd));
	}

	if (dev->has_radio_tx) {
		vfd = &dev->radio_tx_dev;
		strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
		vfd->vfl_dir = VFL_DIR_TX;
		vfd->fops = &vivid_radio_fops;
		vfd->ioctl_ops = &vivid_ioctl_ops;
		vfd->release = video_device_release_empty;
		vfd->v4l2_dev = &dev->v4l2_dev;
		vfd->lock = &dev->mutex;
		video_set_drvdata(vfd, dev);

		ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]);
		if (ret < 0)
			goto unreg_dev;
		v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n",
					  video_device_node_name(vfd));
	}

	/* Now that everything is fine, let's add it to device list */
	vivid_devs[inst] = dev;

	return 0;

unreg_dev:
	video_unregister_device(&dev->radio_tx_dev);
	video_unregister_device(&dev->radio_rx_dev);
	video_unregister_device(&dev->sdr_cap_dev);
	video_unregister_device(&dev->vbi_out_dev);
	video_unregister_device(&dev->vbi_cap_dev);
	video_unregister_device(&dev->vid_out_dev);
	video_unregister_device(&dev->vid_cap_dev);
free_dev:
	v4l2_device_put(&dev->v4l2_dev);
	return ret;
}
示例#2
0
static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
{
	static const u32 colorspaces[] = {
		V4L2_COLORSPACE_SMPTE170M,
		V4L2_COLORSPACE_REC709,
		V4L2_COLORSPACE_SRGB,
		V4L2_COLORSPACE_ADOBERGB,
		V4L2_COLORSPACE_BT2020,
		V4L2_COLORSPACE_SMPTE240M,
		V4L2_COLORSPACE_470_SYSTEM_M,
		V4L2_COLORSPACE_470_SYSTEM_BG,
	};
	struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
	unsigned i;

	switch (ctrl->id) {
	case VIVID_CID_TEST_PATTERN:
		vivid_update_quality(dev);
		tpg_s_pattern(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_COLORSPACE:
		tpg_s_colorspace(&dev->tpg, colorspaces[ctrl->val]);
		vivid_send_source_change(dev, TV);
		vivid_send_source_change(dev, SVID);
		vivid_send_source_change(dev, HDMI);
		vivid_send_source_change(dev, WEBCAM);
		break;
	case VIVID_CID_YCBCR_ENC:
		tpg_s_ycbcr_enc(&dev->tpg, ctrl->val);
		vivid_send_source_change(dev, TV);
		vivid_send_source_change(dev, SVID);
		vivid_send_source_change(dev, HDMI);
		vivid_send_source_change(dev, WEBCAM);
		break;
	case VIVID_CID_QUANTIZATION:
		tpg_s_quantization(&dev->tpg, ctrl->val);
		vivid_send_source_change(dev, TV);
		vivid_send_source_change(dev, SVID);
		vivid_send_source_change(dev, HDMI);
		vivid_send_source_change(dev, WEBCAM);
		break;
	case V4L2_CID_DV_RX_RGB_RANGE:
		if (!vivid_is_hdmi_cap(dev))
			break;
		tpg_s_rgb_range(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_LIMITED_RGB_RANGE:
		tpg_s_real_rgb_range(&dev->tpg, ctrl->val ?
				V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
		break;
	case VIVID_CID_ALPHA_MODE:
		tpg_s_alpha_mode(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_HOR_MOVEMENT:
		tpg_s_mv_hor_mode(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_VERT_MOVEMENT:
		tpg_s_mv_vert_mode(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_OSD_TEXT_MODE:
		dev->osd_mode = ctrl->val;
		break;
	case VIVID_CID_PERCENTAGE_FILL:
		tpg_s_perc_fill(&dev->tpg, ctrl->val);
		for (i = 0; i < VIDEO_MAX_FRAME; i++)
			dev->must_blank[i] = ctrl->val < 100;
		break;
	case VIVID_CID_INSERT_SAV:
		tpg_s_insert_sav(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_INSERT_EAV:
		tpg_s_insert_eav(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_HFLIP:
		dev->sensor_hflip = ctrl->val;
		tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip);
		break;
	case VIVID_CID_VFLIP:
		dev->sensor_vflip = ctrl->val;
		tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
		break;
	case VIVID_CID_HAS_CROP_CAP:
		dev->has_crop_cap = ctrl->val;
		vivid_update_format_cap(dev, true);
		break;
	case VIVID_CID_HAS_COMPOSE_CAP:
		dev->has_compose_cap = ctrl->val;
		vivid_update_format_cap(dev, true);
		break;
	case VIVID_CID_HAS_SCALER_CAP:
		dev->has_scaler_cap = ctrl->val;
		vivid_update_format_cap(dev, true);
		break;
	case VIVID_CID_SHOW_BORDER:
		tpg_s_show_border(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_SHOW_SQUARE:
		tpg_s_show_square(&dev->tpg, ctrl->val);
		break;
	case VIVID_CID_STD_ASPECT_RATIO:
		dev->std_aspect_ratio = ctrl->val;
		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
		break;
	case VIVID_CID_DV_TIMINGS_SIGNAL_MODE:
		dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val;
		if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS)
			dev->query_dv_timings = dev->ctrl_dv_timings->val;
		v4l2_ctrl_activate(dev->ctrl_dv_timings,
				dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS);
		vivid_update_quality(dev);
		vivid_send_source_change(dev, HDMI);
		break;
	case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
		dev->dv_timings_aspect_ratio = ctrl->val;
		tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev));
		break;
	case VIVID_CID_TSTAMP_SRC:
		dev->tstamp_src_is_soe = ctrl->val;
		dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
		if (dev->tstamp_src_is_soe)
			dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
		break;
	case VIVID_CID_MAX_EDID_BLOCKS:
		dev->edid_max_blocks = ctrl->val;
		if (dev->edid_blocks > dev->edid_max_blocks)
			dev->edid_blocks = dev->edid_max_blocks;
		break;
	}
	return 0;
}