git: e2d56447b3a9 - main - hrfkill: Add driver to report RFKILL button press

From: Aymeric Wibo <obiwac_at_FreeBSD.org>
Date: Thu, 09 Jul 2026 07:28:27 UTC
The branch main has been updated by obiwac:

URL: https://cgit.FreeBSD.org/src/commit/?id=e2d56447b3a9d2ef9bd0b80c3aaa69e681f4be0f

commit e2d56447b3a9d2ef9bd0b80c3aaa69e681f4be0f
Author:     Aymeric Wibo <obiwac@FreeBSD.org>
AuthorDate: 2026-06-25 02:03:36 +0000
Commit:     Aymeric Wibo <obiwac@FreeBSD.org>
CommitDate: 2026-07-09 07:27:07 +0000

    hrfkill: Add driver to report RFKILL button press
    
    This driver only reports the RFKILL button presses.
    
    This is needed for the "airplane" key on some Framework laptops.
    
    Reviewed by:    wulf, ziaee
    Event:          Halifax Hackathon 202606
    Location:       vishwin@'s car
    Co-authored-by: Daniel Shaefer
    Sponsored by:   Framework Computer Inc
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D57838
---
 share/man/man4/Makefile          |   1 +
 share/man/man4/hidbus.4          |   1 +
 share/man/man4/hrfkill.4         |  82 +++++++++++++++++++++++++++++
 sys/conf/NOTES                   |   1 +
 sys/conf/files                   |   1 +
 sys/dev/hid/hid.h                |   2 +
 sys/dev/hid/hrfkill.c            | 111 +++++++++++++++++++++++++++++++++++++++
 sys/modules/hid/Makefile         |   1 +
 sys/modules/hid/hrfkill/Makefile |   8 +++
 9 files changed, 208 insertions(+)

diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 56b50d39d6f4..9bee23f1df8f 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -222,6 +222,7 @@ MAN=	aac.4 \
 	${_hptmv.4} \
 	${_hptnr.4} \
 	${_hptrr.4} \
+	hrfkill.4 \
 	hsctrl.4 \
 	htu21.4 \
 	${_hv_kvp.4} \
diff --git a/share/man/man4/hidbus.4 b/share/man/man4/hidbus.4
index f8ebaca8d659..e336eb5eb9b9 100644
--- a/share/man/man4/hidbus.4
+++ b/share/man/man4/hidbus.4
@@ -83,6 +83,7 @@ Default is 0.
 .Xr hms 4 ,
 .Xr hmt 4 ,
 .Xr hpen 4 ,
+.Xr hrfkill 4 ,
 .Xr hsctrl 4 ,
 .Xr hskbd 4 ,
 .Xr iichid 4 ,
