^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * lg-laptop.c - LG Gram ACPI features and hotkeys Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2018 Matan Ziv-Av <matan@svgalib.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/input/sparse-keymap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define LED_DEVICE(_name, max) struct led_classdev _name = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) .name = __stringify(_name), \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) .max_brightness = max, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) .brightness_set = _name##_set, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) .brightness_get = _name##_get, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODULE_AUTHOR("Matan Ziv-Av");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) MODULE_DESCRIPTION("LG WMI Hotkey Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define WMI_EVENT_GUID WMI_EVENT_GUID0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define WMAB_METHOD "\\XINI.WMAB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define WMBB_METHOD "\\XINI.WMBB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define SB_GGOV_METHOD "\\_SB.GGOV"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define GOV_TLED 0x2020008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define WM_GET 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define WM_SET 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define WM_KEY_LIGHT 0x400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define WM_TLED 0x404
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define WM_FN_LOCK 0x407
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define WM_BATT_LIMIT 0x61
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define WM_READER_MODE 0xBF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define WM_FAN_MODE 0x33
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define WMBB_USB_CHARGE 0x10B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define WMBB_BATT_LIMIT 0x10C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define PLATFORM_NAME "lg-laptop"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) MODULE_ALIAS("wmi:" WMI_EVENT_GUID0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) MODULE_ALIAS("wmi:" WMI_EVENT_GUID1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) MODULE_ALIAS("acpi*:LGEX0815:*");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static struct platform_device *pf_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static struct input_dev *wmi_input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static u32 inited;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define INIT_INPUT_WMI_0 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define INIT_INPUT_WMI_2 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define INIT_INPUT_ACPI 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define INIT_SPARSE_KEYMAP 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static const struct key_entry wmi_keymap[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) {KE_KEY, 0x74, {KEY_F13} }, /* Touchpad toggle (F5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * this key both sends an event and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * changes backlight level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) {KE_KEY, 0x80, {KEY_RFKILL} },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {KE_END, 0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int ggov(u32 arg0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) union acpi_object args[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct acpi_object_list arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) args[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) args[0].integer.value = arg0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) pr_err("Cannot get handle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) arg.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) arg.pointer = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) acpi_handle_err(handle, "GGOV: call failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) r = buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (r->type != ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) res = r->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static union acpi_object *lg_wmab(u32 method, u32 arg1, u32 arg2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) union acpi_object args[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct acpi_object_list arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) args[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) args[0].integer.value = method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) args[1].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) args[1].integer.value = arg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) args[2].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) args[2].integer.value = arg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) status = acpi_get_handle(NULL, (acpi_string) WMAB_METHOD, &handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) pr_err("Cannot get handle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) arg.count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) arg.pointer = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) acpi_handle_err(handle, "WMAB: call failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static union acpi_object *lg_wmbb(u32 method_id, u32 arg1, u32 arg2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) union acpi_object args[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct acpi_object_list arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) u8 buf[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) *(u32 *)buf = method_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) *(u32 *)(buf + 4) = arg1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) *(u32 *)(buf + 16) = arg2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) args[0].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) args[0].integer.value = 0; /* ignored */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) args[1].type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) args[2].type = ACPI_TYPE_BUFFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) args[2].buffer.length = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) args[2].buffer.pointer = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) status = acpi_get_handle(NULL, (acpi_string)WMBB_METHOD, &handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) pr_err("Cannot get handle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) arg.count = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) arg.pointer = args;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) acpi_handle_err(handle, "WMAB: call failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return (union acpi_object *)buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static void wmi_notify(u32 value, void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) long data = (long)context;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) pr_debug("event guid %li\n", data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) status = wmi_get_event_data(value, &response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) pr_err("Bad event status 0x%x\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) obj = (union acpi_object *)response.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (obj->type == ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) int eventcode = obj->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct key_entry *key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) key =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) sparse_keymap_entry_from_scancode(wmi_input_dev, eventcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (key && key->type == KE_KEY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) sparse_keymap_report_entry(wmi_input_dev, key, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) obj->integer.value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) kfree(response.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void wmi_input_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) wmi_input_dev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (wmi_input_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) wmi_input_dev->name = "LG WMI hotkeys";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) wmi_input_dev->phys = "wmi/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) wmi_input_dev->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) input_register_device(wmi_input_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) pr_info("Cannot initialize input device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) input_free_device(wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) inited |= INIT_SPARSE_KEYMAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) (void *)0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ACPI_SUCCESS(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) inited |= INIT_INPUT_WMI_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) (void *)2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (ACPI_SUCCESS(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) inited |= INIT_INPUT_WMI_2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pr_info("Cannot allocate input device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) static void acpi_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct key_entry *key;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) acpi_handle_debug(device->handle, "notify: %d\n", event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) if (inited & INIT_SPARSE_KEYMAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) key = sparse_keymap_entry_from_scancode(wmi_input_dev, 0x80);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (key && key->type == KE_KEY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) sparse_keymap_report_entry(wmi_input_dev, key, 1, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static ssize_t fan_mode_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) const char *buffer, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) bool value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) u32 m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) ret = kstrtobool(buffer, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (r->type != ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) m = r->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xffffff0f) | (value << 4));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xfffffff0) | value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static ssize_t fan_mode_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) struct device_attribute *attr, char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (r->type != ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) status = r->integer.value & 0x01;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) return snprintf(buffer, PAGE_SIZE, "%d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) static ssize_t usb_charge_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) const char *buffer, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) bool value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) ret = kstrtobool(buffer, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) r = lg_wmbb(WMBB_USB_CHARGE, WM_SET, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) static ssize_t usb_charge_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) struct device_attribute *attr, char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) r = lg_wmbb(WMBB_USB_CHARGE, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (r->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) status = !!r->buffer.pointer[0x10];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return snprintf(buffer, PAGE_SIZE, "%d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static ssize_t reader_mode_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) const char *buffer, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) bool value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) ret = kstrtobool(buffer, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) r = lg_wmab(WM_READER_MODE, WM_SET, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) static ssize_t reader_mode_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct device_attribute *attr, char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) r = lg_wmab(WM_READER_MODE, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (r->type != ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) status = !!r->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return snprintf(buffer, PAGE_SIZE, "%d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) static ssize_t fn_lock_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) const char *buffer, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) bool value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) ret = kstrtobool(buffer, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) r = lg_wmab(WM_FN_LOCK, WM_SET, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static ssize_t fn_lock_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct device_attribute *attr, char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) r = lg_wmab(WM_FN_LOCK, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (r->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) status = !!r->buffer.pointer[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return snprintf(buffer, PAGE_SIZE, "%d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) static ssize_t battery_care_limit_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) const char *buffer, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) unsigned long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) ret = kstrtoul(buffer, 10, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (value == 100 || value == 80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) r = lg_wmab(WM_BATT_LIMIT, WM_SET, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) static ssize_t battery_care_limit_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) char *buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (r->type != ACPI_TYPE_INTEGER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) status = r->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (status != 80 && status != 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) return snprintf(buffer, PAGE_SIZE, "%d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) static DEVICE_ATTR_RW(fan_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) static DEVICE_ATTR_RW(usb_charge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static DEVICE_ATTR_RW(reader_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static DEVICE_ATTR_RW(fn_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) static DEVICE_ATTR_RW(battery_care_limit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static struct attribute *dev_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) &dev_attr_fan_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) &dev_attr_usb_charge.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) &dev_attr_reader_mode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) &dev_attr_fn_lock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) &dev_attr_battery_care_limit.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) static const struct attribute_group dev_attribute_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) .attrs = dev_attributes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static void tpad_led_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) r = lg_wmab(WM_TLED, WM_SET, brightness > LED_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) static enum led_brightness tpad_led_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static LED_DEVICE(tpad_led, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) static void kbd_backlight_set(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) val = 0x22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (brightness <= LED_OFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (brightness >= LED_FULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) val = 0x24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) r = lg_wmab(WM_KEY_LIGHT, WM_SET, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) union acpi_object *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) r = lg_wmab(WM_KEY_LIGHT, WM_GET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (!r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) switch (r->buffer.pointer[0] & 0x27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) case 0x24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) val = LED_FULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) case 0x22:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) val = LED_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) val = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) kfree(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static LED_DEVICE(kbd_backlight, 255);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static void wmi_input_destroy(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (inited & INIT_INPUT_WMI_2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) wmi_remove_notify_handler(WMI_EVENT_GUID2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) if (inited & INIT_INPUT_WMI_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) wmi_remove_notify_handler(WMI_EVENT_GUID0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (inited & INIT_SPARSE_KEYMAP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) input_unregister_device(wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static struct platform_driver pf_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) .name = PLATFORM_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static int acpi_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (pf_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) ret = platform_driver_register(&pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) pf_device = platform_device_register_simple(PLATFORM_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) PLATFORM_DEVID_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) if (IS_ERR(pf_device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) ret = PTR_ERR(pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) pf_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) pr_err("unable to register platform device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) goto out_platform_registered;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) goto out_platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) /* LEDs are optional */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) led_classdev_register(&pf_device->dev, &kbd_backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) led_classdev_register(&pf_device->dev, &tpad_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) wmi_input_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) out_platform_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) platform_device_unregister(pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) out_platform_registered:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) platform_driver_unregister(&pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) static int acpi_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) led_classdev_unregister(&tpad_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) led_classdev_unregister(&kbd_backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) wmi_input_destroy();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) platform_device_unregister(pf_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) pf_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) platform_driver_unregister(&pf_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) static const struct acpi_device_id device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) {"LGEX0815", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) {"", 0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) MODULE_DEVICE_TABLE(acpi, device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static struct acpi_driver acpi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) .name = "LG Gram Laptop Support",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) .class = "lg-laptop",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) .ids = device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) .add = acpi_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) .remove = acpi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) .notify = acpi_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int __init acpi_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) result = acpi_bus_register_driver(&acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (result < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering driver\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) static void __exit acpi_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) acpi_bus_unregister_driver(&acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) module_init(acpi_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) module_exit(acpi_exit);