diff options
Diffstat (limited to 'drivers/media/test-drivers/vivid/vivid-core.c')
-rw-r--r-- | drivers/media/test-drivers/vivid/vivid-core.c | 674 |
1 files changed, 371 insertions, 303 deletions
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c index f7ee37e9508d..aa8d350fd682 100644 --- a/drivers/media/test-drivers/vivid/vivid-core.c +++ b/drivers/media/test-drivers/vivid/vivid-core.c @@ -832,56 +832,16 @@ static int vivid_create_queue(struct vivid_dev *dev, return vb2_queue_init(q); } -static int vivid_create_instance(struct platform_device *pdev, int inst) +static int vivid_detect_feature_set(struct vivid_dev *dev, int inst, + unsigned node_type, + bool *has_tuner, + bool *has_modulator, + int *ccs_cap, + int *ccs_out, + unsigned in_type_counter[4], + unsigned out_type_counter[4]) { - 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; - unsigned node_type = node_types[inst]; - v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; - int ret; int i; -#ifdef CONFIG_VIDEO_VIVID_CEC - unsigned int cec_tx_bus_cnt = 0; -#endif - - /* allocate main vivid state structure */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->inst = inst; - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->v4l2_dev.mdev = &dev->mdev; - - /* Initialize media device */ - strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); - snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info), - "platform:%s-%03d", VIVID_MODULE_NAME, inst); - dev->mdev.dev = &pdev->dev; - media_device_init(&dev->mdev); - dev->mdev.ops = &vivid_media_ops; -#endif - - /* 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; @@ -947,14 +907,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) !dev->has_vid_cap && !dev->has_meta_cap) { v4l2_warn(&dev->v4l2_dev, "Webcam or HDMI input without video or metadata nodes\n"); - kfree(dev); return -EINVAL; } if ((in_type_counter[TV] || in_type_counter[SVID]) && !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) { v4l2_warn(&dev->v4l2_dev, "TV or S-Video input without video, VBI or metadata nodes\n"); - kfree(dev); return -EINVAL; } @@ -976,13 +934,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) { v4l2_warn(&dev->v4l2_dev, "S-Video output without video, VBI or metadata nodes\n"); - kfree(dev); return -EINVAL; } if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) { v4l2_warn(&dev->v4l2_dev, "HDMI output without video or metadata nodes\n"); - kfree(dev); return -EINVAL; } @@ -999,25 +955,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->has_tv_tuner = in_type_counter[TV]; /* 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; + *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; + *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 (no_error_inj && *ccs_cap == -1) + *ccs_cap = 7; /* if ccs_cap == -1, then the user 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; + 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', @@ -1025,14 +981,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) } /* can we do crop/compose/scaling with video output? */ - if (no_error_inj && ccs_out == -1) - ccs_out = 7; + if (no_error_inj && *ccs_out == -1) + *ccs_out = 7; /* if ccs_out == -1, then the user 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; + 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', @@ -1042,8 +998,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) /* do we create a touch capture device */ dev->has_touch_cap = node_type & 0x80000; - /* end detecting feature set */ + return 0; +} +static void vivid_set_capabilities(struct vivid_dev *dev) +{ if (dev->has_vid_cap) { /* set up the capabilities of the video capture device */ dev->vid_cap_caps = dev->multiplanar ? @@ -1122,58 +1081,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->touch_cap_caps |= dev->multiplanar ? V4L2_CAP_VIDEO_CAPTURE_MPLANE : V4L2_CAP_VIDEO_CAPTURE; } +} - ret = -ENOMEM; - /* initialize the test pattern generator */ - tpg_init(&dev->tpg, 640, 360); - if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM))) - goto free_dev; - dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); - if (!dev->scaled_line) - goto free_dev; - dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); - if (!dev->blended_line) - goto free_dev; - - /* load the edid */ - dev->edid = vmalloc(array_size(256, 128)); - if (!dev->edid) - goto free_dev; - - while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) - dev->query_dv_timings_size++; - - /* - * Create a char pointer array that points to the names of all the - * preset timings - */ - dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size, - sizeof(char *), GFP_KERNEL); - /* - * Create a string array containing the names of all the preset - * timings. Each name is max 31 chars long (+ terminating 0). - */ - dev->query_dv_timings_qmenu_strings = - kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL); - - if (!dev->query_dv_timings_qmenu || - !dev->query_dv_timings_qmenu_strings) - 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 = dev->query_dv_timings_qmenu_strings + i * 32; - u32 htot, vtot; - - 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)); - } - +static void vivid_disable_unused_ioctls(struct vivid_dev *dev, + bool has_tuner, + bool has_modulator, + unsigned in_type_counter[4], + unsigned out_type_counter[4]) +{ /* disable invalid ioctls based on the feature set */ if (!dev->has_audio_inputs) { v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO); @@ -1260,112 +1175,52 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM); v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES); v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS); +} - /* 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_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; - for (i = 0; i < MAX_INPUTS; i++) { - dev->dv_timings_cap[i] = def_dv_timings; - dev->std_cap[i] = V4L2_STD_PAL; - } - 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->sdr_pixelformat = V4L2_SDR_FMT_CU8; - dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; - - dev->edid_max_blocks = dev->edid_blocks = 2; - memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); - dev->radio_rds_init_time = ktime_get(); - - /* 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; +static int vivid_init_dv_timings(struct vivid_dev *dev) +{ + int i; - /* enable/disable interface specific controls */ - if (dev->num_outputs && dev->output_type[0] != HDMI) - v4l2_ctrl_activate(dev->ctrl_display_present, false); - if (dev->num_inputs && dev->input_type[0] != HDMI) { - v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); - v4l2_ctrl_activate(dev->ctrl_dv_timings, false); - } else if (dev->num_inputs && dev->input_type[0] == HDMI) { - v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); - v4l2_ctrl_activate(dev->ctrl_standard, false); - } + while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) + dev->query_dv_timings_size++; /* - * update the capture and output formats to do a proper initial - * configuration. + * Create a char pointer array that points to the names of all the + * preset timings */ - vivid_update_format_cap(dev, false); - vivid_update_format_out(dev); - - /* 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; + dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size, + sizeof(char *), GFP_KERNEL); + /* + * Create a string array containing the names of all the preset + * timings. Each name is max 31 chars long (+ terminating 0). + */ + dev->query_dv_timings_qmenu_strings = + kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL); - /* update touch configuration */ - dev->timeperframe_tch_cap.numerator = 1; - dev->timeperframe_tch_cap.denominator = 10; - vivid_set_touch(dev, 0); + if (!dev->query_dv_timings_qmenu || + !dev->query_dv_timings_qmenu_strings) + return -ENOMEM; - /* initialize locks */ - spin_lock_init(&dev->slock); - mutex_init(&dev->mutex); + for (i = 0; i < dev->query_dv_timings_size; i++) { + const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; + char *p = dev->query_dv_timings_qmenu_strings + i * 32; + u32 htot, vtot; - /* 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); - INIT_LIST_HEAD(&dev->meta_cap_active); - INIT_LIST_HEAD(&dev->meta_out_active); - INIT_LIST_HEAD(&dev->touch_cap_active); + dev->query_dv_timings_qmenu[i] = p; - INIT_LIST_HEAD(&dev->cec_work_list); - spin_lock_init(&dev->cec_slock); - /* - * Same as create_singlethread_workqueue, but now I can use the - * string formatting of alloc_ordered_workqueue. - */ - dev->cec_workqueue = - alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst); - if (!dev->cec_workqueue) { - ret = -ENOMEM; - goto unreg_dev; + 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)); } - if (allocators[inst] == 1) - dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + return 0; +} + +static int vivid_create_queues(struct vivid_dev *dev) +{ + int ret; /* start creating the vb2 queues */ if (dev->has_vid_cap) { @@ -1374,7 +1229,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, &vivid_vid_cap_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_vid_out) { @@ -1383,7 +1238,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, &vivid_vid_out_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_vbi_cap) { @@ -1392,7 +1247,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_VBI_CAPTURE, 2, &vivid_vbi_cap_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_vbi_out) { @@ -1401,7 +1256,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_VBI_OUTPUT, 2, &vivid_vbi_out_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_sdr_cap) { @@ -1410,7 +1265,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_SDR_CAPTURE, 8, &vivid_sdr_cap_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_meta_cap) { @@ -1419,7 +1274,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_META_CAPTURE, 2, &vivid_meta_cap_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_meta_out) { @@ -1428,7 +1283,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_META_OUTPUT, 1, &vivid_meta_out_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_touch_cap) { @@ -1437,63 +1292,31 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, &vivid_touch_cap_qops); if (ret) - goto unreg_dev; + return ret; } if (dev->has_fb) { /* Create framebuffer for testing capture/output overlay */ ret = vivid_fb_init(dev); if (ret) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", dev->fb_info.node); } + return 0; +} -#ifdef CONFIG_VIDEO_VIVID_CEC - if (dev->has_vid_cap && in_type_counter[HDMI]) { - struct cec_adapter *adap; - - adap = vivid_cec_alloc_adap(dev, 0, false); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_rx_adap = adap; - } - - if (dev->has_vid_out) { - for (i = 0; i < dev->num_outputs; i++) { - struct cec_adapter *adap; - - if (dev->output_type[i] != HDMI) - continue; - - dev->cec_output2bus_map[i] = cec_tx_bus_cnt; - adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) { - for (i = 0; i < dev->num_outputs; i++) - cec_delete_adapter(dev->cec_tx_adap[i]); - goto unreg_dev; - } - - dev->cec_tx_adap[cec_tx_bus_cnt] = adap; - cec_tx_bus_cnt++; - } - } -#endif - - 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); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap); +static int vivid_create_devnodes(struct platform_device *pdev, + struct vivid_dev *dev, int inst, + unsigned int cec_tx_bus_cnt, + v4l2_std_id tvnorms_cap, + v4l2_std_id tvnorms_out, + unsigned in_type_counter[4], + unsigned out_type_counter[4]) +{ + struct video_device *vfd; + int ret; - /* finally start creating the device nodes */ if (dev->has_vid_cap) { vfd = &dev->vid_cap_dev; snprintf(vfd->name, sizeof(vfd->name), @@ -1517,7 +1340,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_cap_pad); if (ret) - goto unreg_dev; + return ret; #endif #ifdef CONFIG_VIDEO_VIVID_CEC @@ -1526,7 +1349,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret < 0) { cec_delete_adapter(dev->cec_rx_adap); dev->cec_rx_adap = NULL; - goto unreg_dev; + return ret; } cec_s_phys_addr(dev->cec_rx_adap, 0, false); v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", @@ -1536,12 +1359,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", video_device_node_name(vfd)); } if (dev->has_vid_out) { +#ifdef CONFIG_VIDEO_VIVID_CEC + int i; +#endif vfd = &dev->vid_out_dev; snprintf(vfd->name, sizeof(vfd->name), "vivid-%03d-vid-out", inst); @@ -1565,7 +1391,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vid_out_pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_out_pad); if (ret) - goto unreg_dev; + return ret; #endif #ifdef CONFIG_VIDEO_VIVID_CEC @@ -1576,7 +1402,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) cec_delete_adapter(dev->cec_tx_adap[i]); dev->cec_tx_adap[i] = NULL; } - goto unreg_dev; + return ret; } v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); @@ -1589,7 +1415,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n", video_device_node_name(vfd)); } @@ -1612,12 +1438,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vbi_cap_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_cap_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; 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) ? @@ -1644,12 +1470,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->vbi_out_pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_out_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; 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) ? @@ -1674,12 +1500,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->sdr_cap_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vfd->entity, 1, &dev->sdr_cap_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", video_device_node_name(vfd)); } @@ -1698,7 +1524,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n", video_device_node_name(vfd)); } @@ -1718,7 +1544,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n", video_device_node_name(vfd)); } @@ -1741,12 +1567,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = media_entity_pads_init(&vfd->entity, 1, &dev->meta_cap_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_VIDEO, meta_cap_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 metadata capture device registered as %s\n", video_device_node_name(vfd)); @@ -1771,12 +1597,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = media_entity_pads_init(&vfd->entity, 1, &dev->meta_out_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_VIDEO, meta_out_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 metadata output device registered as %s\n", video_device_node_name(vfd)); @@ -1800,12 +1626,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ret = media_entity_pads_init(&vfd->entity, 1, &dev->touch_cap_pad); if (ret) - goto unreg_dev; + return ret; #endif ret = video_register_device(vfd, VFL_TYPE_TOUCH, touch_cap_nr[inst]); if (ret < 0) - goto unreg_dev; + return ret; v4l2_info(&dev->v4l2_dev, "V4L2 touch capture device registered as %s\n", video_device_node_name(vfd)); @@ -1817,26 +1643,268 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret) { dev_err(dev->mdev.dev, "media device register failed (err=%d)\n", ret); + return ret; + } +#endif + return 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; + unsigned node_type = node_types[inst]; + v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; + unsigned int cec_tx_bus_cnt = 0; + int ret; + int i; + + /* allocate main vivid state structure */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->inst = inst; + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->v4l2_dev.mdev = &dev->mdev; + + /* Initialize media device */ + strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); + snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info), + "platform:%s-%03d", VIVID_MODULE_NAME, inst); + dev->mdev.dev = &pdev->dev; + media_device_init(&dev->mdev); + dev->mdev.ops = &vivid_media_ops; +#endif + + /* 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; + + ret = vivid_detect_feature_set(dev, inst, node_type, + &has_tuner, &has_modulator, + &ccs_cap, &ccs_out, + in_type_counter, out_type_counter); + if (ret) + goto free_dev; + + vivid_set_capabilities(dev); + + ret = -ENOMEM; + /* initialize the test pattern generator */ + tpg_init(&dev->tpg, 640, 360); + if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM))) + goto free_dev; + dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + if (!dev->scaled_line) + goto free_dev; + dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + if (!dev->blended_line) + goto free_dev; + + /* load the edid */ + dev->edid = vmalloc(array_size(256, 128)); + if (!dev->edid) + goto free_dev; + + ret = vivid_init_dv_timings(dev); + if (ret < 0) + goto free_dev; + + vivid_disable_unused_ioctls(dev, has_tuner, has_modulator, + in_type_counter, out_type_counter); + + /* 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_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; + for (i = 0; i < MAX_INPUTS; i++) { + dev->dv_timings_cap[i] = def_dv_timings; + dev->std_cap[i] = V4L2_STD_PAL; + } + 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->sdr_pixelformat = V4L2_SDR_FMT_CU8; + dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; + + dev->edid_max_blocks = dev->edid_blocks = 2; + memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); + dev->radio_rds_init_time = ktime_get(); + + /* 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; + + /* enable/disable interface specific controls */ + if (dev->num_outputs && dev->output_type[0] != HDMI) + v4l2_ctrl_activate(dev->ctrl_display_present, false); + if (dev->num_inputs && dev->input_type[0] != HDMI) { + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_dv_timings, false); + } else if (dev->num_inputs && dev->input_type[0] == HDMI) { + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_standard, false); + } + + /* + * update the capture and output formats to do a proper initial + * configuration. + */ + vivid_update_format_cap(dev, false); + vivid_update_format_out(dev); + + /* 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; + + /* update touch configuration */ + dev->timeperframe_tch_cap.numerator = 1; + dev->timeperframe_tch_cap.denominator = 10; + vivid_set_touch(dev, 0); + + /* 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); + INIT_LIST_HEAD(&dev->meta_cap_active); + INIT_LIST_HEAD(&dev->meta_out_active); + INIT_LIST_HEAD(&dev->touch_cap_active); + + INIT_LIST_HEAD(&dev->cec_work_list); + spin_lock_init(&dev->cec_slock); + /* + * Same as create_singlethread_workqueue, but now I can use the + * string formatting of alloc_ordered_workqueue. + */ + dev->cec_workqueue = alloc_ordered_workqueue("vivid-%03d-cec", + WQ_MEM_RECLAIM, inst); + if (!dev->cec_workqueue) { + ret = -ENOMEM; + goto unreg_dev; + } + + if (allocators[inst] == 1) + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + + ret = vivid_create_queues(dev); + if (ret) + goto unreg_dev; + +#ifdef CONFIG_VIDEO_VIVID_CEC + if (dev->has_vid_cap && in_type_counter[HDMI]) { + struct cec_adapter *adap; + + adap = vivid_cec_alloc_adap(dev, 0, false); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) + goto unreg_dev; + dev->cec_rx_adap = adap; + } + + if (dev->has_vid_out) { + for (i = 0; i < dev->num_outputs; i++) { + struct cec_adapter *adap; + + if (dev->output_type[i] != HDMI) + continue; + + dev->cec_output2bus_map[i] = cec_tx_bus_cnt; + adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) { + for (i = 0; i < dev->num_outputs; i++) + cec_delete_adapter(dev->cec_tx_adap[i]); + goto unreg_dev; + } + + dev->cec_tx_adap[cec_tx_bus_cnt] = adap; + cec_tx_bus_cnt++; + } } #endif + 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); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap); + + /* finally start creating the device nodes */ + ret = vivid_create_devnodes(pdev, dev, inst, cec_tx_bus_cnt, + tvnorms_cap, tvnorms_out, + in_type_counter, out_type_counter); + if (ret) + goto unreg_dev; + /* Now that everything is fine, let's add it to device list */ vivid_devs[inst] = dev; return 0; unreg_dev: - video_unregister_device(&dev->touch_cap_dev); - video_unregister_device(&dev->meta_out_dev); - video_unregister_device(&dev->meta_cap_dev); + vb2_video_unregister_device(&dev->touch_cap_dev); + vb2_video_unregister_device(&dev->meta_out_dev); + vb2_video_unregister_device(&dev->meta_cap_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); + vb2_video_unregister_device(&dev->sdr_cap_dev); + vb2_video_unregister_device(&dev->vbi_out_dev); + vb2_video_unregister_device(&dev->vbi_cap_dev); + vb2_video_unregister_device(&dev->vid_out_dev); + vb2_video_unregister_device(&dev->vid_cap_dev); cec_unregister_adapter(dev->cec_rx_adap); for (i = 0; i < MAX_OUTPUTS; i++) cec_unregister_adapter(dev->cec_tx_adap[i]); @@ -1907,27 +1975,27 @@ static int vivid_remove(struct platform_device *pdev) if (dev->has_vid_cap) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->vid_cap_dev)); - video_unregister_device(&dev->vid_cap_dev); + vb2_video_unregister_device(&dev->vid_cap_dev); } if (dev->has_vid_out) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->vid_out_dev)); - video_unregister_device(&dev->vid_out_dev); + vb2_video_unregister_device(&dev->vid_out_dev); } if (dev->has_vbi_cap) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->vbi_cap_dev)); - video_unregister_device(&dev->vbi_cap_dev); + vb2_video_unregister_device(&dev->vbi_cap_dev); } if (dev->has_vbi_out) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->vbi_out_dev)); - video_unregister_device(&dev->vbi_out_dev); + vb2_video_unregister_device(&dev->vbi_out_dev); } if (dev->has_sdr_cap) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->sdr_cap_dev)); - video_unregister_device(&dev->sdr_cap_dev); + vb2_video_unregister_device(&dev->sdr_cap_dev); } if (dev->has_radio_rx) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", @@ -1948,17 +2016,17 @@ static int vivid_remove(struct platform_device *pdev) if (dev->has_meta_cap) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->meta_cap_dev)); - video_unregister_device(&dev->meta_cap_dev); + vb2_video_unregister_device(&dev->meta_cap_dev); } if (dev->has_meta_out) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->meta_out_dev)); - video_unregister_device(&dev->meta_out_dev); + vb2_video_unregister_device(&dev->meta_out_dev); } if (dev->has_touch_cap) { v4l2_info(&dev->v4l2_dev, "unregistering %s\n", video_device_node_name(&dev->touch_cap_dev)); - video_unregister_device(&dev->touch_cap_dev); + vb2_video_unregister_device(&dev->touch_cap_dev); } cec_unregister_adapter(dev->cec_rx_adap); for (j = 0; j < MAX_OUTPUTS; j++) |