Index: share/man/man4/acpi_asus.4 =================================================================== --- share/man/man4/acpi_asus.4 +++ share/man/man4/acpi_asus.4 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 8, 2010 +.Dd August 4, 2020 .Dt ACPI_ASUS 4 .Os .Sh NAME @@ -49,7 +49,7 @@ The .Nm driver provides support for the extra ACPI-controlled gadgets, such as hotkeys -and leds, found on recent Asus (and Medion) laptops. +and leds, found on older Asus (and Medion) laptops. It allows one to use the .Xr sysctl 8 interface to manipulate the brightness of the LCD panel and the display output @@ -128,6 +128,8 @@ .Sh SYSCTL VARIABLES The following sysctls are currently implemented: .Bl -tag -width indent +.It Va hw.acpi.asus.kbd_backlight +Controls the keyboard backlight brightness (-1 for off). .It Va hw.acpi.asus.lcd_brightness Makes the LCD backlight brighter or dimmer (higher values are brighter). .It Va hw.acpi.asus.lcd_backlight Index: sys/dev/acpi_support/acpi_asus.c =================================================================== --- sys/dev/acpi_support/acpi_asus.c +++ sys/dev/acpi_support/acpi_asus.c @@ -60,6 +60,10 @@ #define ACPI_ASUS_METHOD_CAMERA 4 #define ACPI_ASUS_METHOD_CARDRD 5 #define ACPI_ASUS_METHOD_WLAN 6 +#define ACPI_ASUS_METHOD_KBRN 7 + +#define KB_BACKLIGHT_LEVEL(lvl) \ + ((lvl) == -1 ? 0 : (0x80 | (lvl))) #define _COMPONENT ACPI_OEM ACPI_MODULE_NAME("ASUS") @@ -79,6 +83,10 @@ char *brn_up; char *brn_dn; + char *kbrn_get; + char *kbrn_set; + char *kbrn_levels; + char *lcd_get; char *lcd_set; @@ -132,6 +140,7 @@ struct acpi_asus_led s_wled; int s_brn; + int s_kbrn; int s_disp; int s_lcd; int s_cam; @@ -147,6 +156,23 @@ * as a result of calling the ATK0100 'INIT' method. */ static struct acpi_asus_model acpi_asus_models[] = { + { /* + * G73Jh returns an empty string from 'INIT' and has these + * methods in the DSDT. + */ + .name = "", + .bled_set = "BLED", + .wled_set = "WLED", + .brn_get = "GPLV", + .brn_set = "SPLV", + .kbrn_get = "GLKB", + .kbrn_set = "SLKB", + .kbrn_levels = "PWKB", + .lcd_get = "GBTL", + .lcd_set = "SBTL", + .disp_get = "\\ADVG", + .disp_set = "SDSP" + }, { .name = "xxN", .mled_set = "MLED", @@ -421,6 +447,8 @@ { .name = NULL } }; +static int acpi_asus_kbrn_max(struct acpi_asus_softc *sc); + /* * Samsung P30/P35 laptops have an Asus ATK0100 gadget interface, * but they can't be probed quite the same way as Asus laptops. @@ -479,6 +507,12 @@ .description = "brightness of the lcd panel", .flag_anybody = 1 }, + { + .name = "kbd_backlight", + .method = ACPI_ASUS_METHOD_KBRN, + .description = "brightness of the keyboard backlight", + .flag_anybody = 1 + }, { .name = "video_output", .method = ACPI_ASUS_METHOD_DISP, @@ -881,6 +915,34 @@ return (0); } +static int +acpi_asus_kbrn_max(struct acpi_asus_softc *sc) +{ + ACPI_BUFFER buf; + + ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); + + if (sc->model->kbrn_levels == NULL) + return (-1); + + /* + * kbrn_levels is a lookup table of brightness levels for the + * keyboard backlight. We only need its length. + */ + buf.Pointer = NULL; + buf.Length = 0; + if (AcpiEvaluateObject(sc->handle, sc->model->kbrn_levels, NULL, &buf) + == AE_BUFFER_OVERFLOW) + return (buf.Length); + + /* + * If that didn't work we might have the wrong path to the table. + * The SLKB method commonly takes values up to 127, we'll just get + * an error message on the console if we go past the end of the table. + */ + return (0x7F); +} + static void acpi_asus_led_task(struct acpi_asus_led *led, int pending __unused) { @@ -985,6 +1047,9 @@ case ACPI_ASUS_METHOD_BRN: val = sc->s_brn; break; + case ACPI_ASUS_METHOD_KBRN: + val = sc->s_kbrn; + break; case ACPI_ASUS_METHOD_DISP: val = sc->s_disp; break; @@ -1040,6 +1105,19 @@ if (ACPI_SUCCESS(status)) sc->s_brn = arg; + break; + case ACPI_ASUS_METHOD_KBRN: + /* -1 is off, otherwise an index in the brightness table */ + if (arg < -1 || arg > acpi_asus_kbrn_max(sc)) + return (EINVAL); + + if (sc->model->kbrn_set) + status = acpi_SetInteger(sc->handle, + sc->model->kbrn_set, KB_BACKLIGHT_LEVEL(arg)); + + if (ACPI_SUCCESS(status)) + sc->s_kbrn = arg; + break; case ACPI_ASUS_METHOD_DISP: if (arg < 0 || arg > 7) @@ -1130,6 +1208,14 @@ return (TRUE); } return (FALSE); + case ACPI_ASUS_METHOD_KBRN: + if (sc->model->kbrn_get) { + status = acpi_GetInteger(sc->handle, + sc->model->kbrn_get, &sc->s_kbrn); + if (ACPI_SUCCESS(status)) + return (TRUE); + } + return (FALSE); case ACPI_ASUS_METHOD_DISP: if (sc->model->disp_get) { status = acpi_GetInteger(sc->handle, @@ -1230,6 +1316,14 @@ } else if (notify == 0x87) { acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_BRN, sc->s_brn+1); ACPI_VPRINT(sc->dev, acpi_sc, "Brightness increased\n"); + } else if (notify == 0xC4) { + acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_KBRN, sc->s_kbrn+1); + ACPI_VPRINT(sc->dev, acpi_sc, + "Keyboard backlight brightness increased\n"); + } else if (notify == 0xC5) { + acpi_asus_sysctl_set(sc, ACPI_ASUS_METHOD_KBRN, sc->s_kbrn-1); + ACPI_VPRINT(sc->dev, acpi_sc, + "Keyboard backlight brightness decreased\n"); } else { /* Notify devd(8) */ acpi_UserNotify("ASUS", h, notify);