Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / platform / vivid / vivid-cec.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * vivid-cec.c - A Virtual Video Test Driver, cec emulation
4  *
5  * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6  */
7
8 #include <media/cec.h>
9
10 #include "vivid-core.h"
11 #include "vivid-cec.h"
12
13 #define CEC_TIM_START_BIT_TOTAL         4500
14 #define CEC_TIM_START_BIT_LOW           3700
15 #define CEC_TIM_START_BIT_HIGH          800
16 #define CEC_TIM_DATA_BIT_TOTAL          2400
17 #define CEC_TIM_DATA_BIT_0_LOW          1500
18 #define CEC_TIM_DATA_BIT_0_HIGH         900
19 #define CEC_TIM_DATA_BIT_1_LOW          600
20 #define CEC_TIM_DATA_BIT_1_HIGH         1800
21
22 void vivid_cec_bus_free_work(struct vivid_dev *dev)
23 {
24         spin_lock(&dev->cec_slock);
25         while (!list_empty(&dev->cec_work_list)) {
26                 struct vivid_cec_work *cw =
27                         list_first_entry(&dev->cec_work_list,
28                                          struct vivid_cec_work, list);
29
30                 spin_unlock(&dev->cec_slock);
31                 cancel_delayed_work_sync(&cw->work);
32                 spin_lock(&dev->cec_slock);
33                 list_del(&cw->list);
34                 cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE);
35                 kfree(cw);
36         }
37         spin_unlock(&dev->cec_slock);
38 }
39
40 static bool vivid_cec_find_dest_adap(struct vivid_dev *dev,
41                                      struct cec_adapter *adap, u8 dest)
42 {
43         unsigned int i;
44
45         if (dest >= 0xf)
46                 return false;
47
48         if (adap != dev->cec_rx_adap && dev->cec_rx_adap &&
49             dev->cec_rx_adap->is_configured &&
50             cec_has_log_addr(dev->cec_rx_adap, dest))
51                 return true;
52
53         for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
54                 if (adap == dev->cec_tx_adap[i])
55                         continue;
56                 if (!dev->cec_tx_adap[i]->is_configured)
57                         continue;
58                 if (cec_has_log_addr(dev->cec_tx_adap[i], dest))
59                         return true;
60         }
61         return false;
62 }
63
64 static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts,
65                                       const struct cec_msg *msg, bool nacked)
66 {
67         unsigned int len = nacked ? 1 : msg->len;
68         unsigned int i;
69         bool bit;
70
71         if (adap == NULL)
72                 return;
73
74         /*
75          * Suffix ULL on constant 10 makes the expression
76          * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL
77          * to be evaluated using 64-bit unsigned arithmetic (u64), which
78          * is what ktime_sub_us expects as second argument.
79          */
80         ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL +
81                                10ULL * len * CEC_TIM_DATA_BIT_TOTAL);
82         cec_queue_pin_cec_event(adap, false, false, ts);
83         ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW);
84         cec_queue_pin_cec_event(adap, true, false, ts);
85         ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH);
86
87         for (i = 0; i < 10 * len; i++) {
88                 switch (i % 10) {
89                 case 0 ... 7:
90                         bit = msg->msg[i / 10] & (0x80 >> (i % 10));
91                         break;
92                 case 8: /* EOM */
93                         bit = i / 10 == msg->len - 1;
94                         break;
95                 case 9: /* ACK */
96                         bit = cec_msg_is_broadcast(msg) ^ nacked;
97                         break;
98                 }
99                 cec_queue_pin_cec_event(adap, false, false, ts);
100                 if (bit)
101                         ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW);
102                 else
103                         ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW);
104                 cec_queue_pin_cec_event(adap, true, false, ts);
105                 if (bit)
106                         ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH);
107                 else
108                         ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH);
109         }
110 }
111
112 static void vivid_cec_pin_events(struct vivid_dev *dev,
113                                  const struct cec_msg *msg, bool nacked)
114 {
115         ktime_t ts = ktime_get();
116         unsigned int i;
117
118         vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked);
119         for (i = 0; i < MAX_OUTPUTS; i++)
120                 vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked);
121 }
122
123 static void vivid_cec_xfer_done_worker(struct work_struct *work)
124 {
125         struct vivid_cec_work *cw =
126                 container_of(work, struct vivid_cec_work, work.work);
127         struct vivid_dev *dev = cw->dev;
128         struct cec_adapter *adap = cw->adap;
129         u8 dest = cec_msg_destination(&cw->msg);
130         bool valid_dest;
131         unsigned int i;
132
133         valid_dest = cec_msg_is_broadcast(&cw->msg);
134         if (!valid_dest)
135                 valid_dest = vivid_cec_find_dest_adap(dev, adap, dest);
136
137         cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK;
138         spin_lock(&dev->cec_slock);
139         dev->cec_xfer_time_jiffies = 0;
140         dev->cec_xfer_start_jiffies = 0;
141         list_del(&cw->list);
142         spin_unlock(&dev->cec_slock);
143         vivid_cec_pin_events(dev, &cw->msg, !valid_dest);
144         cec_transmit_attempt_done(cw->adap, cw->tx_status);
145
146         /* Broadcast message */
147         if (adap != dev->cec_rx_adap)
148                 cec_received_msg(dev->cec_rx_adap, &cw->msg);
149         for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
150                 if (adap != dev->cec_tx_adap[i])
151                         cec_received_msg(dev->cec_tx_adap[i], &cw->msg);
152         kfree(cw);
153 }
154
155 static void vivid_cec_xfer_try_worker(struct work_struct *work)
156 {
157         struct vivid_cec_work *cw =
158                 container_of(work, struct vivid_cec_work, work.work);
159         struct vivid_dev *dev = cw->dev;
160
161         spin_lock(&dev->cec_slock);
162         if (dev->cec_xfer_time_jiffies) {
163                 list_del(&cw->list);
164                 spin_unlock(&dev->cec_slock);
165                 cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_ARB_LOST);
166                 kfree(cw);
167         } else {
168                 INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
169                 dev->cec_xfer_start_jiffies = jiffies;
170                 dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
171                 spin_unlock(&dev->cec_slock);
172                 schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies);
173         }
174 }
175
176 static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
177 {
178         adap->cec_pin_is_high = true;
179         return 0;
180 }
181
182 static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
183 {
184         return 0;
185 }
186
187 /*
188  * One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us
189  * per byte.
190  */
191 #define USECS_PER_BYTE 24000
192
193 static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
194                                    u32 signal_free_time, struct cec_msg *msg)
195 {
196         struct vivid_dev *dev = cec_get_drvdata(adap);
197         struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL);
198         long delta_jiffies = 0;
199
200         if (cw == NULL)
201                 return -ENOMEM;
202         cw->dev = dev;
203         cw->adap = adap;
204         cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) +
205                     msg->len * USECS_PER_BYTE;
206         cw->msg = *msg;
207
208         spin_lock(&dev->cec_slock);
209         list_add(&cw->list, &dev->cec_work_list);
210         if (dev->cec_xfer_time_jiffies == 0) {
211                 INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
212                 dev->cec_xfer_start_jiffies = jiffies;
213                 dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
214                 delta_jiffies = dev->cec_xfer_time_jiffies;
215         } else {
216                 INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker);
217                 delta_jiffies = dev->cec_xfer_start_jiffies +
218                         dev->cec_xfer_time_jiffies - jiffies;
219         }
220         spin_unlock(&dev->cec_slock);
221         schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies);
222         return 0;
223 }
224
225 static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
226 {
227         struct vivid_dev *dev = cec_get_drvdata(adap);
228         struct cec_msg reply;
229         u8 dest = cec_msg_destination(msg);
230         u8 disp_ctl;
231         char osd[14];
232
233         if (cec_msg_is_broadcast(msg))
234                 dest = adap->log_addrs.log_addr[0];
235         cec_msg_init(&reply, dest, cec_msg_initiator(msg));
236
237         switch (cec_msg_opcode(msg)) {
238         case CEC_MSG_SET_OSD_STRING:
239                 if (!cec_is_sink(adap))
240                         return -ENOMSG;
241                 cec_ops_set_osd_string(msg, &disp_ctl, osd);
242                 switch (disp_ctl) {
243                 case CEC_OP_DISP_CTL_DEFAULT:
244                         strscpy(dev->osd, osd, sizeof(dev->osd));
245                         dev->osd_jiffies = jiffies;
246                         break;
247                 case CEC_OP_DISP_CTL_UNTIL_CLEARED:
248                         strscpy(dev->osd, osd, sizeof(dev->osd));
249                         dev->osd_jiffies = 0;
250                         break;
251                 case CEC_OP_DISP_CTL_CLEAR:
252                         dev->osd[0] = 0;
253                         dev->osd_jiffies = 0;
254                         break;
255                 default:
256                         cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
257                                               CEC_OP_ABORT_INVALID_OP);
258                         cec_transmit_msg(adap, &reply, false);
259                         break;
260                 }
261                 break;
262         default:
263                 return -ENOMSG;
264         }
265         return 0;
266 }
267
268 static const struct cec_adap_ops vivid_cec_adap_ops = {
269         .adap_enable = vivid_cec_adap_enable,
270         .adap_log_addr = vivid_cec_adap_log_addr,
271         .adap_transmit = vivid_cec_adap_transmit,
272         .received = vivid_received,
273 };
274
275 struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
276                                          unsigned int idx,
277                                          bool is_source)
278 {
279         char name[sizeof(dev->vid_out_dev.name) + 2];
280         u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN;
281
282         snprintf(name, sizeof(name), "%s%d",
283                  is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name,
284                  idx);
285         return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
286                 name, caps, 1);
287 }