Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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