1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021-2023 Val Packett <val@packett.cool> 5 * Copyright (c) 2023 Vladimir Kondratyev <wulf@FreeBSD.org> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "opt_hid.h" 30 #include "opt_spi.h" 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/crc16.h> 35 #include <sys/endian.h> 36 #include <sys/kdb.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/mutex.h> 40 #include <sys/module.h> 41 #include <sys/proc.h> 42 #include <sys/rman.h> 43 #include <sys/sysctl.h> 44 #include <sys/sx.h> 45 #include <sys/taskqueue.h> 46 47 #include <dev/backlight/backlight.h> 48 49 #include <dev/evdev/input.h> 50 51 #define HID_DEBUG_VAR atopcase_debug 52 #include <dev/hid/hid.h> 53 #include <dev/hid/hidquirk.h> 54 55 #include <dev/spibus/spi.h> 56 #include <dev/spibus/spibusvar.h> 57 58 #include "spibus_if.h" 59 60 #include "atopcase_reg.h" 61 #include "atopcase_var.h" 62 63 #define ATOPCASE_IN_KDB() (SCHEDULER_STOPPED() || kdb_active) 64 #define ATOPCASE_IN_POLLING_MODE(sc) \ 65 (((sc)->sc_gpe_bit == 0 && ((sc)->sc_irq_ih == NULL)) || cold ||\ 66 ATOPCASE_IN_KDB()) 67 #define ATOPCASE_WAKEUP(sc, chan) do { \ 68 if (!ATOPCASE_IN_POLLING_MODE(sc)) { \ 69 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "wakeup: %p\n", chan); \ 70 wakeup(chan); \ 71 } \ 72 } while (0) 73 #define ATOPCASE_SPI_PAUSE() DELAY(100) 74 #define ATOPCASE_SPI_NO_SLEEP_FLAG(sc) \ 75 ((sc)->sc_irq_ih != NULL ? SPI_FLAG_NO_SLEEP : 0) 76 77 /* Tunables */ 78 static SYSCTL_NODE(_hw_hid, OID_AUTO, atopcase, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 79 "Apple MacBook Topcase HID driver"); 80 81 #ifdef HID_DEBUG 82 enum atopcase_log_level atopcase_debug = ATOPCASE_LLEVEL_DISABLED; 83 84 SYSCTL_INT(_hw_hid_atopcase, OID_AUTO, debug, CTLFLAG_RWTUN, 85 &atopcase_debug, ATOPCASE_LLEVEL_DISABLED, "atopcase log level"); 86 #endif /* !HID_DEBUG */ 87 88 static const uint8_t booted[] = { 0xa0, 0x80, 0x00, 0x00 }; 89 static const uint8_t status_ok[] = { 0xac, 0x27, 0x68, 0xd5 }; 90 91 static inline struct atopcase_child * 92 atopcase_get_child_by_device(struct atopcase_softc *sc, uint8_t device) 93 { 94 switch (device) { 95 case ATOPCASE_DEV_KBRD: 96 return (&sc->sc_kb); 97 case ATOPCASE_DEV_TPAD: 98 return (&sc->sc_tp); 99 default: 100 return (NULL); 101 } 102 } 103 104 static int 105 atopcase_receive_status(struct atopcase_softc *sc) 106 { 107 struct spi_command cmd = SPI_COMMAND_INITIALIZER; 108 uint8_t dummy_buffer[4] = { 0 }; 109 uint8_t status_buffer[4] = { 0 }; 110 int err; 111 112 cmd.tx_cmd = dummy_buffer; 113 cmd.tx_cmd_sz = sizeof(dummy_buffer); 114 cmd.rx_cmd = status_buffer; 115 cmd.rx_cmd_sz = sizeof(status_buffer); 116 cmd.flags = ATOPCASE_SPI_NO_SLEEP_FLAG(sc); 117 118 err = SPIBUS_TRANSFER(device_get_parent(sc->sc_dev), sc->sc_dev, &cmd); 119 ATOPCASE_SPI_PAUSE(); 120 if (err) { 121 device_printf(sc->sc_dev, "SPI error: %d\n", err); 122 return (err); 123 } 124 125 DPRINTFN(ATOPCASE_LLEVEL_TRACE, "Status: %*D\n", 4, status_buffer, " "); 126 127 if (memcmp(status_buffer, status_ok, sizeof(status_ok)) == 0) { 128 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Wrote command\n"); 129 ATOPCASE_WAKEUP(sc, sc->sc_dev); 130 } else { 131 device_printf(sc->sc_dev, "Failed to write command\n"); 132 return (EIO); 133 } 134 135 return (0); 136 } 137 138 static int 139 atopcase_process_message(struct atopcase_softc *sc, uint8_t device, void *msg, 140 uint16_t msg_len) 141 { 142 struct atopcase_header *hdr = msg; 143 struct atopcase_child *ac; 144 void *payload; 145 uint16_t pl_len, crc; 146 147 payload = (uint8_t *)msg + sizeof(*hdr); 148 pl_len = le16toh(hdr->len); 149 150 if (pl_len + sizeof(*hdr) + sizeof(crc) != msg_len) { 151 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 152 "message with length overflow\n"); 153 return (EIO); 154 } 155 156 crc = le16toh(*(uint16_t *)((uint8_t *)payload + pl_len)); 157 if (crc != crc16(0, msg, msg_len - sizeof(crc))) { 158 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 159 "message with failed checksum\n"); 160 return (EIO); 161 } 162 163 #define CPOFF(dst, len, off) do { \ 164 unsigned _len = le16toh(len); \ 165 unsigned _off = le16toh(off); \ 166 if (pl_len >= _len + _off) { \ 167 memcpy(dst, (uint8_t*)payload + _off, MIN(_len, sizeof(dst)));\ 168 (dst)[MIN(_len, sizeof(dst) - 1)] = '\0'; \ 169 }} while (0); 170 171 if ((ac = atopcase_get_child_by_device(sc, device)) != NULL 172 && hdr->type == ATOPCASE_MSG_TYPE_REPORT(device)) { 173 if (ac->open) 174 ac->intr_handler(ac->intr_ctx, payload, pl_len); 175 } else if (device == ATOPCASE_DEV_INFO 176 && hdr->type == ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_IFACE) 177 && (ac = atopcase_get_child_by_device(sc, hdr->type_arg)) != NULL) { 178 struct atopcase_iface_info_payload *iface = payload; 179 CPOFF(ac->name, iface->name_len, iface->name_off); 180 DPRINTF("Interface #%d name: %s\n", ac->device, ac->name); 181 } else if (device == ATOPCASE_DEV_INFO 182 && hdr->type == ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_DESCRIPTOR) 183 && (ac = atopcase_get_child_by_device(sc, hdr->type_arg)) != NULL) { 184 memcpy(ac->rdesc, payload, pl_len); 185 ac->rdesc_len = ac->hw.rdescsize = pl_len; 186 DPRINTF("%s HID report descriptor: %*D\n", ac->name, 187 (int) ac->hw.rdescsize, ac->rdesc, " "); 188 } else if (device == ATOPCASE_DEV_INFO 189 && hdr->type == ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_DEVICE) 190 && hdr->type_arg == ATOPCASE_INFO_DEVICE) { 191 struct atopcase_device_info_payload *dev = payload; 192 sc->sc_vid = le16toh(dev->vid); 193 sc->sc_pid = le16toh(dev->pid); 194 sc->sc_ver = le16toh(dev->ver); 195 CPOFF(sc->sc_vendor, dev->vendor_len, dev->vendor_off); 196 CPOFF(sc->sc_product, dev->product_len, dev->product_off); 197 CPOFF(sc->sc_serial, dev->serial_len, dev->serial_off); 198 if (bootverbose) { 199 device_printf(sc->sc_dev, "Device info descriptor:\n"); 200 printf(" Vendor: %s\n", sc->sc_vendor); 201 printf(" Product: %s\n", sc->sc_product); 202 printf(" Serial: %s\n", sc->sc_serial); 203 } 204 } 205 206 return (0); 207 } 208 209 int 210 atopcase_receive_packet(struct atopcase_softc *sc) 211 { 212 struct atopcase_packet pkt = { 0 }; 213 struct spi_command cmd = SPI_COMMAND_INITIALIZER; 214 void *msg; 215 int err; 216 uint16_t length, remaining, offset, msg_len; 217 218 bzero(&sc->sc_junk, sizeof(struct atopcase_packet)); 219 cmd.tx_cmd = &sc->sc_junk; 220 cmd.tx_cmd_sz = sizeof(struct atopcase_packet); 221 cmd.rx_cmd = &pkt; 222 cmd.rx_cmd_sz = sizeof(struct atopcase_packet); 223 cmd.flags = ATOPCASE_SPI_NO_SLEEP_FLAG(sc); 224 err = SPIBUS_TRANSFER(device_get_parent(sc->sc_dev), sc->sc_dev, &cmd); 225 ATOPCASE_SPI_PAUSE(); 226 if (err) { 227 device_printf(sc->sc_dev, "SPI error: %d\n", err); 228 return (err); 229 } 230 231 DPRINTFN(ATOPCASE_LLEVEL_TRACE, "Response: %*D\n", 256, &pkt, " "); 232 233 if (le16toh(pkt.checksum) != crc16(0, &pkt, sizeof(pkt) - 2)) { 234 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "packet with failed checksum\n"); 235 return (EIO); 236 } 237 238 /* 239 * When we poll and nothing has arrived we get a particular packet 240 * starting with '80 11 00 01' 241 */ 242 if (pkt.direction == ATOPCASE_DIR_NOTHING) { 243 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "'Nothing' packet: %*D\n", 4, 244 &pkt, " "); 245 return (EAGAIN); 246 } 247 248 if (pkt.direction != ATOPCASE_DIR_READ && 249 pkt.direction != ATOPCASE_DIR_WRITE) { 250 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 251 "unknown message direction 0x%x\n", pkt.direction); 252 return (EIO); 253 } 254 255 length = le16toh(pkt.length); 256 remaining = le16toh(pkt.remaining); 257 offset = le16toh(pkt.offset); 258 259 if (length > sizeof(pkt.data)) { 260 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 261 "packet with length overflow: %u\n", length); 262 return (EIO); 263 } 264 265 if (pkt.direction == ATOPCASE_DIR_READ && 266 pkt.device == ATOPCASE_DEV_INFO && 267 length == sizeof(booted) && 268 memcmp(pkt.data, booted, length) == 0) { 269 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "GPE boot packet\n"); 270 sc->sc_booted = true; 271 ATOPCASE_WAKEUP(sc, sc); 272 return (0); 273 } 274 275 /* handle multi-packet messages */ 276 if (remaining != 0 || offset != 0) { 277 if (offset != sc->sc_msg_len) { 278 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 279 "Unexpected offset (got %u, expected %u)\n", 280 offset, sc->sc_msg_len); 281 sc->sc_msg_len = 0; 282 return (EIO); 283 } 284 285 if ((size_t)remaining + length + offset > sizeof(sc->sc_msg)) { 286 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, 287 "Message with length overflow: %zu\n", 288 (size_t)remaining + length + offset); 289 sc->sc_msg_len = 0; 290 return (EIO); 291 } 292 293 memcpy(sc->sc_msg + offset, &pkt.data, length); 294 sc->sc_msg_len += length; 295 296 if (remaining != 0) 297 return (0); 298 299 msg = sc->sc_msg; 300 msg_len = sc->sc_msg_len; 301 } else { 302 msg = pkt.data; 303 msg_len = length; 304 } 305 sc->sc_msg_len = 0; 306 307 err = atopcase_process_message(sc, pkt.device, msg, msg_len); 308 if (err == 0 && pkt.direction == ATOPCASE_DIR_WRITE) { 309 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Write ack\n"); 310 ATOPCASE_WAKEUP(sc, sc); 311 } 312 313 return (err); 314 } 315 316 static int 317 atopcase_send(struct atopcase_softc *sc, struct atopcase_packet *pkt) 318 { 319 struct spi_command cmd = SPI_COMMAND_INITIALIZER; 320 int err, retries; 321 322 cmd.tx_cmd = pkt; 323 cmd.tx_cmd_sz = sizeof(struct atopcase_packet); 324 cmd.rx_cmd = &sc->sc_junk; 325 cmd.rx_cmd_sz = sizeof(struct atopcase_packet); 326 cmd.flags = SPI_FLAG_KEEP_CS | ATOPCASE_SPI_NO_SLEEP_FLAG(sc); 327 328 DPRINTFN(ATOPCASE_LLEVEL_TRACE, "Request: %*D\n", 329 (int)sizeof(struct atopcase_packet), cmd.tx_cmd, " "); 330 331 if (!ATOPCASE_IN_POLLING_MODE(sc)) { 332 if (sc->sc_irq_ih != NULL) 333 mtx_lock(&sc->sc_mtx); 334 else 335 sx_xlock(&sc->sc_sx); 336 } 337 sc->sc_wait_for_status = true; 338 err = SPIBUS_TRANSFER(device_get_parent(sc->sc_dev), sc->sc_dev, &cmd); 339 ATOPCASE_SPI_PAUSE(); 340 if (!ATOPCASE_IN_POLLING_MODE(sc)) { 341 if (sc->sc_irq_ih != NULL) 342 mtx_unlock(&sc->sc_mtx); 343 else 344 sx_xunlock(&sc->sc_sx); 345 } 346 if (err != 0) { 347 device_printf(sc->sc_dev, "SPI error: %d\n", err); 348 goto exit; 349 } 350 351 if (ATOPCASE_IN_POLLING_MODE(sc)) { 352 err = atopcase_receive_status(sc); 353 } else { 354 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "wait for: %p\n", sc->sc_dev); 355 err = tsleep(sc->sc_dev, 0, "atcstat", hz / 10); 356 } 357 sc->sc_wait_for_status = false; 358 if (err != 0) { 359 DPRINTF("Write status read failed: %d\n", err); 360 goto exit; 361 } 362 363 if (ATOPCASE_IN_POLLING_MODE(sc)) { 364 /* Backlight setting may require a lot of time */ 365 retries = 20; 366 while ((err = atopcase_receive_packet(sc)) == EAGAIN && 367 --retries != 0) 368 DELAY(1000); 369 } else { 370 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "wait for: %p\n", sc); 371 err = tsleep(sc, 0, "atcack", hz / 10); 372 } 373 if (err != 0) 374 DPRINTF("Write ack read failed: %d\n", err); 375 376 exit: 377 if (err == EWOULDBLOCK) 378 err = EIO; 379 380 return (err); 381 } 382 383 static void 384 atopcase_create_message(struct atopcase_packet *pkt, uint8_t device, 385 uint16_t type, uint8_t type_arg, const void *payload, uint8_t len, 386 uint16_t resp_len) 387 { 388 struct atopcase_header *hdr = (struct atopcase_header *)pkt->data; 389 uint16_t msg_checksum; 390 static uint8_t seq_no; 391 392 KASSERT(len <= ATOPCASE_DATA_SIZE - sizeof(struct atopcase_header), 393 ("outgoing msg must be 1 packet")); 394 395 bzero(pkt, sizeof(struct atopcase_packet)); 396 pkt->direction = ATOPCASE_DIR_WRITE; 397 pkt->device = device; 398 pkt->length = htole16(sizeof(*hdr) + len + 2); 399 400 hdr->type = htole16(type); 401 hdr->type_arg = type_arg; 402 hdr->seq_no = seq_no++; 403 hdr->resp_len = htole16((resp_len == 0) ? len : resp_len); 404 hdr->len = htole16(len); 405 406 memcpy(pkt->data + sizeof(*hdr), payload, len); 407 msg_checksum = htole16(crc16(0, pkt->data, pkt->length - 2)); 408 memcpy(pkt->data + sizeof(*hdr) + len, &msg_checksum, 2); 409 pkt->checksum = htole16(crc16(0, (uint8_t*)pkt, sizeof(*pkt) - 2)); 410 411 return; 412 } 413 414 static int 415 atopcase_request_desc(struct atopcase_softc *sc, uint16_t type, uint8_t device) 416 { 417 atopcase_create_message( 418 &sc->sc_buf, ATOPCASE_DEV_INFO, type, device, NULL, 0, 0x200); 419 return (atopcase_send(sc, &sc->sc_buf)); 420 } 421 422 int 423 atopcase_intr(struct atopcase_softc *sc) 424 { 425 int err; 426 427 DPRINTFN(ATOPCASE_LLEVEL_DEBUG, "Interrupt event\n"); 428 429 if (sc->sc_wait_for_status) { 430 err = atopcase_receive_status(sc); 431 sc->sc_wait_for_status = false; 432 } else 433 err = atopcase_receive_packet(sc); 434 435 return (err); 436 } 437 438 static int 439 atopcase_add_child(struct atopcase_softc *sc, struct atopcase_child *ac, 440 uint8_t device) 441 { 442 device_t hidbus; 443 int err = 0; 444 445 ac->device = device; 446 447 /* fill device info */ 448 strlcpy(ac->hw.name, "Apple MacBook", sizeof(ac->hw.name)); 449 ac->hw.idBus = BUS_SPI; 450 ac->hw.idVendor = sc->sc_vid; 451 ac->hw.idProduct = sc->sc_pid; 452 ac->hw.idVersion = sc->sc_ver; 453 strlcpy(ac->hw.idPnP, sc->sc_hid, sizeof(ac->hw.idPnP)); 454 strlcpy(ac->hw.serial, sc->sc_serial, sizeof(ac->hw.serial)); 455 /* 456 * HID write and set_report methods executed on Apple SPI topcase 457 * hardware do the same request on SPI layer. Set HQ_NOWRITE quirk to 458 * force hidmap to convert writes to set_reports. That makes HID bus 459 * write handler unnecessary and reduces code duplication. 460 */ 461 hid_add_dynamic_quirk(&ac->hw, HQ_NOWRITE); 462 463 DPRINTF("Get the interface #%d descriptor\n", device); 464 err = atopcase_request_desc(sc, 465 ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_IFACE), device); 466 if (err) { 467 device_printf(sc->sc_dev, "can't receive iface descriptor\n"); 468 goto exit; 469 } 470 471 DPRINTF("Get the \"%s\" HID report descriptor\n", ac->name); 472 err = atopcase_request_desc(sc, 473 ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_DESCRIPTOR), device); 474 if (err) { 475 device_printf(sc->sc_dev, "can't receive report descriptor\n"); 476 goto exit; 477 } 478 479 hidbus = device_add_child(sc->sc_dev, "hidbus", -1); 480 if (hidbus == NULL) { 481 device_printf(sc->sc_dev, "can't add child\n"); 482 err = ENOMEM; 483 goto exit; 484 } 485 device_set_ivars(hidbus, &ac->hw); 486 ac->hidbus = hidbus; 487 488 exit: 489 return (err); 490 } 491 492 int 493 atopcase_init(struct atopcase_softc *sc) 494 { 495 int err; 496 497 /* Wait until we know we're getting reasonable responses */ 498 if(!sc->sc_booted && tsleep(sc, 0, "atcboot", hz / 20) != 0) { 499 device_printf(sc->sc_dev, "can't establish communication\n"); 500 err = EIO; 501 goto err; 502 } 503 504 /* 505 * Management device may send a message on first boot after power off. 506 * Let interrupt handler to read and discard it. 507 */ 508 DELAY(2000); 509 510 DPRINTF("Get the device descriptor\n"); 511 err = atopcase_request_desc(sc, 512 ATOPCASE_MSG_TYPE_INFO(ATOPCASE_INFO_DEVICE), 513 ATOPCASE_INFO_DEVICE); 514 if (err) { 515 device_printf(sc->sc_dev, "can't receive device descriptor\n"); 516 goto err; 517 } 518 519 err = atopcase_add_child(sc, &sc->sc_kb, ATOPCASE_DEV_KBRD); 520 if (err != 0) 521 goto err; 522 err = atopcase_add_child(sc, &sc->sc_tp, ATOPCASE_DEV_TPAD); 523 if (err != 0) 524 goto err; 525 526 /* TODO: skip on 2015 models where it's controlled by asmc */ 527 sc->sc_backlight = backlight_register("atopcase", sc->sc_dev); 528 if (!sc->sc_backlight) { 529 device_printf(sc->sc_dev, "can't register backlight\n"); 530 err = ENOMEM; 531 } 532 533 if (sc->sc_tq != NULL) 534 taskqueue_enqueue_timeout(sc->sc_tq, &sc->sc_task, hz / 120); 535 536 return (bus_generic_attach(sc->sc_dev)); 537 538 err: 539 return (err); 540 } 541 542 int 543 atopcase_destroy(struct atopcase_softc *sc) 544 { 545 int err; 546 547 err = device_delete_children(sc->sc_dev); 548 if (err) 549 return (err); 550 551 if (sc->sc_backlight) 552 backlight_destroy(sc->sc_backlight); 553 554 return (0); 555 } 556 557 static struct atopcase_child * 558 atopcase_get_child_by_hidbus(device_t child) 559 { 560 device_t parent = device_get_parent(child); 561 struct atopcase_softc *sc = device_get_softc(parent); 562 563 if (child == sc->sc_kb.hidbus) 564 return (&sc->sc_kb); 565 if (child == sc->sc_tp.hidbus) 566 return (&sc->sc_tp); 567 panic("unknown child"); 568 } 569 570 void 571 atopcase_intr_setup(device_t dev, device_t child, hid_intr_t intr, 572 void *context, struct hid_rdesc_info *rdesc) 573 { 574 struct atopcase_child *ac = atopcase_get_child_by_hidbus(child); 575 576 if (intr == NULL) 577 return; 578 579 rdesc->rdsize = ATOPCASE_MSG_SIZE - sizeof(struct atopcase_header) - 2; 580 rdesc->grsize = 0; 581 rdesc->srsize = ATOPCASE_DATA_SIZE - sizeof(struct atopcase_header) - 2; 582 rdesc->wrsize = 0; 583 584 ac->intr_handler = intr; 585 ac->intr_ctx = context; 586 } 587 588 void 589 atopcase_intr_unsetup(device_t dev, device_t child) 590 { 591 } 592 593 int 594 atopcase_intr_start(device_t dev, device_t child) 595 { 596 struct atopcase_softc *sc = device_get_softc(dev); 597 struct atopcase_child *ac = atopcase_get_child_by_hidbus(child); 598 599 if (ATOPCASE_IN_POLLING_MODE(sc)) 600 sx_xlock(&sc->sc_write_sx); 601 else if (sc->sc_irq_ih != NULL) 602 mtx_lock(&sc->sc_mtx); 603 else 604 sx_xlock(&sc->sc_sx); 605 ac->open = true; 606 if (ATOPCASE_IN_POLLING_MODE(sc)) 607 sx_xunlock(&sc->sc_write_sx); 608 else if (sc->sc_irq_ih != NULL) 609 mtx_unlock(&sc->sc_mtx); 610 else 611 sx_xunlock(&sc->sc_sx); 612 613 return (0); 614 } 615 616 int 617 atopcase_intr_stop(device_t dev, device_t child) 618 { 619 struct atopcase_softc *sc = device_get_softc(dev); 620 struct atopcase_child *ac = atopcase_get_child_by_hidbus(child); 621 622 if (ATOPCASE_IN_POLLING_MODE(sc)) 623 sx_xlock(&sc->sc_write_sx); 624 else if (sc->sc_irq_ih != NULL) 625 mtx_lock(&sc->sc_mtx); 626 else 627 sx_xlock(&sc->sc_sx); 628 ac->open = false; 629 if (ATOPCASE_IN_POLLING_MODE(sc)) 630 sx_xunlock(&sc->sc_write_sx); 631 else if (sc->sc_irq_ih != NULL) 632 mtx_unlock(&sc->sc_mtx); 633 else 634 sx_xunlock(&sc->sc_sx); 635 636 return (0); 637 } 638 639 void 640 atopcase_intr_poll(device_t dev, device_t child) 641 { 642 struct atopcase_softc *sc = device_get_softc(dev); 643 644 (void)atopcase_receive_packet(sc); 645 } 646 647 int 648 atopcase_get_rdesc(device_t dev, device_t child, void *buf, hid_size_t len) 649 { 650 struct atopcase_child *ac = atopcase_get_child_by_hidbus(child); 651 652 if (ac->rdesc_len != len) 653 return (ENXIO); 654 memcpy(buf, ac->rdesc, len); 655 656 return (0); 657 } 658 659 int 660 atopcase_set_report(device_t dev, device_t child, const void *buf, 661 hid_size_t len, uint8_t type __unused, uint8_t id) 662 { 663 struct atopcase_softc *sc = device_get_softc(dev); 664 struct atopcase_child *ac = atopcase_get_child_by_hidbus(child); 665 int err; 666 667 if (len >= ATOPCASE_DATA_SIZE - sizeof(struct atopcase_header) - 2) 668 return (EINVAL); 669 670 DPRINTF("%s HID command SET_REPORT %d (len %d): %*D\n", 671 ac->name, id, len, len, buf, " "); 672 673 if (!ATOPCASE_IN_KDB()) 674 sx_xlock(&sc->sc_write_sx); 675 atopcase_create_message(&sc->sc_buf, ac->device, 676 ATOPCASE_MSG_TYPE_SET_REPORT(ac->device, id), 0, buf, len, 0); 677 err = atopcase_send(sc, &sc->sc_buf); 678 if (!ATOPCASE_IN_KDB()) 679 sx_xunlock(&sc->sc_write_sx); 680 681 return (err); 682 } 683 684 int 685 atopcase_backlight_update_status(device_t dev, struct backlight_props *props) 686 { 687 struct atopcase_softc *sc = device_get_softc(dev); 688 struct atopcase_bl_payload payload = { 0 }; 689 690 payload.report_id = ATOPCASE_BKL_REPORT_ID; 691 payload.device = ATOPCASE_DEV_KBRD; 692 /* 693 * Hardware range is 32-255 for visible backlight, 694 * convert from percentages 695 */ 696 payload.level = (props->brightness == 0) ? 0 : 697 (32 + (223 * props->brightness / 100)); 698 payload.status = (payload.level > 0) ? 0x01F4 : 0x1; 699 700 return (atopcase_set_report(dev, sc->sc_kb.hidbus, &payload, 701 sizeof(payload), HID_OUTPUT_REPORT, ATOPCASE_BKL_REPORT_ID)); 702 } 703 704 int 705 atopcase_backlight_get_status(device_t dev, struct backlight_props *props) 706 { 707 struct atopcase_softc *sc = device_get_softc(dev); 708 709 props->brightness = sc->sc_backlight_level; 710 props->nlevels = 0; 711 712 return (0); 713 } 714 715 int 716 atopcase_backlight_get_info(device_t dev, struct backlight_info *info) 717 { 718 info->type = BACKLIGHT_TYPE_KEYBOARD; 719 strlcpy(info->name, "Apple MacBook Keyboard", BACKLIGHTMAXNAMELENGTH); 720 721 return (0); 722 } 723