Download raw body.
aplhidev: enable on amd64, add keyboard backlight support
> Date: Thu, 20 Nov 2025 10:46:08 -0600
> From: joshua stein <jcs@jcs.org>
>
> 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.
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 <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
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
>
>
aplhidev: enable on amd64, add keyboard backlight support