Commit c6c709ee authored by Deborah Brouwer's avatar Deborah Brouwer Committed by Mauro Carvalho Chehab

media: vivid: add signal-free time for cec message xfer

Currently, the vivid emulation of cec message transmission does not force
adapters to wait until the cec bus has been signal-free for a certain
number of bit periods before transmitting or re-transmitting a message.
Without enforcing the signal-free time requirements, adapters do not share
the bus very well and some messages are sent too quickly while other
messages are lost. By emulating a signal-free time and forcing adapters
to wait their turn to transmit, the vivid emulation of cec transmission
is much more reliable.
Signed-off-by: default avatarDeborah Brouwer <deborahbrouwer3563@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 695fb9c6
......@@ -9,12 +9,5 @@
struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
unsigned int idx,
bool is_source);
void vivid_cec_bus_free_work(struct vivid_dev *dev);
#else
static inline void vivid_cec_bus_free_work(struct vivid_dev *dev)
{
}
int vivid_cec_bus_thread(void *_dev);
#endif
......@@ -1888,18 +1888,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
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;
}
spin_lock_init(&dev->cec_xfers_slock);
if (allocators[inst] == 1)
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
......@@ -1939,6 +1928,19 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
cec_tx_bus_cnt++;
}
}
if (dev->cec_rx_adap || cec_tx_bus_cnt) {
init_waitqueue_head(&dev->kthread_waitq_cec);
dev->kthread_cec = kthread_run(vivid_cec_bus_thread, dev,
"vivid_cec-%s", dev->v4l2_dev.name);
if (IS_ERR(dev->kthread_cec)) {
dev->kthread_cec = NULL;
v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
ret = PTR_ERR(dev->kthread_cec);
goto unreg_dev;
}
}
#endif
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
......@@ -1978,10 +1980,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
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);
}
if (dev->kthread_cec)
kthread_stop(dev->kthread_cec);
free_dev:
v4l2_device_put(&dev->v4l2_dev);
return ret;
......@@ -2103,10 +2103,8 @@ static int vivid_remove(struct platform_device *pdev)
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);
}
if (dev->kthread_cec)
kthread_stop(dev->kthread_cec);
v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}
......
......@@ -110,15 +110,11 @@ enum vivid_colorspace {
#define VIVID_INVALID_SIGNAL(mode) \
((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
struct vivid_cec_work {
struct list_head list;
struct delayed_work work;
struct vivid_cec_xfer {
struct cec_adapter *adap;
struct vivid_dev *dev;
unsigned int usecs;
unsigned int timeout_ms;
u8 tx_status;
struct cec_msg msg;
u8 msg[CEC_MAX_MSG_SIZE];
u32 len;
u32 sft;
};
struct vivid_dev {
......@@ -560,12 +556,13 @@ struct vivid_dev {
/* CEC */
struct cec_adapter *cec_rx_adap;
struct cec_adapter *cec_tx_adap[MAX_OUTPUTS];
struct workqueue_struct *cec_workqueue;
spinlock_t cec_slock;
struct list_head cec_work_list;
unsigned int cec_xfer_time_jiffies;
unsigned long cec_xfer_start_jiffies;
u8 cec_output2bus_map[MAX_OUTPUTS];
struct task_struct *kthread_cec;
wait_queue_head_t kthread_waitq_cec;
struct vivid_cec_xfer xfers[MAX_OUTPUTS];
spinlock_t cec_xfers_slock; /* read and write cec messages */
u32 cec_sft; /* bus signal free time, in bit periods */
u8 last_initiator;
/* CEC OSD String */
char osd[14];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment