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

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

DEFINITIONS

This source file includes following definitions.
  1. pulse8_irq_work_handler
  2. pulse8_interrupt
  3. pulse8_disconnect
  4. pulse8_send
  5. pulse8_send_and_wait_once
  6. pulse8_send_and_wait
  7. pulse8_setup
  8. pulse8_apply_persistent_config
  9. pulse8_cec_adap_enable
  10. pulse8_cec_adap_log_addr
  11. pulse8_cec_adap_transmit
  12. pulse8_received
  13. pulse8_connect
  14. pulse8_ping_eeprom_work_handler

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Pulse Eight HDMI CEC driver
   4  *
   5  * Copyright 2016 Hans Verkuil <hverkuil@xs4all.nl
   6  */
   7 
   8 /*
   9  * Notes:
  10  *
  11  * - Devices with firmware version < 2 do not store their configuration in
  12  *   EEPROM.
  13  *
  14  * - In autonomous mode, only messages from a TV will be acknowledged, even
  15  *   polling messages. Upon receiving a message from a TV, the dongle will
  16  *   respond to messages from any logical address.
  17  *
  18  * - In autonomous mode, the dongle will by default reply Feature Abort
  19  *   [Unrecognized Opcode] when it receives Give Device Vendor ID. It will
  20  *   however observe vendor ID's reported by other devices and possibly
  21  *   alter this behavior. When TV's (and TV's only) report that their vendor ID
  22  *   is LG (0x00e091), the dongle will itself reply that it has the same vendor
  23  *   ID, and it will respond to at least one vendor specific command.
  24  *
  25  * - In autonomous mode, the dongle is known to attempt wakeup if it receives
  26  *   <User Control Pressed> ["Power On"], ["Power] or ["Power Toggle"], or if it
  27  *   receives <Set Stream Path> with its own physical address. It also does this
  28  *   if it receives <Vendor Specific Command> [0x03 0x00] from an LG TV.
  29  */
  30 
  31 #include <linux/completion.h>
  32 #include <linux/init.h>
  33 #include <linux/interrupt.h>
  34 #include <linux/kernel.h>
  35 #include <linux/module.h>
  36 #include <linux/workqueue.h>
  37 #include <linux/serio.h>
  38 #include <linux/slab.h>
  39 #include <linux/time.h>
  40 #include <linux/delay.h>
  41 
  42 #include <media/cec.h>
  43 
  44 MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
  45 MODULE_DESCRIPTION("Pulse Eight HDMI CEC driver");
  46 MODULE_LICENSE("GPL");
  47 
  48 static int debug;
  49 static int persistent_config;
  50 module_param(debug, int, 0644);
  51 module_param(persistent_config, int, 0644);
  52 MODULE_PARM_DESC(debug, "debug level (0-1)");
  53 MODULE_PARM_DESC(persistent_config, "read config from persistent memory (0-1)");
  54 
  55 enum pulse8_msgcodes {
  56         MSGCODE_NOTHING = 0,
  57         MSGCODE_PING,
  58         MSGCODE_TIMEOUT_ERROR,
  59         MSGCODE_HIGH_ERROR,
  60         MSGCODE_LOW_ERROR,
  61         MSGCODE_FRAME_START,
  62         MSGCODE_FRAME_DATA,
  63         MSGCODE_RECEIVE_FAILED,
  64         MSGCODE_COMMAND_ACCEPTED,       /* 0x08 */
  65         MSGCODE_COMMAND_REJECTED,
  66         MSGCODE_SET_ACK_MASK,
  67         MSGCODE_TRANSMIT,
  68         MSGCODE_TRANSMIT_EOM,
  69         MSGCODE_TRANSMIT_IDLETIME,
  70         MSGCODE_TRANSMIT_ACK_POLARITY,
  71         MSGCODE_TRANSMIT_LINE_TIMEOUT,
  72         MSGCODE_TRANSMIT_SUCCEEDED,     /* 0x10 */
  73         MSGCODE_TRANSMIT_FAILED_LINE,
  74         MSGCODE_TRANSMIT_FAILED_ACK,
  75         MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA,
  76         MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE,
  77         MSGCODE_FIRMWARE_VERSION,
  78         MSGCODE_START_BOOTLOADER,
  79         MSGCODE_GET_BUILDDATE,
  80         MSGCODE_SET_CONTROLLED,         /* 0x18 */
  81         MSGCODE_GET_AUTO_ENABLED,
  82         MSGCODE_SET_AUTO_ENABLED,
  83         MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS,
  84         MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS,
  85         MSGCODE_GET_LOGICAL_ADDRESS_MASK,
  86         MSGCODE_SET_LOGICAL_ADDRESS_MASK,
  87         MSGCODE_GET_PHYSICAL_ADDRESS,
  88         MSGCODE_SET_PHYSICAL_ADDRESS,   /* 0x20 */
  89         MSGCODE_GET_DEVICE_TYPE,
  90         MSGCODE_SET_DEVICE_TYPE,
  91         MSGCODE_GET_HDMI_VERSION,
  92         MSGCODE_SET_HDMI_VERSION,
  93         MSGCODE_GET_OSD_NAME,
  94         MSGCODE_SET_OSD_NAME,
  95         MSGCODE_WRITE_EEPROM,
  96         MSGCODE_GET_ADAPTER_TYPE,       /* 0x28 */
  97         MSGCODE_SET_ACTIVE_SOURCE,
  98 
  99         MSGCODE_FRAME_EOM = 0x80,
 100         MSGCODE_FRAME_ACK = 0x40,
 101 };
 102 
 103 #define MSGSTART        0xff
 104 #define MSGEND          0xfe
 105 #define MSGESC          0xfd
 106 #define MSGOFFSET       3
 107 
 108 #define DATA_SIZE 256
 109 
 110 #define PING_PERIOD     (15 * HZ)
 111 
 112 struct pulse8 {
 113         struct device *dev;
 114         struct serio *serio;
 115         struct cec_adapter *adap;
 116         unsigned int vers;
 117         struct completion cmd_done;
 118         struct work_struct work;
 119         u8 work_result;
 120         struct delayed_work ping_eeprom_work;
 121         struct cec_msg rx_msg;
 122         u8 data[DATA_SIZE];
 123         unsigned int len;
 124         u8 buf[DATA_SIZE];
 125         unsigned int idx;
 126         bool escape;
 127         bool started;
 128         struct mutex config_lock;
 129         struct mutex write_lock;
 130         bool config_pending;
 131         bool restoring_config;
 132         bool autonomous;
 133 };
 134 
 135 static void pulse8_ping_eeprom_work_handler(struct work_struct *work);
 136 
 137 static void pulse8_irq_work_handler(struct work_struct *work)
 138 {
 139         struct pulse8 *pulse8 =
 140                 container_of(work, struct pulse8, work);
 141         u8 result = pulse8->work_result;
 142 
 143         pulse8->work_result = 0;
 144         switch (result & 0x3f) {
 145         case MSGCODE_FRAME_DATA:
 146                 cec_received_msg(pulse8->adap, &pulse8->rx_msg);
 147                 break;
 148         case MSGCODE_TRANSMIT_SUCCEEDED:
 149                 cec_transmit_attempt_done(pulse8->adap, CEC_TX_STATUS_OK);
 150                 break;
 151         case MSGCODE_TRANSMIT_FAILED_ACK:
 152                 cec_transmit_attempt_done(pulse8->adap, CEC_TX_STATUS_NACK);
 153                 break;
 154         case MSGCODE_TRANSMIT_FAILED_LINE:
 155         case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
 156         case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
 157                 cec_transmit_attempt_done(pulse8->adap, CEC_TX_STATUS_ERROR);
 158                 break;
 159         }
 160 }
 161 
 162 static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
 163                                     unsigned int flags)
 164 {
 165         struct pulse8 *pulse8 = serio_get_drvdata(serio);
 166 
 167         if (!pulse8->started && data != MSGSTART)
 168                 return IRQ_HANDLED;
 169         if (data == MSGESC) {
 170                 pulse8->escape = true;
 171                 return IRQ_HANDLED;
 172         }
 173         if (pulse8->escape) {
 174                 data += MSGOFFSET;
 175                 pulse8->escape = false;
 176         } else if (data == MSGEND) {
 177                 struct cec_msg *msg = &pulse8->rx_msg;
 178                 u8 msgcode = pulse8->buf[0];
 179 
 180                 if (debug)
 181                         dev_info(pulse8->dev, "received: %*ph\n",
 182                                  pulse8->idx, pulse8->buf);
 183                 switch (msgcode & 0x3f) {
 184                 case MSGCODE_FRAME_START:
 185                         msg->len = 1;
 186                         msg->msg[0] = pulse8->buf[1];
 187                         break;
 188                 case MSGCODE_FRAME_DATA:
 189                         if (msg->len == CEC_MAX_MSG_SIZE)
 190                                 break;
 191                         msg->msg[msg->len++] = pulse8->buf[1];
 192                         if (msgcode & MSGCODE_FRAME_EOM) {
 193                                 WARN_ON(pulse8->work_result);
 194                                 pulse8->work_result = msgcode;
 195                                 schedule_work(&pulse8->work);
 196                                 break;
 197                         }
 198                         break;
 199                 case MSGCODE_TRANSMIT_SUCCEEDED:
 200                 case MSGCODE_TRANSMIT_FAILED_LINE:
 201                 case MSGCODE_TRANSMIT_FAILED_ACK:
 202                 case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
 203                 case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
 204                         WARN_ON(pulse8->work_result);
 205                         pulse8->work_result = msgcode;
 206                         schedule_work(&pulse8->work);
 207                         break;
 208                 case MSGCODE_HIGH_ERROR:
 209                 case MSGCODE_LOW_ERROR:
 210                 case MSGCODE_RECEIVE_FAILED:
 211                 case MSGCODE_TIMEOUT_ERROR:
 212                         break;
 213                 case MSGCODE_COMMAND_ACCEPTED:
 214                 case MSGCODE_COMMAND_REJECTED:
 215                 default:
 216                         if (pulse8->idx == 0)
 217                                 break;
 218                         memcpy(pulse8->data, pulse8->buf, pulse8->idx);
 219                         pulse8->len = pulse8->idx;
 220                         complete(&pulse8->cmd_done);
 221                         break;
 222                 }
 223                 pulse8->idx = 0;
 224                 pulse8->started = false;
 225                 return IRQ_HANDLED;
 226         } else if (data == MSGSTART) {
 227                 pulse8->idx = 0;
 228                 pulse8->started = true;
 229                 return IRQ_HANDLED;
 230         }
 231 
 232         if (pulse8->idx >= DATA_SIZE) {
 233                 dev_dbg(pulse8->dev,
 234                         "throwing away %d bytes of garbage\n", pulse8->idx);
 235                 pulse8->idx = 0;
 236         }
 237         pulse8->buf[pulse8->idx++] = data;
 238         return IRQ_HANDLED;
 239 }
 240 
 241 static void pulse8_disconnect(struct serio *serio)
 242 {
 243         struct pulse8 *pulse8 = serio_get_drvdata(serio);
 244 
 245         cec_unregister_adapter(pulse8->adap);
 246         cancel_delayed_work_sync(&pulse8->ping_eeprom_work);
 247         dev_info(&serio->dev, "disconnected\n");
 248         serio_close(serio);
 249         serio_set_drvdata(serio, NULL);
 250         kfree(pulse8);
 251 }
 252 
 253 static int pulse8_send(struct serio *serio, const u8 *command, u8 cmd_len)
 254 {
 255         int err = 0;
 256 
 257         err = serio_write(serio, MSGSTART);
 258         if (err)
 259                 return err;
 260         for (; !err && cmd_len; command++, cmd_len--) {
 261                 if (*command >= MSGESC) {
 262                         err = serio_write(serio, MSGESC);
 263                         if (!err)
 264                                 err = serio_write(serio, *command - MSGOFFSET);
 265                 } else {
 266                         err = serio_write(serio, *command);
 267                 }
 268         }
 269         if (!err)
 270                 err = serio_write(serio, MSGEND);
 271 
 272         return err;
 273 }
 274 
 275 static int pulse8_send_and_wait_once(struct pulse8 *pulse8,
 276                                      const u8 *cmd, u8 cmd_len,
 277                                      u8 response, u8 size)
 278 {
 279         int err;
 280 
 281         /*dev_info(pulse8->dev, "transmit: %*ph\n", cmd_len, cmd);*/
 282         init_completion(&pulse8->cmd_done);
 283 
 284         err = pulse8_send(pulse8->serio, cmd, cmd_len);
 285         if (err)
 286                 return err;
 287 
 288         if (!wait_for_completion_timeout(&pulse8->cmd_done, HZ))
 289                 return -ETIMEDOUT;
 290         if ((pulse8->data[0] & 0x3f) == MSGCODE_COMMAND_REJECTED &&
 291             cmd[0] != MSGCODE_SET_CONTROLLED &&
 292             cmd[0] != MSGCODE_SET_AUTO_ENABLED &&
 293             cmd[0] != MSGCODE_GET_BUILDDATE)
 294                 return -ENOTTY;
 295         if (response &&
 296             ((pulse8->data[0] & 0x3f) != response || pulse8->len < size + 1)) {
 297                 dev_info(pulse8->dev, "transmit: failed %02x\n",
 298                          pulse8->data[0] & 0x3f);
 299                 return -EIO;
 300         }
 301         return 0;
 302 }
 303 
 304 static int pulse8_send_and_wait(struct pulse8 *pulse8,
 305                                 const u8 *cmd, u8 cmd_len, u8 response, u8 size)
 306 {
 307         u8 cmd_sc[2];
 308         int err;
 309 
 310         mutex_lock(&pulse8->write_lock);
 311         err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len, response, size);
 312 
 313         if (err == -ENOTTY) {
 314                 cmd_sc[0] = MSGCODE_SET_CONTROLLED;
 315                 cmd_sc[1] = 1;
 316                 err = pulse8_send_and_wait_once(pulse8, cmd_sc, 2,
 317                                                 MSGCODE_COMMAND_ACCEPTED, 1);
 318                 if (err)
 319                         goto unlock;
 320                 err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len,
 321                                                 response, size);
 322         }
 323 
 324 unlock:
 325         mutex_unlock(&pulse8->write_lock);
 326         return err == -ENOTTY ? -EIO : err;
 327 }
 328 
 329 static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
 330                         struct cec_log_addrs *log_addrs, u16 *pa)
 331 {
 332         u8 *data = pulse8->data + 1;
 333         u8 cmd[2];
 334         int err;
 335         struct tm tm;
 336         time64_t date;
 337 
 338         pulse8->vers = 0;
 339 
 340         cmd[0] = MSGCODE_FIRMWARE_VERSION;
 341         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2);
 342         if (err)
 343                 return err;
 344         pulse8->vers = (data[0] << 8) | data[1];
 345         dev_info(pulse8->dev, "Firmware version %04x\n", pulse8->vers);
 346         if (pulse8->vers < 2) {
 347                 *pa = CEC_PHYS_ADDR_INVALID;
 348                 return 0;
 349         }
 350 
 351         cmd[0] = MSGCODE_GET_BUILDDATE;
 352         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4);
 353         if (err)
 354                 return err;
 355         date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
 356         time64_to_tm(date, 0, &tm);
 357         dev_info(pulse8->dev, "Firmware build date %04ld.%02d.%02d %02d:%02d:%02d\n",
 358                  tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
 359                  tm.tm_hour, tm.tm_min, tm.tm_sec);
 360 
 361         dev_dbg(pulse8->dev, "Persistent config:\n");
 362         cmd[0] = MSGCODE_GET_AUTO_ENABLED;
 363         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
 364         if (err)
 365                 return err;
 366         pulse8->autonomous = data[0];
 367         dev_dbg(pulse8->dev, "Autonomous mode: %s",
 368                 data[0] ? "on" : "off");
 369 
 370         cmd[0] = MSGCODE_GET_DEVICE_TYPE;
 371         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
 372         if (err)
 373                 return err;
 374         log_addrs->primary_device_type[0] = data[0];
 375         dev_dbg(pulse8->dev, "Primary device type: %d\n", data[0]);
 376         switch (log_addrs->primary_device_type[0]) {
 377         case CEC_OP_PRIM_DEVTYPE_TV:
 378                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV;
 379                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TV;
 380                 break;
 381         case CEC_OP_PRIM_DEVTYPE_RECORD:
 382                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_RECORD;
 383                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_RECORD;
 384                 break;
 385         case CEC_OP_PRIM_DEVTYPE_TUNER:
 386                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TUNER;
 387                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TUNER;
 388                 break;
 389         case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
 390                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK;
 391                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_PLAYBACK;
 392                 break;
 393         case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
 394                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK;
 395                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
 396                 break;
 397         case CEC_OP_PRIM_DEVTYPE_SWITCH:
 398                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
 399                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH;
 400                 break;
 401         case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
 402                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_SPECIFIC;
 403                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH;
 404                 break;
 405         default:
 406                 log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
 407                 log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH;
 408                 dev_info(pulse8->dev, "Unknown Primary Device Type: %d\n",
 409                          log_addrs->primary_device_type[0]);
 410                 break;
 411         }
 412 
 413         cmd[0] = MSGCODE_GET_LOGICAL_ADDRESS_MASK;
 414         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2);
 415         if (err)
 416                 return err;
 417         log_addrs->log_addr_mask = (data[0] << 8) | data[1];
 418         dev_dbg(pulse8->dev, "Logical address ACK mask: %x\n",
 419                 log_addrs->log_addr_mask);
 420         if (log_addrs->log_addr_mask)
 421                 log_addrs->num_log_addrs = 1;
 422 
 423         cmd[0] = MSGCODE_GET_PHYSICAL_ADDRESS;
 424         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
 425         if (err)
 426                 return err;
 427         *pa = (data[0] << 8) | data[1];
 428         dev_dbg(pulse8->dev, "Physical address: %x.%x.%x.%x\n",
 429                 cec_phys_addr_exp(*pa));
 430 
 431         cmd[0] = MSGCODE_GET_HDMI_VERSION;
 432         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1);
 433         if (err)
 434                 return err;
 435         log_addrs->cec_version = data[0];
 436         dev_dbg(pulse8->dev, "CEC version: %d\n", log_addrs->cec_version);
 437 
 438         cmd[0] = MSGCODE_GET_OSD_NAME;
 439         err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0);
 440         if (err)
 441                 return err;
 442         strscpy(log_addrs->osd_name, data, sizeof(log_addrs->osd_name));
 443         dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name);
 444 
 445         return 0;
 446 }
 447 
 448 static int pulse8_apply_persistent_config(struct pulse8 *pulse8,
 449                                           struct cec_log_addrs *log_addrs,
 450                                           u16 pa)
 451 {
 452         int err;
 453 
 454         err = cec_s_log_addrs(pulse8->adap, log_addrs, false);
 455         if (err)
 456                 return err;
 457 
 458         cec_s_phys_addr(pulse8->adap, pa, false);
 459 
 460         return 0;
 461 }
 462 
 463 static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable)
 464 {
 465         struct pulse8 *pulse8 = cec_get_drvdata(adap);
 466         u8 cmd[16];
 467         int err;
 468 
 469         cmd[0] = MSGCODE_SET_CONTROLLED;
 470         cmd[1] = enable;
 471         err = pulse8_send_and_wait(pulse8, cmd, 2,
 472                                    MSGCODE_COMMAND_ACCEPTED, 1);
 473         return enable ? err : 0;
 474 }
 475 
 476 static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
 477 {
 478         struct pulse8 *pulse8 = cec_get_drvdata(adap);
 479         u16 mask = 0;
 480         u16 pa = adap->phys_addr;
 481         u8 cmd[16];
 482         int err = 0;
 483 
 484         mutex_lock(&pulse8->config_lock);
 485         if (log_addr != CEC_LOG_ADDR_INVALID)
 486                 mask = 1 << log_addr;
 487         cmd[0] = MSGCODE_SET_ACK_MASK;
 488         cmd[1] = mask >> 8;
 489         cmd[2] = mask & 0xff;
 490         err = pulse8_send_and_wait(pulse8, cmd, 3,
 491                                    MSGCODE_COMMAND_ACCEPTED, 0);
 492         if ((err && mask != 0) || pulse8->restoring_config)
 493                 goto unlock;
 494 
 495         cmd[0] = MSGCODE_SET_AUTO_ENABLED;
 496         cmd[1] = log_addr == CEC_LOG_ADDR_INVALID ? 0 : 1;
 497         err = pulse8_send_and_wait(pulse8, cmd, 2,
 498                                    MSGCODE_COMMAND_ACCEPTED, 0);
 499         if (err)
 500                 goto unlock;
 501         pulse8->autonomous = cmd[1];
 502         if (log_addr == CEC_LOG_ADDR_INVALID)
 503                 goto unlock;
 504 
 505         cmd[0] = MSGCODE_SET_DEVICE_TYPE;
 506         cmd[1] = adap->log_addrs.primary_device_type[0];
 507         err = pulse8_send_and_wait(pulse8, cmd, 2,
 508                                    MSGCODE_COMMAND_ACCEPTED, 0);
 509         if (err)
 510                 goto unlock;
 511 
 512         switch (adap->log_addrs.primary_device_type[0]) {
 513         case CEC_OP_PRIM_DEVTYPE_TV:
 514                 mask = CEC_LOG_ADDR_MASK_TV;
 515                 break;
 516         case CEC_OP_PRIM_DEVTYPE_RECORD:
 517                 mask = CEC_LOG_ADDR_MASK_RECORD;
 518                 break;
 519         case CEC_OP_PRIM_DEVTYPE_TUNER:
 520                 mask = CEC_LOG_ADDR_MASK_TUNER;
 521                 break;
 522         case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
 523                 mask = CEC_LOG_ADDR_MASK_PLAYBACK;
 524                 break;
 525         case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
 526                 mask = CEC_LOG_ADDR_MASK_AUDIOSYSTEM;
 527                 break;
 528         case CEC_OP_PRIM_DEVTYPE_SWITCH:
 529                 mask = CEC_LOG_ADDR_MASK_UNREGISTERED;
 530                 break;
 531         case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
 532                 mask = CEC_LOG_ADDR_MASK_SPECIFIC;
 533                 break;
 534         default:
 535                 mask = 0;
 536                 break;
 537         }
 538         cmd[0] = MSGCODE_SET_LOGICAL_ADDRESS_MASK;
 539         cmd[1] = mask >> 8;
 540         cmd[2] = mask & 0xff;
 541         err = pulse8_send_and_wait(pulse8, cmd, 3,
 542                                    MSGCODE_COMMAND_ACCEPTED, 0);
 543         if (err)
 544                 goto unlock;
 545 
 546         cmd[0] = MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS;
 547         cmd[1] = log_addr;
 548         err = pulse8_send_and_wait(pulse8, cmd, 2,
 549                                    MSGCODE_COMMAND_ACCEPTED, 0);
 550         if (err)
 551                 goto unlock;
 552 
 553         cmd[0] = MSGCODE_SET_PHYSICAL_ADDRESS;
 554         cmd[1] = pa >> 8;
 555         cmd[2] = pa & 0xff;
 556         err = pulse8_send_and_wait(pulse8, cmd, 3,
 557                                    MSGCODE_COMMAND_ACCEPTED, 0);
 558         if (err)
 559                 goto unlock;
 560 
 561         cmd[0] = MSGCODE_SET_HDMI_VERSION;
 562         cmd[1] = adap->log_addrs.cec_version;
 563         err = pulse8_send_and_wait(pulse8, cmd, 2,
 564                                    MSGCODE_COMMAND_ACCEPTED, 0);
 565         if (err)
 566                 goto unlock;
 567 
 568         if (adap->log_addrs.osd_name[0]) {
 569                 size_t osd_len = strlen(adap->log_addrs.osd_name);
 570                 char *osd_str = cmd + 1;
 571 
 572                 cmd[0] = MSGCODE_SET_OSD_NAME;
 573                 strscpy(cmd + 1, adap->log_addrs.osd_name, sizeof(cmd) - 1);
 574                 if (osd_len < 4) {
 575                         memset(osd_str + osd_len, ' ', 4 - osd_len);
 576                         osd_len = 4;
 577                         osd_str[osd_len] = '\0';
 578                         strscpy(adap->log_addrs.osd_name, osd_str,
 579                                 sizeof(adap->log_addrs.osd_name));
 580                 }
 581                 err = pulse8_send_and_wait(pulse8, cmd, 1 + osd_len,
 582                                            MSGCODE_COMMAND_ACCEPTED, 0);
 583                 if (err)
 584                         goto unlock;
 585         }
 586 
 587 unlock:
 588         if (pulse8->restoring_config)
 589                 pulse8->restoring_config = false;
 590         else
 591                 pulse8->config_pending = true;
 592         mutex_unlock(&pulse8->config_lock);
 593         return log_addr == CEC_LOG_ADDR_INVALID ? 0 : err;
 594 }
 595 
 596 static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
 597                                     u32 signal_free_time, struct cec_msg *msg)
 598 {
 599         struct pulse8 *pulse8 = cec_get_drvdata(adap);
 600         u8 cmd[2];
 601         unsigned int i;
 602         int err;
 603 
 604         cmd[0] = MSGCODE_TRANSMIT_IDLETIME;
 605         cmd[1] = signal_free_time;
 606         err = pulse8_send_and_wait(pulse8, cmd, 2,
 607                                    MSGCODE_COMMAND_ACCEPTED, 1);
 608         cmd[0] = MSGCODE_TRANSMIT_ACK_POLARITY;
 609         cmd[1] = cec_msg_is_broadcast(msg);
 610         if (!err)
 611                 err = pulse8_send_and_wait(pulse8, cmd, 2,
 612                                            MSGCODE_COMMAND_ACCEPTED, 1);
 613         cmd[0] = msg->len == 1 ? MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT;
 614         cmd[1] = msg->msg[0];
 615         if (!err)
 616                 err = pulse8_send_and_wait(pulse8, cmd, 2,
 617                                            MSGCODE_COMMAND_ACCEPTED, 1);
 618         if (!err && msg->len > 1) {
 619                 cmd[0] = msg->len == 2 ? MSGCODE_TRANSMIT_EOM :
 620                                          MSGCODE_TRANSMIT;
 621                 cmd[1] = msg->msg[1];
 622                 err = pulse8_send_and_wait(pulse8, cmd, 2,
 623                                            MSGCODE_COMMAND_ACCEPTED, 1);
 624                 for (i = 0; !err && i + 2 < msg->len; i++) {
 625                         cmd[0] = (i + 2 == msg->len - 1) ?
 626                                 MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT;
 627                         cmd[1] = msg->msg[i + 2];
 628                         err = pulse8_send_and_wait(pulse8, cmd, 2,
 629                                                    MSGCODE_COMMAND_ACCEPTED, 1);
 630                 }
 631         }
 632 
 633         return err;
 634 }
 635 
 636 static int pulse8_received(struct cec_adapter *adap, struct cec_msg *msg)
 637 {
 638         return -ENOMSG;
 639 }
 640 
 641 static const struct cec_adap_ops pulse8_cec_adap_ops = {
 642         .adap_enable = pulse8_cec_adap_enable,
 643         .adap_log_addr = pulse8_cec_adap_log_addr,
 644         .adap_transmit = pulse8_cec_adap_transmit,
 645         .received = pulse8_received,
 646 };
 647 
 648 static int pulse8_connect(struct serio *serio, struct serio_driver *drv)
 649 {
 650         u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | CEC_CAP_MONITOR_ALL;
 651         struct pulse8 *pulse8;
 652         int err = -ENOMEM;
 653         struct cec_log_addrs log_addrs = {};
 654         u16 pa = CEC_PHYS_ADDR_INVALID;
 655 
 656         pulse8 = kzalloc(sizeof(*pulse8), GFP_KERNEL);
 657 
 658         if (!pulse8)
 659                 return -ENOMEM;
 660 
 661         pulse8->serio = serio;
 662         pulse8->adap = cec_allocate_adapter(&pulse8_cec_adap_ops, pulse8,
 663                                             dev_name(&serio->dev), caps, 1);
 664         err = PTR_ERR_OR_ZERO(pulse8->adap);
 665         if (err < 0)
 666                 goto free_device;
 667 
 668         pulse8->dev = &serio->dev;
 669         serio_set_drvdata(serio, pulse8);
 670         INIT_WORK(&pulse8->work, pulse8_irq_work_handler);
 671         mutex_init(&pulse8->write_lock);
 672         mutex_init(&pulse8->config_lock);
 673         pulse8->config_pending = false;
 674 
 675         err = serio_open(serio, drv);
 676         if (err)
 677                 goto delete_adap;
 678 
 679         err = pulse8_setup(pulse8, serio, &log_addrs, &pa);
 680         if (err)
 681                 goto close_serio;
 682 
 683         err = cec_register_adapter(pulse8->adap, &serio->dev);
 684         if (err < 0)
 685                 goto close_serio;
 686 
 687         pulse8->dev = &pulse8->adap->devnode.dev;
 688 
 689         if (persistent_config && pulse8->autonomous) {
 690                 err = pulse8_apply_persistent_config(pulse8, &log_addrs, pa);
 691                 if (err)
 692                         goto close_serio;
 693                 pulse8->restoring_config = true;
 694         }
 695 
 696         INIT_DELAYED_WORK(&pulse8->ping_eeprom_work,
 697                           pulse8_ping_eeprom_work_handler);
 698         schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
 699 
 700         return 0;
 701 
 702 close_serio:
 703         serio_close(serio);
 704 delete_adap:
 705         cec_delete_adapter(pulse8->adap);
 706         serio_set_drvdata(serio, NULL);
 707 free_device:
 708         kfree(pulse8);
 709         return err;
 710 }
 711 
 712 static void pulse8_ping_eeprom_work_handler(struct work_struct *work)
 713 {
 714         struct pulse8 *pulse8 =
 715                 container_of(work, struct pulse8, ping_eeprom_work.work);
 716         u8 cmd;
 717 
 718         schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD);
 719         cmd = MSGCODE_PING;
 720         pulse8_send_and_wait(pulse8, &cmd, 1,
 721                              MSGCODE_COMMAND_ACCEPTED, 0);
 722 
 723         if (pulse8->vers < 2)
 724                 return;
 725 
 726         mutex_lock(&pulse8->config_lock);
 727         if (pulse8->config_pending && persistent_config) {
 728                 dev_dbg(pulse8->dev, "writing pending config to EEPROM\n");
 729                 cmd = MSGCODE_WRITE_EEPROM;
 730                 if (pulse8_send_and_wait(pulse8, &cmd, 1,
 731                                          MSGCODE_COMMAND_ACCEPTED, 0))
 732                         dev_info(pulse8->dev, "failed to write pending config to EEPROM\n");
 733                 else
 734                         pulse8->config_pending = false;
 735         }
 736         mutex_unlock(&pulse8->config_lock);
 737 }
 738 
 739 static const struct serio_device_id pulse8_serio_ids[] = {
 740         {
 741                 .type   = SERIO_RS232,
 742                 .proto  = SERIO_PULSE8_CEC,
 743                 .id     = SERIO_ANY,
 744                 .extra  = SERIO_ANY,
 745         },
 746         { 0 }
 747 };
 748 
 749 MODULE_DEVICE_TABLE(serio, pulse8_serio_ids);
 750 
 751 static struct serio_driver pulse8_drv = {
 752         .driver         = {
 753                 .name   = "pulse8-cec",
 754         },
 755         .description    = "Pulse Eight HDMI CEC driver",
 756         .id_table       = pulse8_serio_ids,
 757         .interrupt      = pulse8_interrupt,
 758         .connect        = pulse8_connect,
 759         .disconnect     = pulse8_disconnect,
 760 };
 761 
 762 module_serio_driver(pulse8_drv);

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