diff --git a/share/man/man4/hrfkill.4 b/share/man/man4/hrfkill.4
new file mode 100644
index 000000000000..c1d3b73b28b2
--- /dev/null
+++ b/share/man/man4/hrfkill.4
@@ -0,0 +1,82 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2026 The FreeBSD Foundation
+.\"
+.\" Portions of this software were developed by Aymeric Wibo
+.\" <obiwac@freebsd.org> under sponsorship from the FreeBSD Foundation.
+.\"
+.Dd June 24, 2026
+.Dt HRFKILL 4
+.Os
+.Sh NAME
+.Nm hrfkill
+.Nd HID radio control driver
+.Sh SYNOPSIS
+.Cd device hrfkill
+.Cd device hid
+.Cd device hidbus
+.Cd device hidmap
+.Cd device evdev
+In
+.Xr loader.conf 5 :
+.Cd hrfkill_load="YES"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for HID wireless radio control buttons,
+most often found as an
+.Qq airplane mode
+or RFKILL toggle on laptop keyboards, and presents them to applications over the
+.Ar evdev
+interface.
+.Sh HARDWARE
+The
+.Nm
+driver supports HID radio control buttons and airplane mode keys
+on devices such as:
+.Pp
+.Bl -bullet -compact
+.It
+Framework Laptop Keyboard
+.El
+.Sh FILES
+.Bl -tag -width /dev/input/event* -compact
+.It Pa /dev/input/event*
+input event device node
+.El
+.Sh SEE ALSO
+.Xr hidbus 4 ,
+.Xr hsctrl 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Aymeric Wibo Aq Mt obiwac@freebsd.org
+under sponsorship from the FreeBSD Foundation and by
+.An Daniel Shaefer Aq Mt git@danielschaefer.me
+under sponsorship from Framework Computer Inc.
+.Sh CAVEATS
+Currently,
+.Nm
+only handles radio button reporting.
+The HID Generic Desktop radio control page also defines radio switches and
+status LEDs; support for these should be added in a future revision of the
+driver.
+.Pp
+.Fx
+does not yet have a generic RFKILL framework analogous to the one found in
+Linux.
+As a result,
+.Nm
+can only report radio button events to userspace via
+.Ar evdev ;
+the kernel itself has no mechanism to act on these events to block or unblock
+wireless devices.
+A future RFKILL framework would allow the driver to integrate directly with
+network interfaces and block transmitters in response to hardware events.
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index c7931db374c7..7b253927e9a8 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2435,6 +2435,7 @@ device		hkbd		# HID keyboard
 device		hms		# HID mouse
 device		hmt		# HID multitouch (MS-compatible)
 device		hpen		# Generic pen driver
+device		hrfkill		# RFKILL driver
 device		hsctrl		# System controls
 device		ps4dshock	# Sony PS4 DualShock 4 gamepad driver
 device		u2f		# FIDO/U2F authenticator
diff --git a/sys/conf/files b/sys/conf/files
index 09d4ff70e322..86dbd83e21d9 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1801,6 +1801,7 @@ dev/hid/hkbd.c			optional hkbd
 dev/hid/hms.c			optional hms
 dev/hid/hmt.c			optional hmt hconf
 dev/hid/hpen.c			optional hpen
+dev/hid/hrfkill.c		optional hrfkill
 dev/hid/hsctrl.c		optional hsctrl
 dev/hid/ietp.c			optional ietp
 dev/hid/ps4dshock.c		optional ps4dshock
diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h
index f164e48341ed..848657a7b768 100644
--- a/sys/dev/hid/hid.h
+++ b/sys/dev/hid/hid.h
@@ -74,6 +74,7 @@
 #define	HUG_KEYBOARD		0x0006
 #define	HUG_KEYPAD		0x0007
 #define	HUG_MULTIAXIS_CNTROLLER	0x0008
+#define	HUG_RADIO_CONTROL       0x000c
 #define	HUG_X			0x0030
 #define	HUG_Y			0x0031
 #define	HUG_Z			0x0032
@@ -116,6 +117,7 @@
 #define	HUG_D_PAD_RIGHT		0x0092
 #define	HUG_D_PAD_LEFT		0x0093
 #define	HUG_APPLE_EJECT		0x00b8
+#define	HUG_RADIO_BUTTON        0x00c6
 
 /* Usages Digitizers */
 #define	HUD_UNDEFINED		0x0000
