^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * asus-laptop.c - Asus Laptop Support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2006-2007 Corentin Chary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright (C) 2011 Wind River Systems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * The development page for this driver is located at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * http://sourceforge.net/projects/acpi4asus/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Credits:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Pontus Fuchs - Helper functions, cleanup
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Johann Wiesner - Small compile fixes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Eric Burghard - LED display support for W1N
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Josh Green - Light Sens support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * Thomas Tuttle - His first patch for led support was very helpful
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Sam Lin - GPS support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <linux/input/sparse-keymap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <linux/rfkill.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <acpi/video.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define ASUS_LAPTOP_VERSION "0.42"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define ASUS_LAPTOP_NAME "Asus Laptop Support"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define ASUS_LAPTOP_CLASS "hotkey"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define ASUS_LAPTOP_FILE KBUILD_MODNAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) MODULE_DESCRIPTION(ASUS_LAPTOP_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * WAPF defines the behavior of the Fn+Fx wlan key
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * The significance of values is yet to be found, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * most of the time:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * Bit | Bluetooth | WLAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * 0 | Hardware | Hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * 1 | Hardware | Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * 4 | Software | Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static uint wapf = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) module_param(wapf, uint, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) MODULE_PARM_DESC(wapf, "WAPF value");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) static char *wled_type = "unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static char *bled_type = "unknown";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) module_param(wled_type, charp, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) MODULE_PARM_DESC(wled_type, "Set the wled type on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "(unknown, led or rfkill). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) "default is unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) module_param(bled_type, charp, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) "(unknown, led or rfkill). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) "default is unknown");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static int wlan_status = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int bluetooth_status = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static int wimax_status = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int wwan_status = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int als_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) module_param(wlan_status, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) "(0 = disabled, 1 = enabled, -1 = don't do anything). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) "default is -1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) module_param(bluetooth_status, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) "(0 = disabled, 1 = enabled, -1 = don't do anything). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) "default is -1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) module_param(wimax_status, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) "(0 = disabled, 1 = enabled, -1 = don't do anything). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) "default is -1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) module_param(wwan_status, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) "(0 = disabled, 1 = enabled, -1 = don't do anything). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) "default is -1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) module_param(als_status, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) "(0 = disabled, 1 = enabled). "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) "default is 0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Some events we use, same for all Asus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define ATKD_BRNUP_MIN 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) #define ATKD_BRNUP_MAX 0x1f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define ATKD_BRNDOWN_MIN 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define ATKD_BRNDOWN_MAX 0x2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) #define ATKD_BRNDOWN 0x20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define ATKD_BRNUP 0x2f
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define ATKD_LCD_ON 0x33
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define ATKD_LCD_OFF 0x34
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * Known bits returned by \_SB.ATKD.HWRS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define WL_HWRS 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #define BT_HWRS 0x100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * Flags for hotk status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * WL_ON and BT_ON are also used for wireless_status()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define WL_RSTS 0x01 /* internal Wifi */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define BT_RSTS 0x02 /* internal Bluetooth */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define WM_RSTS 0x08 /* internal wimax */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) #define WW_RSTS 0x20 /* internal wwan */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) /* WLED and BLED type */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define TYPE_UNKNOWN 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #define TYPE_LED 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define TYPE_RFKILL 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) /* LED */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define METHOD_MLED "MLED"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #define METHOD_TLED "TLED"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define METHOD_RLED "RLED" /* W1JC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define METHOD_PLED "PLED" /* A7J */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define METHOD_GLED "GLED" /* G1, G2 (probably) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* LEDD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #define METHOD_LEDD "SLCM"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) * Bluetooth and WLAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * WLED and BLED are not handled like other XLED, because in some dsdt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * they also control the WLAN/Bluetooth device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define METHOD_WLAN "WLED"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define METHOD_BLUETOOTH "BLED"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /* WWAN and WIMAX */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) #define METHOD_WWAN "GSMC"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define METHOD_WIMAX "WMXC"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) #define METHOD_WL_STATUS "RSTS"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) /* Brightness */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #define METHOD_BRIGHTNESS_SET "SPLV"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) #define METHOD_BRIGHTNESS_GET "GPLV"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* Display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) #define METHOD_SWITCH_DISPLAY "SDSP"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* GPS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) /* R2H use different handle for GPS on/off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) #define METHOD_GPS_ON "SDON"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) #define METHOD_GPS_OFF "SDOF"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) #define METHOD_GPS_STATUS "GPST"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* Keyboard light */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) #define METHOD_KBD_LIGHT_SET "SLKB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) #define METHOD_KBD_LIGHT_GET "GLKB"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* For Pegatron Lucid tablet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) #define DEVICE_NAME_PEGA "Lucid"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) #define METHOD_PEGA_ENABLE "ENPR"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) #define METHOD_PEGA_DISABLE "DAPR"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #define PEGA_WLAN 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) #define PEGA_BLUETOOTH 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) #define PEGA_WWAN 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) #define PEGA_ALS 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) #define PEGA_ALS_POWER 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) #define METHOD_PEGA_READ "RDLN"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) #define PEGA_READ_ALS_H 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) #define PEGA_READ_ALS_L 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) #define PEGA_ACCEL_NAME "pega_accel"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) #define PEGA_ACCEL_DESC "Pegatron Lucid Tablet Accelerometer"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) #define METHOD_XLRX "XLRX"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) #define METHOD_XLRY "XLRY"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) #define METHOD_XLRZ "XLRZ"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) #define PEGA_ACC_CLAMP 512 /* 1G accel is reported as ~256, so clamp to 2G */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) #define PEGA_ACC_RETRIES 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) * Define a specific led structure to keep the main structure clean
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) struct asus_led {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int wk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct work_struct work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct led_classdev led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct asus_laptop *asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) const char *method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) };
^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) * Same thing for rfkill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) struct asus_rfkill {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* type of control. Maps to PEGA_* values or *_RSTS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) int control_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct rfkill *rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct asus_laptop *asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * This is the main structure, we can use it to store anything interesting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * about the hotk device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct asus_laptop {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) char *name; /* laptop name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct acpi_table_header *dsdt_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) struct platform_device *platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct acpi_device *device; /* the device we are in */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct backlight_device *backlight_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct input_dev *inputdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct key_entry *keymap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct input_dev *pega_accel_poll;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct asus_led wled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct asus_led bled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct asus_led mled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct asus_led tled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct asus_led rled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) struct asus_led pled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) struct asus_led gled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct asus_led kled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) struct workqueue_struct *led_workqueue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) int wled_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) int bled_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) int wireless_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) bool have_rsts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) bool is_pega_lucid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) bool pega_acc_live;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) int pega_acc_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) int pega_acc_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int pega_acc_z;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct asus_rfkill wlan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct asus_rfkill bluetooth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct asus_rfkill wwan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) struct asus_rfkill wimax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct asus_rfkill gps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) acpi_handle handle; /* the handle of the hotk device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) u32 ledd_status; /* status of the LED display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) u8 light_level; /* light sensor level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) u8 light_switch; /* light sensor switch value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) u16 event_count[128]; /* count for each event TODO make this better */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static const struct key_entry asus_keymap[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /* Lenovo SL Specific keycodes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {KE_KEY, 0x02, { KEY_SCREENLOCK } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {KE_KEY, 0x05, { KEY_WLAN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {KE_KEY, 0x08, { KEY_F13 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) {KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {KE_KEY, 0x17, { KEY_ZOOM } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) {KE_KEY, 0x1f, { KEY_BATTERY } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* End of Lenovo SL Specific keycodes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {KE_KEY, ATKD_BRNDOWN, { KEY_BRIGHTNESSDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) {KE_KEY, ATKD_BRNUP, { KEY_BRIGHTNESSUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {KE_KEY, 0x30, { KEY_VOLUMEUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {KE_KEY, 0x32, { KEY_MUTE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) {KE_KEY, 0x41, { KEY_NEXTSONG } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) {KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {KE_KEY, 0x45, { KEY_PLAYPAUSE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {KE_KEY, 0x50, { KEY_EMAIL } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) {KE_KEY, 0x51, { KEY_WWW } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {KE_KEY, 0x55, { KEY_CALC } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {KE_IGNORE, 0x57, }, /* Battery mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {KE_IGNORE, 0x58, }, /* AC mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) {KE_KEY, 0x5C, { KEY_SCREENLOCK } }, /* Screenlock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {KE_KEY, 0x5D, { KEY_WLAN } }, /* WLAN Toggle */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {KE_KEY, 0x5E, { KEY_WLAN } }, /* WLAN Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {KE_KEY, 0x5F, { KEY_WLAN } }, /* WLAN Disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) {KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) {KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) {KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {KE_KEY, 0x6A, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad Fn + F9 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) {KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {KE_IGNORE, 0x6E, }, /* Low Battery notification */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) {KE_KEY, 0x82, { KEY_CAMERA } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) {KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) {KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) {KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) {KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {KE_KEY, 0x95, { KEY_MEDIA } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) {KE_KEY, 0x99, { KEY_PHONE } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) {KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) {KE_KEY, 0xB5, { KEY_CALC } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) {KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {KE_END, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) * This function evaluates an ACPI method, given an int as parameter, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) * method is searched within the scope of the handle, can be NULL. The output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) * of the method is written is output, which can also be NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * returns 0 if write is successful, -1 else.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) static int write_acpi_int_ret(acpi_handle handle, const char *method, int val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) struct acpi_buffer *output)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) struct acpi_object_list params; /* list of input parameters (an int) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) union acpi_object in_obj; /* the only param we use */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (!handle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) params.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) params.pointer = &in_obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) in_obj.type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) in_obj.integer.value = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) status = acpi_evaluate_object(handle, (char *)method, ¶ms, output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (status == AE_OK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int write_acpi_int(acpi_handle handle, const char *method, int val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return write_acpi_int_ret(handle, method, val, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static int acpi_check_handle(acpi_handle handle, const char *method,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) acpi_handle *ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (method == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) status = acpi_get_handle(handle, (char *)method,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) acpi_handle dummy;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) status = acpi_get_handle(handle, (char *)method,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) &dummy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) if (status != AE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) pr_warn("Error finding %s\n", method);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static bool asus_check_pega_lucid(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) return !strcmp(asus->name, DEVICE_NAME_PEGA) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) !acpi_check_handle(asus->handle, METHOD_PEGA_ENABLE, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) !acpi_check_handle(asus->handle, METHOD_PEGA_DISABLE, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) !acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) char *method = enable ? METHOD_PEGA_ENABLE : METHOD_PEGA_DISABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) return write_acpi_int(asus->handle, method, unit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) int i, delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) unsigned long long val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) for (i = 0; i < PEGA_ACC_RETRIES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) acpi_evaluate_integer(asus->handle, method, NULL, &val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* The output is noisy. From reading the ASL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) * dissassembly, timeout errors are returned with 1's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * in the high word, and the lack of locking around
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * thei hi/lo byte reads means that a transition
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * between (for example) -1 and 0 could be read as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * 0xff00 or 0x00ff. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) delta = abs(curr - (short)val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (delta < 128 && !(val & ~0xffff))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static void pega_accel_poll(struct input_dev *input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) struct device *parent = input->dev.parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct asus_laptop *asus = dev_get_drvdata(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /* In some cases, the very first call to poll causes a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * recursive fault under the polldev worker. This is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * apparently related to very early userspace access to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * device, and perhaps a firmware bug. Fake the first report. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (!asus->pega_acc_live) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) asus->pega_acc_live = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) input_report_abs(input, ABS_X, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) input_report_abs(input, ABS_Y, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) input_report_abs(input, ABS_Z, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) input_sync(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) asus->pega_acc_x = pega_acc_axis(asus, asus->pega_acc_x, METHOD_XLRX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) asus->pega_acc_y = pega_acc_axis(asus, asus->pega_acc_y, METHOD_XLRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) asus->pega_acc_z = pega_acc_axis(asus, asus->pega_acc_z, METHOD_XLRZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) /* Note transform, convert to "right/up/out" in the native
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * landscape orientation (i.e. the vector is the direction of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * "real up" in the device's cartiesian coordinates). */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) input_report_abs(input, ABS_X, -asus->pega_acc_x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) input_report_abs(input, ABS_Y, -asus->pega_acc_y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) input_report_abs(input, ABS_Z, asus->pega_acc_z);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) input_sync(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static void pega_accel_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (asus->pega_accel_poll) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) input_unregister_device(asus->pega_accel_poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) asus->pega_accel_poll = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) static int pega_accel_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (!asus->is_pega_lucid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) if (acpi_check_handle(asus->handle, METHOD_XLRX, NULL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) acpi_check_handle(asus->handle, METHOD_XLRY, NULL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) acpi_check_handle(asus->handle, METHOD_XLRZ, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (!input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) input->name = PEGA_ACCEL_DESC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) input->phys = PEGA_ACCEL_NAME "/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) input->dev.parent = &asus->platform_device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) input_set_abs_params(input, ABS_X,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) input_set_abs_params(input, ABS_Y,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) input_set_abs_params(input, ABS_Z,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) err = input_setup_polling(input, pega_accel_poll);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) input_set_poll_interval(input, 125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) input_set_min_poll_interval(input, 50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) input_set_max_poll_interval(input, 2000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) err = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) asus->pega_accel_poll = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) /* Generic LED function */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) static int asus_led_set(struct asus_laptop *asus, const char *method,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (!strcmp(method, METHOD_MLED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) value = !value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) else if (!strcmp(method, METHOD_GLED))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) value = !value + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) value = !!value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return write_acpi_int(asus->handle, method, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) * LEDs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /* /sys/class/led handlers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) static void asus_led_cdev_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) struct asus_led *led = container_of(led_cdev, struct asus_led, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) struct asus_laptop *asus = led->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) led->wk = !!value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) queue_work(asus->led_workqueue, &led->work);
^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) static void asus_led_cdev_update(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct asus_led *led = container_of(work, struct asus_led, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct asus_laptop *asus = led->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) asus_led_set(asus, led->method, led->wk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) return led_cdev->brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) * Keyboard backlight (also a LED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) static int asus_kled_lvl(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) unsigned long long kblv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct acpi_object_list params;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) union acpi_object in_obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) acpi_status rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) params.count = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) params.pointer = &in_obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) in_obj.type = ACPI_TYPE_INTEGER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) in_obj.integer.value = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) ¶ms, &kblv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (ACPI_FAILURE(rv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) pr_warn("Error reading kled level\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return kblv;
^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) static int asus_kled_set(struct asus_laptop *asus, int kblv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) if (kblv > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) kblv = (1 << 7) | (kblv & 0x7F);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) kblv = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) pr_warn("Keyboard LED display write failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) static void asus_kled_cdev_set(struct led_classdev *led_cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) enum led_brightness value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) struct asus_led *led = container_of(led_cdev, struct asus_led, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) struct asus_laptop *asus = led->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) led->wk = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) queue_work(asus->led_workqueue, &led->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) static void asus_kled_cdev_update(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) struct asus_led *led = container_of(work, struct asus_led, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) struct asus_laptop *asus = led->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) asus_kled_set(asus, led->wk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct asus_led *led = container_of(led_cdev, struct asus_led, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) struct asus_laptop *asus = led->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return asus_kled_lvl(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static void asus_led_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) led_classdev_unregister(&asus->wled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) led_classdev_unregister(&asus->bled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) led_classdev_unregister(&asus->mled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) led_classdev_unregister(&asus->tled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) led_classdev_unregister(&asus->pled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) led_classdev_unregister(&asus->rled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) led_classdev_unregister(&asus->gled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) led_classdev_unregister(&asus->kled.led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (asus->led_workqueue) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) destroy_workqueue(asus->led_workqueue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) asus->led_workqueue = NULL;
^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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) /* Ugly macro, need to fix that later */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static int asus_led_register(struct asus_laptop *asus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) struct asus_led *led,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) const char *name, const char *method)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) struct led_classdev *led_cdev = &led->led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (!method || acpi_check_handle(asus->handle, method, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return 0; /* Led not present */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) led->asus = asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) led->method = method;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) INIT_WORK(&led->work, asus_led_cdev_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) led_cdev->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) led_cdev->brightness_set = asus_led_cdev_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) led_cdev->brightness_get = asus_led_cdev_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) led_cdev->max_brightness = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) return led_classdev_register(&asus->platform_device->dev, led_cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) static int asus_led_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) int r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * The Pegatron Lucid has no physical leds, but all methods are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * available in the DSDT...
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (asus->is_pega_lucid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * Functions that actually update the LED's are called from a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * workqueue. By doing this as separate work rather than when the LED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * subsystem asks, we avoid messing with the Asus ACPI stuff during a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * potentially bad time, such as a timer interrupt.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) if (!asus->led_workqueue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (asus->wled_type == TYPE_LED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) r = asus_led_register(asus, &asus->wled, "asus::wlan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) METHOD_WLAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) if (asus->bled_type == TYPE_LED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) METHOD_BLUETOOTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) struct asus_led *led = &asus->kled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) struct led_classdev *cdev = &led->led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) led->asus = asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) INIT_WORK(&led->work, asus_kled_cdev_update);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) cdev->name = "asus::kbd_backlight";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) cdev->brightness_set = asus_kled_cdev_set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) cdev->brightness_get = asus_kled_cdev_get;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) cdev->max_brightness = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) r = led_classdev_register(&asus->platform_device->dev, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) if (r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) asus_led_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) return r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) * Backlight device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) static int asus_read_brightness(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) struct asus_laptop *asus = bl_get_data(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) unsigned long long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) acpi_status rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (ACPI_FAILURE(rv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) pr_warn("Error reading brightness\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) static int asus_set_brightness(struct backlight_device *bd, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) struct asus_laptop *asus = bl_get_data(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) pr_warn("Error changing brightness\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) static int update_bl_status(struct backlight_device *bd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) int value = bd->props.brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) return asus_set_brightness(bd, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) static const struct backlight_ops asusbl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) .get_brightness = asus_read_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) .update_status = update_bl_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int asus_backlight_notify(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct backlight_device *bd = asus->backlight_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) int old = bd->props.brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) return old;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) static int asus_backlight_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct backlight_device *bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) props.max_brightness = 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) props.type = BACKLIGHT_PLATFORM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) bd = backlight_device_register(ASUS_LAPTOP_FILE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) &asus->platform_device->dev, asus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) &asusbl_ops, &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) if (IS_ERR(bd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) pr_err("Could not register asus backlight device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) asus->backlight_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) return PTR_ERR(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) asus->backlight_device = bd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) bd->props.brightness = asus_read_brightness(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) bd->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) backlight_update_status(bd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) static void asus_backlight_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) backlight_device_unregister(asus->backlight_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) asus->backlight_device = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) * Platform device handlers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * We write our info in page, we begin at offset off and cannot write more
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) * than count bytes. We set eof to 1 if we handle those 2 values. We return the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) * number of bytes written in page
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) static ssize_t infos_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) char *page)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) int len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) unsigned long long temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) char buf[16]; /* enough for all info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) acpi_status rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) * We use the easy way, we don't care of off and count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * so we don't set eof to 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) len += sprintf(page + len, "Model reference : %s\n", asus->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) * The SFUN method probably allows the original driver to get the list
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) * of features supported by a given model. For now, 0x0100 or 0x0800
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) * The significance of others is yet to be found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) if (!ACPI_FAILURE(rv))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) len += sprintf(page + len, "SFUN value : %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) (uint) temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) * The HWRS method return informations about the hardware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) * 0x80 bit is for WLAN, 0x100 for Bluetooth.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) * 0x40 for WWAN, 0x10 for WIMAX.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) * The significance of others is yet to be found.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) * We don't currently use this for device detection, and it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) * takes several seconds to run on some systems.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) if (!ACPI_FAILURE(rv))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) len += sprintf(page + len, "HWRS value : %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) (uint) temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) * Another value for userspace: the ASYM method returns 0x02 for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * battery low and 0x04 for battery critical, its readings tend to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * more accurate than those provided by _BST.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) * Note: since not all the laptops provide this method, errors are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) * silently ignored.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) if (!ACPI_FAILURE(rv))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) len += sprintf(page + len, "ASYM value : %#x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) (uint) temp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) if (asus->dsdt_info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) snprintf(buf, 16, "%d", asus->dsdt_info->length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) len += sprintf(page + len, "DSDT length : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) snprintf(buf, 16, "%d", asus->dsdt_info->checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) len += sprintf(page + len, "DSDT checksum : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) snprintf(buf, 16, "%d", asus->dsdt_info->revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) len += sprintf(page + len, "DSDT revision : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) snprintf(buf, 7, "%s", asus->dsdt_info->oem_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) len += sprintf(page + len, "OEM id : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) len += sprintf(page + len, "OEM table id : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static DEVICE_ATTR_RO(infos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) const char *buf, size_t count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) const char *method)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) if (write_acpi_int(asus->handle, method, value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) * LEDD display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) static ssize_t ledd_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) return sprintf(buf, "0x%08x\n", asus->ledd_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) static ssize_t ledd_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) if (write_acpi_int(asus->handle, METHOD_LEDD, value)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) pr_warn("LED display write failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) asus->ledd_status = (u32) value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) static DEVICE_ATTR_RW(ledd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) * Wireless
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) static int asus_wireless_status(struct asus_laptop *asus, int mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) unsigned long long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) acpi_status rv = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (!asus->have_rsts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return (asus->wireless_status & mask) ? 1 : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) NULL, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (ACPI_FAILURE(rv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) pr_warn("Error reading Wireless status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) return !!(status & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) * WLAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) static int asus_wlan_set(struct asus_laptop *asus, int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) pr_warn("Error setting wlan status to %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) static ssize_t wlan_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) static ssize_t wlan_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) static DEVICE_ATTR_RW(wlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) /*e
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) * Bluetooth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) static int asus_bluetooth_set(struct asus_laptop *asus, int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) pr_warn("Error setting bluetooth status to %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) static ssize_t bluetooth_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) static ssize_t bluetooth_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) struct device_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) static DEVICE_ATTR_RW(bluetooth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) * Wimax
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) static int asus_wimax_set(struct asus_laptop *asus, int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) pr_warn("Error setting wimax status to %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) static ssize_t wimax_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) static ssize_t wimax_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) static DEVICE_ATTR_RW(wimax);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) * Wwan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) static int asus_wwan_set(struct asus_laptop *asus, int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) pr_warn("Error setting wwan status to %d\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) static ssize_t wwan_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) static ssize_t wwan_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) static DEVICE_ATTR_RW(wwan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) * Display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) static void asus_set_display(struct asus_laptop *asus, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) /* no sanity check needed for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) pr_warn("Error setting display\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * Experimental support for display switching. As of now: 1 should activate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) * Any combination (bitwise) of these will suffice. I never actually tested 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * displays hooked up simultaneously, so be warned. See the acpi4asus README
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * for more info.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) static ssize_t display_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) asus_set_display(asus, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) static DEVICE_ATTR_WO(display);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) * Light Sens
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) static void asus_als_switch(struct asus_laptop *asus, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) if (asus->is_pega_lucid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) ret = asus_pega_lucid_set(asus, PEGA_ALS, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) ret = asus_pega_lucid_set(asus, PEGA_ALS_POWER, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) ret = write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) pr_warn("Error setting light sensor switch\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) asus->light_switch = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) static ssize_t ls_switch_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) return sprintf(buf, "%d\n", asus->light_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) static ssize_t ls_switch_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) struct device_attribute *attr, const char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) asus_als_switch(asus, value ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) static DEVICE_ATTR_RW(ls_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) static void asus_als_level(struct asus_laptop *asus, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) pr_warn("Error setting light sensor level\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) asus->light_level = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) static ssize_t ls_level_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return sprintf(buf, "%d\n", asus->light_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) /* 0 <= value <= 15 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) asus_als_level(asus, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) static DEVICE_ATTR_RW(ls_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) int err = write_acpi_int_ret(asus->handle, METHOD_PEGA_READ, arg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) &buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) union acpi_object *obj = buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) if (obj && obj->type == ACPI_TYPE_INTEGER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) *result = obj->integer.value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) static ssize_t ls_value_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) int err, hi, lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) err = pega_int_read(asus, PEGA_READ_ALS_H, &hi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) err = pega_int_read(asus, PEGA_READ_ALS_L, &lo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) return sprintf(buf, "%d\n", 10 * hi + lo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) static DEVICE_ATTR_RO(ls_value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) * GPS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) static int asus_gps_status(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) unsigned long long status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) acpi_status rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) NULL, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) if (ACPI_FAILURE(rv)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) pr_warn("Error reading GPS status\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) return !!status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) static int asus_gps_switch(struct asus_laptop *asus, int status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) const char *meth = status ? METHOD_GPS_ON : METHOD_GPS_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) if (write_acpi_int(asus->handle, meth, 0x02))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) static ssize_t gps_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) return sprintf(buf, "%d\n", asus_gps_status(asus));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) static ssize_t gps_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) int rv, value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) rv = kstrtoint(buf, 0, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) if (rv < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) return rv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) ret = asus_gps_switch(asus, !!value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) rfkill_set_sw_state(asus->gps.rfkill, !value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) static DEVICE_ATTR_RW(gps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) * rfkill
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) static int asus_gps_rfkill_set(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) struct asus_laptop *asus = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) return asus_gps_switch(asus, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) static const struct rfkill_ops asus_gps_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) .set_block = asus_gps_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) static int asus_rfkill_set(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) struct asus_rfkill *rfk = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) struct asus_laptop *asus = rfk->asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) if (rfk->control_id == WL_RSTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) return asus_wlan_set(asus, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) else if (rfk->control_id == BT_RSTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) return asus_bluetooth_set(asus, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) else if (rfk->control_id == WM_RSTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) return asus_wimax_set(asus, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) else if (rfk->control_id == WW_RSTS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) return asus_wwan_set(asus, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) static const struct rfkill_ops asus_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) .set_block = asus_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) static void asus_rfkill_terminate(struct asus_rfkill *rfk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) if (!rfk->rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) rfkill_unregister(rfk->rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) rfkill_destroy(rfk->rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) rfk->rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) static void asus_rfkill_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) asus_rfkill_terminate(&asus->wwan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) asus_rfkill_terminate(&asus->bluetooth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) asus_rfkill_terminate(&asus->wlan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) asus_rfkill_terminate(&asus->gps);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) const char *name, int control_id, int type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) const struct rfkill_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) rfk->control_id = control_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) rfk->asus = asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) type, ops, rfk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) if (!rfk->rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) result = rfkill_register(rfk->rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) if (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) rfkill_destroy(rfk->rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) rfk->rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) static int asus_rfkill_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) if (asus->is_pega_lucid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) -1, RFKILL_TYPE_GPS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) &asus_gps_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) asus->wled_type == TYPE_RFKILL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) WL_RSTS, RFKILL_TYPE_WLAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) &asus_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) asus->bled_type == TYPE_RFKILL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) result = asus_rfkill_setup(asus, &asus->bluetooth,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) "asus-bluetooth", BT_RSTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) RFKILL_TYPE_BLUETOOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) &asus_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) WW_RSTS, RFKILL_TYPE_WWAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) &asus_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) WM_RSTS, RFKILL_TYPE_WIMAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) &asus_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) asus_rfkill_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) static int pega_rfkill_set(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) struct asus_rfkill *rfk = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) static const struct rfkill_ops pega_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) .set_block = pega_rfkill_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) const char *name, int controlid, int rfkill_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) &pega_rfkill_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) static int pega_rfkill_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) if(!asus->is_pega_lucid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) PEGA_WLAN, RFKILL_TYPE_WLAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) if(ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) if(ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) goto exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) PEGA_WWAN, RFKILL_TYPE_WWAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) asus_rfkill_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) * Input device (i.e. hotkeys)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) static void asus_input_notify(struct asus_laptop *asus, int event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) if (!asus->inputdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) pr_info("Unknown key %x pressed\n", event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) static int asus_input_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) input = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) if (!input)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) input->name = "Asus Laptop extra buttons";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) input->phys = ASUS_LAPTOP_FILE "/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) input->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) input->dev.parent = &asus->platform_device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) error = sparse_keymap_setup(input, asus_keymap, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) pr_err("Unable to setup input device keymap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) pr_warn("Unable to register input device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) asus->inputdev = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) err_free_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) input_free_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) static void asus_input_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) if (asus->inputdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) input_unregister_device(asus->inputdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) asus->inputdev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) * ACPI driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) static void asus_acpi_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) struct asus_laptop *asus = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) u16 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) /* TODO Find a better way to handle events count. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) count = asus->event_count[event % 128]++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) dev_name(&asus->device->dev), event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) event = ATKD_BRNUP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) else if (event >= ATKD_BRNDOWN_MIN &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) event <= ATKD_BRNDOWN_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) event = ATKD_BRNDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) /* Brightness events are special */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) if (event == ATKD_BRNDOWN || event == ATKD_BRNUP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) if (asus->backlight_device != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) /* Update the backlight device. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) asus_backlight_notify(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) /* Accelerometer "coarse orientation change" event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) if (asus->pega_accel_poll && event == 0xEA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) kobject_uevent(&asus->pega_accel_poll->dev.kobj, KOBJ_CHANGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) return ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) asus_input_notify(asus, event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) static struct attribute *asus_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) &dev_attr_infos.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) &dev_attr_wlan.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) &dev_attr_bluetooth.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) &dev_attr_wimax.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) &dev_attr_wwan.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) &dev_attr_display.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) &dev_attr_ledd.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) &dev_attr_ls_value.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) &dev_attr_ls_level.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) &dev_attr_ls_switch.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) &dev_attr_gps.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) static umode_t asus_sysfs_is_visible(struct kobject *kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) struct attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) struct device *dev = container_of(kobj, struct device, kobj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) struct asus_laptop *asus = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) acpi_handle handle = asus->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) bool supported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) if (asus->is_pega_lucid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) /* no ls_level interface on the Lucid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) if (attr == &dev_attr_ls_switch.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) else if (attr == &dev_attr_ls_level.attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) supported = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) goto normal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) return supported ? attr->mode : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) normal:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) if (attr == &dev_attr_wlan.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) } else if (attr == &dev_attr_bluetooth.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) } else if (attr == &dev_attr_display.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) } else if (attr == &dev_attr_wimax.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) supported =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) } else if (attr == &dev_attr_wwan.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) } else if (attr == &dev_attr_ledd.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) } else if (attr == &dev_attr_ls_switch.attr ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) attr == &dev_attr_ls_level.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) } else if (attr == &dev_attr_ls_value.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) supported = asus->is_pega_lucid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) } else if (attr == &dev_attr_gps.attr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) supported = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) return supported ? attr->mode : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) static const struct attribute_group asus_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) .is_visible = asus_sysfs_is_visible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) .attrs = asus_attributes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) static int asus_platform_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) if (!asus->platform_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) platform_set_drvdata(asus->platform_device, asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) result = platform_device_add(asus->platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) goto fail_platform_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) result = sysfs_create_group(&asus->platform_device->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) &asus_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) goto fail_sysfs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) fail_sysfs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) platform_device_del(asus->platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) fail_platform_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) platform_device_put(asus->platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) static void asus_platform_exit(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) platform_device_unregister(asus->platform_device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) static struct platform_driver platform_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) .name = ASUS_LAPTOP_FILE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) * This function is used to initialize the context with right values. In this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) * method, we can make all the detection we want, and modify the asus_laptop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) * struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) static int asus_laptop_get_info(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) union acpi_object *model = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680) unsigned long long bsts_result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) char *string = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) * Get DSDT headers early enough to allow for differentiating between
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) * models, but late enough to allow acpi_bus_register_driver() to fail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) * before doing anything ACPI-specific. Should we encounter a machine,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) * which needs special handling (i.e. its hotkey device has a different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) * HID), this bit will be moved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) pr_warn("Couldn't get the DSDT table header\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) /* We have to write 0 on init this far for all ASUS models */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) pr_err("Hotkey initialization failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) /* This needs to be called for some laptops to init properly */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) status =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) pr_warn("Error calling BSTS\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) else if (bsts_result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) pr_notice("BSTS called, 0x%02x returned\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) (uint) bsts_result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) /* This too ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711) if (write_acpi_int(asus->handle, "CWAP", wapf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) pr_err("Error calling CWAP(%d)\n", wapf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) * Try to match the object returned by INIT to the specific model.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715) * Handle every possible object (or the lack of thereof) the DSDT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) * writers might throw at us. When in trouble, we pass NULL to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) * asus_model_match() and try something completely different.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) if (buffer.pointer) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) model = buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721) switch (model->type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) case ACPI_TYPE_STRING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) string = model->string.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) case ACPI_TYPE_BUFFER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) string = model->buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) string = "";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) asus->name = kstrdup(string, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) if (!asus->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735) kfree(buffer.pointer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) if (string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740) pr_notice(" %s model detected\n", string);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742) if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) asus->have_rsts = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) kfree(model);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) static int asus_acpi_init(struct asus_laptop *asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) result = acpi_bus_get_status(asus->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) if (!asus->device->status.present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) pr_err("Hotkey device not present, aborting\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) result = asus_laptop_get_info(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) if (!strcmp(bled_type, "led"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) asus->bled_type = TYPE_LED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) else if (!strcmp(bled_type, "rfkill"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) asus->bled_type = TYPE_RFKILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) if (!strcmp(wled_type, "led"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) asus->wled_type = TYPE_LED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) else if (!strcmp(wled_type, "rfkill"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) asus->wled_type = TYPE_RFKILL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) if (bluetooth_status >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) asus_bluetooth_set(asus, !!bluetooth_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) if (wlan_status >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) asus_wlan_set(asus, !!wlan_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) if (wimax_status >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783) asus_wimax_set(asus, !!wimax_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) if (wwan_status >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) asus_wwan_set(asus, !!wwan_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788) /* Keyboard Backlight is on by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) asus_kled_set(asus, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) /* LED display is off by default */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) asus->ledd_status = 0xFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) /* Set initial values of light sensor and level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796) asus->light_switch = !!als_status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) asus->light_level = 5; /* level 5 for sensor sensitivity */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) if (asus->is_pega_lucid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) asus_als_switch(asus, asus->light_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) } else if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) asus_als_switch(asus, asus->light_switch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) asus_als_level(asus, asus->light_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) static void asus_dmi_check(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) const char *model;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) model = dmi_get_system_info(DMI_PRODUCT_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) if (!model)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) /* On L1400B WLED control the sound card, don't mess with it ... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) if (strncmp(model, "L1400B", 6) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) wlan_status = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) static bool asus_device_present;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826) static int asus_acpi_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) struct asus_laptop *asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) pr_notice("Asus Laptop Support version %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) ASUS_LAPTOP_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) if (!asus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) asus->handle = device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) device->driver_data = asus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) asus->device = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) asus_dmi_check();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) result = asus_acpi_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846) goto fail_platform;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849) * Need platform type detection first, then the platform
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) * device. It is used as a parent for the sub-devices below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) asus->is_pega_lucid = asus_check_pega_lucid(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) result = asus_platform_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) goto fail_platform;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) result = asus_backlight_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) goto fail_backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) result = asus_input_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) goto fail_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) result = asus_led_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) goto fail_led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) result = asus_rfkill_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) if (result && result != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873) goto fail_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) result = pega_accel_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) if (result && result != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877) goto fail_pega_accel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) result = pega_rfkill_init(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) if (result && result != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) goto fail_pega_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) asus_device_present = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) fail_pega_rfkill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887) pega_accel_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) fail_pega_accel:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889) asus_rfkill_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) fail_rfkill:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) asus_led_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) fail_led:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) asus_input_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) fail_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) asus_backlight_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) fail_backlight:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) asus_platform_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) fail_platform:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) kfree(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) static int asus_acpi_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906) struct asus_laptop *asus = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) asus_backlight_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) asus_rfkill_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910) asus_led_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) asus_input_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) pega_accel_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913) asus_platform_exit(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) kfree(asus->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) kfree(asus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920) static const struct acpi_device_id asus_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) {"ATK0100", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) {"ATK0101", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) MODULE_DEVICE_TABLE(acpi, asus_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) static struct acpi_driver asus_acpi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) .name = ASUS_LAPTOP_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) .class = ASUS_LAPTOP_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) .ids = asus_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) .add = asus_acpi_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) .remove = asus_acpi_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) .notify = asus_acpi_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) static int __init asus_laptop_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) result = platform_driver_register(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948) result = acpi_bus_register_driver(&asus_acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) goto fail_acpi_driver;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951) if (!asus_device_present) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) result = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) goto fail_no_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) fail_no_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958) acpi_bus_unregister_driver(&asus_acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) fail_acpi_driver:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960) platform_driver_unregister(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) static void __exit asus_laptop_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) acpi_bus_unregister_driver(&asus_acpi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) platform_driver_unregister(&platform_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) module_init(asus_laptop_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971) module_exit(asus_laptop_exit);