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 @@ ...@@ -9,12 +9,5 @@
struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
unsigned int idx, unsigned int idx,
bool is_source); bool is_source);
void vivid_cec_bus_free_work(struct vivid_dev *dev); int vivid_cec_bus_thread(void *_dev);
#else
static inline void vivid_cec_bus_free_work(struct vivid_dev *dev)
{
}
#endif #endif
...@@ -1888,18 +1888,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -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->meta_out_active);
INIT_LIST_HEAD(&dev->touch_cap_active); INIT_LIST_HEAD(&dev->touch_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list); spin_lock_init(&dev->cec_xfers_slock);
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) if (allocators[inst] == 1)
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); 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) ...@@ -1939,6 +1928,19 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
cec_tx_bus_cnt++; 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 #endif
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
...@@ -1978,10 +1980,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) ...@@ -1978,10 +1980,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
cec_unregister_adapter(dev->cec_rx_adap); cec_unregister_adapter(dev->cec_rx_adap);
for (i = 0; i < MAX_OUTPUTS; i++) for (i = 0; i < MAX_OUTPUTS; i++)
cec_unregister_adapter(dev->cec_tx_adap[i]); cec_unregister_adapter(dev->cec_tx_adap[i]);
if (dev->cec_workqueue) { if (dev->kthread_cec)
vivid_cec_bus_free_work(dev); kthread_stop(dev->kthread_cec);
destroy_workqueue(dev->cec_workqueue);
}
free_dev: free_dev:
v4l2_device_put(&dev->v4l2_dev); v4l2_device_put(&dev->v4l2_dev);
return ret; return ret;
...@@ -2103,10 +2103,8 @@ static int vivid_remove(struct platform_device *pdev) ...@@ -2103,10 +2103,8 @@ static int vivid_remove(struct platform_device *pdev)
cec_unregister_adapter(dev->cec_rx_adap); cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++) for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]); cec_unregister_adapter(dev->cec_tx_adap[j]);
if (dev->cec_workqueue) { if (dev->kthread_cec)
vivid_cec_bus_free_work(dev); kthread_stop(dev->kthread_cec);
destroy_workqueue(dev->cec_workqueue);
}
v4l2_device_put(&dev->v4l2_dev); v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL; vivid_devs[i] = NULL;
} }
......
...@@ -110,15 +110,11 @@ enum vivid_colorspace { ...@@ -110,15 +110,11 @@ enum vivid_colorspace {
#define VIVID_INVALID_SIGNAL(mode) \ #define VIVID_INVALID_SIGNAL(mode) \
((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE) ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
struct vivid_cec_work { struct vivid_cec_xfer {
struct list_head list;
struct delayed_work work;
struct cec_adapter *adap; struct cec_adapter *adap;
struct vivid_dev *dev; u8 msg[CEC_MAX_MSG_SIZE];
unsigned int usecs; u32 len;
unsigned int timeout_ms; u32 sft;
u8 tx_status;
struct cec_msg msg;
}; };
struct vivid_dev { struct vivid_dev {
...@@ -560,12 +556,13 @@ struct vivid_dev { ...@@ -560,12 +556,13 @@ struct vivid_dev {
/* CEC */ /* CEC */
struct cec_adapter *cec_rx_adap; struct cec_adapter *cec_rx_adap;
struct cec_adapter *cec_tx_adap[MAX_OUTPUTS]; 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]; 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 */ /* CEC OSD String */
char osd[14]; 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