Index | Thread | Search

From:
Mark Kettenis <mark.kettenis@xs4all.nl>
Subject:
Re: aplhidev: enable on amd64, add keyboard backlight support
To:
joshua stein <jcs@jcs.org>
Cc:
tech@openbsd.org
Date:
Thu, 20 Nov 2025 13:40:53 +0100

Download raw body.

Thread
> 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:

cc -g -Werror -Wall -Wimplicit-function-declaration  -Wno-pointer-sign  -Wno-constant-conversion -Wno-address-of-packed-member  -Wno-unused-but-set-variable -Wno-gnu-folding-constant  -Wframe-larger-than=2047 -march=armv8-a+nofp+nosimd+rng  -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer  -ffixed-x18 -ffreestanding -fno-pie -moutline-atomics -mbranch-protection=bti -O2  -pipe -nostdinc -I/home/kettenis/src/m2pro/sys -I/home/kettenis/src/m2pro/sys/arch/arm64/compile/GENERIC.MP/obj -I/home/kettenis/src/m2pro/sys/arch  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/include  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/include/uapi  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/include/asic_reg  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/include  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/amdgpu  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/include  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/amdgpu_dm  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/legacy-dpm  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/smu11  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/smu12  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/smu13  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/smu14  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/powerplay/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/powerplay/hwmgr  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/powerplay/smumgr  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/inc/hw  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/clk_mgr  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dccg  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dio  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dpp  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dsc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dwb  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/hubbub  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/hpo  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/hwss  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/hubp  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_core  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_dpmm  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_mcg  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_pmo  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/dml2_standalone_libraries  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/dml2/dml21/src/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/mmhubbub  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/mpc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/opp  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/optc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/pg  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dc/resource  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/modules/inc  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/modules/hdcp  -I/home/kettenis/src/m2pro/sys/dev/pci/drm/amd/display/dmub/inc -DDDB -DDIAGNOSTIC -DKTRACE -DACCOUNTING -DKMEMSTATS -DPTRACE -DPOOL_DEBUG -DCRYPTO -DSYSVMSG -DSYSVSEM -DSYSVSHM -DUVM_SWAP_ENCRYPT -DFFS -DFFS2 -DUFS_DIRHASH -DQUOTA -DEXT2FS -DMFS -DNFSCLIENT -DNFSSERVER -DCD9660 -DUDF -DMSDOSFS -DFIFO -DFUSE -DSOCKET_SPLICE -DTCP_ECN -DTCP_SIGNATURE -DINET6 -DIPSEC -DPPP_BSDCOMP -DPPP_DEFLATE -DPIPEX -DMROUTING -DMPLS -DBOOT_CONFIG -DPCIVERBOSE -DUSER_PCICONF -DUSBVERBOSE -DSUSPEND -DWSDISPLAY_COMPAT_USL -DWSDISPLAY_COMPAT_RAWKBD -DWSDISPLAY_DEFAULTSCREENS="6" -DONEWIREVERBOSE -DMULTIPROCESSOR -DMAXUSERS=80 -D_KERNEL -D__arm64__ -MD -MP  -c /home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:241:19: error: unused variable 'node' [-Werror,-Wunused-variable]
  241 |         struct aml_node *node = (struct aml_node *)sa->sa_cookie;
      |                          ^~~~
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:242:11: error: unused variable 'val' [-Werror,-Wunused-variable]
  242 |         uint64_t val;
      |                  ^~~
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:357:33: error: use of undeclared identifier 'inode'; did you mean 'node'?
  357 |         sc->sc_gpiolen = OF_getproplen(inode, "spien-gpios");
      |                                        ^~~~~
      |                                        node
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:355:6: note: 'node' declared here
  355 |         int node = *(int *)cookie;
      |             ^
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:380:25: error: no member named 'sc_node' in 'struct aplhidev_softc'; did you mean 'sc_mode'?
  380 |         fdt_intr_establish(sc->sc_node, IPL_TTY,
      |                                ^~~~~~~
      |                                sc_mode
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:180:12: note: 'sc_mode' declared here
  180 |         uint8_t                 sc_mode;
      |                                 ^
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:481:6: error: call to undeclared function 'aplhidev_enable_spi'; ISO C99 and later do not support implicit function declarations [-Werror,-Wimplicit-function-declaration]
  481 |         if (aplhidev_enable_spi(sc) != 0)
      |             ^
/home/kettenis/src/m2pro/sys/dev/spi/aplhidev.c:486:46: error: use of undeclared identifier 'aplhidev_gpe_intr'
  486 |                 aml_register_notify(sc->sc_dev_node, NULL, aplhidev_gpe_intr,
      |                                                            ^
6 errors generated.
*** Error 1 in /home/kettenis/src/m2pro/sys/arch/arm64/compile/GENERIC.MP (Makefile:1758 'aplhidev.o')


You really don't have a little arm64 board lying around such that you
can at least do a compile test?  Your previous diff in this area also
broke arm64...

> diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
> index 37f1ac6d7c0..4046a147d47 100644
> --- sys/arch/amd64/conf/GENERIC
> +++ sys/arch/amd64/conf/GENERIC
> @@ -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
>  
> diff --git sys/arch/amd64/conf/files.amd64 sys/arch/amd64/conf/files.amd64
> index 0c1e224f5c2..25476378a97 100644
> --- sys/arch/amd64/conf/files.amd64
> +++ sys/arch/amd64/conf/files.amd64
> @@ -280,6 +280,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
>  #
> diff --git sys/arch/arm64/conf/files.arm64 sys/arch/arm64/conf/files.arm64
> index 34d9f5d35f5..5cf73280050 100644
> --- sys/arch/arm64/conf/files.arm64
> +++ sys/arch/arm64/conf/files.arm64
> @@ -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
> diff --git sys/dev/acpi/ispi_acpi.c sys/dev/acpi/ispi_acpi.c
> index 6a226a30482..8e0b820be58 100644
> --- sys/dev/acpi/ispi_acpi.c
> +++ sys/dev/acpi/ispi_acpi.c
> @@ -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 *node, void *arg)
>  
>  	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;
>  }
> diff --git sys/arch/arm64/dev/aplhidev.c sys/dev/spi/aplhidev.c
> similarity index 74%
> rename from sys/arch/arm64/dev/aplhidev.c
> rename to sys/dev/spi/aplhidev.c
> index 97d00a8878a..f8f0f35d88b 100644
> --- sys/arch/arm64/dev/aplhidev.c
> +++ sys/dev/spi/aplhidev.c
> @@ -25,13 +25,23 @@
>  
>  #include <lib/libkern/crc16.h>
>  
> -#include <machine/fdt.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
> +#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>
>  
> @@ -46,6 +56,14 @@
>  
>  #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
>  
> @@ -63,6 +81,12 @@
>  #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;
> @@ -131,9 +155,19 @@ struct aplhidev_set_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;
> -	int			sc_node;
> +#if NACPI > 0
> +	struct aml_node		*sc_dev_node;
> +#endif
>  
>  	spi_tag_t		sc_spi_tag;
>  	struct spi_config	sc_spi_conf;
> @@ -166,6 +200,13 @@ struct aplhidev_softc {
>  
>  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
> @@ -178,9 +219,16 @@ struct cfdriver aplhidev_cd = {
>  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);
> @@ -189,10 +237,26 @@ int
>  aplhidev_match(struct device *parent, void *match, void *aux)
>  {
>  	struct spi_attach_args *sa = aux;
> +#if NACPI > 0
> +	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;
>  }
>  
> @@ -206,34 +270,15 @@ aplhidev_attach(struct device *parent, struct device *self, void *aux)
>  	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);
> +#ifdef __HAVE_FDT
> +	aplhidev_fdt_init(sc, sa->sa_cookie);
>  
> -		/* 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);
> +#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--) {
> @@ -303,6 +348,179 @@ aplhidev_attach(struct device *parent, struct device *self, void *aux)
>  	}
>  }
>  
> +#ifdef __HAVE_FDT
> +void
> +aplhidev_fdt_init(struct aplhidev_softc *sc, void *cookie)
> +{
> +	int node = *(int *)cookie;
> +
> +	sc->sc_gpiolen = OF_getproplen(inode, "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(sc->sc_node, IPL_TTY,
> +	    aplhidev_intr, sc, sc->sc_dev.dv_xname);
> +}
> +#endif
> +
> +#if NACPI > 0
> +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)
>  {
> @@ -409,6 +627,45 @@ aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds)
>  	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)
>  {
> @@ -477,6 +734,16 @@ aplhidev_get_dimensions(struct aplhidev_softc *sc)
>  	delay(1000);
>  }
>  
> +#if NACPI > 0
> +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)
>  {
> @@ -566,6 +833,7 @@ struct aplkbd_softc {
>  	struct aplhidev_softc	*sc_hidev;
>  	struct hidkbd		sc_kbd;
>  	int			sc_spl;
> +	int			sc_backlight;
>  };
>  
>  void	aplkbd_cngetc(void *, u_int *, int *);
> @@ -641,7 +909,12 @@ aplkbd_attach(struct device *parent, struct device *self, void *aux)
>  		aplkbd_enable(sc, 1);
>  	}
>  
> +
>  	hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops);
> +
> +	sc->sc_backlight = APLHIDEV_BACKLIGHT_MIN;
> +	wskbd_get_backlight = aplkbd_wskbd_get_backlight;
> +	wskbd_set_backlight = aplkbd_wskbd_set_backlight;
>  }
>  
>  void
> @@ -693,6 +966,43 @@ aplkbd_set_leds(void *v, int leds)
>  		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)
> 
>