]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/media/usb/rainshadow-cec/rainshadow-cec.c
treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 55
[linux.git] / drivers / media / usb / rainshadow-cec / rainshadow-cec.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * RainShadow Tech HDMI CEC driver
4  *
5  * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl
6  */
7
8 /*
9  * Notes:
10  *
11  * The higher level protocols are currently disabled. This can be added
12  * later, similar to how this is done for the Pulse Eight CEC driver.
13  *
14  * Documentation of the protocol is available here:
15  *
16  * http://rainshadowtech.com/doc/HDMICECtoUSBandRS232v2.0.pdf
17  */
18
19 #include <linux/completion.h>
20 #include <linux/ctype.h>
21 #include <linux/delay.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/serio.h>
27 #include <linux/slab.h>
28 #include <linux/spinlock.h>
29 #include <linux/time.h>
30 #include <linux/workqueue.h>
31
32 #include <media/cec.h>
33
34 MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
35 MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver");
36 MODULE_LICENSE("GPL");
37
38 #define DATA_SIZE 256
39
40 struct rain {
41         struct device *dev;
42         struct serio *serio;
43         struct cec_adapter *adap;
44         struct completion cmd_done;
45         struct work_struct work;
46
47         /* Low-level ringbuffer, collecting incoming characters */
48         char buf[DATA_SIZE];
49         unsigned int buf_rd_idx;
50         unsigned int buf_wr_idx;
51         unsigned int buf_len;
52         spinlock_t buf_lock;
53
54         /* command buffer */
55         char cmd[DATA_SIZE];
56         unsigned int cmd_idx;
57         bool cmd_started;
58
59         /* reply to a command, only used to store the firmware version */
60         char cmd_reply[DATA_SIZE];
61
62         struct mutex write_lock;
63 };
64
65 static void rain_process_msg(struct rain *rain)
66 {
67         struct cec_msg msg = {};
68         const char *cmd = rain->cmd + 3;
69         int stat = -1;
70
71         for (; *cmd; cmd++) {
72                 if (!isxdigit(*cmd))
73                         continue;
74                 if (isxdigit(cmd[0]) && isxdigit(cmd[1])) {
75                         if (msg.len == CEC_MAX_MSG_SIZE)
76                                 break;
77                         if (hex2bin(msg.msg + msg.len, cmd, 1))
78                                 continue;
79                         msg.len++;
80                         cmd++;
81                         continue;
82                 }
83                 if (!cmd[1])
84                         stat = hex_to_bin(cmd[0]);
85                 break;
86         }
87
88         if (rain->cmd[0] == 'R') {
89                 if (stat == 1 || stat == 2)
90                         cec_received_msg(rain->adap, &msg);
91                 return;
92         }
93
94         switch (stat) {
95         case 1:
96                 cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_OK);
97                 break;
98         case 2:
99                 cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_NACK);
100                 break;
101         default:
102                 cec_transmit_attempt_done(rain->adap, CEC_TX_STATUS_LOW_DRIVE);
103                 break;
104         }
105 }
106
107 static void rain_irq_work_handler(struct work_struct *work)
108 {
109         struct rain *rain =
110                 container_of(work, struct rain, work);
111
112         while (true) {
113                 unsigned long flags;
114                 char data;
115
116                 spin_lock_irqsave(&rain->buf_lock, flags);
117                 if (!rain->buf_len) {
118                         spin_unlock_irqrestore(&rain->buf_lock, flags);
119                         break;
120                 }
121
122                 data = rain->buf[rain->buf_rd_idx];
123                 rain->buf_len--;
124                 rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;
125
126                 spin_unlock_irqrestore(&rain->buf_lock, flags);
127
128                 if (!rain->cmd_started && data != '?')
129                         continue;
130
131                 switch (data) {
132                 case '\r':
133                         rain->cmd[rain->cmd_idx] = '\0';
134                         dev_dbg(rain->dev, "received: %s\n", rain->cmd);
135                         if (!memcmp(rain->cmd, "REC", 3) ||
136                             !memcmp(rain->cmd, "STA", 3)) {
137                                 rain_process_msg(rain);
138                         } else {
139                                 strscpy(rain->cmd_reply, rain->cmd,
140                                         sizeof(rain->cmd_reply));
141                                 complete(&rain->cmd_done);
142                         }
143                         rain->cmd_idx = 0;
144                         rain->cmd_started = false;
145                         break;
146
147                 case '\n':
148                         rain->cmd_idx = 0;
149                         rain->cmd_started = false;
150                         break;
151
152                 case '?':
153                         rain->cmd_idx = 0;
154                         rain->cmd_started = true;
155                         break;
156
157                 default:
158                         if (rain->cmd_idx >= DATA_SIZE - 1) {
159                                 dev_dbg(rain->dev,
160                                         "throwing away %d bytes of garbage\n", rain->cmd_idx);
161                                 rain->cmd_idx = 0;
162                         }
163                         rain->cmd[rain->cmd_idx++] = data;
164                         break;
165                 }
166         }
167 }
168
169 static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data,
170                                     unsigned int flags)
171 {
172         struct rain *rain = serio_get_drvdata(serio);
173
174         if (rain->buf_len == DATA_SIZE) {
175                 dev_warn_once(rain->dev, "buffer overflow\n");
176                 return IRQ_HANDLED;
177         }
178         spin_lock(&rain->buf_lock);
179         rain->buf_len++;
180         rain->buf[rain->buf_wr_idx] = data;
181         rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff;
182         spin_unlock(&rain->buf_lock);
183         schedule_work(&rain->work);
184         return IRQ_HANDLED;
185 }
186
187 static void rain_disconnect(struct serio *serio)
188 {
189         struct rain *rain = serio_get_drvdata(serio);
190
191         cancel_work_sync(&rain->work);
192         cec_unregister_adapter(rain->adap);
193         dev_info(&serio->dev, "disconnected\n");
194         serio_close(serio);
195         serio_set_drvdata(serio, NULL);
196         kfree(rain);
197 }
198
199 static int rain_send(struct rain *rain, const char *command)
200 {
201         int err = serio_write(rain->serio, '!');
202
203         dev_dbg(rain->dev, "send: %s\n", command);
204         while (!err && *command)
205                 err = serio_write(rain->serio, *command++);
206         if (!err)
207                 err = serio_write(rain->serio, '~');
208
209         return err;
210 }
211
212 static int rain_send_and_wait(struct rain *rain,
213                               const char *cmd, const char *reply)
214 {
215         int err;
216
217         init_completion(&rain->cmd_done);
218
219         mutex_lock(&rain->write_lock);
220         err = rain_send(rain, cmd);
221         if (err)
222                 goto err;
223
224         if (!wait_for_completion_timeout(&rain->cmd_done, HZ)) {
225                 err = -ETIMEDOUT;
226                 goto err;
227         }
228         if (reply && strncmp(rain->cmd_reply, reply, strlen(reply))) {
229                 dev_dbg(rain->dev,
230                          "transmit of '%s': received '%s' instead of '%s'\n",
231                          cmd, rain->cmd_reply, reply);
232                 err = -EIO;
233         }
234 err:
235         mutex_unlock(&rain->write_lock);
236         return err;
237 }
238
239 static int rain_setup(struct rain *rain, struct serio *serio,
240                         struct cec_log_addrs *log_addrs, u16 *pa)
241 {
242         int err;
243
244         err = rain_send_and_wait(rain, "R", "REV");
245         if (err)
246                 return err;
247         dev_info(rain->dev, "Firmware version %s\n", rain->cmd_reply + 4);
248
249         err = rain_send_and_wait(rain, "Q 1", "QTY");
250         if (err)
251                 return err;
252         err = rain_send_and_wait(rain, "c0000", "CFG");
253         if (err)
254                 return err;
255         return rain_send_and_wait(rain, "A F 0000", "ADR");
256 }
257
258 static int rain_cec_adap_enable(struct cec_adapter *adap, bool enable)
259 {
260         return 0;
261 }
262
263 static int rain_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
264 {
265         struct rain *rain = cec_get_drvdata(adap);
266         u8 cmd[16];
267
268         if (log_addr == CEC_LOG_ADDR_INVALID)
269                 log_addr = CEC_LOG_ADDR_UNREGISTERED;
270         snprintf(cmd, sizeof(cmd), "A %x", log_addr);
271         return rain_send_and_wait(rain, cmd, "ADR");
272 }
273
274 static int rain_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
275                                     u32 signal_free_time, struct cec_msg *msg)
276 {
277         struct rain *rain = cec_get_drvdata(adap);
278         char cmd[2 * CEC_MAX_MSG_SIZE + 16];
279         unsigned int i;
280         int err;
281
282         if (msg->len == 1) {
283                 snprintf(cmd, sizeof(cmd), "x%x", cec_msg_destination(msg));
284         } else {
285                 char hex[3];
286
287                 snprintf(cmd, sizeof(cmd), "x%x %02x ",
288                          cec_msg_destination(msg), msg->msg[1]);
289                 for (i = 2; i < msg->len; i++) {
290                         snprintf(hex, sizeof(hex), "%02x", msg->msg[i]);
291                         strlcat(cmd, hex, sizeof(cmd));
292                 }
293         }
294         mutex_lock(&rain->write_lock);
295         err = rain_send(rain, cmd);
296         mutex_unlock(&rain->write_lock);
297         return err;
298 }
299
300 static const struct cec_adap_ops rain_cec_adap_ops = {
301         .adap_enable = rain_cec_adap_enable,
302         .adap_log_addr = rain_cec_adap_log_addr,
303         .adap_transmit = rain_cec_adap_transmit,
304 };
305
306 static int rain_connect(struct serio *serio, struct serio_driver *drv)
307 {
308         u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL;
309         struct rain *rain;
310         int err = -ENOMEM;
311         struct cec_log_addrs log_addrs = {};
312         u16 pa = CEC_PHYS_ADDR_INVALID;
313
314         rain = kzalloc(sizeof(*rain), GFP_KERNEL);
315
316         if (!rain)
317                 return -ENOMEM;
318
319         rain->serio = serio;
320         rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain,
321                                           dev_name(&serio->dev), caps, 1);
322         err = PTR_ERR_OR_ZERO(rain->adap);
323         if (err < 0)
324                 goto free_device;
325
326         rain->dev = &serio->dev;
327         serio_set_drvdata(serio, rain);
328         INIT_WORK(&rain->work, rain_irq_work_handler);
329         mutex_init(&rain->write_lock);
330         spin_lock_init(&rain->buf_lock);
331
332         err = serio_open(serio, drv);
333         if (err)
334                 goto delete_adap;
335
336         err = rain_setup(rain, serio, &log_addrs, &pa);
337         if (err)
338                 goto close_serio;
339
340         err = cec_register_adapter(rain->adap, &serio->dev);
341         if (err < 0)
342                 goto close_serio;
343
344         rain->dev = &rain->adap->devnode.dev;
345         return 0;
346
347 close_serio:
348         serio_close(serio);
349 delete_adap:
350         cec_delete_adapter(rain->adap);
351         serio_set_drvdata(serio, NULL);
352 free_device:
353         kfree(rain);
354         return err;
355 }
356
357 static const struct serio_device_id rain_serio_ids[] = {
358         {
359                 .type   = SERIO_RS232,
360                 .proto  = SERIO_RAINSHADOW_CEC,
361                 .id     = SERIO_ANY,
362                 .extra  = SERIO_ANY,
363         },
364         { 0 }
365 };
366
367 MODULE_DEVICE_TABLE(serio, rain_serio_ids);
368
369 static struct serio_driver rain_drv = {
370         .driver         = {
371                 .name   = "rainshadow-cec",
372         },
373         .description    = "RainShadow Tech HDMI CEC driver",
374         .id_table       = rain_serio_ids,
375         .interrupt      = rain_interrupt,
376         .connect        = rain_connect,
377         .disconnect     = rain_disconnect,
378 };
379
380 module_serio_driver(rain_drv);