jcs's openbsd hax
openbsd
at jcs 1269 lines 31 kB view raw
1/* $OpenBSD: aplhidev.c,v 1.13 2024/01/15 13:27:20 kettenis Exp $ */ 2/* 3 * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 4 * Copyright (c) 2013-2014 joshua stein <jcs@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19#include <sys/param.h> 20#include <sys/systm.h> 21#include <sys/kernel.h> 22#include <sys/device.h> 23#include <sys/malloc.h> 24#include <sys/timeout.h> 25 26#include <lib/libkern/crc16.h> 27 28#include <dev/spi/spivar.h> 29 30#ifdef __HAVE_FDT 31#include <machine/fdt.h> 32#include <dev/ofw/openfirm.h> 33#include <dev/ofw/ofw_gpio.h> 34#include <dev/ofw/ofw_pinctrl.h> 35#endif 36 37#include "acpi.h" 38#if NACPI > 0 39#include <dev/acpi/acpireg.h> 40#include <dev/acpi/acpivar.h> 41#include <dev/acpi/acpidev.h> 42#include <dev/acpi/amltypes.h> 43#include <dev/acpi/dsdt.h> 44#endif 45 46#include <dev/usb/usbdevs.h> 47 48#include <dev/wscons/wsconsio.h> 49#include <dev/wscons/wskbdvar.h> 50#include <dev/wscons/wsksymdef.h> 51#include <dev/wscons/wsmousevar.h> 52 53#include <dev/hid/hid.h> 54#include <dev/hid/hidkbdsc.h> 55#include <dev/hid/hidmsvar.h> 56 57#include "aplhidev.h" 58 59/* #define APLHIDEV_DEBUG 1 */ 60 61#ifdef APLHIDEV_DEBUG 62#define DPRINTF(x) printf x 63#else 64#define DPRINTF(x) 65#endif 66 67#define APLHIDEV_READ_PACKET 0x20 68#define APLHIDEV_WRITE_PACKET 0x40 69 70#define APLHIDEV_KBD_DEVICE 1 71#define APLHIDEV_TP_DEVICE 2 72#define APLHIDEV_INFO_DEVICE 208 73 74#define APLHIDEV_GET_INFO 0x0120 75#define APLHIDEV_GET_DESCRIPTOR 0x1020 76#define APLHIDEV_DESC_MAX 512 77#define APLHIDEV_KBD_REPORT 0x0110 78#define APLHIDEV_TP_REPORT 0x0210 79#define APLHIDEV_SET_LEDS 0x0151 80#define APLHIDEV_SET_MODE 0x0252 81#define APLHIDEV_MODE_HID 0x00 82#define APLHIDEV_MODE_RAW 0x01 83#define APLHIDEV_GET_DIMENSIONS 0xd932 84#define APLHIDEV_SET_BACKLIGHT 0xb051 85#define APLHIDEV_BACKLIGHT_MAGIC 0x01b0 86#define APLHIDEV_BACKLIGHT_MIN 32 87#define APLHIDEV_BACKLIGHT_MAX 255 88#define APLHIDEV_BACKLIGHT_ON 0x01f4 89#define APLHIDEV_BACKLIGHT_OFF 0x0001 90 91struct aplhidev_dim { 92 uint32_t width; 93 uint32_t height; 94 int16_t x_min; 95 int16_t y_min; 96 int16_t x_max; 97 int16_t y_max; 98}; 99 100struct aplhidev_attach_args { 101 uint8_t aa_reportid; 102 void *aa_desc; 103 size_t aa_desclen; 104}; 105 106struct aplhidev_spi_packet { 107 uint8_t flags; 108 uint8_t device; 109 uint16_t offset; 110 uint16_t remaining; 111 uint16_t len; 112 uint8_t data[246]; 113 uint16_t crc; 114}; 115 116struct aplhidev_spi_status { 117 uint8_t status[4]; 118}; 119 120struct aplhidev_msghdr { 121 uint16_t type; 122 uint8_t device; 123 uint8_t msgid; 124 uint16_t rsplen; 125 uint16_t cmdlen; 126}; 127 128struct aplhidev_info_hdr { 129 uint16_t unknown[2]; 130 uint16_t num_devices; 131 uint16_t vendor; 132 uint16_t product; 133 uint16_t version; 134 uint16_t vendor_str[2]; 135 uint16_t product_str[2]; 136 uint16_t serial_str[2]; 137}; 138 139struct aplhidev_get_desc { 140 struct aplhidev_msghdr hdr; 141 uint16_t crc; 142}; 143 144struct aplhidev_set_leds { 145 struct aplhidev_msghdr hdr; 146 uint8_t reportid; 147 uint8_t leds; 148 uint16_t crc; 149}; 150 151struct aplhidev_set_mode { 152 struct aplhidev_msghdr hdr; 153 uint8_t reportid; 154 uint8_t mode; 155 uint16_t crc; 156}; 157 158struct aplhidev_set_backlight { 159 struct aplhidev_msghdr hdr; 160 uint16_t magic; 161 uint16_t level; 162 uint16_t on_off; 163 uint16_t crc; 164}; 165 166struct aplhidev_softc { 167 struct device sc_dev; 168#if NACPI > 0 169 struct aml_node *sc_dev_node; 170#endif 171 172 spi_tag_t sc_spi_tag; 173 struct spi_config sc_spi_conf; 174 175 uint8_t sc_msgid; 176 177 uint32_t *sc_gpio; 178 int sc_gpiolen; 179 180 uint8_t sc_mode; 181 uint16_t sc_vendor; 182 uint16_t sc_product; 183 184 struct device *sc_kbd; 185 uint8_t sc_kbddesc[APLHIDEV_DESC_MAX]; 186 size_t sc_kbddesclen; 187 188 struct device *sc_ms; 189 uint8_t sc_tpdesc[APLHIDEV_DESC_MAX]; 190 size_t sc_tpdesclen; 191 uint8_t sc_dimdesc[APLHIDEV_DESC_MAX]; 192 size_t sc_dimdesclen; 193 int sc_x_min; 194 int sc_x_max; 195 int sc_y_min; 196 int sc_y_max; 197 int sc_h_res; 198 int sc_v_res; 199}; 200 201int aplhidev_match(struct device *, void *, void *); 202void aplhidev_attach(struct device *, struct device *, void *); 203#ifdef __HAVE_FDT 204void aplhidev_fdt_init(struct aplhidev_softc *, void *); 205#elif NACPI > 0 206int aplhidev_acpi_init(struct aplhidev_softc *); 207int aplhidev_enable_spi(struct aplhidev_softc *); 208int aplhidev_gpe_intr(struct aml_node *, int, void *); 209#endif 210 211const struct cfattach aplhidev_ca = { 212 sizeof(struct aplhidev_softc), aplhidev_match, aplhidev_attach 213}; 214 215struct cfdriver aplhidev_cd = { 216 NULL, "aplhidev", DV_DULL 217}; 218 219void aplhidev_get_info(struct aplhidev_softc *); 220void aplhidev_get_descriptor(struct aplhidev_softc *, uint8_t); 221void aplhidev_set_leds(struct aplhidev_softc *, uint8_t); 222void aplhidev_set_backlight(struct aplhidev_softc *, uint8_t); 223void aplhidev_set_mode(struct aplhidev_softc *, uint8_t); 224void aplhidev_get_dimensions(struct aplhidev_softc *); 225 226void aplkbd_set_backlight(void *); 227extern int (*wskbd_get_backlight)(struct wskbd_backlight *); 228extern int (*wskbd_set_backlight)(struct wskbd_backlight *); 229int aplkbd_wskbd_get_backlight(struct wskbd_backlight *); 230int aplkbd_wskbd_set_backlight(struct wskbd_backlight *); 231 232int aplhidev_intr(void *); 233void aplkbd_intr(struct device *, uint8_t *, size_t); 234void aplms_intr(struct device *, uint8_t *, size_t); 235 236int 237aplhidev_match(struct device *parent, void *match, void *aux) 238{ 239 struct spi_attach_args *sa = aux; 240#if NACPI > 0 241 struct aml_node *node = (struct aml_node *)sa->sa_cookie; 242 uint64_t val; 243#endif 244 245#if defined(__HAVE_FDT) 246 if (strcmp(sa->sa_name, "apple,spi-hid-transport") == 0) 247 return 1; 248 249#elif NACPI > 0 250 if (strcmp(sa->sa_name, "apple-spi-topcase") == 0) { 251 /* don't attach if USB interface is present */ 252 if (aml_evalinteger(acpi_softc, node, "UIST", 0, NULL, 253 &val) == 0 && val) 254 return 0; 255 256 return 1; 257 } 258#endif 259 260 return 0; 261} 262 263void 264aplhidev_attach(struct device *parent, struct device *self, void *aux) 265{ 266 struct aplhidev_softc *sc = (struct aplhidev_softc *)self; 267 struct spi_attach_args *sa = aux; 268 struct aplhidev_attach_args aa; 269 struct aplhidev_dim dim; 270 int retry; 271 272 sc->sc_spi_tag = sa->sa_tag; 273 274#ifdef __HAVE_FDT 275 aplhidev_fdt_init(sc, sa->sa_cookie); 276 277#elif NACPI > 0 278 sc->sc_dev_node = (struct aml_node *)sa->sa_cookie; 279 if (aplhidev_acpi_init(sc) != 0) 280 return; 281#endif 282 283 aplhidev_get_info(sc); 284 for (retry = 10; retry > 0; retry--) { 285 aplhidev_intr(sc); 286 delay(1000); 287 if (sc->sc_vendor != 0 && sc->sc_product != 0) 288 break; 289 } 290 291 aplhidev_get_descriptor(sc, APLHIDEV_KBD_DEVICE); 292 for (retry = 10; retry > 0; retry--) { 293 aplhidev_intr(sc); 294 delay(1000); 295 if (sc->sc_kbddesclen > 0) 296 break; 297 } 298 299 aplhidev_get_descriptor(sc, APLHIDEV_TP_DEVICE); 300 for (retry = 10; retry > 0; retry--) { 301 aplhidev_intr(sc); 302 delay(1000); 303 if (sc->sc_tpdesclen > 0) 304 break; 305 } 306 307 sc->sc_mode = APLHIDEV_MODE_HID; 308 aplhidev_set_mode(sc, APLHIDEV_MODE_RAW); 309 for (retry = 10; retry > 0; retry--) { 310 aplhidev_intr(sc); 311 delay(1000); 312 if (sc->sc_mode == APLHIDEV_MODE_RAW) 313 break; 314 } 315 316 aplhidev_get_dimensions(sc); 317 for (retry = 10; retry > 0; retry--) { 318 aplhidev_intr(sc); 319 delay(1000); 320 if (sc->sc_dimdesclen > 0) 321 break; 322 } 323 324 printf("\n"); 325 326 if (sc->sc_dimdesclen == sizeof(dim) + 1) { 327 memcpy(&dim, &sc->sc_dimdesc[1], sizeof(dim)); 328 sc->sc_x_min = dim.x_min; 329 sc->sc_x_max = dim.x_max; 330 sc->sc_y_min = dim.y_min; 331 sc->sc_y_max = dim.y_max; 332 sc->sc_h_res = (100 * (dim.x_max - dim.x_min)) / dim.width; 333 sc->sc_v_res = (100 * (dim.y_max - dim.y_min)) / dim.height; 334 } 335 336 if (sc->sc_kbddesclen > 0) { 337 aa.aa_reportid = APLHIDEV_KBD_DEVICE; 338 aa.aa_desc = sc->sc_kbddesc; 339 aa.aa_desclen = sc->sc_kbddesclen; 340 sc->sc_kbd = config_found(self, &aa, NULL); 341 } 342 343 if (sc->sc_tpdesclen > 0) { 344 aa.aa_reportid = APLHIDEV_TP_DEVICE; 345 aa.aa_desc = sc->sc_tpdesc; 346 aa.aa_desclen = sc->sc_tpdesclen; 347 sc->sc_ms = config_found(self, &aa, NULL); 348 } 349} 350 351#ifdef __HAVE_FDT 352void 353aplhidev_fdt_init(struct aplhidev_softc *sc, void *cookie) 354{ 355 int node = *(int *)cookie; 356 357 sc->sc_gpiolen = OF_getproplen(inode, "spien-gpios"); 358 if (sc->sc_gpiolen > 0) { 359 sc->sc_gpio = malloc(sc->sc_gpiolen, M_TEMP, M_WAITOK); 360 OF_getpropintarray(node, "spien-gpios", 361 sc->sc_gpio, sc->sc_gpiolen); 362 gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT); 363 364 /* Reset */ 365 gpio_controller_set_pin(sc->sc_gpio, 1); 366 delay(5000); 367 gpio_controller_set_pin(sc->sc_gpio, 0); 368 delay(5000); 369 370 /* Enable. */ 371 gpio_controller_set_pin(sc->sc_gpio, 1); 372 delay(50000); 373 } 374 375 sc->sc_spi_conf.sc_bpw = 8; 376 sc->sc_spi_conf.sc_freq = OF_getpropint(node, "spi-max-frequency", 0); 377 sc->sc_spi_conf.sc_cs = OF_getpropint(node, "reg", 0); 378 sc->sc_spi_conf.sc_cs_delay = 100; 379 380 fdt_intr_establish(sc->sc_node, IPL_TTY, 381 aplhidev_intr, sc, sc->sc_dev.dv_xname); 382} 383#endif 384 385#if NACPI > 0 386int 387aplhidev_acpi_init(struct aplhidev_softc *sc) 388{ 389 /* a0b5b7c6-1318-441c-b0c9-fe695eaf949b */ 390 static uint8_t guid[] = { 391 0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44, 392 0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B, 393 }; 394 struct aml_value cmd[4], res; 395 struct aml_node *node; 396 uint64_t val; 397 int i; 398 399 /* 400 * On newer Apple hardware where we claim an OSI of Darwin, _CRS 401 * doesn't return a useful SpiSerialBusV2 object but instead returns 402 * parameters from a _DSM method when called with a particular UUID 403 * which macOS does. 404 */ 405 if (!aml_searchname(sc->sc_dev_node, "_DSM")) { 406 printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname, 407 aml_nodename(sc->sc_dev_node)); 408 return 1; 409 } 410 411 bzero(&cmd, sizeof(cmd)); 412 cmd[0].type = AML_OBJTYPE_BUFFER; 413 cmd[0].v_buffer = (uint8_t *)&guid; 414 cmd[0].length = sizeof(guid); 415 cmd[1].type = AML_OBJTYPE_INTEGER; 416 cmd[1].v_integer = 1; 417 cmd[1].length = 1; 418 cmd[2].type = AML_OBJTYPE_INTEGER; 419 cmd[2].v_integer = 1; 420 cmd[2].length = 1; 421 cmd[3].type = AML_OBJTYPE_BUFFER; 422 cmd[3].length = 0; 423 424 if (aml_evalname(acpi_softc, sc->sc_dev_node, "_DSM", 4, cmd, &res)) { 425 printf("%s: eval of _DSM at %s failed\n", 426 sc->sc_dev.dv_xname, aml_nodename(sc->sc_dev_node)); 427 return 1; 428 } 429 430 if (res.type != AML_OBJTYPE_PACKAGE) { 431 printf("%s: bad _DSM result at %s: %d\n", 432 sc->sc_dev.dv_xname, aml_nodename(sc->sc_dev_node), 433 res.type); 434 aml_freevalue(&res); 435 return 1; 436 } 437 438 if (res.length % 2 != 0) { 439 printf("%s: _DSM length %d not even\n", sc->sc_dev.dv_xname, 440 res.length); 441 aml_freevalue(&res); 442 return 1; 443 } 444 445 for (i = 0; i < res.length; i += 2) { 446 char *k; 447 448 if (res.v_package[i]->type != AML_OBJTYPE_STRING || 449 res.v_package[i + 1]->type != AML_OBJTYPE_BUFFER) { 450 printf("%s: expected string+buffer, got %d+%d\n", 451 sc->sc_dev.dv_xname, res.v_package[i]->type, 452 res.v_package[i + 1]->type); 453 aml_freevalue(&res); 454 return 1; 455 } 456 457 k = res.v_package[i]->v_string; 458 val = aml_val2int(res.v_package[i + 1]); 459 460 DPRINTF(("%s: %s = %lld\n", sc->sc_dev.dv_xname, k, val)); 461 462 if (strcmp(k, "spiSclkPeriod") == 0) { 463 sc->sc_spi_conf.sc_freq = 1000000000 / val; 464 } else if (strcmp(k, "spiWordSize") == 0) { 465 sc->sc_spi_conf.sc_bpw = val; 466 } else if (strcmp(k, "spiSPO") == 0) { 467 if (val) 468 sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL; 469 } else if (strcmp(k, "spiSPH") == 0) { 470 if (val) 471 sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA; 472 } else if (strcmp(k, "spiCSDelay") == 0) { 473 sc->sc_spi_conf.sc_cs_delay = val; 474 } else { 475 DPRINTF(("%s: unused _DSM key %s\n", 476 sc->sc_dev.dv_xname, k)); 477 } 478 } 479 aml_freevalue(&res); 480 481 if (aplhidev_enable_spi(sc) != 0) 482 return 1; 483 484 node = aml_searchname(sc->sc_dev_node, "_GPE"); 485 if (node) 486 aml_register_notify(sc->sc_dev_node, NULL, aplhidev_gpe_intr, 487 sc, ACPIDEV_NOPOLL); 488 489 return 0; 490} 491 492int 493aplhidev_enable_spi(struct aplhidev_softc *sc) 494{ 495 struct aml_value arg; 496 uint64_t val; 497 498 /* if SPI is not enabled, enable it */ 499 if (aml_evalinteger(acpi_softc, sc->sc_dev_node, "SIST", 0, NULL, 500 &val) == 0 && !val) { 501 DPRINTF(("%s: SIST is %lld\n", sc->sc_dev.dv_xname, val)); 502 503 bzero(&arg, sizeof(arg)); 504 arg.type = AML_OBJTYPE_INTEGER; 505 arg.v_integer = 1; 506 arg.length = 1; 507 508 if (aml_evalname(acpi_softc, sc->sc_dev_node, "SIEN", 1, &arg, 509 NULL) != 0) { 510 DPRINTF(("%s: couldn't enable SPI mode\n", __func__)); 511 return 1; 512 } 513 514 DELAY(500); 515 } else { 516 DPRINTF(("%s: SIST is already %lld\n", sc->sc_dev.dv_xname, 517 val)); 518 } 519 520 return 0; 521} 522#endif 523 524void 525aplhidev_get_info(struct aplhidev_softc *sc) 526{ 527 struct aplhidev_spi_packet packet; 528 struct aplhidev_get_desc *msg; 529 struct aplhidev_spi_status status; 530 531 memset(&packet, 0, sizeof(packet)); 532 packet.flags = APLHIDEV_WRITE_PACKET; 533 packet.device = APLHIDEV_INFO_DEVICE; 534 packet.len = sizeof(*msg); 535 536 msg = (void *)&packet.data[0]; 537 msg->hdr.type = APLHIDEV_GET_INFO; 538 msg->hdr.device = APLHIDEV_INFO_DEVICE; 539 msg->hdr.msgid = sc->sc_msgid++; 540 msg->hdr.cmdlen = 0; 541 msg->hdr.rsplen = APLHIDEV_DESC_MAX; 542 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 543 544 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 545 546 spi_acquire_bus(sc->sc_spi_tag, 0); 547 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 548 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 549 SPI_KEEP_CS); 550 delay(100); 551 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 552 spi_release_bus(sc->sc_spi_tag, 0); 553 554 delay(1000); 555} 556 557void 558aplhidev_get_descriptor(struct aplhidev_softc *sc, uint8_t device) 559{ 560 struct aplhidev_spi_packet packet; 561 struct aplhidev_get_desc *msg; 562 struct aplhidev_spi_status status; 563 564 memset(&packet, 0, sizeof(packet)); 565 packet.flags = APLHIDEV_WRITE_PACKET; 566 packet.device = APLHIDEV_INFO_DEVICE; 567 packet.len = sizeof(*msg); 568 569 msg = (void *)&packet.data[0]; 570 msg->hdr.type = APLHIDEV_GET_DESCRIPTOR; 571 msg->hdr.device = device; 572 msg->hdr.msgid = sc->sc_msgid++; 573 msg->hdr.cmdlen = 0; 574 msg->hdr.rsplen = APLHIDEV_DESC_MAX; 575 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 576 577 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 578 579 spi_acquire_bus(sc->sc_spi_tag, 0); 580 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 581 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 582 SPI_KEEP_CS); 583 delay(100); 584 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 585 spi_release_bus(sc->sc_spi_tag, 0); 586 587 delay(1000); 588} 589 590void 591aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds) 592{ 593 struct aplhidev_spi_packet packet; 594 struct aplhidev_set_leds *msg; 595 struct aplhidev_spi_status status; 596 597 memset(&packet, 0, sizeof(packet)); 598 packet.flags = APLHIDEV_WRITE_PACKET; 599 packet.device = APLHIDEV_KBD_DEVICE; 600 packet.len = sizeof(*msg); 601 602 msg = (void *)&packet.data[0]; 603 msg->hdr.type = APLHIDEV_SET_LEDS; 604 msg->hdr.device = APLHIDEV_KBD_DEVICE; 605 msg->hdr.msgid = sc->sc_msgid++; 606 msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; 607 msg->hdr.rsplen = msg->hdr.cmdlen; 608 msg->reportid = APLHIDEV_KBD_DEVICE; 609 msg->leds = leds; 610 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 611 612 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 613 614 /* 615 * XXX Without a delay here, the command will fail. Does the 616 * controller need a bit of time between sending us a keypress 617 * event and accepting a new command from us? 618 */ 619 delay(250); 620 621 spi_acquire_bus(sc->sc_spi_tag, 0); 622 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 623 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 624 SPI_KEEP_CS); 625 delay(100); 626 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 627 spi_release_bus(sc->sc_spi_tag, 0); 628} 629 630void 631aplhidev_set_backlight(struct aplhidev_softc *sc, uint8_t level) 632{ 633 struct aplhidev_spi_packet packet; 634 struct aplhidev_set_backlight *msg; 635 struct aplhidev_spi_status status; 636 637 memset(&packet, 0, sizeof(packet)); 638 packet.flags = APLHIDEV_WRITE_PACKET; 639 packet.device = APLHIDEV_KBD_DEVICE; 640 packet.len = sizeof(*msg); 641 642 msg = (void *)&packet.data[0]; 643 msg->hdr.type = APLHIDEV_SET_BACKLIGHT; 644 msg->hdr.device = APLHIDEV_KBD_DEVICE; 645 msg->hdr.msgid = sc->sc_msgid++; 646 msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; 647 msg->hdr.rsplen = msg->hdr.cmdlen; 648 msg->magic = htole16(APLHIDEV_BACKLIGHT_MAGIC); 649 if (level <= APLHIDEV_BACKLIGHT_MIN) { 650 msg->level = 0; 651 msg->on_off = htole16(APLHIDEV_BACKLIGHT_OFF); 652 } else { 653 msg->level = htole16(level); 654 msg->on_off = htole16(APLHIDEV_BACKLIGHT_ON); 655 } 656 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 657 658 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 659 660 spi_acquire_bus(sc->sc_spi_tag, 0); 661 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 662 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 663 SPI_KEEP_CS); 664 delay(100); 665 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 666 spi_release_bus(sc->sc_spi_tag, 0); 667} 668 669void 670aplhidev_set_mode(struct aplhidev_softc *sc, uint8_t mode) 671{ 672 struct aplhidev_spi_packet packet; 673 struct aplhidev_set_mode *msg; 674 struct aplhidev_spi_status status; 675 676 memset(&packet, 0, sizeof(packet)); 677 packet.flags = APLHIDEV_WRITE_PACKET; 678 packet.device = APLHIDEV_TP_DEVICE; 679 packet.len = sizeof(*msg); 680 681 msg = (void *)&packet.data[0]; 682 msg->hdr.type = APLHIDEV_SET_MODE; 683 msg->hdr.device = APLHIDEV_TP_DEVICE; 684 msg->hdr.msgid = sc->sc_msgid++; 685 msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; 686 msg->hdr.rsplen = msg->hdr.cmdlen; 687 msg->reportid = APLHIDEV_TP_DEVICE; 688 msg->mode = mode; 689 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 690 691 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 692 693 spi_acquire_bus(sc->sc_spi_tag, 0); 694 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 695 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 696 SPI_KEEP_CS); 697 delay(100); 698 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 699 spi_release_bus(sc->sc_spi_tag, 0); 700 701 delay(1000); 702} 703 704void 705aplhidev_get_dimensions(struct aplhidev_softc *sc) 706{ 707 struct aplhidev_spi_packet packet; 708 struct aplhidev_get_desc *msg; 709 struct aplhidev_spi_status status; 710 711 memset(&packet, 0, sizeof(packet)); 712 packet.flags = APLHIDEV_WRITE_PACKET; 713 packet.device = APLHIDEV_TP_DEVICE; 714 packet.len = sizeof(*msg); 715 716 msg = (void *)&packet.data[0]; 717 msg->hdr.type = APLHIDEV_GET_DIMENSIONS; 718 msg->hdr.device = 0; 719 msg->hdr.msgid = sc->sc_msgid++; 720 msg->hdr.cmdlen = 0; 721 msg->hdr.rsplen = APLHIDEV_DESC_MAX; 722 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 723 724 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 725 726 spi_acquire_bus(sc->sc_spi_tag, 0); 727 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 728 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 729 SPI_KEEP_CS); 730 delay(100); 731 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 732 spi_release_bus(sc->sc_spi_tag, 0); 733 734 delay(1000); 735} 736 737#if NACPI > 0 738int 739aplhidev_gpe_intr(struct aml_node *node, int gpe, void *arg) 740{ 741 struct aplhidev_softc *sc = arg; 742 743 return aplhidev_intr(sc); 744} 745#endif 746 747int 748aplhidev_intr(void *arg) 749{ 750 struct aplhidev_softc *sc = arg; 751 struct aplhidev_spi_packet packet; 752 struct aplhidev_msghdr *hdr = (struct aplhidev_msghdr *)&packet.data[0]; 753 754 memset(&packet, 0, sizeof(packet)); 755 spi_acquire_bus(sc->sc_spi_tag, 0); 756 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 757 spi_read(sc->sc_spi_tag, (char *)&packet, sizeof(packet)); 758 spi_release_bus(sc->sc_spi_tag, 0); 759 760 /* Treat empty packets as spurious interrupts. */ 761 if (packet.flags == 0 && packet.device == 0 && packet.crc == 0) 762 return 0; 763 764 if (crc16(0, (uint8_t *)&packet, sizeof(packet))) 765 return 1; 766 767 /* Keyboard input. */ 768 if (packet.flags == APLHIDEV_READ_PACKET && 769 packet.device == APLHIDEV_KBD_DEVICE && 770 hdr->type == APLHIDEV_KBD_REPORT) { 771 if (sc->sc_kbd) 772 aplkbd_intr(sc->sc_kbd, &packet.data[8], hdr->cmdlen); 773 return 1; 774 } 775 776 /* Touchpad input. */ 777 if (packet.flags == APLHIDEV_READ_PACKET && 778 packet.device == APLHIDEV_TP_DEVICE && 779 hdr->type == APLHIDEV_TP_REPORT) { 780 if (sc->sc_ms) 781 aplms_intr(sc->sc_ms, &packet.data[8], hdr->cmdlen); 782 return 1; 783 } 784 785 /* Replies to commands we sent. */ 786 if (packet.flags == APLHIDEV_WRITE_PACKET && 787 packet.device == APLHIDEV_INFO_DEVICE && 788 hdr->type == APLHIDEV_GET_INFO) { 789 struct aplhidev_info_hdr *info = 790 (struct aplhidev_info_hdr *)&packet.data[8]; 791 sc->sc_vendor = info->vendor; 792 sc->sc_product = info->product; 793 return 1; 794 } 795 if (packet.flags == APLHIDEV_WRITE_PACKET && 796 packet.device == APLHIDEV_INFO_DEVICE && 797 hdr->type == APLHIDEV_GET_DESCRIPTOR) { 798 switch (hdr->device) { 799 case APLHIDEV_KBD_DEVICE: 800 memcpy(sc->sc_kbddesc, &packet.data[8], hdr->cmdlen); 801 sc->sc_kbddesclen = hdr->cmdlen; 802 break; 803 case APLHIDEV_TP_DEVICE: 804 memcpy(sc->sc_tpdesc, &packet.data[8], hdr->cmdlen); 805 sc->sc_tpdesclen = hdr->cmdlen; 806 break; 807 } 808 809 return 1; 810 } 811 if (packet.flags == APLHIDEV_WRITE_PACKET && 812 packet.device == APLHIDEV_TP_DEVICE && 813 hdr->type == APLHIDEV_SET_MODE) { 814 sc->sc_mode = APLHIDEV_MODE_RAW; 815 return 1; 816 } 817 if (packet.flags == APLHIDEV_WRITE_PACKET && 818 packet.device == APLHIDEV_TP_DEVICE && 819 hdr->type == APLHIDEV_GET_DIMENSIONS) { 820 memcpy(sc->sc_dimdesc, &packet.data[8], hdr->cmdlen); 821 sc->sc_dimdesclen = hdr->cmdlen; 822 return 1; 823 } 824 825 /* Valid, but unrecognized packet; ignore for now. */ 826 return 1; 827} 828 829/* Keyboard */ 830 831struct aplkbd_softc { 832 struct device sc_dev; 833 struct aplhidev_softc *sc_hidev; 834 struct hidkbd sc_kbd; 835 int sc_spl; 836 int sc_backlight; 837}; 838 839void aplkbd_cngetc(void *, u_int *, int *); 840void aplkbd_cnpollc(void *, int); 841void aplkbd_cnbell(void *, u_int, u_int, u_int); 842 843const struct wskbd_consops aplkbd_consops = { 844 aplkbd_cngetc, 845 aplkbd_cnpollc, 846 aplkbd_cnbell, 847}; 848 849int aplkbd_enable(void *, int); 850void aplkbd_set_leds(void *, int); 851int aplkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 852 853const struct wskbd_accessops aplkbd_accessops = { 854 .enable = aplkbd_enable, 855 .ioctl = aplkbd_ioctl, 856 .set_leds = aplkbd_set_leds, 857}; 858 859int aplkbd_match(struct device *, void *, void *); 860void aplkbd_attach(struct device *, struct device *, void *); 861 862const struct cfattach aplkbd_ca = { 863 sizeof(struct aplkbd_softc), aplkbd_match, aplkbd_attach 864}; 865 866struct cfdriver aplkbd_cd = { 867 NULL, "aplkbd", DV_DULL 868}; 869 870int 871aplkbd_match(struct device *parent, void *match, void *aux) 872{ 873 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 874 875 return (aa->aa_reportid == APLHIDEV_KBD_DEVICE); 876} 877 878void 879aplkbd_attach(struct device *parent, struct device *self, void *aux) 880{ 881 struct aplkbd_softc *sc = (struct aplkbd_softc *)self; 882 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 883 struct hidkbd *kbd = &sc->sc_kbd; 884 885 sc->sc_hidev = (struct aplhidev_softc *)parent; 886 if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE, 887 aa->aa_desc, aa->aa_desclen)) 888 return; 889 890 printf("\n"); 891 892 if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), 893 1, hid_input, &kbd->sc_fn, NULL)) { 894 switch (sc->sc_hidev->sc_product) { 895 case USB_PRODUCT_APPLE_WELLSPRINGM1_J293: 896 kbd->sc_munge = hidkbd_apple_tb_munge; 897 break; 898 default: 899 kbd->sc_munge = hidkbd_apple_munge; 900 break; 901 } 902 } 903 904 if (kbd->sc_console_keyboard) { 905 extern struct wskbd_mapdata ukbd_keymapdata; 906 907 ukbd_keymapdata.layout = KB_US | KB_DEFAULT; 908 wskbd_cnattach(&aplkbd_consops, sc, &ukbd_keymapdata); 909 aplkbd_enable(sc, 1); 910 } 911 912 913 hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops); 914 915 sc->sc_backlight = APLHIDEV_BACKLIGHT_MIN; 916 wskbd_get_backlight = aplkbd_wskbd_get_backlight; 917 wskbd_set_backlight = aplkbd_wskbd_set_backlight; 918} 919 920void 921aplkbd_intr(struct device *self, uint8_t *packet, size_t packetlen) 922{ 923 struct aplkbd_softc *sc = (struct aplkbd_softc *)self; 924 struct hidkbd *kbd = &sc->sc_kbd; 925 926 if (kbd->sc_enabled) 927 hidkbd_input(kbd, &packet[1], packetlen - 1); 928} 929 930int 931aplkbd_enable(void *v, int on) 932{ 933 struct aplkbd_softc *sc = v; 934 struct hidkbd *kbd = &sc->sc_kbd; 935 936 return hidkbd_enable(kbd, on); 937} 938 939int 940aplkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 941{ 942 struct aplkbd_softc *sc = v; 943 struct hidkbd *kbd = &sc->sc_kbd; 944 945 switch (cmd) { 946 case WSKBDIO_GTYPE: 947 /* XXX: should we set something else? */ 948 *(u_int *)data = WSKBD_TYPE_USB; 949 return 0; 950 case WSKBDIO_SETLEDS: 951 aplkbd_set_leds(v, *(int *)data); 952 return 0; 953 default: 954 return hidkbd_ioctl(kbd, cmd, data, flag, p); 955 } 956} 957 958void 959aplkbd_set_leds(void *v, int leds) 960{ 961 struct aplkbd_softc *sc = v; 962 struct hidkbd *kbd = &sc->sc_kbd; 963 uint8_t res; 964 965 if (hidkbd_set_leds(kbd, leds, &res)) 966 aplhidev_set_leds(sc->sc_hidev, res); 967} 968 969int 970aplkbd_wskbd_get_backlight(struct wskbd_backlight *kbl) 971{ 972 struct aplkbd_softc *sc = aplkbd_cd.cd_devs[0]; 973 974 if (sc == NULL) 975 return 0; 976 977 kbl->min = APLHIDEV_BACKLIGHT_MIN; 978 kbl->max = APLHIDEV_BACKLIGHT_MAX; 979 kbl->curval = sc->sc_backlight; 980 981 return 0; 982} 983 984int 985aplkbd_wskbd_set_backlight(struct wskbd_backlight *kbl) 986{ 987 struct aplkbd_softc *sc = aplkbd_cd.cd_devs[0]; 988 int val; 989 990 if (sc == NULL) 991 return -1; 992 993 val = kbl->curval; 994 if (val < APLHIDEV_BACKLIGHT_MIN) 995 val = APLHIDEV_BACKLIGHT_MIN; 996 if (val > APLHIDEV_BACKLIGHT_MAX) 997 val = APLHIDEV_BACKLIGHT_MAX; 998 999 sc->sc_backlight = val; 1000 aplhidev_set_backlight((struct aplhidev_softc *)sc->sc_dev.dv_parent, 1001 sc->sc_backlight); 1002 1003 return 0; 1004} 1005 1006/* Console interface. */ 1007void 1008aplkbd_cngetc(void *v, u_int *type, int *data) 1009{ 1010 struct aplkbd_softc *sc = v; 1011 struct hidkbd *kbd = &sc->sc_kbd; 1012 1013 kbd->sc_polling = 1; 1014 while (kbd->sc_npollchar <= 0) { 1015 aplhidev_intr(sc->sc_dev.dv_parent); 1016 delay(1000); 1017 } 1018 kbd->sc_polling = 0; 1019 hidkbd_cngetc(kbd, type, data); 1020} 1021 1022void 1023aplkbd_cnpollc(void *v, int on) 1024{ 1025 struct aplkbd_softc *sc = v; 1026 1027 if (on) 1028 sc->sc_spl = spltty(); 1029 else 1030 splx(sc->sc_spl); 1031} 1032 1033void 1034aplkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 1035{ 1036 hidkbd_bell(pitch, period, volume, 1); 1037} 1038 1039#if NAPLMS > 0 1040 1041/* Touchpad */ 1042 1043/* 1044 * The contents of the touchpad event packets is identical to those 1045 * used by the ubcmtp(4) driver. The relevant definitions and the 1046 * code to decode the packets is replicated here. 1047 */ 1048 1049struct ubcmtp_finger { 1050 uint16_t origin; 1051 uint16_t abs_x; 1052 uint16_t abs_y; 1053 uint16_t rel_x; 1054 uint16_t rel_y; 1055 uint16_t tool_major; 1056 uint16_t tool_minor; 1057 uint16_t orientation; 1058 uint16_t touch_major; 1059 uint16_t touch_minor; 1060 uint16_t unused[2]; 1061 uint16_t pressure; 1062 uint16_t multi; 1063} __packed __attribute((aligned(2))); 1064 1065#define UBCMTP_MAX_FINGERS 16 1066 1067#define UBCMTP_TYPE4_TPOFF (24 * sizeof(uint16_t)) 1068#define UBCMTP_TYPE4_BTOFF 31 1069#define UBCMTP_TYPE4_FINGERPAD (1 * sizeof(uint16_t)) 1070 1071/* Use a constant, synaptics-compatible pressure value for now. */ 1072#define DEFAULT_PRESSURE 40 1073 1074static struct wsmouse_param aplms_wsmousecfg[] = { 1075 { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */ 1076}; 1077 1078struct aplms_softc { 1079 struct device sc_dev; 1080 struct aplhidev_softc *sc_hidev; 1081 struct device *sc_wsmousedev; 1082 1083 int sc_enabled; 1084 1085 int tp_offset; 1086 int tp_fingerpad; 1087 1088 struct mtpoint frame[UBCMTP_MAX_FINGERS]; 1089 int contacts; 1090 int btn; 1091}; 1092 1093int aplms_enable(void *); 1094void aplms_disable(void *); 1095int aplms_ioctl(void *, u_long, caddr_t, int, struct proc *); 1096 1097const struct wsmouse_accessops aplms_accessops = { 1098 .enable = aplms_enable, 1099 .disable = aplms_disable, 1100 .ioctl = aplms_ioctl, 1101}; 1102 1103int aplms_match(struct device *, void *, void *); 1104void aplms_attach(struct device *, struct device *, void *); 1105 1106const struct cfattach aplms_ca = { 1107 sizeof(struct aplms_softc), aplms_match, aplms_attach 1108}; 1109 1110struct cfdriver aplms_cd = { 1111 NULL, "aplms", DV_DULL 1112}; 1113 1114int aplms_configure(struct aplms_softc *); 1115 1116int 1117aplms_match(struct device *parent, void *match, void *aux) 1118{ 1119 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 1120 1121 return (aa->aa_reportid == APLHIDEV_TP_DEVICE); 1122} 1123 1124void 1125aplms_attach(struct device *parent, struct device *self, void *aux) 1126{ 1127 struct aplms_softc *sc = (struct aplms_softc *)self; 1128 struct wsmousedev_attach_args aa; 1129 1130 sc->sc_hidev = (struct aplhidev_softc *)parent; 1131 1132 printf("\n"); 1133 1134 sc->tp_offset = UBCMTP_TYPE4_TPOFF; 1135 sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; 1136 1137 aa.accessops = &aplms_accessops; 1138 aa.accesscookie = sc; 1139 1140 sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint); 1141 if (sc->sc_wsmousedev != NULL && aplms_configure(sc)) 1142 aplms_disable(sc); 1143} 1144 1145int 1146aplms_configure(struct aplms_softc *sc) 1147{ 1148 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 1149 1150 hw->type = WSMOUSE_TYPE_TOUCHPAD; 1151 hw->hw_type = WSMOUSEHW_CLICKPAD; 1152 hw->x_min = sc->sc_hidev->sc_x_min; 1153 hw->x_max = sc->sc_hidev->sc_x_max; 1154 hw->y_min = sc->sc_hidev->sc_y_min; 1155 hw->y_max = sc->sc_hidev->sc_y_max; 1156 hw->h_res = sc->sc_hidev->sc_h_res; 1157 hw->v_res = sc->sc_hidev->sc_v_res; 1158 hw->mt_slots = UBCMTP_MAX_FINGERS; 1159 hw->flags = WSMOUSEHW_MT_TRACKING; 1160 1161 return wsmouse_configure(sc->sc_wsmousedev, 1162 aplms_wsmousecfg, nitems(aplms_wsmousecfg)); 1163} 1164 1165void 1166aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 1167{ 1168 struct aplms_softc *sc = (struct aplms_softc *)self; 1169 struct ubcmtp_finger *finger; 1170 int off, s, btn, contacts; 1171 1172 if (!sc->sc_enabled) 1173 return; 1174 1175 contacts = 0; 1176 for (off = sc->tp_offset; off < packetlen; 1177 off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { 1178 finger = (struct ubcmtp_finger *)(packet + off); 1179 1180 if ((int16_t)letoh16(finger->touch_major) == 0) 1181 continue; /* finger lifted */ 1182 1183 sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); 1184 sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); 1185 sc->frame[contacts].pressure = DEFAULT_PRESSURE; 1186 contacts++; 1187 } 1188 1189 btn = sc->btn; 1190 sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF])); 1191 1192 if (contacts || sc->contacts || sc->btn != btn) { 1193 sc->contacts = contacts; 1194 s = spltty(); 1195 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 1196 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); 1197 wsmouse_input_sync(sc->sc_wsmousedev); 1198 splx(s); 1199 } 1200} 1201 1202int 1203aplms_enable(void *v) 1204{ 1205 struct aplms_softc *sc = v; 1206 1207 if (sc->sc_enabled) 1208 return EBUSY; 1209 1210 sc->sc_enabled = 1; 1211 return 0; 1212} 1213 1214void 1215aplms_disable(void *v) 1216{ 1217 struct aplms_softc *sc = v; 1218 1219 sc->sc_enabled = 0; 1220} 1221 1222int 1223aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 1224{ 1225 struct aplms_softc *sc = v; 1226 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 1227 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 1228 int wsmode; 1229 1230 switch (cmd) { 1231 case WSMOUSEIO_GTYPE: 1232 *(u_int *)data = hw->type; 1233 break; 1234 1235 case WSMOUSEIO_GCALIBCOORDS: 1236 wsmc->minx = hw->x_min; 1237 wsmc->maxx = hw->x_max; 1238 wsmc->miny = hw->y_min; 1239 wsmc->maxy = hw->y_max; 1240 wsmc->swapxy = 0; 1241 wsmc->resx = hw->h_res; 1242 wsmc->resy = hw->v_res; 1243 break; 1244 1245 case WSMOUSEIO_SETMODE: 1246 wsmode = *(u_int *)data; 1247 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 1248 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 1249 wsmode); 1250 return (EINVAL); 1251 } 1252 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 1253 break; 1254 1255 default: 1256 return -1; 1257 } 1258 1259 return 0; 1260} 1261 1262#else 1263 1264void 1265aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 1266{ 1267} 1268 1269#endif