Download raw body.
aplhidev: enable on amd64, add keyboard backlight support
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 <jcs@jcs.org>
> >
> > 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.
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 <kettenis@openbsd.org>
- * Copyright (c) 2013-2014 joshua stein <jcs@openbsd.org>
- *
- * 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 <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/device.h>
-#include <sys/malloc.h>
-#include <sys/timeout.h>
-
-#include <lib/libkern/crc16.h>
-
-#include <machine/fdt.h>
-
-#include <dev/spi/spivar.h>
-
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_gpio.h>
-#include <dev/ofw/ofw_pinctrl.h>
-
-#include <dev/usb/usbdevs.h>
-
-#include <dev/wscons/wsconsio.h>
-#include <dev/wscons/wskbdvar.h>
-#include <dev/wscons/wsksymdef.h>
-#include <dev/wscons/wsmousevar.h>
-
-#include <dev/hid/hid.h>
-#include <dev/hid/hidkbdsc.h>
-#include <dev/hid/hidmsvar.h>
-
-#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 <kettenis@openbsd.org>
+ * Copyright (c) 2013-2014 joshua stein <jcs@openbsd.org>
+ *
+ * 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 <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/timeout.h>
+
+#include <lib/libkern/crc16.h>
+
+#include <dev/spi/spivar.h>
+
+#ifdef __HAVE_FDT
+#include <machine/fdt.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_gpio.h>
+#include <dev/ofw/ofw_pinctrl.h>
+#endif
+
+#include "acpi.h"
+#if NACPI > 0 && !defined(__HAVE_FDT)
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+#endif
+
+#include <dev/usb/usbdevs.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidkbdsc.h>
+#include <dev/hid/hidmsvar.h>
+
+#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
+#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) {
+ /* 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);
+}
+
+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);
+}
+
+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;
+ 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
aplhidev: enable on amd64, add keyboard backlight support