rainshadow-cec.c (8540B)
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 34MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); 35MODULE_DESCRIPTION("RainShadow Tech HDMI CEC driver"); 36MODULE_LICENSE("GPL"); 37 38#define DATA_SIZE 256 39 40struct 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 65static 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 107static 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 169static 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 187static 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 199static 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 212static 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 } 234err: 235 mutex_unlock(&rain->write_lock); 236 return err; 237} 238 239static 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 258static int rain_cec_adap_enable(struct cec_adapter *adap, bool enable) 259{ 260 return 0; 261} 262 263static 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 274static 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 300static 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 306static 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 347close_serio: 348 serio_close(serio); 349delete_adap: 350 cec_delete_adapter(rain->adap); 351 serio_set_drvdata(serio, NULL); 352free_device: 353 kfree(rain); 354 return err; 355} 356 357static 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 367MODULE_DEVICE_TABLE(serio, rain_serio_ids); 368 369static 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 380module_serio_driver(rain_drv);