1 /* $OpenBSD: aplhidev.c,v 1.11 2023/04/10 15:14:04 tobhe 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 struct aplms_softc { 687 struct device sc_dev; 688 struct device *sc_wsmousedev; 689 690 int sc_enabled; 691 692 int tp_offset; 693 int tp_fingerpad; 694 695 struct mtpoint frame[UBCMTP_MAX_FINGERS]; 696 int contacts; 697 int btn; 698 }; 699 700 int aplms_enable(void *); 701 void aplms_disable(void *); 702 int aplms_ioctl(void *, u_long, caddr_t, int, struct proc *); 703 704 const struct wsmouse_accessops aplms_accessops = { 705 .enable = aplms_enable, 706 .disable = aplms_disable, 707 .ioctl = aplms_ioctl, 708 }; 709 710 int aplms_match(struct device *, void *, void *); 711 void aplms_attach(struct device *, struct device *, void *); 712 713 const struct cfattach aplms_ca = { 714 sizeof(struct aplms_softc), aplms_match, aplms_attach 715 }; 716 717 struct cfdriver aplms_cd = { 718 NULL, "aplms", DV_DULL 719 }; 720 721 int aplms_configure(struct aplms_softc *); 722 723 int 724 aplms_match(struct device *parent, void *match, void *aux) 725 { 726 struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; 727 728 return (aa->aa_reportid == APLHIDEV_TP_DEVICE); 729 } 730 731 void 732 aplms_attach(struct device *parent, struct device *self, void *aux) 733 { 734 struct aplms_softc *sc = (struct aplms_softc *)self; 735 struct wsmousedev_attach_args aa; 736 737 printf("\n"); 738 739 sc->tp_offset = UBCMTP_TYPE4_TPOFF; 740 sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; 741 742 aa.accessops = &aplms_accessops; 743 aa.accesscookie = sc; 744 745 sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint); 746 if (sc->sc_wsmousedev != NULL && aplms_configure(sc)) 747 aplms_disable(sc); 748 } 749 750 int 751 aplms_configure(struct aplms_softc *sc) 752 { 753 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 754 755 /* The values below are for the MacBookPro17,1 */ 756 hw->type = WSMOUSE_TYPE_TOUCHPAD; 757 hw->hw_type = WSMOUSEHW_CLICKPAD; 758 hw->x_min = -6046; 759 hw->x_max = 6536; 760 hw->y_min = -164; 761 hw->y_max = 7439; 762 hw->mt_slots = UBCMTP_MAX_FINGERS; 763 hw->flags = WSMOUSEHW_MT_TRACKING; 764 765 return wsmouse_configure(sc->sc_wsmousedev, NULL, 0); 766 } 767 768 void 769 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 770 { 771 struct aplms_softc *sc = (struct aplms_softc *)self; 772 struct ubcmtp_finger *finger; 773 int off, s, btn, contacts; 774 775 if (!sc->sc_enabled) 776 return; 777 778 contacts = 0; 779 for (off = sc->tp_offset; off < packetlen; 780 off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { 781 finger = (struct ubcmtp_finger *)(packet + off); 782 783 if ((int16_t)letoh16(finger->touch_major) == 0) 784 continue; /* finger lifted */ 785 786 sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); 787 sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); 788 sc->frame[contacts].pressure = DEFAULT_PRESSURE; 789 contacts++; 790 } 791 792 btn = sc->btn; 793 sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF])); 794 795 if (contacts || sc->contacts || sc->btn != btn) { 796 sc->contacts = contacts; 797 s = spltty(); 798 wsmouse_buttons(sc->sc_wsmousedev, sc->btn); 799 wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); 800 wsmouse_input_sync(sc->sc_wsmousedev); 801 splx(s); 802 } 803 } 804 805 int 806 aplms_enable(void *v) 807 { 808 struct aplms_softc *sc = v; 809 810 if (sc->sc_enabled) 811 return EBUSY; 812 813 sc->sc_enabled = 1; 814 return 0; 815 } 816 817 void 818 aplms_disable(void *v) 819 { 820 struct aplms_softc *sc = v; 821 822 sc->sc_enabled = 0; 823 } 824 825 int 826 aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 827 { 828 struct aplms_softc *sc = v; 829 struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); 830 struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; 831 int wsmode; 832 833 switch (cmd) { 834 case WSMOUSEIO_GTYPE: 835 *(u_int *)data = hw->type; 836 break; 837 838 case WSMOUSEIO_GCALIBCOORDS: 839 wsmc->minx = hw->x_min; 840 wsmc->maxx = hw->x_max; 841 wsmc->miny = hw->y_min; 842 wsmc->maxy = hw->y_max; 843 wsmc->swapxy = 0; 844 wsmc->resx = 0; 845 wsmc->resy = 0; 846 break; 847 848 case WSMOUSEIO_SETMODE: 849 wsmode = *(u_int *)data; 850 if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { 851 printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, 852 wsmode); 853 return (EINVAL); 854 } 855 wsmouse_set_mode(sc->sc_wsmousedev, wsmode); 856 break; 857 858 default: 859 return -1; 860 } 861 862 return 0; 863 } 864 865 #else 866 867 void 868 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) 869 { 870 } 871 872 #endif 873