jcs's openbsd hax
openbsd
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