diff options
Diffstat (limited to 'sys/dev/acpi_support')
-rw-r--r-- | sys/dev/acpi_support/acpi_asus.c | 22 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_asus_wmi.c | 431 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_fujitsu.c | 4 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_hp.c | 4 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_ibm.c | 43 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_sbl_wmi.c | 193 | ||||
-rw-r--r-- | sys/dev/acpi_support/acpi_wmi.c | 14 |
7 files changed, 659 insertions, 52 deletions
diff --git a/sys/dev/acpi_support/acpi_asus.c b/sys/dev/acpi_support/acpi_asus.c index 6e63d8fabab1..b9ba6650d2b7 100644 --- a/sys/dev/acpi_support/acpi_asus.c +++ b/sys/dev/acpi_support/acpi_asus.c @@ -43,7 +43,6 @@ #include <sys/kernel.h> #include <sys/module.h> #include <sys/bus.h> -#include <sys/sbuf.h> #include <contrib/dev/acpica/include/acpi.h> #include <contrib/dev/acpica/include/accommon.h> @@ -535,7 +534,6 @@ acpi_asus_probe(device_t dev) { struct acpi_asus_model *model; struct acpi_asus_softc *sc; - struct sbuf *sb; ACPI_BUFFER Buf; ACPI_OBJECT Arg, *Obj; ACPI_OBJECT_LIST Args; @@ -599,24 +597,17 @@ acpi_asus_probe(device_t dev) } } - sb = sbuf_new_auto(); - if (sb == NULL) - return (ENOMEM); - /* * Asus laptops are simply identified by name, easy! */ for (model = acpi_asus_models; model->name != NULL; model++) { if (strncmp(Obj->String.Pointer, model->name, 3) == 0) { good: - sbuf_printf(sb, "Asus %s Laptop Extras", - Obj->String.Pointer); - sbuf_finish(sb); - sc->model = model; - device_set_desc_copy(dev, sbuf_data(sb)); - sbuf_delete(sb); + device_set_descf(dev, "Asus %s Laptop Extras", + Obj->String.Pointer); + AcpiOsFree(Buf.Pointer); return (rv); } @@ -695,12 +686,9 @@ good: } } - sbuf_printf(sb, "Unsupported Asus laptop: %s\n", Obj->String.Pointer); - sbuf_finish(sb); - - device_printf(dev, "%s", sbuf_data(sb)); + device_printf(dev, "Unsupported Asus laptop: %s\n", + Obj->String.Pointer); - sbuf_delete(sb); AcpiOsFree(Buf.Pointer); return (ENXIO); diff --git a/sys/dev/acpi_support/acpi_asus_wmi.c b/sys/dev/acpi_support/acpi_asus_wmi.c index 853696e67f84..0198ccada3ed 100644 --- a/sys/dev/acpi_support/acpi_asus_wmi.c +++ b/sys/dev/acpi_support/acpi_asus_wmi.c @@ -26,6 +26,7 @@ #include <sys/cdefs.h> #include "opt_acpi.h" +#include "opt_evdev.h" #include <sys/param.h> #include <sys/conf.h> #include <sys/uio.h> @@ -41,6 +42,15 @@ #include <dev/acpica/acpivar.h> #include "acpi_wmi_if.h" +#include <dev/backlight/backlight.h> +#include "backlight_if.h" + +#ifdef EVDEV_SUPPORT +#include <dev/evdev/input.h> +#include <dev/evdev/evdev.h> +#define NO_KEY KEY_RESERVED +#endif + #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("ASUS-WMI") @@ -89,9 +99,11 @@ ACPI_MODULE_NAME("ASUS-WMI") #define ASUS_WMI_DEVID_CARDREADER 0x00080013 #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 +#define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056 #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 +#define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY 0x00120075 /* DSTS masks */ #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 @@ -102,6 +114,12 @@ ACPI_MODULE_NAME("ASUS-WMI") #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 +/* Events */ +#define ASUS_WMI_EVENT_QUEUE_SIZE 0x10 +#define ASUS_WMI_EVENT_QUEUE_END 0x1 +#define ASUS_WMI_EVENT_MASK 0xFFFF +#define ASUS_WMI_EVENT_VALUE_ATK 0xFF + struct acpi_asus_wmi_softc { device_t dev; device_t wmi_dev; @@ -110,6 +128,14 @@ struct acpi_asus_wmi_softc { struct sysctl_oid *sysctl_tree; int dsts_id; int handle_keys; + bool event_queue; + struct cdev *kbd_bkl; + uint32_t kbd_bkl_level; + uint32_t tuf_rgb_mode; + uint32_t ttp_mode; +#ifdef EVDEV_SUPPORT + struct evdev_dev *evdev; +#endif }; static struct { @@ -250,33 +276,133 @@ static struct { .dev_id = ASUS_WMI_DEVID_PROCESSOR_STATE, .flag_rdonly = 1 }, + { + .name = "throttle_thermal_policy", + .dev_id = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, + .description = "Throttle Thermal Policy " + "(0 - default, 1 - overboost, 2 - silent)", + }, { NULL, 0, NULL, 0 } }; +#ifdef EVDEV_SUPPORT +static const struct { + UINT32 notify; + uint16_t key; +} acpi_asus_wmi_evdev_map[] = { + { 0x20, KEY_BRIGHTNESSDOWN }, + { 0x2f, KEY_BRIGHTNESSUP }, + { 0x30, KEY_VOLUMEUP }, + { 0x31, KEY_VOLUMEDOWN }, + { 0x32, KEY_MUTE }, + { 0x35, KEY_SCREENLOCK }, + { 0x38, KEY_PROG3 }, /* Armoury Crate */ + { 0x40, KEY_PREVIOUSSONG }, + { 0x41, KEY_NEXTSONG }, + { 0x43, KEY_STOPCD }, /* Stop/Eject */ + { 0x45, KEY_PLAYPAUSE }, + { 0x4f, KEY_LEFTMETA }, /* Fn-locked "Windows" Key */ + { 0x4c, KEY_MEDIA }, /* WMP Key */ + { 0x50, KEY_EMAIL }, + { 0x51, KEY_WWW }, + { 0x55, KEY_CALC }, + { 0x57, NO_KEY }, /* Battery mode */ + { 0x58, NO_KEY }, /* AC mode */ + { 0x5C, KEY_F15 }, /* Power Gear key */ + { 0x5D, KEY_WLAN }, /* Wireless console Toggle */ + { 0x5E, KEY_WLAN }, /* Wireless console Enable */ + { 0x5F, KEY_WLAN }, /* Wireless console Disable */ + { 0x60, KEY_TOUCHPAD_ON }, + { 0x61, KEY_SWITCHVIDEOMODE }, /* SDSP LCD only */ + { 0x62, KEY_SWITCHVIDEOMODE }, /* SDSP CRT only */ + { 0x63, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT */ + { 0x64, KEY_SWITCHVIDEOMODE }, /* SDSP TV */ + { 0x65, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV */ + { 0x66, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV */ + { 0x67, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV */ + { 0x6B, KEY_TOUCHPAD_TOGGLE }, + { 0x6E, NO_KEY }, /* Low Battery notification */ + { 0x71, KEY_F13 }, /* General-purpose button */ + { 0x79, NO_KEY }, /* Charger type dectection notification */ + { 0x7a, KEY_ALS_TOGGLE }, /* Ambient Light Sensor Toggle */ + { 0x7c, KEY_MICMUTE }, + { 0x7D, KEY_BLUETOOTH }, /* Bluetooth Enable */ + { 0x7E, KEY_BLUETOOTH }, /* Bluetooth Disable */ + { 0x82, KEY_CAMERA }, + { 0x86, KEY_PROG1 }, /* MyASUS Key */ + { 0x88, KEY_RFKILL }, /* Radio Toggle Key */ + { 0x8A, KEY_PROG1 }, /* Color enhancement mode */ + { 0x8C, KEY_SWITCHVIDEOMODE }, /* SDSP DVI only */ + { 0x8D, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + DVI */ + { 0x8E, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + DVI */ + { 0x8F, KEY_SWITCHVIDEOMODE }, /* SDSP TV + DVI */ + { 0x90, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + DVI */ + { 0x91, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + DVI */ + { 0x92, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + DVI */ + { 0x93, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + DVI */ + { 0x95, KEY_MEDIA }, + { 0x99, KEY_PHONE }, /* Conflicts with fan mode switch */ + { 0xA0, KEY_SWITCHVIDEOMODE }, /* SDSP HDMI only */ + { 0xA1, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + HDMI */ + { 0xA2, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + HDMI */ + { 0xA3, KEY_SWITCHVIDEOMODE }, /* SDSP TV + HDMI */ + { 0xA4, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + HDMI */ + { 0xA5, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + TV + HDMI */ + { 0xA6, KEY_SWITCHVIDEOMODE }, /* SDSP CRT + TV + HDMI */ + { 0xA7, KEY_SWITCHVIDEOMODE }, /* SDSP LCD + CRT + TV + HDMI */ + { 0xAE, KEY_FN_F5 }, /* Fn+F5 fan mode on 2020+ */ + { 0xB3, KEY_PROG4 }, /* AURA */ + { 0xB5, KEY_CALC }, + { 0xC4, KEY_KBDILLUMUP }, + { 0xC5, KEY_KBDILLUMDOWN }, + { 0xC6, NO_KEY }, /* Ambient Light Sensor notification */ + { 0xFA, KEY_PROG2 }, /* Lid flip action */ + { 0xBD, KEY_PROG2 }, /* Lid flip action on ROG xflow laptops */ +}; +#endif + ACPI_SERIAL_DECL(asus_wmi, "ASUS WMI device"); static void acpi_asus_wmi_identify(driver_t *driver, device_t parent); static int acpi_asus_wmi_probe(device_t dev); static int acpi_asus_wmi_attach(device_t dev); static int acpi_asus_wmi_detach(device_t dev); +static int acpi_asus_wmi_suspend(device_t dev); +static int acpi_asus_wmi_resume(device_t dev); static int acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, int oldarg); static int acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id); static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, - UINT32 arg0, UINT32 arg1, UINT32 *retval); + UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval); static int acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, UINT32 dev_id, UINT32 *retval); static int acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval); +static int acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, + int *code); static void acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context); +static int acpi_asus_wmi_backlight_update_status(device_t dev, + struct backlight_props *props); +static int acpi_asus_wmi_backlight_get_status(device_t dev, + struct backlight_props *props); +static int acpi_asus_wmi_backlight_get_info(device_t dev, + struct backlight_info *info); static device_method_t acpi_asus_wmi_methods[] = { + /* Device interface */ DEVMETHOD(device_identify, acpi_asus_wmi_identify), DEVMETHOD(device_probe, acpi_asus_wmi_probe), DEVMETHOD(device_attach, acpi_asus_wmi_attach), DEVMETHOD(device_detach, acpi_asus_wmi_detach), + DEVMETHOD(device_suspend, acpi_asus_wmi_suspend), + DEVMETHOD(device_resume, acpi_asus_wmi_resume), + + /* Backlight interface */ + DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status), + DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status), + DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info), DEVMETHOD_END }; @@ -290,6 +416,34 @@ static driver_t acpi_asus_wmi_driver = { DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0); MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1); MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1); +MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1); +#ifdef EVDEV_SUPPORT +MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1); +#endif + +static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 }; + +static inline uint32_t +devstate_to_kbd_bkl_level(UINT32 val) +{ + return (acpi_asus_wmi_backlight_levels[val & 0x3]); +} + +static inline UINT32 +kbd_bkl_level_to_devstate(uint32_t bkl) +{ + UINT32 val; + int i; + + for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) { + if (bkl < acpi_asus_wmi_backlight_levels[i]) + break; + } + val = (i - 1) & 0x3; + if (val != 0) + val |= 0x80; + return(val); +} static void acpi_asus_wmi_identify(driver_t *driver, device_t parent) @@ -300,7 +454,7 @@ acpi_asus_wmi_identify(driver_t *driver, device_t parent) return; /* Add only a single device instance. */ - if (device_find_child(parent, "acpi_asus_wmi", -1) != NULL) + if (device_find_child(parent, "acpi_asus_wmi", DEVICE_UNIT_ANY) != NULL) return; /* Check management GUID to see whether system is compatible. */ @@ -308,7 +462,7 @@ acpi_asus_wmi_identify(driver_t *driver, device_t parent) ACPI_ASUS_WMI_MGMT_GUID)) return; - if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", -1) == NULL) + if (BUS_ADD_CHILD(parent, 0, "acpi_asus_wmi", DEVICE_UNIT_ANY) == NULL) device_printf(parent, "add acpi_asus_wmi child failed\n"); } @@ -328,7 +482,8 @@ acpi_asus_wmi_attach(device_t dev) { struct acpi_asus_wmi_softc *sc; UINT32 val; - int dev_id, i; + int dev_id, i, code; + bool have_kbd_bkl = false; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); @@ -383,14 +538,14 @@ next: /* Initialize. */ if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, - ASUS_WMI_METHODID_INIT, 0, 0, &val) && bootverbose) + ASUS_WMI_METHODID_INIT, 0, 0, 0, &val) && bootverbose) device_printf(dev, "Initialization: %#x\n", val); if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, - ASUS_WMI_METHODID_SPEC, 0, 0x9, &val) && bootverbose) + ASUS_WMI_METHODID_SPEC, 0, 0x9, 0, &val) && bootverbose) device_printf(dev, "WMI BIOS version: %d.%d\n", val >> 16, val & 0xFF); if (!acpi_asus_wmi_evaluate_method(sc->wmi_dev, - ASUS_WMI_METHODID_SFUN, 0, 0, &val) && bootverbose) + ASUS_WMI_METHODID_SFUN, 0, 0, 0, &val) && bootverbose) device_printf(dev, "SFUN value: %#x\n", val); ACPI_SERIAL_BEGIN(asus_wmi); @@ -413,6 +568,10 @@ next: if (val == 0) continue; break; + case ASUS_WMI_DEVID_KBD_BACKLIGHT: + sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val); + have_kbd_bkl = true; + /* FALLTHROUGH */ default: if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0) continue; @@ -437,6 +596,54 @@ next: } ACPI_SERIAL_END(asus_wmi); + /* Detect and flush event queue */ + if (sc->dsts_id == ASUS_WMI_METHODID_DSTS2) { + for (i = 0; i <= ASUS_WMI_EVENT_QUEUE_SIZE; i++) { + if (acpi_asus_wmi_get_event_code(sc->wmi_dev, + ASUS_WMI_EVENT_VALUE_ATK, &code) != 0) { + device_printf(dev, + "Can not flush event queue\n"); + break; + } + if (code == ASUS_WMI_EVENT_QUEUE_END || + code == ASUS_WMI_EVENT_MASK) { + sc->event_queue = true; + break; + } + } + } + +#ifdef EVDEV_SUPPORT + if (sc->notify_guid != NULL) { + sc->evdev = evdev_alloc(); + evdev_set_name(sc->evdev, device_get_desc(dev)); + evdev_set_phys(sc->evdev, device_get_nameunit(dev)); + evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1); + evdev_support_event(sc->evdev, EV_SYN); + evdev_support_event(sc->evdev, EV_KEY); + for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) { + if (acpi_asus_wmi_evdev_map[i].key != NO_KEY) + evdev_support_key(sc->evdev, + acpi_asus_wmi_evdev_map[i].key); + } + + if (evdev_register(sc->evdev) != 0) { + device_printf(dev, "Can not register evdev\n"); + acpi_asus_wmi_detach(dev); + return (ENXIO); + } + } +#endif + + if (have_kbd_bkl) { + sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev); + if (sc->kbd_bkl == NULL) { + device_printf(dev, "Can not register backlight\n"); + acpi_asus_wmi_detach(dev); + return (ENXIO); + } + } + return (0); } @@ -447,8 +654,43 @@ acpi_asus_wmi_detach(device_t dev) ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); - if (sc->notify_guid) + if (sc->kbd_bkl != NULL) + backlight_destroy(sc->kbd_bkl); + + if (sc->notify_guid) { ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid); +#ifdef EVDEV_SUPPORT + evdev_free(sc->evdev); +#endif + } + + return (0); +} + +static int +acpi_asus_wmi_suspend(device_t dev) +{ + struct acpi_asus_wmi_softc *sc = device_get_softc(dev); + + if (sc->kbd_bkl != NULL) { + ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); + acpi_wpi_asus_set_devstate(sc, + ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL); + } + + return (0); +} + +static int +acpi_asus_wmi_resume(device_t dev) +{ + struct acpi_asus_wmi_softc *sc = device_get_softc(dev); + + if (sc->kbd_bkl != NULL) { + ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); + acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT, + kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL); + } return (0); } @@ -488,6 +730,13 @@ acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id) ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); ACPI_SERIAL_ASSERT(asus_wmi); + switch(dev_id) { + case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY: + return (sc->ttp_mode); + default: + break; + } + acpi_wpi_asus_get_devstate(sc, dev_id, &val); switch(dev_id) { @@ -501,7 +750,7 @@ acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id) val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK; break; case ASUS_WMI_DEVID_KBD_BACKLIGHT: - val &= 0x7; + val &= 0x3; break; default: if (val & ASUS_WMI_DSTS_UNKNOWN_BIT) @@ -522,10 +771,14 @@ acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, in switch(dev_id) { case ASUS_WMI_DEVID_KBD_BACKLIGHT: - arg = min(0x7, arg); + arg = min(0x3, arg); if (arg != 0) arg |= 0x80; break; + case ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY: + arg = min(0x2, arg); + sc->ttp_mode = arg; + break; } acpi_wpi_asus_set_devstate(sc, dev_id, arg, NULL); @@ -540,32 +793,65 @@ acpi_asus_wmi_free_buffer(ACPI_BUFFER* buf) { } } -static void -acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) +static int +acpi_asus_wmi_get_event_code(device_t wmi_dev, UINT32 notify, int *code) { - device_t dev = context; - ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); - UINT32 val; - int code = 0; - - struct acpi_asus_wmi_softc *sc = device_get_softc(dev); ACPI_BUFFER response = { ACPI_ALLOCATE_BUFFER, NULL }; ACPI_OBJECT *obj; - ACPI_WMI_GET_EVENT_DATA(sc->wmi_dev, notify, &response); + int error = 0; + + if (ACPI_FAILURE(ACPI_WMI_GET_EVENT_DATA(wmi_dev, notify, &response))) + return (EIO); obj = (ACPI_OBJECT*) response.Pointer; - if (obj && obj->Type == ACPI_TYPE_INTEGER) { - code = obj->Integer.Value; + if (obj && obj->Type == ACPI_TYPE_INTEGER) + *code = obj->Integer.Value & ASUS_WMI_EVENT_MASK; + else + error = EINVAL; + acpi_asus_wmi_free_buffer(&response); + return (error); +} + +#ifdef EVDEV_SUPPORT +static void +acpi_asus_wmi_push_evdev_event(struct evdev_dev *evdev, UINT32 notify) +{ + int i; + uint16_t key; + + for (i = 0; i < nitems(acpi_asus_wmi_evdev_map); i++) { + if (acpi_asus_wmi_evdev_map[i].notify == notify && + acpi_asus_wmi_evdev_map[i].key != NO_KEY) { + key = acpi_asus_wmi_evdev_map[i].key; + evdev_push_key(evdev, key, 1); + evdev_sync(evdev); + evdev_push_key(evdev, key, 0); + evdev_sync(evdev); + break; + } + } +} +#endif + +static void +acpi_asus_wmi_handle_event(struct acpi_asus_wmi_softc *sc, int code) +{ + UINT32 val; + + if (code != 0) { acpi_UserNotify("ASUS", ACPI_ROOT_OBJECT, code); +#ifdef EVDEV_SUPPORT + acpi_asus_wmi_push_evdev_event(sc->evdev, code); +#endif } if (code && sc->handle_keys) { /* Keyboard backlight control. */ if (code == 0xc4 || code == 0xc5) { acpi_wpi_asus_get_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT, &val); - val &= 0x7; + val &= 0x3; if (code == 0xc4) { - if (val < 0x7) + if (val < 0x3) val++; } else if (val > 0) val--; @@ -573,6 +859,7 @@ acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) val |= 0x80; acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL); + sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val); } /* Touchpad control. */ if (code == 0x6b) { @@ -582,15 +869,68 @@ acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_TOUCHPAD, val, NULL); } + /* Throttle thermal policy control. */ + if (code == 0xae) { + sc->ttp_mode++; + if (sc->ttp_mode > 2) + sc->ttp_mode = 0; + acpi_wpi_asus_set_devstate(sc, + ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY, + sc->ttp_mode, NULL); + } + /* TUF laptop RGB mode control. */ + if (code == 0xb3) { + const uint32_t cmd = 0xb4; /* Save to BIOS */ + const uint32_t r = 0xff, g = 0xff, b = 0xff; + const uint32_t speed = 0xeb; /* Medium */ + if (sc->tuf_rgb_mode < 2) + sc->tuf_rgb_mode++; + else if (sc->tuf_rgb_mode == 2) + sc->tuf_rgb_mode = 10; + else sc->tuf_rgb_mode = 0; + acpi_asus_wmi_evaluate_method(sc->wmi_dev, + ASUS_WMI_METHODID_DEVS, + ASUS_WMI_DEVID_TUF_RGB_MODE, + cmd | (sc->tuf_rgb_mode << 8) | (r << 16) | (g << 24), + b | (speed << 8), NULL); + } } - acpi_asus_wmi_free_buffer(&response); +} + +static void +acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context) +{ + device_t dev = context; + struct acpi_asus_wmi_softc *sc = device_get_softc(dev); + int code = 0, i = 1; + + ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); + + if (sc->event_queue) + i += ASUS_WMI_EVENT_QUEUE_SIZE; + do { + if (acpi_asus_wmi_get_event_code(sc->wmi_dev, notify, &code) + != 0) { + device_printf(dev, "Failed to get event code\n"); + return; + } + if (code == ASUS_WMI_EVENT_QUEUE_END || + code == ASUS_WMI_EVENT_MASK) + return; + acpi_asus_wmi_handle_event(sc, code); + if (notify != ASUS_WMI_EVENT_VALUE_ATK) + return; + } while (--i != 0); + if (sc->event_queue) + device_printf(dev, "Can not read event queue, " + "last code: 0x%x\n", code); } static int acpi_asus_wmi_evaluate_method(device_t wmi_dev, int method, - UINT32 arg0, UINT32 arg1, UINT32 *retval) + UINT32 arg0, UINT32 arg1, UINT32 arg2, UINT32 *retval) { - UINT32 params[2] = { arg0, arg1 }; + UINT32 params[3] = { arg0, arg1, arg2 }; UINT32 result; ACPI_OBJECT *obj; ACPI_BUFFER in = { sizeof(params), ¶ms }; @@ -618,7 +958,7 @@ acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc, { return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, - sc->dsts_id, dev_id, 0, retval)); + sc->dsts_id, dev_id, 0, 0, retval)); } static int @@ -627,5 +967,40 @@ acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc, { return (acpi_asus_wmi_evaluate_method(sc->wmi_dev, - ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval)); + ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, 0, retval)); +} + +static int +acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props + *props) +{ + struct acpi_asus_wmi_softc *sc = device_get_softc(dev); + + acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT, + kbd_bkl_level_to_devstate(props->brightness), NULL); + sc->kbd_bkl_level = props->brightness; + + return (0); +} + +static int +acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props) +{ + struct acpi_asus_wmi_softc *sc = device_get_softc(dev); + + props->brightness = sc->kbd_bkl_level; + props->nlevels = nitems(acpi_asus_wmi_backlight_levels); + memcpy(props->levels, acpi_asus_wmi_backlight_levels, + sizeof(acpi_asus_wmi_backlight_levels)); + + return (0); +} + +static int +acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info) +{ + info->type = BACKLIGHT_TYPE_KEYBOARD; + strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH); + + return (0); } diff --git a/sys/dev/acpi_support/acpi_fujitsu.c b/sys/dev/acpi_support/acpi_fujitsu.c index 2d3c6f17dfe2..1649f74d873c 100644 --- a/sys/dev/acpi_support/acpi_fujitsu.c +++ b/sys/dev/acpi_support/acpi_fujitsu.c @@ -222,14 +222,12 @@ static int acpi_fujitsu_probe(device_t dev) { char *name; - char buffer[64]; int rv; rv = ACPI_ID_PROBE(device_get_parent(dev), dev, fujitsu_ids, &name); if (acpi_disabled("fujitsu") || rv > 0 || device_get_unit(dev) > 1) return (ENXIO); - sprintf(buffer, "Fujitsu Function Hotkeys %s", name); - device_set_desc_copy(dev, buffer); + device_set_descf(dev, "Fujitsu Function Hotkeys %s", name); return (rv); } diff --git a/sys/dev/acpi_support/acpi_hp.c b/sys/dev/acpi_support/acpi_hp.c index 088e46af2ce3..5523b8768d41 100644 --- a/sys/dev/acpi_support/acpi_hp.c +++ b/sys/dev/acpi_support/acpi_hp.c @@ -465,7 +465,7 @@ acpi_hp_identify(driver_t *driver, device_t parent) return; /* Add only a single device instance. */ - if (device_find_child(parent, "acpi_hp", -1) != NULL) + if (device_find_child(parent, "acpi_hp", DEVICE_UNIT_ANY) != NULL) return; /* Check BIOS GUID to see whether system is compatible. */ @@ -473,7 +473,7 @@ acpi_hp_identify(driver_t *driver, device_t parent) ACPI_HP_WMI_BIOS_GUID)) return; - if (BUS_ADD_CHILD(parent, 0, "acpi_hp", -1) == NULL) + if (BUS_ADD_CHILD(parent, 0, "acpi_hp", DEVICE_UNIT_ANY) == NULL) device_printf(parent, "add acpi_hp child failed\n"); } diff --git a/sys/dev/acpi_support/acpi_ibm.c b/sys/dev/acpi_support/acpi_ibm.c index a617088d4246..c1302508b8a2 100644 --- a/sys/dev/acpi_support/acpi_ibm.c +++ b/sys/dev/acpi_support/acpi_ibm.c @@ -37,6 +37,7 @@ */ #include "opt_acpi.h" +#include "opt_evdev.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -55,6 +56,11 @@ #include <sys/sysctl.h> #include <isa/rtc.h> +#ifdef EVDEV_SUPPORT +#include <dev/evdev/input.h> +#include <dev/evdev/evdev.h> +#endif + #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("IBM") @@ -198,6 +204,9 @@ struct acpi_ibm_softc { struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; +#ifdef EVDEV_SUPPORT + struct evdev_dev *evdev; +#endif }; static struct { @@ -363,6 +372,9 @@ static driver_t acpi_ibm_driver = { DRIVER_MODULE(acpi_ibm, acpi, acpi_ibm_driver, 0, 0); MODULE_DEPEND(acpi_ibm, acpi, 1, 1, 1); +#ifdef EVDEV_SUPPORT +MODULE_DEPEND(acpi_ibm, evdev, 1, 1, 1); +#endif static char *ibm_ids[] = {"IBM0068", "LEN0068", "LEN0268", NULL}; static int @@ -482,6 +494,20 @@ acpi_ibm_attach(device_t dev) } sc->ec_handle = acpi_get_handle(sc->ec_dev); +#ifdef EVDEV_SUPPORT + sc->evdev = evdev_alloc(); + evdev_set_name(sc->evdev, device_get_desc(dev)); + evdev_set_phys(sc->evdev, device_get_nameunit(dev)); + evdev_set_id(sc->evdev, BUS_HOST, 0, 0, 1); + evdev_support_event(sc->evdev, EV_SYN); + evdev_support_event(sc->evdev, EV_KEY); + evdev_support_key(sc->evdev, KEY_BRIGHTNESSUP); + evdev_support_key(sc->evdev, KEY_BRIGHTNESSDOWN); + + if (evdev_register(sc->evdev) != 0) + return (ENXIO); +#endif + /* Get the sysctl tree */ sc->sysctl_ctx = device_get_sysctl_ctx(dev); sc->sysctl_tree = device_get_sysctl_tree(dev); @@ -627,6 +653,10 @@ acpi_ibm_detach(device_t dev) if (sc->led_dev != NULL) led_destroy(sc->led_dev); +#ifdef EVDEV_SUPPORT + evdev_free(sc->evdev); +#endif + return (0); } @@ -1499,6 +1529,19 @@ acpi_ibm_notify(ACPI_HANDLE h, UINT32 notify, void *context) /* Execute event handler */ if (sc->handler_events & (1 << (arg - 1))) acpi_ibm_eventhandler(sc, (arg & 0xff)); +#ifdef EVDEV_SUPPORT + else if ((arg & 0xff) == IBM_EVENT_BRIGHTNESS_UP || + (arg & 0xff) == IBM_EVENT_BRIGHTNESS_DOWN) { + uint16_t key; + + key = arg == IBM_EVENT_BRIGHTNESS_UP ? + KEY_BRIGHTNESSUP : KEY_BRIGHTNESSDOWN; + evdev_push_key(sc->evdev, key, 1); + evdev_sync(sc->evdev); + evdev_push_key(sc->evdev, key, 0); + evdev_sync(sc->evdev); + } +#endif /* Notify devd(8) */ acpi_UserNotify("IBM", h, (arg & 0xff)); diff --git a/sys/dev/acpi_support/acpi_sbl_wmi.c b/sys/dev/acpi_support/acpi_sbl_wmi.c new file mode 100644 index 000000000000..8abee8c94e26 --- /dev/null +++ b/sys/dev/acpi_support/acpi_sbl_wmi.c @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 2024 Rubicon Communications, LLC (Netgate) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include "opt_acpi.h" +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/uio.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/sbuf.h> +#include <sys/module.h> +#include <sys/sysctl.h> + +#include <contrib/dev/acpica/include/acpi.h> +#include <contrib/dev/acpica/include/accommon.h> +#include <dev/acpica/acpivar.h> +#include "acpi_wmi_if.h" + +#define _COMPONENT ACPI_OEM +ACPI_MODULE_NAME("SBL-FW-UPDATE-WMI") +ACPI_SERIAL_DECL(sbl_wmi, "SBL WMI device"); + +#define ACPI_SBL_FW_UPDATE_WMI_GUID "44FADEB1-B204-40F2-8581-394BBDC1B651" + +struct acpi_sbl_wmi_softc { + device_t dev; + device_t wmi_dev; +}; + +static void +acpi_sbl_wmi_identify(driver_t *driver, device_t parent) +{ + /* Don't do anything if driver is disabled. */ + if (acpi_disabled("sbl_wmi")) + return; + + /* Add only a single device instance. */ + if (device_find_child(parent, "acpi_sbl_wmi", DEVICE_UNIT_ANY) != NULL) + return; + + /* Check management GUID to see whether system is compatible. */ + if (!ACPI_WMI_PROVIDES_GUID_STRING(parent, + ACPI_SBL_FW_UPDATE_WMI_GUID)) + return; + + if (BUS_ADD_CHILD(parent, 0, "acpi_sbl_wmi", DEVICE_UNIT_ANY) == NULL) + device_printf(parent, "add acpi_sbl_wmi child failed\n"); +} + +static int +acpi_sbl_wmi_probe(device_t dev) +{ + if (!ACPI_WMI_PROVIDES_GUID_STRING(device_get_parent(dev), + ACPI_SBL_FW_UPDATE_WMI_GUID)) + return (EINVAL); + device_set_desc(dev, "SBL Firmware Update WMI device"); + return (0); +} + +static int +acpi_sbl_wmi_sysctl_get(struct acpi_sbl_wmi_softc *sc, int *val) +{ + ACPI_OBJECT *obj; + ACPI_BUFFER out = { ACPI_ALLOCATE_BUFFER, NULL }; + int error = 0; + + if (ACPI_FAILURE(ACPI_WMI_GET_BLOCK(sc->wmi_dev, + ACPI_SBL_FW_UPDATE_WMI_GUID, 0, &out))) { + error = EINVAL; + goto out; + } + + obj = out.Pointer; + if (obj->Type != ACPI_TYPE_INTEGER) { + error = EINVAL; + goto out; + } + + *val = obj->Integer.Value; + +out: + if (out.Pointer) + AcpiOsFree(out.Pointer); + + return (error); +} + +static int +acpi_sbl_wmi_sysctl_set(struct acpi_sbl_wmi_softc *sc, int in) +{ + ACPI_BUFFER input = { ACPI_ALLOCATE_BUFFER, NULL }; + uint32_t val; + + val = in; + input.Length = sizeof(val); + input.Pointer = &val; + + if (ACPI_FAILURE(ACPI_WMI_SET_BLOCK(sc->wmi_dev, + ACPI_SBL_FW_UPDATE_WMI_GUID, 0, &input))) + return (ENODEV); + + return (0); +} + +static int +acpi_sbl_wmi_fw_upgrade_sysctl(SYSCTL_HANDLER_ARGS) +{ + struct acpi_sbl_wmi_softc *sc; + int arg; + int error = 0; + + ACPI_SERIAL_BEGIN(sbl_wmi); + + sc = (struct acpi_sbl_wmi_softc *)oidp->oid_arg1; + error = acpi_sbl_wmi_sysctl_get(sc, &arg); + if (error != 0) + goto out; + + error = sysctl_handle_int(oidp, &arg, 0, req); + if (! error && req->newptr != NULL) + error = acpi_sbl_wmi_sysctl_set(sc, arg); + +out: + ACPI_SERIAL_END(sbl_wmi); + + return (error); +} + +static int +acpi_sbl_wmi_attach(device_t dev) +{ + struct acpi_sbl_wmi_softc *sc; + struct sysctl_ctx_list *sysctl_ctx; + struct sysctl_oid *sysctl_tree; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->wmi_dev = device_get_parent(dev); + + sysctl_ctx = device_get_sysctl_ctx(dev); + sysctl_tree = device_get_sysctl_tree(dev); + + SYSCTL_ADD_PROC(sysctl_ctx, + SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, + "firmware_update_request", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + sc, 0, acpi_sbl_wmi_fw_upgrade_sysctl, "I", + "Signal SBL that a firmware update is available"); + + return (0); +} + +static device_method_t acpi_sbl_wmi_methods[] = { + DEVMETHOD(device_identify, acpi_sbl_wmi_identify), + DEVMETHOD(device_probe, acpi_sbl_wmi_probe), + DEVMETHOD(device_attach, acpi_sbl_wmi_attach), + + DEVMETHOD_END +}; + +static driver_t acpi_sbl_wmi_driver = { + "acpi_sbl_wmi", + acpi_sbl_wmi_methods, + sizeof(struct acpi_sbl_wmi_softc), +}; + +DRIVER_MODULE(acpi_sbl_wmi, acpi_wmi, acpi_sbl_wmi_driver, 0, 0); +MODULE_DEPEND(acpi_sbl_wmi, acpi_wmi, 1, 1, 1); +MODULE_DEPEND(acpi_sbl_wmi, acpi, 1, 1, 1); diff --git a/sys/dev/acpi_support/acpi_wmi.c b/sys/dev/acpi_support/acpi_wmi.c index 6601db4317cb..e973b287dbb4 100644 --- a/sys/dev/acpi_support/acpi_wmi.c +++ b/sys/dev/acpi_support/acpi_wmi.c @@ -296,8 +296,8 @@ acpi_wmi_attach(device_t dev) } if (ret == 0) { - bus_generic_probe(dev); - ret = bus_generic_attach(dev); + bus_identify_children(dev); + bus_attach_children(dev); } return (ret); @@ -580,6 +580,16 @@ acpi_wmi_get_block_method(device_t dev, const char *guid_string, UINT8 instance, } wq_method[2] = winfo->ginfo.oid[0]; wq_method[3] = winfo->ginfo.oid[1]; + { + ACPI_HANDLE wq_handle; + ACPI_OBJECT_TYPE at; + + if (ACPI_SUCCESS(AcpiGetHandle(sc->wmi_handle, wq_method, &wq_handle)) && + ACPI_SUCCESS(AcpiGetType(wq_handle, &at)) && + at != ACPI_TYPE_METHOD) { + wq_input.Count = 0; + } + } status = AcpiEvaluateObject(sc->wmi_handle, wq_method, &wq_input, out); if ((winfo->ginfo.flags & ACPI_WMI_REGFLAG_EXPENSIVE) |