aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/acpi_support
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/acpi_support')
-rw-r--r--sys/dev/acpi_support/acpi_asus.c22
-rw-r--r--sys/dev/acpi_support/acpi_asus_wmi.c431
-rw-r--r--sys/dev/acpi_support/acpi_fujitsu.c4
-rw-r--r--sys/dev/acpi_support/acpi_hp.c4
-rw-r--r--sys/dev/acpi_support/acpi_ibm.c43
-rw-r--r--sys/dev/acpi_support/acpi_sbl_wmi.c193
-rw-r--r--sys/dev/acpi_support/acpi_wmi.c14
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), &params };
@@ -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)