Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F161555388
D56729.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D56729.diff
View Options
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -208,6 +208,7 @@
hidbus.4 \
hidquirk.4 \
hidraw.4 \
+ hidwacom.4 \
hkbd.4 \
hms.4 \
hmt.4 \
diff --git a/share/man/man4/hidwacom.4 b/share/man/man4/hidwacom.4
new file mode 100644
--- /dev/null
+++ b/share/man/man4/hidwacom.4
@@ -0,0 +1,87 @@
+.\"
+.\" Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.Dd April 18, 2026
+.Dt HIDWACOM 4
+.Os
+.Sh NAME
+.Nm hidwacom
+.Nd Wacom ExpressKey Remote driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device hidwacom"
+.Cd "device hidbus"
+.Cd "device hid"
+.Cd "device evdev"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+hidwacom_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Wacom ExpressKey Remote, a wireless
+button pad with 18 programmable buttons and a touch ring.
+The device communicates via a USB wireless receiver using vendor-specific
+HID reports.
+.Pp
+The driver exposes the following inputs through
+.Xr evdev 4 :
+.Bl -tag -width "MSC_PULSELED"
+.It Dv BTN_0 Ns \(en Ns Dv BTN_Z , Dv BTN_BASE , Dv BTN_BASE2
+18 buttons.
+.It Dv ABS_WHEEL
+Touch ring position (0\(en71).
+Reports 0 when the ring is not being touched.
+.It Dv ABS_MISC
+Touch ring mode (0\(en3), as reported by the device.
+Reports 0 when the ring is not being touched.
+.It Dv MSC_PULSELED
+Battery charge level as a percentage (0\(en100).
+.It Dv MSC_SERIAL
+Remote serial number, identifying which physical remote generated the event.
+.El
+.Pp
+Only a single paired remote is supported.
+The multi-remote pairing protocol (up to 5 remotes) is not implemented.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following device:
+.Pp
+.Bl -bullet -compact
+.It
+Wacom ExpressKey Remote (ACK-411050), connected via the Wacom USB
+wireless receiver
+.El
+.Sh FILES
+.Bl -tag -width "/dev/input/eventX" -compact
+.It Pa /dev/input/eventX
+evdev input device
+.El
+.Sh SEE ALSO
+.Xr evdev 4 ,
+.Xr hidbus 4 ,
+.Xr usbhid 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 16.0 .
+.Sh BUGS
+Only a single paired remote is fully supported.
+When multiple remotes are paired, button state may be corrupted as all
+remotes share a single evdev device.
+.Sh AUTHORS
+.An Abdelkader Boudih Aq Mt freebsd@seuros.com
+.Pp
+Protocol decoded from USB traffic analysis.
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1787,6 +1787,7 @@
dev/hid/hidmap.c optional hidmap | hms
dev/hid/hidquirk.c optional hid
dev/hid/hidraw.c optional hidraw
+dev/hid/hidwacom.c optional hidwacom
dev/hid/hkbd.c optional hkbd
dev/hid/hms.c optional hms
dev/hid/hmt.c optional hmt hconf
diff --git a/sys/dev/hid/hidwacom.c b/sys/dev/hid/hidwacom.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/hid/hidwacom.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2026 Abdelkader Boudih <freebsd@seuros.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Wacom ExpressKey Remote Driver
+ *
+ * HID driver for Wacom ExpressKey Remote (USB HID, vendor 0x056a).
+ * The device uses a vendor-specific HID usage page (0xFF0C) with
+ * proprietary report formats. Only a single remote is supported;
+ * multi-remote pairing (up to 5) is not implemented.
+ *
+ * Protocol decoded from USB traffic capture (HydraUSB3 analyser).
+ * Report structure cross-referenced with the HID report descriptor
+ * and publicly available Wacom protocol documentation.
+ *
+ * Report ID 0x10 (DEVICE_LIST): pairing status (ignored)
+ * Report ID 0x11 (REMOTE): button and touch ring events
+ * buf[0]: report ID (0x11)
+ * buf[3..5]: serial number (LE 24-bit)
+ * buf[7]: battery (bit 7 = charging, bits 0-6 = percent 0-100)
+ * buf[9]: buttons 0-7
+ * buf[10]: buttons 8-15
+ * buf[11]: bits 0-1 = buttons 16-17, bits 6-7 = touch ring mode
+ * buf[12]: touch ring (bit 7 = active, bits 0-6 = position 1-72,
+ * where raw value 1 maps to position 0 and 72 maps to 71)
+ */
+
+#include <sys/cdefs.h>
+
+#include "opt_hid.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sysctl.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+
+#define HID_DEBUG_VAR hidwacom_debug
+#include <dev/hid/hid.h>
+#include <dev/hid/hidbus.h>
+#include "usbdevs.h"
+
+#ifdef HID_DEBUG
+static int hidwacom_debug = 0;
+
+static SYSCTL_NODE(_hw_hid, OID_AUTO, hidwacom, CTLFLAG_RW, 0,
+ "Wacom ExpressKey Remote");
+SYSCTL_INT(_hw_hid_hidwacom, OID_AUTO, debug, CTLFLAG_RWTUN,
+ &hidwacom_debug, 0, "Debug level");
+#endif
+
+/* Report IDs */
+#define WACOM_REPORT_DEVICE_LIST 0x10
+#define WACOM_REPORT_REMOTE 0x11
+
+/* Minimum report length (report ID + 12 data bytes for ring at buf[12]) */
+#define WACOM_REMOTE_MIN_LEN 13
+
+/* Touch ring modes (buf[11] bits 6-7) */
+#define WACOM_RING_MODE_MASK 0xc0
+#define WACOM_RING_MODE_SHIFT 6
+
+/* Touch ring */
+#define WACOM_RING_ACTIVE 0x80
+#define WACOM_RING_POSITION_MASK 0x7f
+#define WACOM_RING_MAX 71
+
+/* Battery: bit 7 = charging flag, bits 0-6 = percent */
+#define WACOM_BATTERY_CHARGING 0x80
+#define WACOM_BATTERY_PERCENT_MASK 0x7f
+
+/* Pad device ID for ABS_MISC activity marker (matches Linux PAD_DEVICE_ID) */
+#define WACOM_PAD_DEVICE_ID 0x0f
+
+#define HIDWACOM_DEV_NAME "Wacom ExpressKey Remote"
+
+/* Button evdev keycodes */
+static const uint16_t hidwacom_buttons[] = {
+ BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, /* buf[9] */
+ BTN_8, BTN_9, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* buf[10] */
+ BTN_BASE, BTN_BASE2, /* buf[11] */
+};
+
+struct hidwacom_softc {
+ struct mtx sc_mtx;
+ struct evdev_dev *sc_evdev;
+};
+
+static void
+hidwacom_intr(void *context, void *data, hid_size_t len)
+{
+ struct hidwacom_softc *sc = context;
+ uint8_t *buf = data;
+ uint8_t report_id;
+ uint8_t b9, b10, b11, ring, battery;
+ uint32_t serial;
+ int i, pos;
+
+ if (len < 1)
+ return;
+
+ report_id = buf[0];
+
+ if (report_id == WACOM_REPORT_DEVICE_LIST) {
+ DPRINTFN(2, "device list report (pairing)\n");
+ return;
+ }
+
+ if (report_id != WACOM_REPORT_REMOTE) {
+ DPRINTFN(1, "unknown report id: 0x%02x\n", report_id);
+ return;
+ }
+
+ if (len < WACOM_REMOTE_MIN_LEN) {
+ DPRINTFN(1, "short remote report: %zu\n", (size_t)len);
+ return;
+ }
+
+ mtx_lock(&sc->sc_mtx);
+
+ /* Serial number (LE 24-bit) */
+ serial = buf[3] + ((uint32_t)buf[4] << 8) + ((uint32_t)buf[5] << 16);
+
+ /* Battery: percent in bits 0-6, charging flag in bit 7 */
+ battery = buf[7] & WACOM_BATTERY_PERCENT_MASK;
+
+ /* Extract button bytes */
+ b9 = buf[9];
+ b10 = buf[10];
+ b11 = buf[11];
+
+ /* Buttons 0-7 from buf[9] */
+ for (i = 0; i < 8; i++)
+ evdev_push_key(sc->sc_evdev, hidwacom_buttons[i],
+ (b9 >> i) & 1);
+
+ /* Buttons 8-15 from buf[10] */
+ for (i = 0; i < 8; i++)
+ evdev_push_key(sc->sc_evdev, hidwacom_buttons[8 + i],
+ (b10 >> i) & 1);
+
+ /* Buttons 16-17 from buf[11] bits 0-1 */
+ evdev_push_key(sc->sc_evdev, BTN_BASE, b11 & 0x01);
+ evdev_push_key(sc->sc_evdev, BTN_BASE2, b11 & 0x02);
+
+ /* Touch ring: raw position is 1-based (1..72); subtract 1 for 0..71 */
+ ring = buf[12];
+ if (ring & WACOM_RING_ACTIVE) {
+ pos = (ring & WACOM_RING_POSITION_MASK) - 1;
+ if (pos < 0)
+ pos = 0;
+ if (pos > WACOM_RING_MAX)
+ pos = WACOM_RING_MAX;
+ evdev_push_abs(sc->sc_evdev, ABS_WHEEL, pos);
+ evdev_push_abs(sc->sc_evdev, ABS_MISC,
+ (b11 >> WACOM_RING_MODE_SHIFT) & 0x03);
+ } else {
+ evdev_push_abs(sc->sc_evdev, ABS_WHEEL, 0);
+ evdev_push_abs(sc->sc_evdev, ABS_MISC, 0);
+ }
+
+ /* Battery percent */
+ evdev_push_event(sc->sc_evdev, EV_MSC, MSC_PULSELED, battery);
+
+ /* Remote serial number */
+ evdev_push_event(sc->sc_evdev, EV_MSC, MSC_SERIAL, serial);
+
+ evdev_sync(sc->sc_evdev);
+
+ mtx_unlock(&sc->sc_mtx);
+}
+
+static const struct hid_device_id hidwacom_devs[] = {
+ { HID_BVP(BUS_USB, USB_VENDOR_WACOM,
+ USB_PRODUCT_WACOM_EXPRESSKEY_REMOTE) },
+};
+
+static int
+hidwacom_probe(device_t dev)
+{
+ int error;
+
+ error = HIDBUS_LOOKUP_DRIVER_INFO(dev, hidwacom_devs);
+ if (error != 0)
+ return (error);
+
+ if (hidbus_get_index(dev) != 0)
+ return (ENXIO);
+
+ hidbus_set_desc(dev, HIDWACOM_DEV_NAME);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+hidwacom_attach(device_t dev)
+{
+ struct hidwacom_softc *sc = device_get_softc(dev);
+ const struct hid_device_info *hw;
+ int i, error;
+
+ hw = hid_get_device_info(dev);
+ mtx_init(&sc->sc_mtx, "hidwacom", NULL, MTX_DEF);
+
+ sc->sc_evdev = evdev_alloc();
+ evdev_set_name(sc->sc_evdev, HIDWACOM_DEV_NAME);
+ evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
+ evdev_set_id(sc->sc_evdev, hw->idBus, hw->idVendor, hw->idProduct,
+ hw->idVersion);
+ evdev_set_serial(sc->sc_evdev, hw->serial);
+
+ evdev_support_event(sc->sc_evdev, EV_SYN);
+ evdev_support_event(sc->sc_evdev, EV_KEY);
+ evdev_support_event(sc->sc_evdev, EV_ABS);
+ evdev_support_event(sc->sc_evdev, EV_MSC);
+
+ for (i = 0; i < (int)nitems(hidwacom_buttons); i++)
+ evdev_support_key(sc->sc_evdev, hidwacom_buttons[i]);
+
+ evdev_support_abs(sc->sc_evdev, ABS_WHEEL, 0, WACOM_RING_MAX,
+ 0, 0, 0);
+ evdev_support_abs(sc->sc_evdev, ABS_MISC, 0, 3, 0, 0, 0);
+ evdev_support_msc(sc->sc_evdev, MSC_SERIAL);
+ evdev_support_msc(sc->sc_evdev, MSC_PULSELED);
+
+ error = evdev_register_mtx(sc->sc_evdev, &sc->sc_mtx);
+ if (error != 0) {
+ device_printf(dev, "evdev_register_mtx failed: %d\n", error);
+ goto fail;
+ }
+
+ hidbus_set_intr(dev, hidwacom_intr, sc);
+
+ error = hid_intr_start(dev);
+ if (error != 0) {
+ device_printf(dev, "hid_intr_start failed: %d\n", error);
+ hid_intr_stop(dev);
+ goto fail;
+ }
+
+ return (0);
+
+fail:
+ if (sc->sc_evdev != NULL)
+ evdev_free(sc->sc_evdev);
+ mtx_destroy(&sc->sc_mtx);
+ return (error);
+}
+
+static int
+hidwacom_detach(device_t dev)
+{
+ struct hidwacom_softc *sc = device_get_softc(dev);
+ int error;
+
+ error = hid_intr_stop(dev);
+ if (error != 0) {
+ device_printf(dev, "hid_intr_stop failed: %d\n", error);
+ return (error);
+ }
+ evdev_free(sc->sc_evdev);
+ mtx_destroy(&sc->sc_mtx);
+
+ return (0);
+}
+
+static device_method_t hidwacom_methods[] = {
+ DEVMETHOD(device_probe, hidwacom_probe),
+ DEVMETHOD(device_attach, hidwacom_attach),
+ DEVMETHOD(device_detach, hidwacom_detach),
+ DEVMETHOD_END
+};
+
+static driver_t hidwacom_driver = {
+ "hidwacom",
+ hidwacom_methods,
+ sizeof(struct hidwacom_softc)
+};
+
+DRIVER_MODULE(hidwacom, hidbus, hidwacom_driver, NULL, NULL);
+MODULE_DEPEND(hidwacom, hid, 1, 1, 1);
+MODULE_DEPEND(hidwacom, hidbus, 1, 1, 1);
+MODULE_DEPEND(hidwacom, evdev, 1, 1, 1);
+MODULE_VERSION(hidwacom, 1);
+HID_PNP_INFO(hidwacom_devs);
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -4979,6 +4979,7 @@
product WACOM GRAPHIRE3_4X5 0x0013 Graphire 3 4x5
product WACOM INTUOSA5 0x0021 Intuos A5
product WACOM GD0912U 0x0022 Intuos 9x12 Graphics Tablet
+product WACOM EXPRESSKEY_REMOTE 0x0331 ExpressKey Remote
/* WAGO Kontakttechnik GmbH products */
product WAGO SERVICECABLE 0x07a6 USB Service Cable 750-923
diff --git a/sys/modules/hid/Makefile b/sys/modules/hid/Makefile
--- a/sys/modules/hid/Makefile
+++ b/sys/modules/hid/Makefile
@@ -11,6 +11,7 @@
hconf \
hcons \
hgame \
+ hidwacom \
hkbd \
hms \
hmt \
diff --git a/sys/modules/hid/hidwacom/Makefile b/sys/modules/hid/hidwacom/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/hid/hidwacom/Makefile
@@ -0,0 +1,8 @@
+.PATH: ${SRCTOP}/sys/dev/hid
+
+KMOD= hidwacom
+SRCS= hidwacom.c
+SRCS+= opt_hid.h
+SRCS+= bus_if.h device_if.h usbdevs.h
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jul 5, 8:15 PM (5 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34722247
Default Alt Text
D56729.diff (11 KB)
Attached To
Mode
D56729: hidwacom: Add Wacom ExpressKey Remote driver
Attached
Detach File
Event Timeline
Log In to Comment