Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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, &params, 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) 				   &params, &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);