root/drivers/media/usb/rainshadow-cec/rainshadow-cec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rain_process_msg
  2. rain_irq_work_handler
  3. rain_interrupt
  4. rain_disconnect
  5. rain_send
  6. rain_send_and_wait
  7. rain_setup
  8. rain_cec_adap_enable
  9. rain_cec_adap_log_addr
  10. rain_cec_adap_transmit
  11. rain_connect

   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);

/* [<][>][^][v][top][bottom][index][help] */