diff --git a/sys/dev/acpi_support/acpi_ibm.c b/sys/dev/acpi_support/acpi_ibm.c index c1302508b8a2..6c01d87caba7 100644 --- a/sys/dev/acpi_support/acpi_ibm.c +++ b/sys/dev/acpi_support/acpi_ibm.c @@ -1,8 +1,9 @@ /*- * Copyright (c) 2004 Takanori Watanabe * Copyright (c) 2005 Markus Brueffer - * All rights reserved. + * Copyright (c) 2018 Michael Gmelin * Copyright (c) 2020 Ali Abdallah + * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -81,6 +82,9 @@ ACPI_MODULE_NAME("IBM") #define ACPI_IBM_METHOD_HANDLEREVENTS 14 #define ACPI_IBM_METHOD_MIC_LED 15 #define ACPI_IBM_METHOD_PRIVACYGUARD 16 +#define ACPI_IBM_METHOD_KBD_BACKLIGHT 17 +#define ACPI_IBM_METHOD_KBD_BL_LEDON 18 +#define ACPI_IBM_METHOD_KBD_BL_LEDOFF 19 /* Hotkeys/Buttons */ #define IBM_RTC_HOTKEY1 0x64 @@ -138,6 +142,12 @@ ACPI_MODULE_NAME("IBM") #define IBM_NAME_EVENTS_MASK_SET "MHKM" #define IBM_NAME_EVENTS_GET "MHKP" #define IBM_NAME_EVENTS_AVAILMASK "MHKA" +#define IBM_NAME_EVENTS_VERSION "MHKV" + +#define IBM_NAME_KBD_BACKLIGHT_GET "MLCG" +#define IBM_NAME_MASK_KBD_BL_SUPPORT (1 << 9) +#define IBM_NAME_MASK_KBD_BL_LEVEL 0x3 +#define IBM_NAME_KBD_BACKLIGHT_SET "MLCS" /* Event Code */ #define IBM_EVENT_LCD_BACKLIGHT 0x03 @@ -188,6 +198,18 @@ struct acpi_ibm_softc { int led_busy; int led_state; + /* Keyboard backlight support */ + int kbd_backlight_supported; + int kbd_backlight_val; + + /* led(4) interface for keyboard backlight */ + struct cdev *kbd_backlight_led_dev; + int kbd_backlight_led_busy; + int kbd_backlight_led_state; + int kbd_backlight_ledon; + int kbd_backlight_ledoff; + + /* Mic led handle */ ACPI_HANDLE mic_led_handle; int mic_led_state; @@ -289,6 +311,21 @@ static struct { .method = ACPI_IBM_METHOD_PRIVACYGUARD, .description = "PrivacyGuard enable", }, + { + .name = "kbd_backlight", + .method = ACPI_IBM_METHOD_KBD_BACKLIGHT, + .description = "Keyboard backlight level", + }, + { + .name = "kbd_backlight_ledon", + .method = ACPI_IBM_METHOD_KBD_BL_LEDON, + .description = "Keyboard backlight LED on level", + }, + { + .name = "kbd_backlight_ledoff", + .method = ACPI_IBM_METHOD_KBD_BL_LEDOFF, + .description = "Keyboard backlight LED off level", + }, { NULL, 0, NULL, 0 } }; @@ -333,6 +370,10 @@ static int acpi_ibm_resume(device_t dev); static void ibm_led(void *softc, int onoff); static void ibm_led_task(struct acpi_ibm_softc *sc, int pending __unused); +static void ibm_kbd_backlight_led(void *softc, int onoff); +static void ibm_kbd_backlight_led_task(struct acpi_ibm_softc *sc, + int pending __unused); + static int acpi_ibm_sysctl(SYSCTL_HANDLER_ARGS); static int acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method); static int acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method); @@ -349,6 +390,9 @@ static int acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_volume_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_mute_set(struct acpi_ibm_softc *sc, int arg); static int acpi_ibm_privacyguard_get(struct acpi_ibm_softc *sc); + +static int acpi_ibm_kbd_backlight_set(struct acpi_ibm_softc *sc, int arg); + static ACPI_STATUS acpi_ibm_privacyguard_set(struct acpi_ibm_softc *sc, int arg); static ACPI_STATUS acpi_ibm_privacyguard_acpi_call(struct acpi_ibm_softc *sc, bool write, int *arg); @@ -418,6 +462,38 @@ ibm_led_task(struct acpi_ibm_softc *sc, int pending __unused) sc->led_busy = 0; } +static void +ibm_kbd_backlight_led(void *softc, int onoff) +{ + struct acpi_ibm_softc* sc = (struct acpi_ibm_softc*) softc; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + if (sc->kbd_backlight_led_busy) + return; + + sc->kbd_backlight_led_busy = 1; + sc->kbd_backlight_led_state = onoff; + + AcpiOsExecute(OSL_NOTIFY_HANDLER, (void *)ibm_kbd_backlight_led_task, + sc); +} + +static void +ibm_kbd_backlight_led_task(struct acpi_ibm_softc *sc, int pending __unused) +{ + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + ACPI_SERIAL_BEGIN(ibm); + acpi_ibm_sysctl_set(sc, ACPI_IBM_METHOD_KBD_BACKLIGHT, + sc->kbd_backlight_led_state ? + sc->kbd_backlight_ledon : sc->kbd_backlight_ledoff); + ACPI_SERIAL_END(ibm); + + sc->kbd_backlight_led_busy = 0; +} + + static int acpi_ibm_mic_led_set(struct acpi_ibm_softc *sc, int arg) { @@ -607,6 +683,13 @@ acpi_ibm_attach(device_t dev) sc->led_dev = led_create_state(ibm_led, sc, "thinklight", (sc->light_val ? 1 : 0)); + /* Hook up keyboard backlight to led(4) */ + if (sc->kbd_backlight_supported) + sc->kbd_backlight_led_dev = led_create_state( + ibm_kbd_backlight_led, sc, "kbd_backlight", + (sc->kbd_backlight_val ? 1 : 0)); + + /* Enable per-model events. */ maker = kern_getenv("smbios.system.maker"); product = kern_getenv("smbios.system.product"); @@ -653,6 +736,9 @@ acpi_ibm_detach(device_t dev) if (sc->led_dev != NULL) led_destroy(sc->led_dev); + if (sc->kbd_backlight_led_dev != NULL) + led_destroy(sc->kbd_backlight_led_dev); + #ifdef EVDEV_SUPPORT evdev_free(sc->evdev); #endif @@ -878,6 +964,21 @@ acpi_ibm_sysctl_get(struct acpi_ibm_softc *sc, int method) else val = -1; break; + case ACPI_IBM_METHOD_KBD_BACKLIGHT: + if (sc->kbd_backlight_supported) + acpi_GetInteger(sc->handle, IBM_NAME_KBD_BACKLIGHT_GET, &val); + else + val = sc->kbd_backlight_val; + val &= IBM_NAME_MASK_KBD_BL_LEVEL; + break; + + case ACPI_IBM_METHOD_KBD_BL_LEDON: + val = sc->kbd_backlight_ledon; + break; + + case ACPI_IBM_METHOD_KBD_BL_LEDOFF: + val = sc->kbd_backlight_ledoff; + break; case ACPI_IBM_METHOD_PRIVACYGUARD: val = acpi_ibm_privacyguard_get(sc); @@ -975,6 +1076,25 @@ acpi_ibm_sysctl_set(struct acpi_ibm_softc *sc, int method, int arg) (arg == 1) ? (val_ec | IBM_EC_MASK_FANSTATUS) : (val_ec & (~IBM_EC_MASK_FANSTATUS)), 1); } break; + + case ACPI_IBM_METHOD_KBD_BACKLIGHT: + return acpi_ibm_kbd_backlight_set(sc, arg); + break; + + case ACPI_IBM_METHOD_KBD_BL_LEDON: + if (arg < 0 || arg > 2) + return (EINVAL); + + sc->kbd_backlight_ledon = arg; + break; + + case ACPI_IBM_METHOD_KBD_BL_LEDOFF: + if (arg < 0 || arg > 2) + return (EINVAL); + + sc->kbd_backlight_ledoff = arg; + break; + } return (0); @@ -1080,6 +1200,29 @@ acpi_ibm_sysctl_init(struct acpi_ibm_softc *sc, int method) case ACPI_IBM_METHOD_HANDLEREVENTS: return (TRUE); + case ACPI_IBM_METHOD_KBD_BACKLIGHT: + if (ACPI_FAILURE(acpi_GetInteger(sc->handle, IBM_NAME_KBD_BACKLIGHT_GET, + &sc->kbd_backlight_val))) + sc->kbd_backlight_val = 0; + sc->kbd_backlight_supported = sc->kbd_backlight_val & + IBM_NAME_MASK_KBD_BL_SUPPORT; + sc->kbd_backlight_val &= IBM_NAME_MASK_KBD_BL_LEVEL; + if (sc->kbd_backlight_supported) + return (TRUE); + return (FALSE); + + case ACPI_IBM_METHOD_KBD_BL_LEDON: + sc->kbd_backlight_ledon = 1; + if (sc->kbd_backlight_supported) + return (TRUE); + return (FALSE); + + case ACPI_IBM_METHOD_KBD_BL_LEDOFF: + sc->kbd_backlight_ledoff = 0; + if (sc->kbd_backlight_supported) + return (TRUE); + return (FALSE); + case ACPI_IBM_METHOD_PRIVACYGUARD: return (acpi_ibm_privacyguard_get(sc) != -1); } @@ -1299,6 +1442,27 @@ acpi_ibm_thinklight_set(struct acpi_ibm_softc *sc, int arg) return (0); } +static int +acpi_ibm_kbd_backlight_set(struct acpi_ibm_softc *sc, int arg) +{ + ACPI_STATUS status; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + ACPI_SERIAL_ASSERT(ibm); + + if (arg < 0 || arg > 2) + return (EINVAL); + + if (sc->kbd_backlight_supported) { + status = acpi_SetInteger(sc->handle, IBM_NAME_KBD_BACKLIGHT_SET, arg); + if (ACPI_SUCCESS(status)) + sc->kbd_backlight_val = arg; + return (status); + } + + return (0); +} + /* * Helper function to make a get or set ACPI call to the PrivacyGuard handle. * Only meant to be used internally by the get/set functions below.