From: Mark Kettenis Subject: Re: aplhidev: enable on amd64, add keyboard backlight support To: joshua stein Cc: tech@openbsd.org Date: Fri, 21 Nov 2025 23:52:22 +0100 > Date: Thu, 20 Nov 2025 10:46:08 -0600 > From: joshua stein > > On Thu, 20 Nov 2025 at 13:40:53 +0100, Mark Kettenis wrote: > > > Date: Thu, 13 Nov 2025 20:15:16 -0600 > > > From: joshua stein > > > > > > This moves aplhidev out of arch/arm64 and into dev/spi, adds > > > attachment via ACPI through ispi, enables it on amd64, and adds > > > support for adjusting keyboard backlight through 'wsconsctl > > > keyboard.backlight'. > > > > > > Tested on a 2017 MacBook 12". Hopefully it didn't break anything on > > > Apple M* arm64 laptops and I'm curious if the keyboard backlight > > > support also works there. > > > > > > Individual commits are here but this is just one consolidated diff: > > > > > > https://github.com/jcs/openbsd-src/commit/5cc8811f104532139877139b6852ae627963a602 > > > https://github.com/jcs/openbsd-src/commit/3a57a3b8440efc45d4e75a36e843328f8e5ff015 > > > https://github.com/jcs/openbsd-src/commit/852de258b6625c33641bdf36303699ba157f3d55 > > > > > > I also tested it in RAMDISK_CD so the keyboard works during > > > installation but that's not included here. > > > > Diff doesn't apply because of the file rename. I guess it is helpful > > to show the changes you made, and I can move the file by hand. > > > > But if I do so, things don't compile on arm64: > > Here is an updated diff that was tested on amd64 and compiles on > arm64. The wskbd backlight change is now only done on amd64. Thanks. Tested on a MacBook Pro (14-inch, M1 Pro, 2021). Everything still works. A few remarks below: > Index: arch/amd64/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v > retrieving revision 1.536 > diff -u -p -u -r1.536 GENERIC > --- arch/amd64/conf/GENERIC 14 Nov 2025 01:55:07 -0000 1.536 > +++ arch/amd64/conf/GENERIC 20 Nov 2025 16:42:41 -0000 > @@ -208,6 +208,11 @@ gpio* at skgpio? > > ispi* at acpi? # Intel LPSS SPI controller > ispi* at pci? > +aplhidev* at spi? # Apple SPI HID > +aplkbd* at aplhidev? > +wskbd* at aplkbd? mux 1 > +aplms* at aplhidev? > +wsmouse* at aplms? mux 0 > > #option PCMCIAVERBOSE > > Index: arch/amd64/conf/files.amd64 > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v > retrieving revision 1.117 > diff -u -p -u -r1.117 files.amd64 > --- arch/amd64/conf/files.amd64 12 Nov 2025 11:34:36 -0000 1.117 > +++ arch/amd64/conf/files.amd64 20 Nov 2025 16:42:41 -0000 > @@ -281,6 +281,17 @@ include "dev/onewire/files.onewire" > attach ipmi at mainbus > > # > +# SPI > +# > +device aplhidev {} > +attach aplhidev at spi > +device aplkbd: hid, hidkbd, wskbddev > +attach aplkbd at aplhidev > +device aplms: hid, hidms, wsmousedev > +attach aplms at aplhidev > +file dev/spi/aplhidev.c aplhidev | aplkbd | aplms needs-flag > + > +# > # device major numbers > # > > Index: arch/arm64/conf/files.arm64 > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v > retrieving revision 1.79 > diff -u -p -u -r1.79 files.arm64 > --- arch/arm64/conf/files.arm64 17 Sep 2025 09:32:55 -0000 1.79 > +++ arch/arm64/conf/files.arm64 20 Nov 2025 16:42:41 -0000 > @@ -186,7 +186,7 @@ device aplkbd: hid, hidkbd, wskbddev > attach aplkbd at aplhidev > device aplms: hid, hidms, wsmousedev > attach aplms at aplhidev > -file arch/arm64/dev/aplhidev.c aplhidev | aplkbd | aplms needs-flag > +file dev/spi/aplhidev.c aplhidev | aplkbd | aplms needs-flag > > device aplmbox > attach aplmbox at fdt > Index: arch/arm64/dev/aplhidev.c > =================================================================== > RCS file: arch/arm64/dev/aplhidev.c > diff -N arch/arm64/dev/aplhidev.c > --- arch/arm64/dev/aplhidev.c 15 Jan 2024 13:27:20 -0000 1.13 > +++ /dev/null 1 Jan 1970 00:00:00 -0000 > @@ -1,959 +0,0 @@ > -/* $OpenBSD: aplhidev.c,v 1.13 2024/01/15 13:27:20 kettenis Exp $ */ > -/* > - * Copyright (c) 2021 Mark Kettenis > - * Copyright (c) 2013-2014 joshua stein > - * > - * Permission to use, copy, modify, and distribute this software for any > - * purpose with or without fee is hereby granted, provided that the above > - * copyright notice and this permission notice appear in all copies. > - * > - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > - > -#include > - > -#include > - > -#include > - > -#include > -#include > -#include > - > -#include > - > -#include > -#include > -#include > -#include > - > -#include > -#include > -#include > - > -#include "aplhidev.h" > - > -#define APLHIDEV_READ_PACKET 0x20 > -#define APLHIDEV_WRITE_PACKET 0x40 > - > -#define APLHIDEV_KBD_DEVICE 1 > -#define APLHIDEV_TP_DEVICE 2 > -#define APLHIDEV_INFO_DEVICE 208 > - > -#define APLHIDEV_GET_INFO 0x0120 > -#define APLHIDEV_GET_DESCRIPTOR 0x1020 > -#define APLHIDEV_DESC_MAX 512 > -#define APLHIDEV_KBD_REPORT 0x0110 > -#define APLHIDEV_TP_REPORT 0x0210 > -#define APLHIDEV_SET_LEDS 0x0151 > -#define APLHIDEV_SET_MODE 0x0252 > -#define APLHIDEV_MODE_HID 0x00 > -#define APLHIDEV_MODE_RAW 0x01 > -#define APLHIDEV_GET_DIMENSIONS 0xd932 > - > -struct aplhidev_dim { > - uint32_t width; > - uint32_t height; > - int16_t x_min; > - int16_t y_min; > - int16_t x_max; > - int16_t y_max; > -}; > - > -struct aplhidev_attach_args { > - uint8_t aa_reportid; > - void *aa_desc; > - size_t aa_desclen; > -}; > - > -struct aplhidev_spi_packet { > - uint8_t flags; > - uint8_t device; > - uint16_t offset; > - uint16_t remaining; > - uint16_t len; > - uint8_t data[246]; > - uint16_t crc; > -}; > - > -struct aplhidev_spi_status { > - uint8_t status[4]; > -}; > - > -struct aplhidev_msghdr { > - uint16_t type; > - uint8_t device; > - uint8_t msgid; > - uint16_t rsplen; > - uint16_t cmdlen; > -}; > - > -struct aplhidev_info_hdr { > - uint16_t unknown[2]; > - uint16_t num_devices; > - uint16_t vendor; > - uint16_t product; > - uint16_t version; > - uint16_t vendor_str[2]; > - uint16_t product_str[2]; > - uint16_t serial_str[2]; > -}; > - > -struct aplhidev_get_desc { > - struct aplhidev_msghdr hdr; > - uint16_t crc; > -}; > - > -struct aplhidev_set_leds { > - struct aplhidev_msghdr hdr; > - uint8_t reportid; > - uint8_t leds; > - uint16_t crc; > -}; > - > -struct aplhidev_set_mode { > - struct aplhidev_msghdr hdr; > - uint8_t reportid; > - uint8_t mode; > - uint16_t crc; > -}; > - > -struct aplhidev_softc { > - struct device sc_dev; > - int sc_node; > - > - spi_tag_t sc_spi_tag; > - struct spi_config sc_spi_conf; > - > - uint8_t sc_msgid; > - > - uint32_t *sc_gpio; > - int sc_gpiolen; > - > - uint8_t sc_mode; > - uint16_t sc_vendor; > - uint16_t sc_product; > - > - struct device *sc_kbd; > - uint8_t sc_kbddesc[APLHIDEV_DESC_MAX]; > - size_t sc_kbddesclen; > - > - struct device *sc_ms; > - uint8_t sc_tpdesc[APLHIDEV_DESC_MAX]; > - size_t sc_tpdesclen; > - uint8_t sc_dimdesc[APLHIDEV_DESC_MAX]; > - size_t sc_dimdesclen; > - int sc_x_min; > - int sc_x_max; > - int sc_y_min; > - int sc_y_max; > - int sc_h_res; > - int sc_v_res; > -}; > - > -int aplhidev_match(struct device *, void *, void *); > -void aplhidev_attach(struct device *, struct device *, void *); > - > -const struct cfattach aplhidev_ca = { > - sizeof(struct aplhidev_softc), aplhidev_match, aplhidev_attach > -}; > - > -struct cfdriver aplhidev_cd = { > - NULL, "aplhidev", DV_DULL > -}; > - > -void aplhidev_get_info(struct aplhidev_softc *); > -void aplhidev_get_descriptor(struct aplhidev_softc *, uint8_t); > -void aplhidev_set_leds(struct aplhidev_softc *, uint8_t); > -void aplhidev_set_mode(struct aplhidev_softc *, uint8_t); > -void aplhidev_get_dimensions(struct aplhidev_softc *); > - > -int aplhidev_intr(void *); > -void aplkbd_intr(struct device *, uint8_t *, size_t); > -void aplms_intr(struct device *, uint8_t *, size_t); > - > -int > -aplhidev_match(struct device *parent, void *match, void *aux) > -{ > - struct spi_attach_args *sa = aux; > - > - if (strcmp(sa->sa_name, "apple,spi-hid-transport") == 0) > - return 1; > - > - return 0; > -} > - > -void > -aplhidev_attach(struct device *parent, struct device *self, void *aux) > -{ > - struct aplhidev_softc *sc = (struct aplhidev_softc *)self; > - struct spi_attach_args *sa = aux; > - struct aplhidev_attach_args aa; > - struct aplhidev_dim dim; > - int retry; > - > - sc->sc_spi_tag = sa->sa_tag; > - sc->sc_node = *(int *)sa->sa_cookie; > - > - sc->sc_gpiolen = OF_getproplen(sc->sc_node, "spien-gpios"); > - if (sc->sc_gpiolen > 0) { > - sc->sc_gpio = malloc(sc->sc_gpiolen, M_TEMP, M_WAITOK); > - OF_getpropintarray(sc->sc_node, "spien-gpios", > - sc->sc_gpio, sc->sc_gpiolen); > - gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT); > - > - /* Reset */ > - gpio_controller_set_pin(sc->sc_gpio, 1); > - delay(5000); > - gpio_controller_set_pin(sc->sc_gpio, 0); > - delay(5000); > - > - /* Enable. */ > - gpio_controller_set_pin(sc->sc_gpio, 1); > - delay(50000); > - } > - > - sc->sc_spi_conf.sc_bpw = 8; > - sc->sc_spi_conf.sc_freq = OF_getpropint(sc->sc_node, > - "spi-max-frequency", 0); > - sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0); > - sc->sc_spi_conf.sc_cs_delay = 100; > - > - fdt_intr_establish(sc->sc_node, IPL_TTY, > - aplhidev_intr, sc, sc->sc_dev.dv_xname); > - > - aplhidev_get_info(sc); > - for (retry = 10; retry > 0; retry--) { > - aplhidev_intr(sc); > - delay(1000); > - if (sc->sc_vendor != 0 && sc->sc_product != 0) > - break; > - } > - > - aplhidev_get_descriptor(sc, APLHIDEV_KBD_DEVICE); > - for (retry = 10; retry > 0; retry--) { > - aplhidev_intr(sc); > - delay(1000); > - if (sc->sc_kbddesclen > 0) > - break; > - } > - > - aplhidev_get_descriptor(sc, APLHIDEV_TP_DEVICE); > - for (retry = 10; retry > 0; retry--) { > - aplhidev_intr(sc); > - delay(1000); > - if (sc->sc_tpdesclen > 0) > - break; > - } > - > - sc->sc_mode = APLHIDEV_MODE_HID; > - aplhidev_set_mode(sc, APLHIDEV_MODE_RAW); > - for (retry = 10; retry > 0; retry--) { > - aplhidev_intr(sc); > - delay(1000); > - if (sc->sc_mode == APLHIDEV_MODE_RAW) > - break; > - } > - > - aplhidev_get_dimensions(sc); > - for (retry = 10; retry > 0; retry--) { > - aplhidev_intr(sc); > - delay(1000); > - if (sc->sc_dimdesclen > 0) > - break; > - } > - > - printf("\n"); > - > - if (sc->sc_dimdesclen == sizeof(dim) + 1) { > - memcpy(&dim, &sc->sc_dimdesc[1], sizeof(dim)); > - sc->sc_x_min = dim.x_min; > - sc->sc_x_max = dim.x_max; > - sc->sc_y_min = dim.y_min; > - sc->sc_y_max = dim.y_max; > - sc->sc_h_res = (100 * (dim.x_max - dim.x_min)) / dim.width; > - sc->sc_v_res = (100 * (dim.y_max - dim.y_min)) / dim.height; > - } > - > - if (sc->sc_kbddesclen > 0) { > - aa.aa_reportid = APLHIDEV_KBD_DEVICE; > - aa.aa_desc = sc->sc_kbddesc; > - aa.aa_desclen = sc->sc_kbddesclen; > - sc->sc_kbd = config_found(self, &aa, NULL); > - } > - > - if (sc->sc_tpdesclen > 0) { > - aa.aa_reportid = APLHIDEV_TP_DEVICE; > - aa.aa_desc = sc->sc_tpdesc; > - aa.aa_desclen = sc->sc_tpdesclen; > - sc->sc_ms = config_found(self, &aa, NULL); > - } > -} > - > -void > -aplhidev_get_info(struct aplhidev_softc *sc) > -{ > - struct aplhidev_spi_packet packet; > - struct aplhidev_get_desc *msg; > - struct aplhidev_spi_status status; > - > - memset(&packet, 0, sizeof(packet)); > - packet.flags = APLHIDEV_WRITE_PACKET; > - packet.device = APLHIDEV_INFO_DEVICE; > - packet.len = sizeof(*msg); > - > - msg = (void *)&packet.data[0]; > - msg->hdr.type = APLHIDEV_GET_INFO; > - msg->hdr.device = APLHIDEV_INFO_DEVICE; > - msg->hdr.msgid = sc->sc_msgid++; > - msg->hdr.cmdlen = 0; > - msg->hdr.rsplen = APLHIDEV_DESC_MAX; > - msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > - > - packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > - > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > - SPI_KEEP_CS); > - delay(100); > - spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > - spi_release_bus(sc->sc_spi_tag, 0); > - > - delay(1000); > -} > - > -void > -aplhidev_get_descriptor(struct aplhidev_softc *sc, uint8_t device) > -{ > - struct aplhidev_spi_packet packet; > - struct aplhidev_get_desc *msg; > - struct aplhidev_spi_status status; > - > - memset(&packet, 0, sizeof(packet)); > - packet.flags = APLHIDEV_WRITE_PACKET; > - packet.device = APLHIDEV_INFO_DEVICE; > - packet.len = sizeof(*msg); > - > - msg = (void *)&packet.data[0]; > - msg->hdr.type = APLHIDEV_GET_DESCRIPTOR; > - msg->hdr.device = device; > - msg->hdr.msgid = sc->sc_msgid++; > - msg->hdr.cmdlen = 0; > - msg->hdr.rsplen = APLHIDEV_DESC_MAX; > - msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > - > - packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > - > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > - SPI_KEEP_CS); > - delay(100); > - spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > - spi_release_bus(sc->sc_spi_tag, 0); > - > - delay(1000); > -} > - > -void > -aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds) > -{ > - struct aplhidev_spi_packet packet; > - struct aplhidev_set_leds *msg; > - struct aplhidev_spi_status status; > - > - memset(&packet, 0, sizeof(packet)); > - packet.flags = APLHIDEV_WRITE_PACKET; > - packet.device = APLHIDEV_KBD_DEVICE; > - packet.len = sizeof(*msg); > - > - msg = (void *)&packet.data[0]; > - msg->hdr.type = APLHIDEV_SET_LEDS; > - msg->hdr.device = APLHIDEV_KBD_DEVICE; > - msg->hdr.msgid = sc->sc_msgid++; > - msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; > - msg->hdr.rsplen = msg->hdr.cmdlen; > - msg->reportid = APLHIDEV_KBD_DEVICE; > - msg->leds = leds; > - msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > - > - packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > - > - /* > - * XXX Without a delay here, the command will fail. Does the > - * controller need a bit of time between sending us a keypress > - * event and accepting a new command from us? > - */ > - delay(250); > - > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > - SPI_KEEP_CS); > - delay(100); > - spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > - spi_release_bus(sc->sc_spi_tag, 0); > -} > - > -void > -aplhidev_set_mode(struct aplhidev_softc *sc, uint8_t mode) > -{ > - struct aplhidev_spi_packet packet; > - struct aplhidev_set_mode *msg; > - struct aplhidev_spi_status status; > - > - memset(&packet, 0, sizeof(packet)); > - packet.flags = APLHIDEV_WRITE_PACKET; > - packet.device = APLHIDEV_TP_DEVICE; > - packet.len = sizeof(*msg); > - > - msg = (void *)&packet.data[0]; > - msg->hdr.type = APLHIDEV_SET_MODE; > - msg->hdr.device = APLHIDEV_TP_DEVICE; > - msg->hdr.msgid = sc->sc_msgid++; > - msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; > - msg->hdr.rsplen = msg->hdr.cmdlen; > - msg->reportid = APLHIDEV_TP_DEVICE; > - msg->mode = mode; > - msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > - > - packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > - > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > - SPI_KEEP_CS); > - delay(100); > - spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > - spi_release_bus(sc->sc_spi_tag, 0); > - > - delay(1000); > -} > - > -void > -aplhidev_get_dimensions(struct aplhidev_softc *sc) > -{ > - struct aplhidev_spi_packet packet; > - struct aplhidev_get_desc *msg; > - struct aplhidev_spi_status status; > - > - memset(&packet, 0, sizeof(packet)); > - packet.flags = APLHIDEV_WRITE_PACKET; > - packet.device = APLHIDEV_TP_DEVICE; > - packet.len = sizeof(*msg); > - > - msg = (void *)&packet.data[0]; > - msg->hdr.type = APLHIDEV_GET_DIMENSIONS; > - msg->hdr.device = 0; > - msg->hdr.msgid = sc->sc_msgid++; > - msg->hdr.cmdlen = 0; > - msg->hdr.rsplen = APLHIDEV_DESC_MAX; > - msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > - > - packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > - > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > - SPI_KEEP_CS); > - delay(100); > - spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > - spi_release_bus(sc->sc_spi_tag, 0); > - > - delay(1000); > -} > - > -int > -aplhidev_intr(void *arg) > -{ > - struct aplhidev_softc *sc = arg; > - struct aplhidev_spi_packet packet; > - struct aplhidev_msghdr *hdr = (struct aplhidev_msghdr *)&packet.data[0]; > - > - memset(&packet, 0, sizeof(packet)); > - spi_acquire_bus(sc->sc_spi_tag, 0); > - spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > - spi_read(sc->sc_spi_tag, (char *)&packet, sizeof(packet)); > - spi_release_bus(sc->sc_spi_tag, 0); > - > - /* Treat empty packets as spurious interrupts. */ > - if (packet.flags == 0 && packet.device == 0 && packet.crc == 0) > - return 0; > - > - if (crc16(0, (uint8_t *)&packet, sizeof(packet))) > - return 1; > - > - /* Keyboard input. */ > - if (packet.flags == APLHIDEV_READ_PACKET && > - packet.device == APLHIDEV_KBD_DEVICE && > - hdr->type == APLHIDEV_KBD_REPORT) { > - if (sc->sc_kbd) > - aplkbd_intr(sc->sc_kbd, &packet.data[8], hdr->cmdlen); > - return 1; > - } > - > - /* Touchpad input. */ > - if (packet.flags == APLHIDEV_READ_PACKET && > - packet.device == APLHIDEV_TP_DEVICE && > - hdr->type == APLHIDEV_TP_REPORT) { > - if (sc->sc_ms) > - aplms_intr(sc->sc_ms, &packet.data[8], hdr->cmdlen); > - return 1; > - } > - > - /* Replies to commands we sent. */ > - if (packet.flags == APLHIDEV_WRITE_PACKET && > - packet.device == APLHIDEV_INFO_DEVICE && > - hdr->type == APLHIDEV_GET_INFO) { > - struct aplhidev_info_hdr *info = > - (struct aplhidev_info_hdr *)&packet.data[8]; > - sc->sc_vendor = info->vendor; > - sc->sc_product = info->product; > - return 1; > - } > - if (packet.flags == APLHIDEV_WRITE_PACKET && > - packet.device == APLHIDEV_INFO_DEVICE && > - hdr->type == APLHIDEV_GET_DESCRIPTOR) { > - switch (hdr->device) { > - case APLHIDEV_KBD_DEVICE: > - memcpy(sc->sc_kbddesc, &packet.data[8], hdr->cmdlen); > - sc->sc_kbddesclen = hdr->cmdlen; > - break; > - case APLHIDEV_TP_DEVICE: > - memcpy(sc->sc_tpdesc, &packet.data[8], hdr->cmdlen); > - sc->sc_tpdesclen = hdr->cmdlen; > - break; > - } > - > - return 1; > - } > - if (packet.flags == APLHIDEV_WRITE_PACKET && > - packet.device == APLHIDEV_TP_DEVICE && > - hdr->type == APLHIDEV_SET_MODE) { > - sc->sc_mode = APLHIDEV_MODE_RAW; > - return 1; > - } > - if (packet.flags == APLHIDEV_WRITE_PACKET && > - packet.device == APLHIDEV_TP_DEVICE && > - hdr->type == APLHIDEV_GET_DIMENSIONS) { > - memcpy(sc->sc_dimdesc, &packet.data[8], hdr->cmdlen); > - sc->sc_dimdesclen = hdr->cmdlen; > - return 1; > - } > - > - /* Valid, but unrecognized packet; ignore for now. */ > - return 1; > -} > - > -/* Keyboard */ > - > -struct aplkbd_softc { > - struct device sc_dev; > - struct aplhidev_softc *sc_hidev; > - struct hidkbd sc_kbd; > - int sc_spl; > -}; > - > -void aplkbd_cngetc(void *, u_int *, int *); > -void aplkbd_cnpollc(void *, int); > -void aplkbd_cnbell(void *, u_int, u_int, u_int); > - > -const struct wskbd_consops aplkbd_consops = { > - aplkbd_cngetc, > - aplkbd_cnpollc, > - aplkbd_cnbell, > -}; > - > -int aplkbd_enable(void *, int); > -void aplkbd_set_leds(void *, int); > -int aplkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); > - > -const struct wskbd_accessops aplkbd_accessops = { > - .enable = aplkbd_enable, > - .ioctl = aplkbd_ioctl, > - .set_leds = aplkbd_set_leds, > -}; > - > -int aplkbd_match(struct device *, void *, void *); > -void aplkbd_attach(struct device *, struct device *, void *); > - > -const struct cfattach aplkbd_ca = { > - sizeof(struct aplkbd_softc), aplkbd_match, aplkbd_attach > -}; > - > -struct cfdriver aplkbd_cd = { > - NULL, "aplkbd", DV_DULL > -}; > - > -int > -aplkbd_match(struct device *parent, void *match, void *aux) > -{ > - struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > - > - return (aa->aa_reportid == APLHIDEV_KBD_DEVICE); > -} > - > -void > -aplkbd_attach(struct device *parent, struct device *self, void *aux) > -{ > - struct aplkbd_softc *sc = (struct aplkbd_softc *)self; > - struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > - struct hidkbd *kbd = &sc->sc_kbd; > - > - sc->sc_hidev = (struct aplhidev_softc *)parent; > - if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE, > - aa->aa_desc, aa->aa_desclen)) > - return; > - > - printf("\n"); > - > - if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), > - 1, hid_input, &kbd->sc_fn, NULL)) { > - switch (sc->sc_hidev->sc_product) { > - case USB_PRODUCT_APPLE_WELLSPRINGM1_J293: > - kbd->sc_munge = hidkbd_apple_tb_munge; > - break; > - default: > - kbd->sc_munge = hidkbd_apple_munge; > - break; > - } > - } > - > - if (kbd->sc_console_keyboard) { > - extern struct wskbd_mapdata ukbd_keymapdata; > - > - ukbd_keymapdata.layout = KB_US | KB_DEFAULT; > - wskbd_cnattach(&aplkbd_consops, sc, &ukbd_keymapdata); > - aplkbd_enable(sc, 1); > - } > - > - hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops); > -} > - > -void > -aplkbd_intr(struct device *self, uint8_t *packet, size_t packetlen) > -{ > - struct aplkbd_softc *sc = (struct aplkbd_softc *)self; > - struct hidkbd *kbd = &sc->sc_kbd; > - > - if (kbd->sc_enabled) > - hidkbd_input(kbd, &packet[1], packetlen - 1); > -} > - > -int > -aplkbd_enable(void *v, int on) > -{ > - struct aplkbd_softc *sc = v; > - struct hidkbd *kbd = &sc->sc_kbd; > - > - return hidkbd_enable(kbd, on); > -} > - > -int > -aplkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) > -{ > - struct aplkbd_softc *sc = v; > - struct hidkbd *kbd = &sc->sc_kbd; > - > - switch (cmd) { > - case WSKBDIO_GTYPE: > - /* XXX: should we set something else? */ > - *(u_int *)data = WSKBD_TYPE_USB; > - return 0; > - case WSKBDIO_SETLEDS: > - aplkbd_set_leds(v, *(int *)data); > - return 0; > - default: > - return hidkbd_ioctl(kbd, cmd, data, flag, p); > - } > -} > - > -void > -aplkbd_set_leds(void *v, int leds) > -{ > - struct aplkbd_softc *sc = v; > - struct hidkbd *kbd = &sc->sc_kbd; > - uint8_t res; > - > - if (hidkbd_set_leds(kbd, leds, &res)) > - aplhidev_set_leds(sc->sc_hidev, res); > -} > - > -/* Console interface. */ > -void > -aplkbd_cngetc(void *v, u_int *type, int *data) > -{ > - struct aplkbd_softc *sc = v; > - struct hidkbd *kbd = &sc->sc_kbd; > - > - kbd->sc_polling = 1; > - while (kbd->sc_npollchar <= 0) { > - aplhidev_intr(sc->sc_dev.dv_parent); > - delay(1000); > - } > - kbd->sc_polling = 0; > - hidkbd_cngetc(kbd, type, data); > -} > - > -void > -aplkbd_cnpollc(void *v, int on) > -{ > - struct aplkbd_softc *sc = v; > - > - if (on) > - sc->sc_spl = spltty(); > - else > - splx(sc->sc_spl); > -} > - > -void > -aplkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) > -{ > - hidkbd_bell(pitch, period, volume, 1); > -} > - > -#if NAPLMS > 0 > - > -/* Touchpad */ > - > -/* > - * The contents of the touchpad event packets is identical to those > - * used by the ubcmtp(4) driver. The relevant definitions and the > - * code to decode the packets is replicated here. > - */ > - > -struct ubcmtp_finger { > - uint16_t origin; > - uint16_t abs_x; > - uint16_t abs_y; > - uint16_t rel_x; > - uint16_t rel_y; > - uint16_t tool_major; > - uint16_t tool_minor; > - uint16_t orientation; > - uint16_t touch_major; > - uint16_t touch_minor; > - uint16_t unused[2]; > - uint16_t pressure; > - uint16_t multi; > -} __packed __attribute((aligned(2))); > - > -#define UBCMTP_MAX_FINGERS 16 > - > -#define UBCMTP_TYPE4_TPOFF (24 * sizeof(uint16_t)) > -#define UBCMTP_TYPE4_BTOFF 31 > -#define UBCMTP_TYPE4_FINGERPAD (1 * sizeof(uint16_t)) > - > -/* Use a constant, synaptics-compatible pressure value for now. */ > -#define DEFAULT_PRESSURE 40 > - > -static struct wsmouse_param aplms_wsmousecfg[] = { > - { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */ > -}; > - > -struct aplms_softc { > - struct device sc_dev; > - struct aplhidev_softc *sc_hidev; > - struct device *sc_wsmousedev; > - > - int sc_enabled; > - > - int tp_offset; > - int tp_fingerpad; > - > - struct mtpoint frame[UBCMTP_MAX_FINGERS]; > - int contacts; > - int btn; > -}; > - > -int aplms_enable(void *); > -void aplms_disable(void *); > -int aplms_ioctl(void *, u_long, caddr_t, int, struct proc *); > - > -const struct wsmouse_accessops aplms_accessops = { > - .enable = aplms_enable, > - .disable = aplms_disable, > - .ioctl = aplms_ioctl, > -}; > - > -int aplms_match(struct device *, void *, void *); > -void aplms_attach(struct device *, struct device *, void *); > - > -const struct cfattach aplms_ca = { > - sizeof(struct aplms_softc), aplms_match, aplms_attach > -}; > - > -struct cfdriver aplms_cd = { > - NULL, "aplms", DV_DULL > -}; > - > -int aplms_configure(struct aplms_softc *); > - > -int > -aplms_match(struct device *parent, void *match, void *aux) > -{ > - struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > - > - return (aa->aa_reportid == APLHIDEV_TP_DEVICE); > -} > - > -void > -aplms_attach(struct device *parent, struct device *self, void *aux) > -{ > - struct aplms_softc *sc = (struct aplms_softc *)self; > - struct wsmousedev_attach_args aa; > - > - sc->sc_hidev = (struct aplhidev_softc *)parent; > - > - printf("\n"); > - > - sc->tp_offset = UBCMTP_TYPE4_TPOFF; > - sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; > - > - aa.accessops = &aplms_accessops; > - aa.accesscookie = sc; > - > - sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint); > - if (sc->sc_wsmousedev != NULL && aplms_configure(sc)) > - aplms_disable(sc); > -} > - > -int > -aplms_configure(struct aplms_softc *sc) > -{ > - struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); > - > - hw->type = WSMOUSE_TYPE_TOUCHPAD; > - hw->hw_type = WSMOUSEHW_CLICKPAD; > - hw->x_min = sc->sc_hidev->sc_x_min; > - hw->x_max = sc->sc_hidev->sc_x_max; > - hw->y_min = sc->sc_hidev->sc_y_min; > - hw->y_max = sc->sc_hidev->sc_y_max; > - hw->h_res = sc->sc_hidev->sc_h_res; > - hw->v_res = sc->sc_hidev->sc_v_res; > - hw->mt_slots = UBCMTP_MAX_FINGERS; > - hw->flags = WSMOUSEHW_MT_TRACKING; > - > - return wsmouse_configure(sc->sc_wsmousedev, > - aplms_wsmousecfg, nitems(aplms_wsmousecfg)); > -} > - > -void > -aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) > -{ > - struct aplms_softc *sc = (struct aplms_softc *)self; > - struct ubcmtp_finger *finger; > - int off, s, btn, contacts; > - > - if (!sc->sc_enabled) > - return; > - > - contacts = 0; > - for (off = sc->tp_offset; off < packetlen; > - off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { > - finger = (struct ubcmtp_finger *)(packet + off); > - > - if ((int16_t)letoh16(finger->touch_major) == 0) > - continue; /* finger lifted */ > - > - sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); > - sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); > - sc->frame[contacts].pressure = DEFAULT_PRESSURE; > - contacts++; > - } > - > - btn = sc->btn; > - sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF])); > - > - if (contacts || sc->contacts || sc->btn != btn) { > - sc->contacts = contacts; > - s = spltty(); > - wsmouse_buttons(sc->sc_wsmousedev, sc->btn); > - wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); > - wsmouse_input_sync(sc->sc_wsmousedev); > - splx(s); > - } > -} > - > -int > -aplms_enable(void *v) > -{ > - struct aplms_softc *sc = v; > - > - if (sc->sc_enabled) > - return EBUSY; > - > - sc->sc_enabled = 1; > - return 0; > -} > - > -void > -aplms_disable(void *v) > -{ > - struct aplms_softc *sc = v; > - > - sc->sc_enabled = 0; > -} > - > -int > -aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) > -{ > - struct aplms_softc *sc = v; > - struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); > - struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; > - int wsmode; > - > - switch (cmd) { > - case WSMOUSEIO_GTYPE: > - *(u_int *)data = hw->type; > - break; > - > - case WSMOUSEIO_GCALIBCOORDS: > - wsmc->minx = hw->x_min; > - wsmc->maxx = hw->x_max; > - wsmc->miny = hw->y_min; > - wsmc->maxy = hw->y_max; > - wsmc->swapxy = 0; > - wsmc->resx = hw->h_res; > - wsmc->resy = hw->v_res; > - break; > - > - case WSMOUSEIO_SETMODE: > - wsmode = *(u_int *)data; > - if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { > - printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, > - wsmode); > - return (EINVAL); > - } > - wsmouse_set_mode(sc->sc_wsmousedev, wsmode); > - break; > - > - default: > - return -1; > - } > - > - return 0; > -} > - > -#else > - > -void > -aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) > -{ > -} > - > -#endif > Index: dev/acpi/ispi_acpi.c > =================================================================== > RCS file: /cvs/src/sys/dev/acpi/ispi_acpi.c,v > retrieving revision 1.1 > diff -u -p -u -r1.1 ispi_acpi.c > --- dev/acpi/ispi_acpi.c 14 Nov 2025 01:55:07 -0000 1.1 > +++ dev/acpi/ispi_acpi.c 20 Nov 2025 16:42:41 -0000 > @@ -92,6 +92,7 @@ int > ispi_acpi_found_hid(struct aml_node *node, void *arg) > { > struct ispi_softc *sc = (struct ispi_softc *)arg; > + struct spi_attach_args sa; > int64_t sta; > char cdev[32], dev[32]; > > @@ -110,7 +111,17 @@ ispi_acpi_found_hid(struct aml_node *nod > > acpi_attach_deps(acpi_softc, node->parent); > > - /* TODO */ > + if (strcmp(cdev, "apple-spi-topcase") == 0) { > + memset(&sa, 0, sizeof(sa)); > + sa.sa_tag = &sc->sc_spi_tag; > + sa.sa_name = cdev; > + sa.sa_cookie = node->parent; > + > + if (config_found(&sc->sc_dev, &sa, ispi_spi_print)) { > + node->attached = 1; > + return 1; > + } > + } > > return 0; > } > Index: dev/spi/aplhidev.c > =================================================================== > RCS file: dev/spi/aplhidev.c > diff -N dev/spi/aplhidev.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ dev/spi/aplhidev.c 20 Nov 2025 16:42:42 -0000 > @@ -0,0 +1,1271 @@ > +/* $OpenBSD: aplhidev.c,v 1.13 2024/01/15 13:27:20 kettenis Exp $ */ > +/* > + * Copyright (c) 2021 Mark Kettenis > + * Copyright (c) 2013-2014 joshua stein > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include > + > +#ifdef __HAVE_FDT > +#include > +#include > +#include > +#include > +#endif > + > +#include "acpi.h" > +#if NACPI > 0 && !defined(__HAVE_FDT) > +#include > +#include > +#include > +#include > +#include > +#endif > + > +#include > + > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > + > +#include "aplhidev.h" > + > +/* #define APLHIDEV_DEBUG 1 */ > + > +#ifdef APLHIDEV_DEBUG > +#define DPRINTF(x) printf x > +#else > +#define DPRINTF(x) > +#endif > + > +#define APLHIDEV_READ_PACKET 0x20 > +#define APLHIDEV_WRITE_PACKET 0x40 > + > +#define APLHIDEV_KBD_DEVICE 1 > +#define APLHIDEV_TP_DEVICE 2 > +#define APLHIDEV_INFO_DEVICE 208 > + > +#define APLHIDEV_GET_INFO 0x0120 > +#define APLHIDEV_GET_DESCRIPTOR 0x1020 > +#define APLHIDEV_DESC_MAX 512 > +#define APLHIDEV_KBD_REPORT 0x0110 > +#define APLHIDEV_TP_REPORT 0x0210 > +#define APLHIDEV_SET_LEDS 0x0151 > +#define APLHIDEV_SET_MODE 0x0252 > +#define APLHIDEV_MODE_HID 0x00 > +#define APLHIDEV_MODE_RAW 0x01 > +#define APLHIDEV_GET_DIMENSIONS 0xd932 > +#define APLHIDEV_SET_BACKLIGHT 0xb051 > +#define APLHIDEV_BACKLIGHT_MAGIC 0x01b0 This line probably needs a tab instead of a space to align the values. > +#define APLHIDEV_BACKLIGHT_MIN 32 > +#define APLHIDEV_BACKLIGHT_MAX 255 > +#define APLHIDEV_BACKLIGHT_ON 0x01f4 > +#define APLHIDEV_BACKLIGHT_OFF 0x0001 > + > +struct aplhidev_dim { > + uint32_t width; > + uint32_t height; > + int16_t x_min; > + int16_t y_min; > + int16_t x_max; > + int16_t y_max; > +}; > + > +struct aplhidev_attach_args { > + uint8_t aa_reportid; > + void *aa_desc; > + size_t aa_desclen; > +}; > + > +struct aplhidev_spi_packet { > + uint8_t flags; > + uint8_t device; > + uint16_t offset; > + uint16_t remaining; > + uint16_t len; > + uint8_t data[246]; > + uint16_t crc; > +}; > + > +struct aplhidev_spi_status { > + uint8_t status[4]; > +}; > + > +struct aplhidev_msghdr { > + uint16_t type; > + uint8_t device; > + uint8_t msgid; > + uint16_t rsplen; > + uint16_t cmdlen; > +}; > + > +struct aplhidev_info_hdr { > + uint16_t unknown[2]; > + uint16_t num_devices; > + uint16_t vendor; > + uint16_t product; > + uint16_t version; > + uint16_t vendor_str[2]; > + uint16_t product_str[2]; > + uint16_t serial_str[2]; > +}; > + > +struct aplhidev_get_desc { > + struct aplhidev_msghdr hdr; > + uint16_t crc; > +}; > + > +struct aplhidev_set_leds { > + struct aplhidev_msghdr hdr; > + uint8_t reportid; > + uint8_t leds; > + uint16_t crc; > +}; > + > +struct aplhidev_set_mode { > + struct aplhidev_msghdr hdr; > + uint8_t reportid; > + uint8_t mode; > + uint16_t crc; > +}; > + > +struct aplhidev_set_backlight { > + struct aplhidev_msghdr hdr; > + uint16_t magic; > + uint16_t level; > + uint16_t on_off; > + uint16_t crc; > +}; > + > +struct aplhidev_softc { > + struct device sc_dev; > +#if NACPI > 0 && !defined(__HAVE_FDT) > + struct aml_node *sc_dev_node; > +#endif > + > + spi_tag_t sc_spi_tag; > + struct spi_config sc_spi_conf; > + > + uint8_t sc_msgid; > + > + uint32_t *sc_gpio; > + int sc_gpiolen; > + > + uint8_t sc_mode; > + uint16_t sc_vendor; > + uint16_t sc_product; > + > + struct device *sc_kbd; > + uint8_t sc_kbddesc[APLHIDEV_DESC_MAX]; > + size_t sc_kbddesclen; > + > + struct device *sc_ms; > + uint8_t sc_tpdesc[APLHIDEV_DESC_MAX]; > + size_t sc_tpdesclen; > + uint8_t sc_dimdesc[APLHIDEV_DESC_MAX]; > + size_t sc_dimdesclen; > + int sc_x_min; > + int sc_x_max; > + int sc_y_min; > + int sc_y_max; > + int sc_h_res; > + int sc_v_res; > +}; > + > +int aplhidev_match(struct device *, void *, void *); > +void aplhidev_attach(struct device *, struct device *, void *); > +#ifdef __HAVE_FDT > +void aplhidev_fdt_init(struct aplhidev_softc *, void *); > +#elif NACPI > 0 > +int aplhidev_acpi_init(struct aplhidev_softc *); > +int aplhidev_enable_spi(struct aplhidev_softc *); > +int aplhidev_gpe_intr(struct aml_node *, int, void *); > +#endif > + > +const struct cfattach aplhidev_ca = { > + sizeof(struct aplhidev_softc), aplhidev_match, aplhidev_attach > +}; > + > +struct cfdriver aplhidev_cd = { > + NULL, "aplhidev", DV_DULL > +}; > + > +void aplhidev_get_info(struct aplhidev_softc *); > +void aplhidev_get_descriptor(struct aplhidev_softc *, uint8_t); > +void aplhidev_set_leds(struct aplhidev_softc *, uint8_t); > +void aplhidev_set_backlight(struct aplhidev_softc *, uint8_t); > +void aplhidev_set_mode(struct aplhidev_softc *, uint8_t); > +void aplhidev_get_dimensions(struct aplhidev_softc *); > + > +void aplkbd_set_backlight(void *); > +extern int (*wskbd_get_backlight)(struct wskbd_backlight *); > +extern int (*wskbd_set_backlight)(struct wskbd_backlight *); > +int aplkbd_wskbd_get_backlight(struct wskbd_backlight *); > +int aplkbd_wskbd_set_backlight(struct wskbd_backlight *); > + > +int aplhidev_intr(void *); > +void aplkbd_intr(struct device *, uint8_t *, size_t); > +void aplms_intr(struct device *, uint8_t *, size_t); > + > +int > +aplhidev_match(struct device *parent, void *match, void *aux) > +{ > + struct spi_attach_args *sa = aux; > +#if NACPI > 0 && !defined(__HAVE_FDT) > + struct aml_node *node = (struct aml_node *)sa->sa_cookie; > + uint64_t val; > +#endif > + > +#if defined(__HAVE_FDT) > + if (strcmp(sa->sa_name, "apple,spi-hid-transport") == 0) > + return 1; > + > +#elif NACPI > 0 > + if (strcmp(sa->sa_name, "apple-spi-topcase") == 0) { Maybe put the "node" and "val" definitions here to reduce the #ifdef spaghetti? They're only used in this block. > + /* don't attach if USB interface is present */ > + if (aml_evalinteger(acpi_softc, node, "UIST", 0, NULL, > + &val) == 0 && val) > + return 0; > + > + return 1; > + } > +#endif > + > + return 0; > +} > + > +void > +aplhidev_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct aplhidev_softc *sc = (struct aplhidev_softc *)self; > + struct spi_attach_args *sa = aux; > + struct aplhidev_attach_args aa; > + struct aplhidev_dim dim; > + int retry; > + > + sc->sc_spi_tag = sa->sa_tag; > + > +#ifdef __HAVE_FDT > + aplhidev_fdt_init(sc, sa->sa_cookie); > + > +#elif NACPI > 0 > + sc->sc_dev_node = (struct aml_node *)sa->sa_cookie; > + if (aplhidev_acpi_init(sc) != 0) > + return; > +#endif > + > + aplhidev_get_info(sc); > + for (retry = 10; retry > 0; retry--) { > + aplhidev_intr(sc); > + delay(1000); > + if (sc->sc_vendor != 0 && sc->sc_product != 0) > + break; > + } > + > + aplhidev_get_descriptor(sc, APLHIDEV_KBD_DEVICE); > + for (retry = 10; retry > 0; retry--) { > + aplhidev_intr(sc); > + delay(1000); > + if (sc->sc_kbddesclen > 0) > + break; > + } > + > + aplhidev_get_descriptor(sc, APLHIDEV_TP_DEVICE); > + for (retry = 10; retry > 0; retry--) { > + aplhidev_intr(sc); > + delay(1000); > + if (sc->sc_tpdesclen > 0) > + break; > + } > + > + sc->sc_mode = APLHIDEV_MODE_HID; > + aplhidev_set_mode(sc, APLHIDEV_MODE_RAW); > + for (retry = 10; retry > 0; retry--) { > + aplhidev_intr(sc); > + delay(1000); > + if (sc->sc_mode == APLHIDEV_MODE_RAW) > + break; > + } > + > + aplhidev_get_dimensions(sc); > + for (retry = 10; retry > 0; retry--) { > + aplhidev_intr(sc); > + delay(1000); > + if (sc->sc_dimdesclen > 0) > + break; > + } > + > + printf("\n"); > + > + if (sc->sc_dimdesclen == sizeof(dim) + 1) { > + memcpy(&dim, &sc->sc_dimdesc[1], sizeof(dim)); > + sc->sc_x_min = dim.x_min; > + sc->sc_x_max = dim.x_max; > + sc->sc_y_min = dim.y_min; > + sc->sc_y_max = dim.y_max; > + sc->sc_h_res = (100 * (dim.x_max - dim.x_min)) / dim.width; > + sc->sc_v_res = (100 * (dim.y_max - dim.y_min)) / dim.height; > + } > + > + if (sc->sc_kbddesclen > 0) { > + aa.aa_reportid = APLHIDEV_KBD_DEVICE; > + aa.aa_desc = sc->sc_kbddesc; > + aa.aa_desclen = sc->sc_kbddesclen; > + sc->sc_kbd = config_found(self, &aa, NULL); > + } > + > + if (sc->sc_tpdesclen > 0) { > + aa.aa_reportid = APLHIDEV_TP_DEVICE; > + aa.aa_desc = sc->sc_tpdesc; > + aa.aa_desclen = sc->sc_tpdesclen; > + sc->sc_ms = config_found(self, &aa, NULL); > + } > +} > + > +#ifdef __HAVE_FDT > +void > +aplhidev_fdt_init(struct aplhidev_softc *sc, void *cookie) > +{ > + int node = *(int *)cookie; > + > + sc->sc_gpiolen = OF_getproplen(node, "spien-gpios"); > + if (sc->sc_gpiolen > 0) { > + sc->sc_gpio = malloc(sc->sc_gpiolen, M_TEMP, M_WAITOK); > + OF_getpropintarray(node, "spien-gpios", > + sc->sc_gpio, sc->sc_gpiolen); > + gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT); > + > + /* Reset */ > + gpio_controller_set_pin(sc->sc_gpio, 1); > + delay(5000); > + gpio_controller_set_pin(sc->sc_gpio, 0); > + delay(5000); > + > + /* Enable. */ > + gpio_controller_set_pin(sc->sc_gpio, 1); > + delay(50000); > + } > + > + sc->sc_spi_conf.sc_bpw = 8; > + sc->sc_spi_conf.sc_freq = OF_getpropint(node, "spi-max-frequency", 0); > + sc->sc_spi_conf.sc_cs = OF_getpropint(node, "reg", 0); > + sc->sc_spi_conf.sc_cs_delay = 100; > + > + fdt_intr_establish(node, IPL_TTY, aplhidev_intr, sc, > + sc->sc_dev.dv_xname); > +} > +#endif > + > +#if NACPI > 0 && !defined(__HAVE_FDT) > +int > +aplhidev_acpi_init(struct aplhidev_softc *sc) > +{ > + /* a0b5b7c6-1318-441c-b0c9-fe695eaf949b */ > + static uint8_t guid[] = { > + 0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44, > + 0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B, > + }; > + struct aml_value cmd[4], res; > + struct aml_node *node; > + uint64_t val; > + int i; > + > + /* > + * On newer Apple hardware where we claim an OSI of Darwin, _CRS > + * doesn't return a useful SpiSerialBusV2 object but instead returns > + * parameters from a _DSM method when called with a particular UUID > + * which macOS does. > + */ > + if (!aml_searchname(sc->sc_dev_node, "_DSM")) { > + printf("%s: couldn't find _DSM at %s\n", sc->sc_dev.dv_xname, > + aml_nodename(sc->sc_dev_node)); > + return 1; > + } > + > + bzero(&cmd, sizeof(cmd)); > + cmd[0].type = AML_OBJTYPE_BUFFER; > + cmd[0].v_buffer = (uint8_t *)&guid; > + cmd[0].length = sizeof(guid); > + cmd[1].type = AML_OBJTYPE_INTEGER; > + cmd[1].v_integer = 1; > + cmd[1].length = 1; > + cmd[2].type = AML_OBJTYPE_INTEGER; > + cmd[2].v_integer = 1; > + cmd[2].length = 1; > + cmd[3].type = AML_OBJTYPE_BUFFER; > + cmd[3].length = 0; > + > + if (aml_evalname(acpi_softc, sc->sc_dev_node, "_DSM", 4, cmd, &res)) { > + printf("%s: eval of _DSM at %s failed\n", > + sc->sc_dev.dv_xname, aml_nodename(sc->sc_dev_node)); > + return 1; > + } > + > + if (res.type != AML_OBJTYPE_PACKAGE) { > + printf("%s: bad _DSM result at %s: %d\n", > + sc->sc_dev.dv_xname, aml_nodename(sc->sc_dev_node), > + res.type); > + aml_freevalue(&res); > + return 1; > + } > + > + if (res.length % 2 != 0) { > + printf("%s: _DSM length %d not even\n", sc->sc_dev.dv_xname, > + res.length); > + aml_freevalue(&res); > + return 1; > + } > + > + for (i = 0; i < res.length; i += 2) { > + char *k; > + > + if (res.v_package[i]->type != AML_OBJTYPE_STRING || > + res.v_package[i + 1]->type != AML_OBJTYPE_BUFFER) { > + printf("%s: expected string+buffer, got %d+%d\n", > + sc->sc_dev.dv_xname, res.v_package[i]->type, > + res.v_package[i + 1]->type); > + aml_freevalue(&res); > + return 1; > + } > + > + k = res.v_package[i]->v_string; > + val = aml_val2int(res.v_package[i + 1]); > + > + DPRINTF(("%s: %s = %lld\n", sc->sc_dev.dv_xname, k, val)); > + > + if (strcmp(k, "spiSclkPeriod") == 0) { > + sc->sc_spi_conf.sc_freq = 1000000000 / val; > + } else if (strcmp(k, "spiWordSize") == 0) { > + sc->sc_spi_conf.sc_bpw = val; > + } else if (strcmp(k, "spiSPO") == 0) { > + if (val) > + sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPOL; > + } else if (strcmp(k, "spiSPH") == 0) { > + if (val) > + sc->sc_spi_conf.sc_flags |= SPI_CONFIG_CPHA; > + } else if (strcmp(k, "spiCSDelay") == 0) { > + sc->sc_spi_conf.sc_cs_delay = val; > + } else { > + DPRINTF(("%s: unused _DSM key %s\n", > + sc->sc_dev.dv_xname, k)); > + } > + } > + aml_freevalue(&res); > + > + if (aplhidev_enable_spi(sc) != 0) > + return 1; > + > + node = aml_searchname(sc->sc_dev_node, "_GPE"); > + if (node) > + aml_register_notify(sc->sc_dev_node, NULL, aplhidev_gpe_intr, > + sc, ACPIDEV_NOPOLL); > + > + return 0; > +} > + > +int > +aplhidev_enable_spi(struct aplhidev_softc *sc) > +{ > + struct aml_value arg; > + uint64_t val; > + > + /* if SPI is not enabled, enable it */ > + if (aml_evalinteger(acpi_softc, sc->sc_dev_node, "SIST", 0, NULL, > + &val) == 0 && !val) { > + DPRINTF(("%s: SIST is %lld\n", sc->sc_dev.dv_xname, val)); > + > + bzero(&arg, sizeof(arg)); > + arg.type = AML_OBJTYPE_INTEGER; > + arg.v_integer = 1; > + arg.length = 1; > + > + if (aml_evalname(acpi_softc, sc->sc_dev_node, "SIEN", 1, &arg, > + NULL) != 0) { > + DPRINTF(("%s: couldn't enable SPI mode\n", __func__)); > + return 1; > + } > + > + DELAY(500); > + } else { > + DPRINTF(("%s: SIST is already %lld\n", sc->sc_dev.dv_xname, > + val)); > + } > + > + return 0; > +} > +#endif > + > +void > +aplhidev_get_info(struct aplhidev_softc *sc) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_get_desc *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_INFO_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_GET_INFO; > + msg->hdr.device = APLHIDEV_INFO_DEVICE; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = 0; > + msg->hdr.rsplen = APLHIDEV_DESC_MAX; > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > + > + delay(1000); > +} > + > +void > +aplhidev_get_descriptor(struct aplhidev_softc *sc, uint8_t device) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_get_desc *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_INFO_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_GET_DESCRIPTOR; > + msg->hdr.device = device; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = 0; > + msg->hdr.rsplen = APLHIDEV_DESC_MAX; > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > + > + delay(1000); > +} > + > +void > +aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_set_leds *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_KBD_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_SET_LEDS; > + msg->hdr.device = APLHIDEV_KBD_DEVICE; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; > + msg->hdr.rsplen = msg->hdr.cmdlen; > + msg->reportid = APLHIDEV_KBD_DEVICE; > + msg->leds = leds; > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + /* > + * XXX Without a delay here, the command will fail. Does the > + * controller need a bit of time between sending us a keypress > + * event and accepting a new command from us? > + */ > + delay(250); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > +} > + The function below isn't used when __HAVE_FDT is defined. So maybe move it down into the #if NACPI > 0 && !defined(__HAVE_FDT) bit below? > +void > +aplhidev_set_backlight(struct aplhidev_softc *sc, uint8_t level) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_set_backlight *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_KBD_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_SET_BACKLIGHT; > + msg->hdr.device = APLHIDEV_KBD_DEVICE; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; > + msg->hdr.rsplen = msg->hdr.cmdlen; > + msg->magic = htole16(APLHIDEV_BACKLIGHT_MAGIC); > + if (level <= APLHIDEV_BACKLIGHT_MIN) { > + msg->level = 0; > + msg->on_off = htole16(APLHIDEV_BACKLIGHT_OFF); > + } else { > + msg->level = htole16(level); > + msg->on_off = htole16(APLHIDEV_BACKLIGHT_ON); > + } > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > +} > + > +void > +aplhidev_set_mode(struct aplhidev_softc *sc, uint8_t mode) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_set_mode *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_TP_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_SET_MODE; > + msg->hdr.device = APLHIDEV_TP_DEVICE; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2; > + msg->hdr.rsplen = msg->hdr.cmdlen; > + msg->reportid = APLHIDEV_TP_DEVICE; > + msg->mode = mode; > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > + > + delay(1000); > +} > + > +void > +aplhidev_get_dimensions(struct aplhidev_softc *sc) > +{ > + struct aplhidev_spi_packet packet; > + struct aplhidev_get_desc *msg; > + struct aplhidev_spi_status status; > + > + memset(&packet, 0, sizeof(packet)); > + packet.flags = APLHIDEV_WRITE_PACKET; > + packet.device = APLHIDEV_TP_DEVICE; > + packet.len = sizeof(*msg); > + > + msg = (void *)&packet.data[0]; > + msg->hdr.type = APLHIDEV_GET_DIMENSIONS; > + msg->hdr.device = 0; > + msg->hdr.msgid = sc->sc_msgid++; > + msg->hdr.cmdlen = 0; > + msg->hdr.rsplen = APLHIDEV_DESC_MAX; > + msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2); > + > + packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2); > + > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet), > + SPI_KEEP_CS); > + delay(100); > + spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status)); > + spi_release_bus(sc->sc_spi_tag, 0); > + > + delay(1000); > +} > + > +#if NACPI > 0 && !defined(__HAVE_FDT) > +int > +aplhidev_gpe_intr(struct aml_node *node, int gpe, void *arg) > +{ > + struct aplhidev_softc *sc = arg; > + > + return aplhidev_intr(sc); > +} > +#endif > + > +int > +aplhidev_intr(void *arg) > +{ > + struct aplhidev_softc *sc = arg; > + struct aplhidev_spi_packet packet; > + struct aplhidev_msghdr *hdr = (struct aplhidev_msghdr *)&packet.data[0]; > + > + memset(&packet, 0, sizeof(packet)); > + spi_acquire_bus(sc->sc_spi_tag, 0); > + spi_config(sc->sc_spi_tag, &sc->sc_spi_conf); > + spi_read(sc->sc_spi_tag, (char *)&packet, sizeof(packet)); > + spi_release_bus(sc->sc_spi_tag, 0); > + > + /* Treat empty packets as spurious interrupts. */ > + if (packet.flags == 0 && packet.device == 0 && packet.crc == 0) > + return 0; > + > + if (crc16(0, (uint8_t *)&packet, sizeof(packet))) > + return 1; > + > + /* Keyboard input. */ > + if (packet.flags == APLHIDEV_READ_PACKET && > + packet.device == APLHIDEV_KBD_DEVICE && > + hdr->type == APLHIDEV_KBD_REPORT) { > + if (sc->sc_kbd) > + aplkbd_intr(sc->sc_kbd, &packet.data[8], hdr->cmdlen); > + return 1; > + } > + > + /* Touchpad input. */ > + if (packet.flags == APLHIDEV_READ_PACKET && > + packet.device == APLHIDEV_TP_DEVICE && > + hdr->type == APLHIDEV_TP_REPORT) { > + if (sc->sc_ms) > + aplms_intr(sc->sc_ms, &packet.data[8], hdr->cmdlen); > + return 1; > + } > + > + /* Replies to commands we sent. */ > + if (packet.flags == APLHIDEV_WRITE_PACKET && > + packet.device == APLHIDEV_INFO_DEVICE && > + hdr->type == APLHIDEV_GET_INFO) { > + struct aplhidev_info_hdr *info = > + (struct aplhidev_info_hdr *)&packet.data[8]; > + sc->sc_vendor = info->vendor; > + sc->sc_product = info->product; > + return 1; > + } > + if (packet.flags == APLHIDEV_WRITE_PACKET && > + packet.device == APLHIDEV_INFO_DEVICE && > + hdr->type == APLHIDEV_GET_DESCRIPTOR) { > + switch (hdr->device) { > + case APLHIDEV_KBD_DEVICE: > + memcpy(sc->sc_kbddesc, &packet.data[8], hdr->cmdlen); > + sc->sc_kbddesclen = hdr->cmdlen; > + break; > + case APLHIDEV_TP_DEVICE: > + memcpy(sc->sc_tpdesc, &packet.data[8], hdr->cmdlen); > + sc->sc_tpdesclen = hdr->cmdlen; > + break; > + } > + > + return 1; > + } > + if (packet.flags == APLHIDEV_WRITE_PACKET && > + packet.device == APLHIDEV_TP_DEVICE && > + hdr->type == APLHIDEV_SET_MODE) { > + sc->sc_mode = APLHIDEV_MODE_RAW; > + return 1; > + } > + if (packet.flags == APLHIDEV_WRITE_PACKET && > + packet.device == APLHIDEV_TP_DEVICE && > + hdr->type == APLHIDEV_GET_DIMENSIONS) { > + memcpy(sc->sc_dimdesc, &packet.data[8], hdr->cmdlen); > + sc->sc_dimdesclen = hdr->cmdlen; > + return 1; > + } > + > + /* Valid, but unrecognized packet; ignore for now. */ > + return 1; > +} > + > +/* Keyboard */ > + > +struct aplkbd_softc { > + struct device sc_dev; > + struct aplhidev_softc *sc_hidev; > + struct hidkbd sc_kbd; > + int sc_spl; > + int sc_backlight; > +}; > + > +void aplkbd_cngetc(void *, u_int *, int *); > +void aplkbd_cnpollc(void *, int); > +void aplkbd_cnbell(void *, u_int, u_int, u_int); > + > +const struct wskbd_consops aplkbd_consops = { > + aplkbd_cngetc, > + aplkbd_cnpollc, > + aplkbd_cnbell, > +}; > + > +int aplkbd_enable(void *, int); > +void aplkbd_set_leds(void *, int); > +int aplkbd_ioctl(void *, u_long, caddr_t, int, struct proc *); > + > +const struct wskbd_accessops aplkbd_accessops = { > + .enable = aplkbd_enable, > + .ioctl = aplkbd_ioctl, > + .set_leds = aplkbd_set_leds, > +}; > + > +int aplkbd_match(struct device *, void *, void *); > +void aplkbd_attach(struct device *, struct device *, void *); > + > +const struct cfattach aplkbd_ca = { > + sizeof(struct aplkbd_softc), aplkbd_match, aplkbd_attach > +}; > + > +struct cfdriver aplkbd_cd = { > + NULL, "aplkbd", DV_DULL > +}; > + > +int > +aplkbd_match(struct device *parent, void *match, void *aux) > +{ > + struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > + > + return (aa->aa_reportid == APLHIDEV_KBD_DEVICE); > +} > + > +void > +aplkbd_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct aplkbd_softc *sc = (struct aplkbd_softc *)self; > + struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > + struct hidkbd *kbd = &sc->sc_kbd; > + > + sc->sc_hidev = (struct aplhidev_softc *)parent; > + if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE, > + aa->aa_desc, aa->aa_desclen)) > + return; > + > + printf("\n"); > + > + if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), > + 1, hid_input, &kbd->sc_fn, NULL)) { > + switch (sc->sc_hidev->sc_product) { > + case USB_PRODUCT_APPLE_WELLSPRINGM1_J293: > + kbd->sc_munge = hidkbd_apple_tb_munge; > + break; > + default: > + kbd->sc_munge = hidkbd_apple_munge; > + break; > + } > + } > + > + if (kbd->sc_console_keyboard) { > + extern struct wskbd_mapdata ukbd_keymapdata; > + > + ukbd_keymapdata.layout = KB_US | KB_DEFAULT; > + wskbd_cnattach(&aplkbd_consops, sc, &ukbd_keymapdata); > + aplkbd_enable(sc, 1); > + } > + > + > + hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops); > + > +#if NACPI > 0 && !defined(__HAVE_FDT) > + sc->sc_backlight = APLHIDEV_BACKLIGHT_MIN; > + wskbd_get_backlight = aplkbd_wskbd_get_backlight; > + wskbd_set_backlight = aplkbd_wskbd_set_backlight; > +#endif > +} > + > +void > +aplkbd_intr(struct device *self, uint8_t *packet, size_t packetlen) > +{ > + struct aplkbd_softc *sc = (struct aplkbd_softc *)self; > + struct hidkbd *kbd = &sc->sc_kbd; > + > + if (kbd->sc_enabled) > + hidkbd_input(kbd, &packet[1], packetlen - 1); > +} > + > +int > +aplkbd_enable(void *v, int on) > +{ > + struct aplkbd_softc *sc = v; > + struct hidkbd *kbd = &sc->sc_kbd; > + > + return hidkbd_enable(kbd, on); > +} > + > +int > +aplkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) > +{ > + struct aplkbd_softc *sc = v; > + struct hidkbd *kbd = &sc->sc_kbd; > + > + switch (cmd) { > + case WSKBDIO_GTYPE: > + /* XXX: should we set something else? */ > + *(u_int *)data = WSKBD_TYPE_USB; > + return 0; > + case WSKBDIO_SETLEDS: > + aplkbd_set_leds(v, *(int *)data); > + return 0; > + default: > + return hidkbd_ioctl(kbd, cmd, data, flag, p); > + } > +} > + > +void > +aplkbd_set_leds(void *v, int leds) > +{ > + struct aplkbd_softc *sc = v; > + struct hidkbd *kbd = &sc->sc_kbd; > + uint8_t res; > + > + if (hidkbd_set_leds(kbd, leds, &res)) > + aplhidev_set_leds(sc->sc_hidev, res); > +} > + The two functions below are also not used when __HAVE_FDT is defined. > +int > +aplkbd_wskbd_get_backlight(struct wskbd_backlight *kbl) > +{ > + struct aplkbd_softc *sc = aplkbd_cd.cd_devs[0]; > + > + if (sc == NULL) > + return 0; > + > + kbl->min = APLHIDEV_BACKLIGHT_MIN; Is this the right approach? I guess what I'm asking is whether APLHIDEV_BACKLIGHT_MIN is the minimal brightness level of the backlight or if it really is "off". If it is the format, the minimum should probably be 0 here and if the level is below APLHIDEV_BACKLIGHT_MIN, you turn the backlight off, where if it is set to APLHIDEV_BACKLIGHT_MIN you keep the backlight on. > + kbl->max = APLHIDEV_BACKLIGHT_MAX; > + kbl->curval = sc->sc_backlight; > + > + return 0; > +} > + > +int > +aplkbd_wskbd_set_backlight(struct wskbd_backlight *kbl) > +{ > + struct aplkbd_softc *sc = aplkbd_cd.cd_devs[0]; > + int val; > + > + if (sc == NULL) > + return -1; > + > + val = kbl->curval; > + if (val < APLHIDEV_BACKLIGHT_MIN) > + val = APLHIDEV_BACKLIGHT_MIN; > + if (val > APLHIDEV_BACKLIGHT_MAX) > + val = APLHIDEV_BACKLIGHT_MAX; > + > + sc->sc_backlight = val; > + aplhidev_set_backlight((struct aplhidev_softc *)sc->sc_dev.dv_parent, > + sc->sc_backlight); > + > + return 0; > +} > + > +/* Console interface. */ > +void > +aplkbd_cngetc(void *v, u_int *type, int *data) > +{ > + struct aplkbd_softc *sc = v; > + struct hidkbd *kbd = &sc->sc_kbd; > + > + kbd->sc_polling = 1; > + while (kbd->sc_npollchar <= 0) { > + aplhidev_intr(sc->sc_dev.dv_parent); > + delay(1000); > + } > + kbd->sc_polling = 0; > + hidkbd_cngetc(kbd, type, data); > +} > + > +void > +aplkbd_cnpollc(void *v, int on) > +{ > + struct aplkbd_softc *sc = v; > + > + if (on) > + sc->sc_spl = spltty(); > + else > + splx(sc->sc_spl); > +} > + > +void > +aplkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) > +{ > + hidkbd_bell(pitch, period, volume, 1); > +} > + > +#if NAPLMS > 0 > + > +/* Touchpad */ > + > +/* > + * The contents of the touchpad event packets is identical to those > + * used by the ubcmtp(4) driver. The relevant definitions and the > + * code to decode the packets is replicated here. > + */ > + > +struct ubcmtp_finger { > + uint16_t origin; > + uint16_t abs_x; > + uint16_t abs_y; > + uint16_t rel_x; > + uint16_t rel_y; > + uint16_t tool_major; > + uint16_t tool_minor; > + uint16_t orientation; > + uint16_t touch_major; > + uint16_t touch_minor; > + uint16_t unused[2]; > + uint16_t pressure; > + uint16_t multi; > +} __packed __attribute((aligned(2))); > + > +#define UBCMTP_MAX_FINGERS 16 > + > +#define UBCMTP_TYPE4_TPOFF (24 * sizeof(uint16_t)) > +#define UBCMTP_TYPE4_BTOFF 31 > +#define UBCMTP_TYPE4_FINGERPAD (1 * sizeof(uint16_t)) > + > +/* Use a constant, synaptics-compatible pressure value for now. */ > +#define DEFAULT_PRESSURE 40 > + > +static struct wsmouse_param aplms_wsmousecfg[] = { > + { WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */ > +}; > + > +struct aplms_softc { > + struct device sc_dev; > + struct aplhidev_softc *sc_hidev; > + struct device *sc_wsmousedev; > + > + int sc_enabled; > + > + int tp_offset; > + int tp_fingerpad; > + > + struct mtpoint frame[UBCMTP_MAX_FINGERS]; > + int contacts; > + int btn; > +}; > + > +int aplms_enable(void *); > +void aplms_disable(void *); > +int aplms_ioctl(void *, u_long, caddr_t, int, struct proc *); > + > +const struct wsmouse_accessops aplms_accessops = { > + .enable = aplms_enable, > + .disable = aplms_disable, > + .ioctl = aplms_ioctl, > +}; > + > +int aplms_match(struct device *, void *, void *); > +void aplms_attach(struct device *, struct device *, void *); > + > +const struct cfattach aplms_ca = { > + sizeof(struct aplms_softc), aplms_match, aplms_attach > +}; > + > +struct cfdriver aplms_cd = { > + NULL, "aplms", DV_DULL > +}; > + > +int aplms_configure(struct aplms_softc *); > + > +int > +aplms_match(struct device *parent, void *match, void *aux) > +{ > + struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux; > + > + return (aa->aa_reportid == APLHIDEV_TP_DEVICE); > +} > + > +void > +aplms_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct aplms_softc *sc = (struct aplms_softc *)self; > + struct wsmousedev_attach_args aa; > + > + sc->sc_hidev = (struct aplhidev_softc *)parent; > + > + printf("\n"); > + > + sc->tp_offset = UBCMTP_TYPE4_TPOFF; > + sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD; > + > + aa.accessops = &aplms_accessops; > + aa.accesscookie = sc; > + > + sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint); > + if (sc->sc_wsmousedev != NULL && aplms_configure(sc)) > + aplms_disable(sc); > +} > + > +int > +aplms_configure(struct aplms_softc *sc) > +{ > + struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); > + > + hw->type = WSMOUSE_TYPE_TOUCHPAD; > + hw->hw_type = WSMOUSEHW_CLICKPAD; > + hw->x_min = sc->sc_hidev->sc_x_min; > + hw->x_max = sc->sc_hidev->sc_x_max; > + hw->y_min = sc->sc_hidev->sc_y_min; > + hw->y_max = sc->sc_hidev->sc_y_max; > + hw->h_res = sc->sc_hidev->sc_h_res; > + hw->v_res = sc->sc_hidev->sc_v_res; > + hw->mt_slots = UBCMTP_MAX_FINGERS; > + hw->flags = WSMOUSEHW_MT_TRACKING; > + > + return wsmouse_configure(sc->sc_wsmousedev, > + aplms_wsmousecfg, nitems(aplms_wsmousecfg)); > +} > + > +void > +aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) > +{ > + struct aplms_softc *sc = (struct aplms_softc *)self; > + struct ubcmtp_finger *finger; > + int off, s, btn, contacts; > + > + if (!sc->sc_enabled) > + return; > + > + contacts = 0; > + for (off = sc->tp_offset; off < packetlen; > + off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) { > + finger = (struct ubcmtp_finger *)(packet + off); > + > + if ((int16_t)letoh16(finger->touch_major) == 0) > + continue; /* finger lifted */ > + > + sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x); > + sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y); > + sc->frame[contacts].pressure = DEFAULT_PRESSURE; > + contacts++; > + } > + > + btn = sc->btn; > + sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF])); > + > + if (contacts || sc->contacts || sc->btn != btn) { > + sc->contacts = contacts; > + s = spltty(); > + wsmouse_buttons(sc->sc_wsmousedev, sc->btn); > + wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts); > + wsmouse_input_sync(sc->sc_wsmousedev); > + splx(s); > + } > +} > + > +int > +aplms_enable(void *v) > +{ > + struct aplms_softc *sc = v; > + > + if (sc->sc_enabled) > + return EBUSY; > + > + sc->sc_enabled = 1; > + return 0; > +} > + > +void > +aplms_disable(void *v) > +{ > + struct aplms_softc *sc = v; > + > + sc->sc_enabled = 0; > +} > + > +int > +aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) > +{ > + struct aplms_softc *sc = v; > + struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev); > + struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data; > + int wsmode; > + > + switch (cmd) { > + case WSMOUSEIO_GTYPE: > + *(u_int *)data = hw->type; > + break; > + > + case WSMOUSEIO_GCALIBCOORDS: > + wsmc->minx = hw->x_min; > + wsmc->maxx = hw->x_max; > + wsmc->miny = hw->y_min; > + wsmc->maxy = hw->y_max; > + wsmc->swapxy = 0; > + wsmc->resx = hw->h_res; > + wsmc->resy = hw->v_res; > + break; > + > + case WSMOUSEIO_SETMODE: > + wsmode = *(u_int *)data; > + if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) { > + printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname, > + wsmode); > + return (EINVAL); > + } > + wsmouse_set_mode(sc->sc_wsmousedev, wsmode); > + break; > + > + default: > + return -1; > + } > + > + return 0; > +} > + > +#else > + > +void > +aplms_intr(struct device *self, uint8_t *packet, size_t packetlen) > +{ > +} > + > +#endif > >