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