diff --git a/sys/dev/hid/hrfkill.c b/sys/dev/hid/hrfkill.c
new file mode 100644
index 000000000000..279d04c54f6e
--- /dev/null
+++ b/sys/dev/hid/hrfkill.c
@@ -0,0 +1,111 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 The FreeBSD Foundation
+ * Copyright (c) 2026 Framework Computer Inc
+ *
+ * This software was developed by Aymeric Wibo <obiwac@freebsd.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Portions of this software were developed by Daniel Schaefer
+ * <git@danielschaefer.me> under sponsorship from Framework Computer Inc.
+ */
+
+#include "opt_hid.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/input.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidbus.h>
+#include <dev/hid/hidmap.h>
+
+/*
+ * Reference document:
+ * https://www.usb.org/sites/default/files/hutrr40radiohidusagesfinal_0.pdf
+ */
+
+static hidmap_cb_t	hrfkill_cb;
+
+static const struct hidmap_item hrfkill_map[] = {
+	{ HIDMAP_REL_CB(HUP_GENERIC_DESKTOP, HUG_RADIO_BUTTON, &hrfkill_cb) },
+};
+
+static const struct hid_device_id hrfkill_devs[] = {
+	{ HID_TLC(HUP_GENERIC_DESKTOP, HUG_RADIO_CONTROL) },
+};
+
+/*
+ * Synthesize key-down + key-up for the wireless radio button,
+ * which only reports a relative pulse (value=1) on press.
+ * The firmware latches value=1 and never resets it, so we
+ * track the last value via HIDMAP_CB_UDATA64 and only fire
+ * on the 0 -> non-zero transition.
+ */
+static int
+hrfkill_cb(HIDMAP_CB_ARGS)
+{
+	struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV();
+	int32_t last;
+
+	switch (HIDMAP_CB_GET_STATE()) {
+	case HIDMAP_CB_IS_ATTACHING:
+		evdev_support_event(evdev, EV_KEY);
+		evdev_support_key(evdev, KEY_RFKILL);
+		HIDMAP_CB_UDATA64 = 0;
+		break;
+	case HIDMAP_CB_IS_RUNNING:
+		last = (int32_t)HIDMAP_CB_UDATA64;
+		HIDMAP_CB_UDATA64 = (uint64_t)ctx.data;
+		if (ctx.data == 0 || ctx.data == last)
+			return (ENOMSG);
+		evdev_push_key(evdev, KEY_RFKILL, 1);
+		evdev_push_key(evdev, KEY_RFKILL, 0);
+		break;
+	default:
+		break;
+	}
+
+	return (0);
+}
+
+static int
+hrfkill_probe(device_t dev)
+{
+	return (HIDMAP_PROBE(device_get_softc(dev), dev,
+	    hrfkill_devs, hrfkill_map, "RFKILL Switch"));
+}
+
+static int
+hrfkill_attach(device_t dev)
+{
+	return (hidmap_attach(device_get_softc(dev)));
+}
+
+static int
+hrfkill_detach(device_t dev)
+{
+	return (hidmap_detach(device_get_softc(dev)));
+}
+
+static device_method_t hrfkill_methods[] = {
+	DEVMETHOD(device_probe,		hrfkill_probe),
+	DEVMETHOD(device_attach,	hrfkill_attach),
+	DEVMETHOD(device_detach,	hrfkill_detach),
+
+	DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(hrfkill, hrfkill_driver, hrfkill_methods, sizeof(struct hidmap));
+DRIVER_MODULE(hrfkill, hidbus, hrfkill_driver, NULL, NULL);
+MODULE_DEPEND(hrfkill, hid, 1, 1, 1);
+MODULE_DEPEND(hrfkill, hidbus, 1, 1, 1);
+MODULE_DEPEND(hrfkill, hidmap, 1, 1, 1);
+MODULE_DEPEND(hrfkill, evdev, 1, 1, 1);
+MODULE_VERSION(hrfkill, 1);
+HID_PNP_INFO(hrfkill_devs);
diff --git a/sys/modules/hid/Makefile b/sys/modules/hid/Makefile
index a32b9326647e..c6d856c45ed1 100644
--- a/sys/modules/hid/Makefile
+++ b/sys/modules/hid/Makefile
@@ -15,6 +15,7 @@ SUBDIR += \
 	hms \
 	hmt \
 	hpen \
+	hrfkill \
 	hsctrl \
 	ietp \
 	ps4dshock \
diff --git a/sys/modules/hid/hrfkill/Makefile b/sys/modules/hid/hrfkill/Makefile
new file mode 100644
index 000000000000..e6c46696fb7d
--- /dev/null
+++ b/sys/modules/hid/hrfkill/Makefile
@@ -0,0 +1,8 @@
+.PATH: ${SRCTOP}/sys/dev/hid
+
+KMOD=	hrfkill
+SRCS=	hrfkill.c
+SRCS+=	opt_kbd.h
+SRCS+=	bus_if.h device_if.h
+
+.include <bsd.kmod.mk>