mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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
112 lines
2.7 KiB
C
112 lines
2.7 KiB
C
/*
|
|
* 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 <[email protected]>
|
|
* under sponsorship from the FreeBSD Foundation.
|
|
*
|
|
* Portions of this software were developed by Daniel Schaefer
|
|
* <[email protected]> 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);
|