1 /* $OpenBSD: aplhidev.c,v 1.12 2023/07/02 21:44:04 bru 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 <machine/fdt.h> 29 30 #include <dev/spi/spivar.h> 31 32 #include <dev/ofw/openfirm.h> 33 #include <dev/ofw/ofw_gpio.h> 34 #include <dev/ofw/ofw_pinctrl.h> 35 36 #include <dev/usb/usbdevs.h> 37 38 #include <dev/wscons/wsconsio.h> 39 #include <dev/wscons/wskbdvar.h> 40 #include <dev/wscons/wsksymdef.h> 41 #include <dev/wscons/wsmousevar.h> 42 43 #include <dev/hid/hid.h> 44 #include <dev/hid/hidkbdsc.h> 45 #include <dev/hid/hidmsvar.h> 46 47 #include "aplhidev.h" 48 49 #define APLHIDEV_READ_PACKET 0x20 50 #define APLHIDEV_WRITE_PACKET 0x40 51 52 #define APLHIDEV_KBD_DEVICE 1 53 #define APLHIDEV_TP_DEVICE 2 54 #define APLHIDEV_INFO_DEVICE 208 55 56 #define APLHIDEV_GET_INFO 0x0120 57 #define APLHIDEV_GET_DESCRIPTOR 0x1020 58 #define APLHIDEV_DESC_MAX 512 59 #define APLHIDEV_KBD_REPORT 0x0110 60 #define APLHIDEV_TP_REPORT 0x0210 61 #define APLHIDEV_SET_LEDS 0x0151 62 #define APLHIDEV_SET_MODE 0x0252 63 #define APLHIDEV_MODE_HID 0x00 64 #define APLHIDEV_MODE_RAW 0x01 65 66 struct aplhidev_attach_args { 67 uint8_t aa_reportid; 68 void *aa_desc; 69 size_t aa_desclen; 70 }; 71 72 struct aplhidev_spi_packet { 73 uint8_t flags; 74 uint8_t device; 75 uint16_t offset; 76 uint16_t remaining; 77 uint16_t len; 78 uint8_t data[246]; 79 uint16_t crc; 80 }; 81 82 struct aplhidev_spi_status { 83 uint8_t status[4]; 84 }; 85 86 struct aplhidev_msghdr { 87 uint16_t type; 88 uint8_t device; 89 uint8_t msgid; 90 uint16_t rsplen; 91 uint16_t cmdlen; 92 }; 93 94 struct aplhidev_info_hdr { 95 uint16_t unknown[2]; 96 uint16_t num_devices; 97 uint16_t vendor; 98 uint16_t product; 99 uint16_t version; 100 uint16_t vendor_str[2]; 101 uint16_t product_str[2]; 102 uint16_t serial_str[2]; 103 }; 104 105 struct aplhidev_get_desc { 106 struct aplhidev_msghdr hdr; 107 uint16_t crc; 108 }; 109 110 struct aplhidev_set_leds { 111 struct aplhidev_msghdr hdr; 112 uint8_t reportid; 113 uint8_t leds; 114 uint16_t crc; 115 }; 116 117 struct aplhidev_set_mode { 118 struct aplhidev_msghdr hdr; 119 uint8_t reportid; 120 uint8_t mode; 121 uint16_t crc; 122 }; 123 124 struct aplhidev_softc { 125 struct device sc_dev; 126 int sc_node; 127 128 spi_tag_t sc_spi_tag; 129 struct spi_config sc_spi_conf; 130 131 uint8_t sc_msgid; 132 133 uint32_t *sc_gpio; 134 int sc_gpiolen; 135 136 uint8_t sc_mode; 137 uint16_t sc_vendor; 138 uint16_t sc_product; 139 140 struct device *sc_kbd; 141 uint8_t sc_kbddesc[APLHIDEV_DESC_MAX]; 142 size_t sc_kbddesclen; 143 144 struct device *sc_ms; 145 uint8_t sc_tpdesc[APLHIDEV_DESC_MAX]; 146 size_t sc_tpdesclen; 147 }; 148 149 int aplhidev_match(struct device *, void *, void *); 150 void aplhidev_attach(struct device *, struct device *, void *); 151 152 const struct cfattach aplhidev_ca = { 153 sizeof(struct aplhidev_softc), aplhidev_match, aplhidev_attach 154 }; 155 156 struct cfdriver aplhidev_cd = { 157 NULL, "aplhidev", DV_DULL 158 }; 159 160 void aplhidev_get_info(struct aplhidev_softc *); 161 void aplhidev_get_descriptor(struct aplhidev_softc *, uint8_t); 162 void aplhidev_set_leds(struct aplhidev_softc *, uint8_t); 163 void aplhidev_set_mode(struct aplhidev_softc *, uint8_t); 164 165 int aplhidev_intr(void *); 166 void aplkbd_intr(struct device *, uint8_t *, size_t); 167 void aplms_intr(struct device *, uint8_t *, size_t); 168 169 int 170 aplhidev_match(struct device *parent, void *match, void *aux) 171 { 172 struct spi_attach_args *sa = aux; 173 174 if (strcmp(sa->sa_name, "apple,spi-hid-transport") == 0) 175 return 1; 176 177 return 0; 178 } 179 180 void 181 aplhidev_attach(struct device *parent, struct device *self, void *aux) 182 { 183 struct aplhidev_softc *sc = (struct aplhidev_softc *)self; 184 struct spi_attach_args *sa = aux; 185 struct aplhidev_attach_args aa; 186 int retry; 187 188 sc->sc_spi_tag = sa->sa_tag; 189 sc->sc_node = *(int *)sa->sa_cookie; 190 191 sc->sc_gpiolen = OF_getproplen(sc->sc_node, "spien-gpios"); 192 if (sc->sc_gpiolen > 0) { 193 sc->sc_gpio = malloc(sc->sc_gpiolen, M_TEMP, M_WAITOK); 194 OF_getpropintarray(sc->sc_node, "spien-gpios", 195 sc->sc_gpio, sc->sc_gpiolen); 196 gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT); 197 198 /* Reset */ 199 gpio_controller_set_pin(sc->sc_gpio, 1); 200 delay(5000); 201 gpio_controller_set_pin(sc->sc_gpio, 0); 202 delay(5000); 203 204 /* Enable. */ 205 gpio_controller_set_pin(sc->sc_gpio, 1); 206 delay(50000); 207 } 208 209 sc->sc_spi_conf.sc_bpw = 8; 210 sc->sc_spi_conf.sc_freq = OF_getpropint(sc->sc_node, 211 "spi-max-frequency", 0); 212 sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0); 213 sc->sc_spi_conf.sc_cs_delay = 100; 214 215 fdt_intr_establish(sc->sc_node, IPL_TTY, 216 aplhidev_intr, sc, sc->sc_dev.dv_xname); 217 218 aplhidev_get_info(sc); 219 for (retry = 10; retry > 0; retry--) { 220 aplhidev_intr(sc); 221 delay(1000); 222 if (sc->sc_vendor != 0 && sc->sc_product != 0) 223 break; 224 } 225 226 aplhidev_get_descriptor(sc, APLHIDEV_KBD_DEVICE); 227 for (retry = 10; retry > 0; retry--) { 228 aplhidev_intr(sc); 229 delay(1000); 230 if (sc->sc_kbddesclen > 0) 231 break; 232 } 233 234 aplhidev_get_descriptor(sc, APLHIDEV_TP_DEVICE); 235 for (retry = 10; retry > 0; retry--) { 236 aplhidev_intr(sc); 237 delay(1000); 238 if (sc->sc_tpdesclen > 0) 239 break; 240 } 241 242 sc->sc_mode = APLHIDEV_MODE_HID; 243 aplhidev_set_mode(sc, APLHIDEV_MODE_RAW); 244 for (retry = 10; retry > 0; retry--) { 245 aplhidev_intr(sc); 246 delay(1000); 247 if (sc->sc_mode == APLHIDEV_MODE_RAW) 248 break; 249 } 250 251 printf("\n"); 252 253 if (sc->sc_kbddesclen > 0) { 254 aa.aa_reportid = APLHIDEV_KBD_DEVICE; 255 aa.aa_desc = sc->sc_kbddesc; 256 aa.aa_desclen = sc->sc_kbddesclen; 257 sc->sc_kbd = config_found(self, &aa, NULL); 258 } 259 260 if (sc->sc_tpdesclen > 0) { 261 aa.aa_reportid = APLHIDEV_TP_DEVICE; 262 aa.aa_desc = sc->sc_tpdesc; 263 aa.aa_desclen = sc->sc_tpdesclen; 264 sc->sc_ms = config_found(self, &aa, NULL); 265 } 266 } 267 268 void 269 aplhidev_get_info(struct aplhidev_softc *sc) 270 { 271 struct aplhidev_spi_packet packet; 272 struct aplhidev_get_desc *msg; 273 struct aplhidev_spi_status status; 274 275 memset(&packet, 0, sizeof(packet)); 276 packet.flags = APLHIDEV_WRITE_PACKET; 277 packet.device = APLHIDEV_INFO_DEVICE; 278 packet.len = sizeof(*msg); 279 280 msg = (void *)&packet.data[0]; 281 msg->hdr.type = APLHIDEV_GET_INFO; 282 msg->hdr.device = APLHIDEV_INFO_DEVICE; 283 msg->hdr.msgid = sc->sc_msgid++; 284 msg->hdr.cmdlen = 0; 285 msg->hdr.rsplen = APLHIDEV_DESC_MAX; 286 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 287 288 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 289 290 spi_acquire_bus(sc->sc_spi_tag, 0); 291 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 292 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 293 SPI_KEEP_CS); 294 delay(100); 295 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 296 spi_release_bus(sc->sc_spi_tag, 0); 297 298 delay(1000); 299 } 300 301 void 302 aplhidev_get_descriptor(struct aplhidev_softc *sc, uint8_t device) 303 { 304 struct aplhidev_spi_packet packet; 305 struct aplhidev_get_desc *msg; 306 struct aplhidev_spi_status status; 307 308 memset(&packet, 0, sizeof(packet)); 309 packet.flags = APLHIDEV_WRITE_PACKET; 310 packet.device = APLHIDEV_INFO_DEVICE; 311 packet.len = sizeof(*msg); 312 313 msg = (void *)&packet.data[0]; 314 msg->hdr.type = APLHIDEV_GET_DESCRIPTOR; 315 msg->hdr.device = device; 316 msg->hdr.msgid = sc->sc_msgid++; 317 msg->hdr.cmdlen = 0; 318 msg->hdr.rsplen = APLHIDEV_DESC_MAX; 319 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 320 321 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 322 323 spi_acquire_bus(sc->sc_spi_tag, 0); 324 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 325 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 326 SPI_KEEP_CS); 327 delay(100); 328 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 329 spi_release_bus(sc->sc_spi_tag, 0); 330 331 delay(1000); 332 } 333 334 void 335 aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds) 336 { 337 struct aplhidev_spi_packet packet; 338 struct aplhidev_set_leds *msg; 339 struct aplhidev_spi_status status; 340 341 memset(&packet, 0, sizeof(packet)); 342 packet.flags = APLHIDEV_WRITE_PACKET; 343 packet.device = APLHIDEV_KBD_DEVICE; 344 packet.len = sizeof(*msg); 345 346 msg = (void *)&packet.data[0]; 347 msg->hdr.type = APLHIDEV_SET_LEDS; 348 msg->hdr.device = APLHIDEV_KBD_DEVICE; 349 msg->hdr.msgid = sc->sc_msgid++; 350 msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; 351 msg->hdr.rsplen = msg->hdr.cmdlen; 352 msg->reportid = APLHIDEV_KBD_DEVICE; 353 msg->leds = leds; 354 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 355 356 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 357 358 /* 359 * XXX Without a delay here, the command will fail. Does the 360 * controller need a bit of time between sending us a keypress 361 * event and accepting a new command from us? 362 */ 363 delay(250); 364 365 spi_acquire_bus(sc->sc_spi_tag, 0); 366 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 367 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 368 SPI_KEEP_CS); 369 delay(100); 370 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 371 spi_release_bus(sc->sc_spi_tag, 0); 372 } 373 374 void 375 aplhidev_set_mode(struct aplhidev_softc *sc, uint8_t mode) 376 { 377 struct aplhidev_spi_packet packet; 378 struct aplhidev_set_mode *msg; 379 struct aplhidev_spi_status status; 380 381 memset(&packet, 0, sizeof(packet)); 382 packet.flags = APLHIDEV_WRITE_PACKET; 383 packet.device = APLHIDEV_TP_DEVICE; 384 packet.len = sizeof(*msg); 385 386 msg = (void *)&packet.data[0]; 387 msg->hdr.type = APLHIDEV_SET_MODE; 388 msg->hdr.device = APLHIDEV_TP_DEVICE; 389 msg->hdr.msgid = sc->sc_msgid++; 390 msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; 391 msg->hdr.rsplen = msg->hdr.cmdlen; 392 msg->reportid = APLHIDEV_TP_DEVICE; 393 msg->mode = mode; 394 msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); 395 396 packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); 397 398 spi_acquire_bus(sc->sc_spi_tag, 0); 399 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 400 spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), 401 SPI_KEEP_CS); 402 delay(100); 403 spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); 404 spi_release_bus(sc->sc_spi_tag, 0); 405 406 delay(1000); 407 } 408 409 int 410 aplhidev_intr(void *arg) 411 { 412 struct aplhidev_softc *sc = arg; 413 struct aplhidev_spi_packet packet; 414 struct aplhidev_msghdr *hdr = (struct aplhidev_msghdr *)&packet.data[0]; 415 416 memset(&packet, 0, sizeof(packet)); 417 spi_acquire_bus(sc->sc_spi_tag, 0); 418 spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); 419 spi_read(sc->sc_spi_tag, (char *)&packet, sizeof(packet)); 420 spi_release_bus(sc->sc_spi_tag, 0); 421 422 /* Treat empty packets as spurious interrupts. */ 423 if (packet.flags == 0 && packet.device == 0 && packet.crc == 0) 424 return 0; 425 426 if (crc16(0, (uint8_t *)&packet, sizeof(packet))) 427 return 1; 428 429 /* Keyboard input. */ 430 if (packet.flags == APLHIDEV_READ_PACKET && 431 packet.device == APLHIDEV_KBD_DEVICE && 432 hdr->type == APLHIDEV_KBD_REPORT) { 433 if (sc->sc_kbd) 434 aplkbd_intr(sc->sc_kbd, &packet.data[8], hdr->cmdlen); 435 return 1; 436 } 437 438 /* Touchpad input. */ 439 if (packet.flags == APLHIDEV_READ_PACKET && 440 packet.device == APLHIDEV_TP_DEVICE && 441 hdr->type == APLHIDEV_TP_REPORT) { 442 if (sc->sc_ms) 443 aplms_intr(sc->sc_ms, &packet.data[8], hdr->cmdlen); 444 return 1; 445 } 446 447 /* Replies to commands we sent. */ 448 if (packet.flags == APLHIDEV_WRITE_PACKET && 449 packet.device == APLHIDEV_INFO_DEVICE && 450 hdr->type == APLHIDEV_GET_INFO) { 451 struct aplhidev_info_hdr *info = 452 (struct aplhidev_info_hdr *)&packet.data[8]; 453 sc->sc_vendor = info->vendor; 454 sc->sc_product = info->product; 455 return 1; 456 } 457 if (packet.flags == APLHIDEV_WRITE_PACKET && 458 packet.device == APLHIDEV_INFO_DEVICE && 459 hdr->type == APLHIDEV_GET_DESCRIPTOR) { 460 switch (hdr->device) { 461 case APLHIDEV_KBD_DEVICE: 462 memcpy(sc->sc_kbddesc, &packet.data[8], hdr->cmdlen); 463 sc->sc_kbddesclen = hdr->cmdlen; 464 break; 465 case APLHIDEV_TP_DEVICE: 466 memcpy(sc->sc_tpdesc, &packet.data[8], hdr->cmdlen); 467 sc->sc_tpdesclen = hdr->cmdlen; 468 break; 469 } 470 471 return 1; 472 } 473 if (packet.flags == APLHIDEV_WRITE_PACKET && 474 packet.device == APLHIDEV_TP_DEVICE && 475 hdr->type == APLHIDEV_SET_MODE) { 476 sc->sc_mode = APLHIDEV_MODE_RAW; 477 return 1; 478 } 479 480 /* Valid, but unrecognized packet; ignore for now. */ 481 return 1; 482 } 483 484 /* Keyboard */ 485 486 struct aplkbd_softc { 487 struct device sc_dev; 488 struct aplhidev_softc *sc_hidev; 489 struct hidkbd sc_kbd; 490 int sc_spl; 491 }; 492 493 void aplkbd_cngetc(void *, u_int *, int *); 494 void aplkbd_cnpollc(void *, int); 495 void aplkbd_cnbell(void *, u_int, u_int, u_int); 496 497 const struct wskbd_consops aplkbd_consops = { 498 aplkbd_cngetc, 499 aplkbd_cnpollc, 500 aplkbd_cnbell, 501 }; 502 503 int aplkbd_enable(void *, int); 504 void aplkbd_set_leds(void *, int); 505 int aplkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 506 507 const struct wskbd_accessops aplkbd_accessops = { 508 .enable = aplkbd_enable, 509 .ioctl = aplkbd_ioctl, 510 .set_leds = aplkbd_set_leds, 511 }; 512 513 int aplkbd_match(struct device *, void *, void *); 514 void aplkbd_attach(struct device *, struct device *, void *); 515 516 const struct cfattach aplkbd_ca = { 517 sizeof(struct aplkbd_softc), aplkbd_match, aplkbd_attach 518 }; 519 520 struct cfdriver aplkbd_cd = { 521 NULL, "aplkbd", DV_DULL 522 }; 523 524 int 525 aplkbd_match(struct device *parent, void *match, void *aux) 526 { 527 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 528 529 return (aa->aa_reportid == APLHIDEV_KBD_DEVICE); 530 } 531 532 void 533 aplkbd_attach(struct device *parent, struct device *self, void *aux) 534 { 535 struct aplkbd_softc *sc = (struct aplkbd_softc *)self; 536 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 537 struct hidkbd *kbd = &sc->sc_kbd; 538 539 sc->sc_hidev = (struct aplhidev_softc *)parent; 540 if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE, 541 aa->aa_desc, aa->aa_desclen)) 542 return; 543 544 printf("\n"); 545 546 if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), 547 1, hid_input, &kbd->sc_fn, NULL)) { 548 switch (sc->sc_hidev->sc_product) { 549 case USB_PRODUCT_APPLE_WELLSPRINGM1_J293: 550 kbd->sc_munge = hidkbd_apple_tb_munge; 551 break; 552 default: 553 kbd->sc_munge = hidkbd_apple_munge; 554 break; 555 } 556 } 557 558 if (kbd->sc_console_keyboard) { 559 extern struct wskbd_mapdata ukbd_keymapdata; 560 561 ukbd_keymapdata.layout = KB_US | KB_DEFAULT; 562 wskbd_cnattach(&aplkbd_consops, sc, &ukbd_keymapdata); 563 aplkbd_enable(sc, 1); 564 } 565 566 hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops); 567 } 568 569 void 570 aplkbd_intr(struct device *self, uint8_t *packet, size_t packetlen) 571 { 572 struct aplkbd_softc *sc = (struct aplkbd_softc *)self; 573 struct hidkbd *kbd = &sc->sc_kbd; 574 575 if (kbd->sc_enabled) 576 hidkbd_input(kbd, &packet[1], packetlen - 1); 577 } 578 579 int 580 aplkbd_enable(void *v, int on) 581 { 582 struct aplkbd_softc *sc = v; 583 struct hidkbd *kbd = &sc->sc_kbd; 584 585 return hidkbd_enable(kbd, on); 586 } 587 588 int 589 aplkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 590 { 591 struct aplkbd_softc *sc = v; 592 struct hidkbd *kbd = &sc->sc_kbd; 593 594 switch (cmd) { 595 case WSKBDIO_GTYPE: 596 /* XXX: should we set something else? */ 597 *(u_int *)data = WSKBD_TYPE_USB; 598 return 0; 599 case WSKBDIO_SETLEDS: 600 aplkbd_set_leds(v, *(int *)data); 601 return 0; 602 default: 603 return hidkbd_ioctl(kbd, cmd, data, flag, p); 604 } 605 } 606 607 void 608 aplkbd_set_leds(void *v, int leds) 609 { 610 struct aplkbd_softc *sc = v; 611 struct hidkbd *kbd = &sc->sc_kbd; 612 uint8_t res; 613 614 if (hidkbd_set_leds(kbd, leds, &res)) 615 aplhidev_set_leds(sc->sc_hidev, res); 616 } 617 618 /* Console interface. */ 619 void 620 aplkbd_cngetc(void *v, u_int *type, int *data) 621 { 622 struct aplkbd_softc *sc = v; 623 struct hidkbd *kbd = &sc->sc_kbd; 624 625 kbd->sc_polling = 1; 626 while (kbd->sc_npollchar <= 0) { 627 aplhidev_intr(sc->sc_dev.dv_parent); 628 delay(1000); 629 } 630 kbd->sc_polling = 0; 631 hidkbd_cngetc(kbd, type, data); 632 } 633 634 void 635 aplkbd_cnpollc(void *v, int on) 636 { 637 struct aplkbd_softc *sc = v; 638 639 if (on) 640 sc->sc_spl = spltty(); 641 else 642 splx(sc->sc_spl); 643 } 644 645 void 646 aplkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 647 { 648 hidkbd_bell(pitch, period, volume, 1); 649 } 650 651 #if NAPLMS > 0 652 653 /* Touchpad */ 654 655 /* 656 * The contents of the touchpad event packets is identical to those 657 * used by the ubcmtp(4) driver. The relevant definitions and the 658 * code to decode the packets is replicated here. 659 */ 660 661 struct ubcmtp_finger { 662 uint16_t origin; 663 uint16_t abs_x; 664 uint16_t abs_y; 665 uint16_t rel_x; 666 uint16_t rel_y; 667 uint16_t tool_major; 668 uint16_t tool_minor; 669 uint16_t orientation; 670 uint16_t touch_major; 671 uint16_t touch_minor; 672 uint16_t unused[2]; 673 uint16_t pressure; 674 uint16_t multi; 675 } __packed __attribute((aligned(2))); 676 677 #define UBCMTP_MAX_FINGERS 16 678 679 #define UBCMTP_TYPE4_TPOFF (24 * sizeof(uint16_t)) 680 #define UBCMTP_TYPE4_BTOFF 31 681 #define UBCMTP_TYPE4_FINGERPAD (1 * sizeof(uint16_t)) 682 683 /* Use a constant, synaptics-compatible pressure value for now. */ 684 #define DEFAULT_PRESSURE 40 685 686 static struct wsmouse_param aplms_wsmousecfg[] = { 687 { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */ 688 }; 689 690 struct aplms_softc { 691 struct device sc_dev; 692 struct device *sc_wsmousedev; 693 694 int sc_enabled; 695 696 int tp_offset; 697 int tp_fingerpad; 698 699 struct mtpoint frame[UBCMTP_MAX_FINGERS]; 700 int contacts; 701 int btn; 702 }; 703 704 int aplms_enable(void *); 705 void aplms_disable(void *); 706 int aplms_ioctl(void *, u_long, caddr_t, int, struct proc *); 707 708 const struct wsmouse_accessops aplms_accessops = { 709 .enable = aplms_enable, 710 .disable = aplms_disable, 711 .ioctl = aplms_ioctl, 712 }; 713 714 int aplms_match(struct device *, void *, void *); 715 void aplms_attach(struct device *, struct device *, void *); 716 717 const struct cfattach aplms_ca = { 718 sizeof(struct aplms_softc), aplms_match, aplms_attach 719 }; 720 721 struct cfdriver aplms_cd = { 722 NULL, "aplms", DV_DULL 723 }; 724 725 int aplms_configure(struct aplms_softc *); 726 727 int 728 aplms_match(struct device *parent, void *match, void *aux) 729 { 730 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 731 732 return (aa->aa_reportid == APLHIDEV_TP_DEVICE); 733 } 734 735 void 736 aplms_attach(struct device *parent, struct device *self, void *aux) 737 { 738 struct aplms_softc *sc = (struct aplms_softc *)self; 739 struct wsmousedev_attach_args aa; 740 741 printf("\n"); 742 743 sc->tp_offset = UBCMTP_TYPE4_TPOFF; 744 sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; 745 746 aa.accessops = &aplms_accessops; 747 aa.accesscookie = sc; 748 749 sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint); 750 if (sc->sc_wsmousedev != NULL && aplms_configure(sc)) 751 aplms_disable(sc); 752 } 753 754 int 755 aplms_configure(struct aplms_softc *sc) 756 { 757 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 758 759 /* The values below are for the MacBookPro17,1 */ 760 hw->type = WSMOUSE_TYPE_TOUCHPAD; 761 hw->hw_type = WSMOUSEHW_CLICKPAD; 762 hw->x_min = -6046; 763 hw->x_max = 6536; 764 hw->y_min = -164; 765 hw->y_max = 7439; 766 hw->mt_slots = UBCMTP_MAX_FINGERS; 767 hw->flags = WSMOUSEHW_MT_TRACKING; 768 769 return wsmouse_configure(sc->sc_wsmousedev, 770 aplms_wsmousecfg, nitems(aplms_wsmousecfg)); 771 } 772 773 void 774 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 775 { 776 struct aplms_softc *sc = (struct aplms_softc *)self; 777 struct ubcmtp_finger *finger; 778 int off, s, btn, contacts; 779 780 if (!sc->sc_enabled) 781 return; 782 783 contacts = 0; 784 for (off = sc->tp_offset; off < packetlen; 785 off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { 786 finger = (struct ubcmtp_finger *)(packet + off); 787 788 if ((int16_t)letoh16(finger->touch_major) == 0) 789 continue; /* finger lifted */ 790 791 sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); 792 sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); 793 sc->frame[contacts].pressure = DEFAULT_PRESSURE; 794 contacts++; 795 } 796 797 btn = sc->btn; 798 sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF])); 799 800 if (contacts || sc->contacts || sc->btn != btn) { 801 sc->contacts = contacts; 802 s = spltty(); 803 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 804 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); 805 wsmouse_input_sync(sc->sc_wsmousedev); 806 splx(s); 807 } 808 } 809 810 int 811 aplms_enable(void *v) 812 { 813 struct aplms_softc *sc = v; 814 815 if (sc->sc_enabled) 816 return EBUSY; 817 818 sc->sc_enabled = 1; 819 return 0; 820 } 821 822 void 823 aplms_disable(void *v) 824 { 825 struct aplms_softc *sc = v; 826 827 sc->sc_enabled = 0; 828 } 829 830 int 831 aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 832 { 833 struct aplms_softc *sc = v; 834 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 835 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 836 int wsmode; 837 838 switch (cmd) { 839 case WSMOUSEIO_GTYPE: 840 *(u_int *)data = hw->type; 841 break; 842 843 case WSMOUSEIO_GCALIBCOORDS: 844 wsmc->minx = hw->x_min; 845 wsmc->maxx = hw->x_max; 846 wsmc->miny = hw->y_min; 847 wsmc->maxy = hw->y_max; 848 wsmc->swapxy = 0; 849 wsmc->resx = 0; 850 wsmc->resy = 0; 851 break; 852 853 case WSMOUSEIO_SETMODE: 854 wsmode = *(u_int *)data; 855 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 856 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 857 wsmode); 858 return (EINVAL); 859 } 860 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 861 break; 862 863 default: 864 return -1; 865 } 866 867 return 0; 868 } 869 870 #else 871 872 void 873 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 874 { 875 } 876 877 #endif 878