aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/vivid/vivid-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/vivid/vivid-core.c')
-rw-r--r--drivers/media/platform/vivid/vivid-core.c118
1 files changed, 109 insertions, 9 deletions
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index c14da84af09b..7f937136c3f5 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -46,6 +46,7 @@
#include "vivid-vbi-cap.h"
#include "vivid-vbi-out.h"
#include "vivid-osd.h"
+#include "vivid-cec.h"
#include "vivid-ctrls.h"
#define VIVID_MODULE_NAME "vivid"
@@ -684,6 +685,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
}
dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];
+ if (in_type_counter[HDMI] == 16) {
+ /* The CEC physical address only allows for max 15 inputs */
+ in_type_counter[HDMI]--;
+ dev->num_inputs--;
+ }
/* how many outputs do we have and of what type? */
dev->num_outputs = num_outputs[inst];
@@ -696,6 +702,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
}
dev->has_audio_outputs = out_type_counter[SVID];
+ if (out_type_counter[HDMI] == 16) {
+ /*
+ * The CEC physical address only allows for max 15 inputs,
+ * so outputs are also limited to 15 to allow for easy
+ * CEC output to input mapping.
+ */
+ out_type_counter[HDMI]--;
+ dev->num_outputs--;
+ }
/* do we create a video capture device? */
dev->has_vid_cap = node_type & 0x0001;
@@ -1010,6 +1025,17 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->vbi_out_active);
INIT_LIST_HEAD(&dev->sdr_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)
+ goto unreg_dev;
+
/* start creating the vb2 queues */
if (dev->has_vid_cap) {
/* initialize vid_cap queue */
@@ -1117,7 +1143,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* 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));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vid-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->vid_cap_caps;
@@ -1133,6 +1160,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ if (in_type_counter[HDMI]) {
+ struct cec_adapter *adap;
+
+ adap = vivid_cec_alloc_adap(dev, 0, &pdev->dev, false);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0)
+ goto unreg_dev;
+ dev->cec_rx_adap = adap;
+ ret = cec_register_adapter(adap);
+ if (ret < 0) {
+ cec_delete_adapter(adap);
+ dev->cec_rx_adap = NULL;
+ goto unreg_dev;
+ }
+ cec_s_phys_addr(adap, 0, false);
+ v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input %d\n",
+ dev_name(&adap->devnode.dev), i);
+ }
+#endif
+
ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
if (ret < 0)
goto unreg_dev;
@@ -1141,8 +1189,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
}
if (dev->has_vid_out) {
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ unsigned int bus_cnt = 0;
+#endif
+
vfd = &dev->vid_out_dev;
- strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vid-out", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
@@ -1159,6 +1212,35 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ for (i = 0; i < dev->num_outputs; i++) {
+ struct cec_adapter *adap;
+
+ if (dev->output_type[i] != HDMI)
+ continue;
+ dev->cec_output2bus_map[i] = bus_cnt;
+ adap = vivid_cec_alloc_adap(dev, bus_cnt,
+ &pdev->dev, true);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0)
+ goto unreg_dev;
+ dev->cec_tx_adap[bus_cnt] = adap;
+ ret = cec_register_adapter(adap);
+ if (ret < 0) {
+ cec_delete_adapter(adap);
+ dev->cec_tx_adap[bus_cnt] = NULL;
+ goto unreg_dev;
+ }
+ bus_cnt++;
+ if (bus_cnt <= out_type_counter[HDMI])
+ cec_s_phys_addr(adap, bus_cnt << 12, false);
+ else
+ cec_s_phys_addr(adap, 0x1000, false);
+ v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
+ dev_name(&adap->devnode.dev), i);
+ }
+#endif
+
ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
if (ret < 0)
goto unreg_dev;
@@ -1168,7 +1250,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_vbi_cap) {
vfd = &dev->vbi_cap_dev;
- strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vbi-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->vbi_cap_caps;
@@ -1191,7 +1274,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_vbi_out) {
vfd = &dev->vbi_out_dev;
- strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-vbi-out", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
@@ -1215,7 +1299,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_sdr_cap) {
vfd = &dev->sdr_cap_dev;
- strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-sdr-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->sdr_cap_caps;
@@ -1234,7 +1319,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_radio_rx) {
vfd = &dev->radio_rx_dev;
- strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-rad-rx", inst);
vfd->fops = &vivid_radio_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->radio_rx_caps;
@@ -1252,7 +1338,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_radio_tx) {
vfd = &dev->radio_tx_dev;
- strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
+ snprintf(vfd->name, sizeof(vfd->name),
+ "vivid-%03d-rad-tx", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_radio_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
@@ -1282,6 +1369,13 @@ unreg_dev:
video_unregister_device(&dev->vbi_cap_dev);
video_unregister_device(&dev->vid_out_dev);
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]);
+ if (dev->cec_workqueue) {
+ vivid_cec_bus_free_work(dev);
+ destroy_workqueue(dev->cec_workqueue);
+ }
free_dev:
v4l2_device_put(&dev->v4l2_dev);
return ret;
@@ -1331,8 +1425,7 @@ static int vivid_probe(struct platform_device *pdev)
static int vivid_remove(struct platform_device *pdev)
{
struct vivid_dev *dev;
- unsigned i;
-
+ unsigned int i, j;
for (i = 0; i < n_devs; i++) {
dev = vivid_devs[i];
@@ -1380,6 +1473,13 @@ static int vivid_remove(struct platform_device *pdev)
unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev);
}
+ cec_unregister_adapter(dev->cec_rx_adap);
+ for (j = 0; j < MAX_OUTPUTS; j++)
+ cec_unregister_adapter(dev->cec_tx_adap[j]);
+ if (dev->cec_workqueue) {
+ vivid_cec_bus_free_work(dev);
+ destroy_workqueue(dev->cec_workqueue);
+ }
v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}