2 * RainShadow Tech HDMI CEC driver
4 * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version of 2 of the License, or (at your
9 * option) any later version. See the file COPYING in the main directory of
10 * this archive for more details.
16 * The higher level protocols are currently disabled. This can be added
17 * later, similar to how this is done for the Pulse Eight CEC driver.
19 * Documentation of the protocol is available here:
21 * http://rainshadowtech.com/doc/HDMICECtoUSBandRS232v2.0.pdf
24 #include <linux/completion.h>
25 #include <linux/ctype.h>
26 #include <linux/delay.h>
27 #include <linux/init.h>
28 #include <linux/interrupt.h>
29 #include <linux/kernel.h>
30 #include <linux/module.h>
31 #include <linux/serio.h>
32 #include <linux/slab.h>
33 #include <linux/spinlock.h>
34 #include <linux/time.h>
35 #include <linux/workqueue.h>
37 #include <media/cec.h>
39 MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
40 MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver");
41 MODULE_LICENSE("GPL");
48 struct cec_adapter *adap;
49 struct completion cmd_done;
50 struct work_struct work;
52 /* Low-level ringbuffer, collecting incoming characters */
54 unsigned int buf_rd_idx;
55 unsigned int buf_wr_idx;
64 /* reply to a command, only used to store the firmware version */
65 char cmd_reply[DATA_SIZE];
67 struct mutex write_lock;
70 static void rain_process_msg(struct rain *rain)
72 struct cec_msg msg = {};
73 const char *cmd = rain->cmd + 3;
79 if (isxdigit(cmd[0]) && isxdigit(cmd[1])) {
80 if (msg.len == CEC_MAX_MSG_SIZE)
82 if (hex2bin(msg.msg + msg.len, cmd, 1))
89 stat = hex_to_bin(cmd[0]);
93 if (rain->cmd[0] == 'R') {
94 if (stat == 1 || stat == 2)
95 cec_received_msg(rain->adap, &msg);
101 cec_transmit_done(rain->adap, CEC_TX_STATUS_OK,
105 cec_transmit_done(rain->adap, CEC_TX_STATUS_NACK,
109 cec_transmit_done(rain->adap, CEC_TX_STATUS_LOW_DRIVE,
115 static void rain_irq_work_handler(struct work_struct *work)
118 container_of(work, struct rain, work);
122 bool exit_loop = false;
125 spin_lock_irqsave(&rain->buf_lock, flags);
126 exit_loop = rain->buf_len == 0;
128 data = rain->buf[rain->buf_rd_idx];
130 rain->buf_rd_idx = (rain->buf_rd_idx + 1) & 0xff;
132 spin_unlock_irqrestore(&rain->buf_lock, flags);
137 if (!rain->cmd_started && data != '?')
142 rain->cmd[rain->cmd_idx] = '\0';
143 dev_dbg(rain->dev, "received: %s\n", rain->cmd);
144 if (!memcmp(rain->cmd, "REC", 3) ||
145 !memcmp(rain->cmd, "STA", 3)) {
146 rain_process_msg(rain);
148 strcpy(rain->cmd_reply, rain->cmd);
149 complete(&rain->cmd_done);
152 rain->cmd_started = false;
157 rain->cmd_started = false;
162 rain->cmd_started = true;
166 if (rain->cmd_idx >= DATA_SIZE - 1) {
168 "throwing away %d bytes of garbage\n", rain->cmd_idx);
171 rain->cmd[rain->cmd_idx++] = data;
177 static irqreturn_t rain_interrupt(struct serio *serio, unsigned char data,
180 struct rain *rain = serio_get_drvdata(serio);
182 if (rain->buf_len == DATA_SIZE) {
183 dev_warn_once(rain->dev, "buffer overflow\n");
186 spin_lock(&rain->buf_lock);
188 rain->buf[rain->buf_wr_idx] = data;
189 rain->buf_wr_idx = (rain->buf_wr_idx + 1) & 0xff;
190 spin_unlock(&rain->buf_lock);
191 schedule_work(&rain->work);
195 static void rain_disconnect(struct serio *serio)
197 struct rain *rain = serio_get_drvdata(serio);
199 cancel_work_sync(&rain->work);
200 cec_unregister_adapter(rain->adap);
201 dev_info(&serio->dev, "disconnected\n");
203 serio_set_drvdata(serio, NULL);
207 static int rain_send(struct rain *rain, const char *command)
209 int err = serio_write(rain->serio, '!');
211 dev_dbg(rain->dev, "send: %s\n", command);
212 while (!err && *command)
213 err = serio_write(rain->serio, *command++);
215 err = serio_write(rain->serio, '~');
220 static int rain_send_and_wait(struct rain *rain,
221 const char *cmd, const char *reply)
225 init_completion(&rain->cmd_done);
227 mutex_lock(&rain->write_lock);
228 err = rain_send(rain, cmd);
232 if (!wait_for_completion_timeout(&rain->cmd_done, HZ)) {
236 if (reply && strncmp(rain->cmd_reply, reply, strlen(reply))) {
238 "transmit of '%s': received '%s' instead of '%s'\n",
239 cmd, rain->cmd_reply, reply);
243 mutex_unlock(&rain->write_lock);
247 static int rain_setup(struct rain *rain, struct serio *serio,
248 struct cec_log_addrs *log_addrs, u16 *pa)
252 err = rain_send_and_wait(rain, "R", "REV");
255 dev_info(rain->dev, "Firmware version %s\n", rain->cmd_reply + 4);
257 err = rain_send_and_wait(rain, "Q 1", "QTY");
260 err = rain_send_and_wait(rain, "c0000", "CFG");
263 return rain_send_and_wait(rain, "A F 0000", "ADR");
266 static int rain_cec_adap_enable(struct cec_adapter *adap, bool enable)
271 static int rain_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
273 struct rain *rain = cec_get_drvdata(adap);
276 if (log_addr == CEC_LOG_ADDR_INVALID)
277 log_addr = CEC_LOG_ADDR_UNREGISTERED;
278 snprintf(cmd, sizeof(cmd), "A %x", log_addr);
279 return rain_send_and_wait(rain, cmd, "ADR");
282 static int rain_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
283 u32 signal_free_time, struct cec_msg *msg)
285 struct rain *rain = cec_get_drvdata(adap);
286 char cmd[2 * CEC_MAX_MSG_SIZE + 16];
291 snprintf(cmd, sizeof(cmd), "x%x", cec_msg_destination(msg));
295 snprintf(cmd, sizeof(cmd), "x%x %02x ",
296 cec_msg_destination(msg), msg->msg[1]);
297 for (i = 2; i < msg->len; i++) {
298 snprintf(hex, sizeof(hex), "%02x", msg->msg[i]);
299 strncat(cmd, hex, sizeof(cmd));
302 mutex_lock(&rain->write_lock);
303 err = rain_send(rain, cmd);
304 mutex_unlock(&rain->write_lock);
308 static const struct cec_adap_ops rain_cec_adap_ops = {
309 .adap_enable = rain_cec_adap_enable,
310 .adap_log_addr = rain_cec_adap_log_addr,
311 .adap_transmit = rain_cec_adap_transmit,
314 static int rain_connect(struct serio *serio, struct serio_driver *drv)
316 u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR |
317 CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL;
320 struct cec_log_addrs log_addrs = {};
321 u16 pa = CEC_PHYS_ADDR_INVALID;
323 rain = kzalloc(sizeof(*rain), GFP_KERNEL);
329 rain->adap = cec_allocate_adapter(&rain_cec_adap_ops, rain,
330 "HDMI CEC", caps, 1);
331 err = PTR_ERR_OR_ZERO(rain->adap);
335 rain->dev = &serio->dev;
336 serio_set_drvdata(serio, rain);
337 INIT_WORK(&rain->work, rain_irq_work_handler);
338 mutex_init(&rain->write_lock);
339 spin_lock_init(&rain->buf_lock);
341 err = serio_open(serio, drv);
345 err = rain_setup(rain, serio, &log_addrs, &pa);
349 err = cec_register_adapter(rain->adap, &serio->dev);
353 rain->dev = &rain->adap->devnode.dev;
359 cec_delete_adapter(rain->adap);
360 serio_set_drvdata(serio, NULL);
366 static struct serio_device_id rain_serio_ids[] = {
369 .proto = SERIO_RAINSHADOW_CEC,
376 MODULE_DEVICE_TABLE(serio, rain_serio_ids);
378 static struct serio_driver rain_drv = {
380 .name = "rainshadow-cec",
382 .description = "RainShadow Tech HDMI CEC driver",
383 .id_table = rain_serio_ids,
384 .interrupt = rain_interrupt,
385 .connect = rain_connect,
386 .disconnect = rain_disconnect,
389 module_serio_driver(rain_drv);