Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
db38a291
Commit
db38a291
authored
Mar 01, 2010
by
Matthew Garrett
Browse files
Options
Browse Files
Download
Plain Diff
Merge
git://git.iksaif.net/acpi4asus
into x86-platform
parents
b466301b
b1a96e36
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
939 additions
and
847 deletions
+939
-847
Documentation/ABI/testing/sysfs-platform-asus-laptop
Documentation/ABI/testing/sysfs-platform-asus-laptop
+6
-6
Documentation/ABI/testing/sysfs-platform-eeepc-laptop
Documentation/ABI/testing/sysfs-platform-eeepc-laptop
+5
-5
drivers/platform/x86/Kconfig
drivers/platform/x86/Kconfig
+2
-0
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-laptop.c
+906
-835
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/eeepc-laptop.c
+20
-1
No files found.
Documentation/ABI/testing/sysfs-platform-asus-laptop
View file @
db38a291
What: /sys/devices/platform/asus
-
laptop/display
What: /sys/devices/platform/asus
_
laptop/display
Date: January 2007
Date: January 2007
KernelVersion: 2.6.20
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -13,7 +13,7 @@ Description:
...
@@ -13,7 +13,7 @@ Description:
Ex: - 0 (0000b) means no display
Ex: - 0 (0000b) means no display
- 3 (0011b) CRT+LCD.
- 3 (0011b) CRT+LCD.
What: /sys/devices/platform/asus
-
laptop/gps
What: /sys/devices/platform/asus
_
laptop/gps
Date: January 2007
Date: January 2007
KernelVersion: 2.6.20
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -21,7 +21,7 @@ Description:
...
@@ -21,7 +21,7 @@ Description:
Control the gps device. 1 means on, 0 means off.
Control the gps device. 1 means on, 0 means off.
Users: Lapsus
Users: Lapsus
What: /sys/devices/platform/asus
-
laptop/ledd
What: /sys/devices/platform/asus
_
laptop/ledd
Date: January 2007
Date: January 2007
KernelVersion: 2.6.20
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -29,11 +29,11 @@ Description:
...
@@ -29,11 +29,11 @@ Description:
Some models like the W1N have a LED display that can be
Some models like the W1N have a LED display that can be
used to display several informations.
used to display several informations.
To control the LED display, use the following :
To control the LED display, use the following :
echo 0x0T000DDD > /sys/devices/platform/asus
-
laptop/
echo 0x0T000DDD > /sys/devices/platform/asus
_
laptop/
where T control the 3 letters display, and DDD the 3 digits display.
where T control the 3 letters display, and DDD the 3 digits display.
The DDD table can be found in Documentation/laptops/asus-laptop.txt
The DDD table can be found in Documentation/laptops/asus-laptop.txt
What: /sys/devices/platform/asus
-
laptop/bluetooth
What: /sys/devices/platform/asus
_
laptop/bluetooth
Date: January 2007
Date: January 2007
KernelVersion: 2.6.20
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -42,7 +42,7 @@ Description:
...
@@ -42,7 +42,7 @@ Description:
This may control the led, the device or both.
This may control the led, the device or both.
Users: Lapsus
Users: Lapsus
What: /sys/devices/platform/asus
-
laptop/wlan
What: /sys/devices/platform/asus
_
laptop/wlan
Date: January 2007
Date: January 2007
KernelVersion: 2.6.20
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
Documentation/ABI/testing/sysfs-platform-eeepc-laptop
View file @
db38a291
What: /sys/devices/platform/eeepc
-laptop
/disp
What: /sys/devices/platform/eeepc/disp
Date: May 2008
Date: May 2008
KernelVersion: 2.6.26
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -9,21 +9,21 @@ Description:
...
@@ -9,21 +9,21 @@ Description:
- 3 = LCD+CRT
- 3 = LCD+CRT
If you run X11, you should use xrandr instead.
If you run X11, you should use xrandr instead.
What: /sys/devices/platform/eeepc
-laptop
/camera
What: /sys/devices/platform/eeepc/camera
Date: May 2008
Date: May 2008
KernelVersion: 2.6.26
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
Description:
Description:
Control the camera. 1 means on, 0 means off.
Control the camera. 1 means on, 0 means off.
What: /sys/devices/platform/eeepc
-laptop
/cardr
What: /sys/devices/platform/eeepc/cardr
Date: May 2008
Date: May 2008
KernelVersion: 2.6.26
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
Description:
Description:
Control the card reader. 1 means on, 0 means off.
Control the card reader. 1 means on, 0 means off.
What: /sys/devices/platform/eeepc
-laptop
/cpufv
What: /sys/devices/platform/eeepc/cpufv
Date: Jun 2009
Date: Jun 2009
KernelVersion: 2.6.31
KernelVersion: 2.6.31
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
@@ -42,7 +42,7 @@ Description:
...
@@ -42,7 +42,7 @@ Description:
`------------ Availables modes
`------------ Availables modes
For example, 0x301 means: mode 1 selected, 3 available modes.
For example, 0x301 means: mode 1 selected, 3 available modes.
What: /sys/devices/platform/eeepc
-laptop
/available_cpufv
What: /sys/devices/platform/eeepc/available_cpufv
Date: Jun 2009
Date: Jun 2009
KernelVersion: 2.6.31
KernelVersion: 2.6.31
Contact: "Corentin Chary" <corentincj@iksaif.net>
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
drivers/platform/x86/Kconfig
View file @
db38a291
...
@@ -59,6 +59,8 @@ config ASUS_LAPTOP
...
@@ -59,6 +59,8 @@ config ASUS_LAPTOP
select NEW_LEDS
select NEW_LEDS
select BACKLIGHT_CLASS_DEVICE
select BACKLIGHT_CLASS_DEVICE
depends on INPUT
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
---help---
---help---
This is the new Linux driver for Asus laptops. It may also support some
This is the new Linux driver for Asus laptops. It may also support some
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
...
...
drivers/platform/x86/asus-laptop.c
View file @
db38a291
...
@@ -45,58 +45,23 @@
...
@@ -45,58 +45,23 @@
#include <linux/fb.h>
#include <linux/fb.h>
#include <linux/leds.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/rfkill.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
#include <linux/input.h>
#define ASUS_LAPTOP_VERSION "0.42"
#define ASUS_HOTK_NAME "Asus Laptop Support"
#define ASUS_HOTK_CLASS "hotkey"
#define ASUS_HOTK_DEVICE_NAME "Hotkey"
#define ASUS_HOTK_FILE KBUILD_MODNAME
#define ASUS_HOTK_PREFIX "\\_SB.ATKD."
#define ASUS_LAPTOP_VERSION "0.42"
/*
#define ASUS_LAPTOP_NAME "Asus Laptop Support"
* Some events we use, same for all Asus
#define ASUS_LAPTOP_CLASS "hotkey"
*/
#define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
#define ATKD_BR_UP 0x10
#define ASUS_LAPTOP_FILE KBUILD_MODNAME
#define ATKD_BR_DOWN 0x20
#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
#define ATKD_LCD_ON 0x33
#define ATKD_LCD_OFF 0x34
/*
* Known bits returned by \_SB.ATKD.HWRS
*/
#define WL_HWRS 0x80
#define BT_HWRS 0x100
/*
* Flags for hotk status
* WL_ON and BT_ON are also used for wireless_status()
*/
#define WL_ON 0x01
/* internal Wifi */
#define BT_ON 0x02
/* internal Bluetooth */
#define MLED_ON 0x04
/* mail LED */
#define TLED_ON 0x08
/* touchpad LED */
#define RLED_ON 0x10
/* Record LED */
#define PLED_ON 0x20
/* Phone LED */
#define GLED_ON 0x40
/* Gaming LED */
#define LCD_ON 0x80
/* LCD backlight */
#define GPS_ON 0x100
/* GPS */
#define KEY_ON 0x200
/* Keyboard backlight */
#define ASUS_LOG ASUS_HOTK_FILE ": "
#define ASUS_ERR KERN_ERR ASUS_LOG
#define ASUS_WARNING KERN_WARNING ASUS_LOG
#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
#define ASUS_INFO KERN_INFO ASUS_LOG
#define ASUS_DEBUG KERN_DEBUG ASUS_LOG
MODULE_AUTHOR
(
"Julien Lerouge, Karol Kozimor, Corentin Chary"
);
MODULE_AUTHOR
(
"Julien Lerouge, Karol Kozimor, Corentin Chary"
);
MODULE_DESCRIPTION
(
ASUS_
HOTK
_NAME
);
MODULE_DESCRIPTION
(
ASUS_
LAPTOP
_NAME
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
/*
/*
...
@@ -113,225 +78,209 @@ static uint wapf = 1;
...
@@ -113,225 +78,209 @@ static uint wapf = 1;
module_param
(
wapf
,
uint
,
0644
);
module_param
(
wapf
,
uint
,
0644
);
MODULE_PARM_DESC
(
wapf
,
"WAPF value"
);
MODULE_PARM_DESC
(
wapf
,
"WAPF value"
);
#define ASUS_HANDLE(object, paths...) \
static
uint
wlan_status
=
1
;
static acpi_handle object##_handle = NULL; \
static
uint
bluetooth_status
=
1
;
static char *object##_paths[] = { paths }
module_param
(
wlan_status
,
uint
,
0644
);
MODULE_PARM_DESC
(
wlan_status
,
"Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1"
);
module_param
(
bluetooth_status
,
uint
,
0644
);
MODULE_PARM_DESC
(
bluetooth_status
,
"Set the wireless status on boot "
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
"default is 1"
);
/*
* Some events we use, same for all Asus
*/
#define ATKD_BR_UP 0x10
/* (event & ~ATKD_BR_UP) = brightness level */
#define ATKD_BR_DOWN 0x20
/* (event & ~ATKD_BR_DOWN) = britghness level */
#define ATKD_BR_MIN ATKD_BR_UP
#define ATKD_BR_MAX (ATKD_BR_DOWN | 0xF)
/* 0x2f */
#define ATKD_LCD_ON 0x33
#define ATKD_LCD_OFF 0x34
/*
* Known bits returned by \_SB.ATKD.HWRS
*/
#define WL_HWRS 0x80
#define BT_HWRS 0x100
/*
* Flags for hotk status
* WL_ON and BT_ON are also used for wireless_status()
*/
#define WL_RSTS 0x01
/* internal Wifi */
#define BT_RSTS 0x02
/* internal Bluetooth */
/* LED */
/* LED */
ASUS_HANDLE
(
mled_set
,
ASUS_HOTK_PREFIX
"MLED"
);
#define METHOD_MLED "MLED"
ASUS_HANDLE
(
tled_set
,
ASUS_HOTK_PREFIX
"TLED"
);
#define METHOD_TLED "TLED"
ASUS_HANDLE
(
rled_set
,
ASUS_HOTK_PREFIX
"RLED"
);
/* W1JC */
#define METHOD_RLED "RLED"
/* W1JC */
ASUS_HANDLE
(
pled_set
,
ASUS_HOTK_PREFIX
"PLED"
);
/* A7J */
#define METHOD_PLED "PLED"
/* A7J */
ASUS_HANDLE
(
gled_set
,
ASUS_HOTK_PREFIX
"GLED"
);
/* G1, G2 (probably) */
#define METHOD_GLED "GLED"
/* G1, G2 (probably) */
/* LEDD */
/* LEDD */
ASUS_HANDLE
(
ledd_set
,
ASUS_HOTK_PREFIX
"SLCM"
);
#define METHOD_LEDD "SLCM"
/*
/*
* Bluetooth and WLAN
* Bluetooth and WLAN
* WLED and BLED are not handled like other XLED, because in some dsdt
* WLED and BLED are not handled like other XLED, because in some dsdt
* they also control the WLAN/Bluetooth device.
* they also control the WLAN/Bluetooth device.
*/
*/
ASUS_HANDLE
(
wl_switch
,
ASUS_HOTK_PREFIX
"WLED"
);
#define METHOD_WLAN "WLED"
ASUS_HANDLE
(
bt_switch
,
ASUS_HOTK_PREFIX
"BLED"
);
#define METHOD_BLUETOOTH "BLED"
ASUS_HANDLE
(
wireless_status
,
ASUS_HOTK_PREFIX
"RSTS"
);
/* All new models */
#define METHOD_WL_STATUS "RSTS"
/* Brightness */
/* Brightness */
ASUS_HANDLE
(
brightness_set
,
ASUS_HOTK_PREFIX
"SPLV"
);
#define METHOD_BRIGHTNESS_SET "SPLV"
ASUS_HANDLE
(
brightness_get
,
ASUS_HOTK_PREFIX
"GPLV"
);
#define METHOD_BRIGHTNESS_GET "GPLV"
/* Backlight */
/* Backlight */
ASUS_HANDLE
(
lcd_switch
,
"
\\
_SB.PCI0.SBRG.EC0._Q10"
,
/* All new models */
static
acpi_handle
lcd_switch_handle
;
"
\\
_SB.PCI0.ISA.EC0._Q10"
,
/* A1x */
static
const
char
*
lcd_switch_paths
[]
=
{
"
\\
_SB.PCI0.PX40.ECD0._Q10"
,
/* L3C */
"
\\
_SB.PCI0.SBRG.EC0._Q10"
,
/* All new models */
"
\\
_SB.PCI0.PX40.EC0.Q10"
,
/* M1A */
"
\\
_SB.PCI0.ISA.EC0._Q10"
,
/* A1x */
"
\\
_SB.PCI0.LPCB.EC0._Q10"
,
/* P30 */
"
\\
_SB.PCI0.PX40.ECD0._Q10"
,
/* L3C */
"
\\
_SB.PCI0.LPCB.EC0._Q0E"
,
/* P30/P35 */
"
\\
_SB.PCI0.PX40.EC0.Q10"
,
/* M1A */
"
\\
_SB.PCI0.PX40.Q10"
,
/* S1x */
"
\\
_SB.PCI0.LPCB.EC0._Q10"
,
/* P30 */
"
\\
Q10"
);
/* A2x, L2D, L3D, M2E */
"
\\
_SB.PCI0.LPCB.EC0._Q0E"
,
/* P30/P35 */
"
\\
_SB.PCI0.PX40.Q10"
,
/* S1x */
"
\\
Q10"
};
/* A2x, L2D, L3D, M2E */
/* Display */
/* Display */
ASUS_HANDLE
(
display_set
,
ASUS_HOTK_PREFIX
"SDSP"
);
#define METHOD_SWITCH_DISPLAY "SDSP"
ASUS_HANDLE
(
display_get
,
/* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
static
acpi_handle
display_get_handle
;
"
\\
_SB.PCI0.P0P1.VGA.GETD"
,
static
const
char
*
display_get_paths
[]
=
{
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
/* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
"
\\
_SB.PCI0.P0P2.VGA.GETD"
,
"
\\
_SB.PCI0.P0P1.VGA.GETD"
,
/* A6V A6Q */
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
"
\\
_SB.PCI0.P0P3.VGA.GETD"
,
"
\\
_SB.PCI0.P0P2.VGA.GETD"
,
/* A6T, A6M */
/* A6V A6Q */
"
\\
_SB.PCI0.P0PA.VGA.GETD"
,
"
\\
_SB.PCI0.P0P3.VGA.GETD"
,
/* L3C */
/* A6T, A6M */
"
\\
_SB.PCI0.PCI1.VGAC.NMAP"
,
"
\\
_SB.PCI0.P0PA.VGA.GETD"
,
/* Z96F */
/* L3C */
"
\\
_SB.PCI0.VGA.GETD"
,
"
\\
_SB.PCI0.PCI1.VGAC.NMAP"
,
/* A2D */
/* Z96F */
"
\\
ACTD"
,
"
\\
_SB.PCI0.VGA.GETD"
,
/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
/* A2D */
"
\\
ADVG"
,
"
\\
ACTD"
,
/* P30 */
/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
"
\\
DNXT"
,
"
\\
ADVG"
,
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
/* P30 */
"
\\
INFB"
,
"
\\
DNXT"
,
/* A3F A6F A3N A3L M6N W3N W6A */
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
"
\\
SSTE"
);
"
\\
INFB"
,
/* A3F A6F A3N A3L M6N W3N W6A */
ASUS_HANDLE
(
ls_switch
,
ASUS_HOTK_PREFIX
"ALSC"
);
/* Z71A Z71V */
"
\\
SSTE"
};
ASUS_HANDLE
(
ls_level
,
ASUS_HOTK_PREFIX
"ALSL"
);
/* Z71A Z71V */
#define METHOD_ALS_CONTROL "ALSC"
/* Z71A Z71V */
#define METHOD_ALS_LEVEL "ALSL"
/* Z71A Z71V */
/* GPS */
/* GPS */
/* R2H use different handle for GPS on/off */
/* R2H use different handle for GPS on/off */
ASUS_HANDLE
(
gps_on
,
ASUS_HOTK_PREFIX
"SDON"
);
/* R2H */
#define METHOD_GPS_ON "SDON"
ASUS_HANDLE
(
gps_off
,
ASUS_HOTK_PREFIX
"SDOF"
);
/* R2H */
#define METHOD_GPS_OFF "SDOF"
ASUS_HANDLE
(
gps_status
,
ASUS_HOTK_PREFIX
"GPST"
);
#define METHOD_GPS_STATUS "GPST"
/* Keyboard light */
/* Keyboard light */
ASUS_HANDLE
(
kled_set
,
ASUS_HOTK_PREFIX
"SLKB"
);
#define METHOD_KBD_LIGHT_SET "SLKB"
ASUS_HANDLE
(
kled_get
,
ASUS_HOTK_PREFIX
"GLKB"
);
#define METHOD_KBD_LIGHT_GET "GLKB"
/*
/*
* This is the main structure, we can use it to store anything interesting
* Define a specific led structure to keep the main structure clean
* about the hotk device
*/
*/
struct
asus_hotk
{
struct
asus_led
{
char
*
name
;
/* laptop name */
int
wk
;
struct
acpi_device
*
device
;
/* the device we are in */
struct
work_struct
work
;
acpi_handle
handle
;
/* the handle of the hotk device */
struct
led_classdev
led
;
char
status
;
/* status of the hotk, for LEDs, ... */
struct
asus_laptop
*
asus
;
u32
ledd_status
;
/* status of the LED display */
const
char
*
method
;
u8
light_level
;
/* light sensor level */
u8
light_switch
;
/* light sensor switch value */
u16
event_count
[
128
];
/* count for each event TODO make this better */
struct
input_dev
*
inputdev
;
u16
*
keycode_map
;
};
};
/*
/*
* This header is made available to allow proper configuration given model,
* This is the main structure, we can use it to store anything interesting
* revision number , ... this info cannot go in struct asus_hotk because it is
* about the hotk device
* available before the hotk
*/
static
struct
acpi_table_header
*
asus_info
;
/* The actual device the driver binds to */
static
struct
asus_hotk
*
hotk
;
/*
* The hotkey driver declaration
*/
*/
static
const
struct
acpi_device_id
asus_device_ids
[]
=
{
struct
asus_laptop
{
{
"ATK0100"
,
0
},
char
*
name
;
/* laptop name */
{
"ATK0101"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
asus_device_ids
);
static
int
asus_hotk_add
(
struct
acpi_device
*
device
);
struct
acpi_table_header
*
dsdt_info
;
static
int
asus_hotk_remove
(
struct
acpi_device
*
device
,
int
type
);
struct
platform_device
*
platform_device
;
static
void
asus_hotk_notify
(
struct
acpi_device
*
device
,
u32
event
);
struct
acpi_device
*
device
;
/* the device we are in */
struct
backlight_device
*
backlight_device
;
static
struct
acpi_driver
asus_hotk_driver
=
{
struct
input_dev
*
inputdev
;
.
name
=
ASUS_HOTK_NAME
,
struct
key_entry
*
keymap
;
.
class
=
ASUS_HOTK_CLASS
,
.
owner
=
THIS_MODULE
,
.
ids
=
asus_device_ids
,
.
flags
=
ACPI_DRIVER_ALL_NOTIFY_EVENTS
,
.
ops
=
{
.
add
=
asus_hotk_add
,
.
remove
=
asus_hotk_remove
,
.
notify
=
asus_hotk_notify
,
},
};
/* The backlight device /sys/class/backlight */
struct
asus_led
mled
;
static
struct
backlight_device
*
asus_backlight_device
;
struct
asus_led
tled
;
struct
asus_led
rled
;
struct
asus_led
pled
;
struct
asus_led
gled
;
struct
asus_led
kled
;
struct
workqueue_struct
*
led_workqueue
;
/*
int
wireless_status
;
* The backlight class declaration
bool
have_rsts
;
*/
int
lcd_state
;
static
int
read_brightness
(
struct
backlight_device
*
bd
);
static
int
update_bl_status
(
struct
backlight_device
*
bd
);
static
struct
backlight_ops
asusbl_ops
=
{
.
get_brightness
=
read_brightness
,
.
update_status
=
update_bl_status
,
};
/*
struct
rfkill
*
gps_rfkill
;
* These functions actually update the LED's, and are called from a
* workqueue. By doing this as separate work rather than when the LED
* subsystem asks, we avoid messing with the Asus ACPI stuff during a
* potentially bad time, such as a timer interrupt.
*/
static
struct
workqueue_struct
*
led_workqueue
;
#define ASUS_LED(object, ledname, max) \
static void object##_led_set(struct led_classdev *led_cdev, \
enum led_brightness value); \
static enum led_brightness object##_led_get( \
struct led_classdev *led_cdev); \
static void object##_led_update(struct work_struct *ignored); \
static int object##_led_wk; \
static DECLARE_WORK(object##_led_work, object##_led_update); \
static struct led_classdev object##_led = { \
.name = "asus::" ledname, \
.brightness_set = object##_led_set, \
.brightness_get = object##_led_get, \
.max_brightness = max \
}
ASUS_LED
(
mled
,
"mail"
,
1
);
acpi_handle
handle
;
/* the handle of the hotk device */
ASUS_LED
(
tled
,
"touchpad"
,
1
);
u32
ledd_status
;
/* status of the LED display */
ASUS_LED
(
rled
,
"record"
,
1
);
u8
light_level
;
/* light sensor level */
ASUS_LED
(
pled
,
"phone"
,
1
);
u8
light_switch
;
/* light sensor switch value */
ASUS_LED
(
gled
,
"gaming"
,
1
);
u16
event_count
[
128
];
/* count for each event TODO make this better */
ASUS_LED
(
kled
,
"kbd_backlight"
,
3
);
u16
*
keycode_map
;
struct
key_entry
{
char
type
;
u8
code
;
u16
keycode
;
};
};
enum
{
KE_KEY
,
KE_END
};
static
const
struct
key_entry
asus_keymap
[]
=
{
/* Lenovo SL Specific keycodes */
static
struct
key_entry
asus_keymap
[]
=
{
{
KE_KEY
,
0x02
,
{
KEY_SCREENLOCK
}
},
{
KE_KEY
,
0x02
,
KEY_SCREENLOCK
},
{
KE_KEY
,
0x05
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x05
,
KEY_WLAN
},
{
KE_KEY
,
0x08
,
{
KEY_F13
}
},
{
KE_KEY
,
0x08
,
KEY_F13
},
{
KE_KEY
,
0x17
,
{
KEY_ZOOM
}
},
{
KE_KEY
,
0x17
,
KEY_ZOOM
},
{
KE_KEY
,
0x1f
,
{
KEY_BATTERY
}
},
{
KE_KEY
,
0x1f
,
KEY_BATTERY
},
/* End of Lenovo SL Specific keycodes */
{
KE_KEY
,
0x30
,
KEY_VOLUMEUP
},
{
KE_KEY
,
0x30
,
{
KEY_VOLUMEUP
}
},
{
KE_KEY
,
0x31
,
KEY_VOLUMEDOWN
},
{
KE_KEY
,
0x31
,
{
KEY_VOLUMEDOWN
}
},
{
KE_KEY
,
0x32
,
KEY_MUTE
},
{
KE_KEY
,
0x32
,
{
KEY_MUTE
}
},
{
KE_KEY
,
0x33
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x33
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x34
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x34
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x40
,
KEY_PREVIOUSSONG
},
{
KE_KEY
,
0x40
,
{
KEY_PREVIOUSSONG
}
},
{
KE_KEY
,
0x41
,
KEY_NEXTSONG
},
{
KE_KEY
,
0x41
,
{
KEY_NEXTSONG
}
},
{
KE_KEY
,
0x43
,
KEY_STOPCD
},
{
KE_KEY
,
0x43
,
{
KEY_STOPCD
}
},
{
KE_KEY
,
0x45
,
KEY_PLAYPAUSE
},
{
KE_KEY
,
0x45
,
{
KEY_PLAYPAUSE
}
},
{
KE_KEY
,
0x4c
,
KEY_MEDIA
},
{
KE_KEY
,
0x4c
,
{
KEY_MEDIA
}
},
{
KE_KEY
,
0x50
,
KEY_EMAIL
},
{
KE_KEY
,
0x50
,
{
KEY_EMAIL
}
},
{
KE_KEY
,
0x51
,
KEY_WWW
},
{
KE_KEY
,
0x51
,
{
KEY_WWW
}
},
{
KE_KEY
,
0x55
,
KEY_CALC
},
{
KE_KEY
,
0x55
,
{
KEY_CALC
}
},
{
KE_KEY
,
0x5C
,
KEY_SCREENLOCK
},
/* Screenlock */
{
KE_KEY
,
0x5C
,
{
KEY_SCREENLOCK
}
},
/* Screenlock */
{
KE_KEY
,
0x5D
,
KEY_WLAN
},
{
KE_KEY
,
0x5D
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x5E
,
KEY_WLAN
},
{
KE_KEY
,
0x5E
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x5F
,
KEY_WLAN
},
{
KE_KEY
,
0x5F
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x60
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x60
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x61
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x61
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x62
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x62
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x63
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x63
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x6B
,
KEY_F13
},
/* Lock Touchpad */
{
KE_KEY
,
0x6B
,
{
KEY_F13
}
},
/* Lock Touchpad */
{
KE_KEY
,
0x82
,
KEY_CAMERA
},
{
KE_KEY
,
0x7E
,
{
KEY_BLUETOOTH
}
},
{
KE_KEY
,
0x88
,
KEY_WLAN
},
{
KE_KEY
,
0x7D
,
{
KEY_BLUETOOTH
}
},
{
KE_KEY
,
0x8A
,
KEY_PROG1
},
{
KE_KEY
,
0x82
,
{
KEY_CAMERA
}
},
{
KE_KEY
,
0x95
,
KEY_MEDIA
},
{
KE_KEY
,
0x88
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x99
,
KEY_PHONE
},
{
KE_KEY
,
0x8A
,
{
KEY_PROG1
}
},
{
KE_KEY
,
0xc4
,
KEY_KBDILLUMUP
},
{
KE_KEY
,
0x95
,
{
KEY_MEDIA
}
},
{
KE_KEY
,
0xc5
,
KEY_KBDILLUMDOWN
},
{
KE_KEY
,
0x99
,
{
KEY_PHONE
}
},
{
KE_KEY
,
0xc4
,
{
KEY_KBDILLUMUP
}
},
{
KE_KEY
,
0xc5
,
{
KEY_KBDILLUMDOWN
}
},
{
KE_END
,
0
},
{
KE_END
,
0
},
};
};
/*
/*
* This function evaluates an ACPI method, given an int as parameter, the
* This function evaluates an ACPI method, given an int as parameter, the
* method is searched within the scope of the handle, can be NULL. The output
* method is searched within the scope of the handle, can be NULL. The output
...
@@ -339,8 +288,8 @@ static struct key_entry asus_keymap[] = {
...
@@ -339,8 +288,8 @@ static struct key_entry asus_keymap[] = {
*
*
* returns 0 if write is successful, -1 else.
* returns 0 if write is successful, -1 else.
*/
*/
static
int
write_acpi_int
(
acpi_handle
handle
,
const
char
*
method
,
int
val
,
static
int
write_acpi_int
_ret
(
acpi_handle
handle
,
const
char
*
method
,
int
val
,
struct
acpi_buffer
*
output
)
struct
acpi_buffer
*
output
)
{
{
struct
acpi_object_list
params
;
/* list of input parameters (an int) */
struct
acpi_object_list
params
;
/* list of input parameters (an int) */
union
acpi_object
in_obj
;
/* the only param we use */
union
acpi_object
in_obj
;
/* the only param we use */
...
@@ -361,102 +310,82 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
...
@@ -361,102 +310,82 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
return
-
1
;
return
-
1
;
}
}
static
int
read_wireless_status
(
int
mask
)
static
int
write_acpi_int
(
acpi_handle
handle
,
const
char
*
method
,
int
val
)
{
{
unsigned
long
long
status
;
return
write_acpi_int_ret
(
handle
,
method
,
val
,
NULL
);
acpi_status
rv
=
AE_OK
;
}
static
int
acpi_check_handle
(
acpi_handle
handle
,
const
char
*
method
,
acpi_handle
*
ret
)
{
acpi_status
status
;
if
(
!
wireless_status_handle
)
if
(
method
==
NULL
)
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
return
-
ENODEV
;
rv
=
acpi_evaluate_integer
(
wireless_status_handle
,
NULL
,
NULL
,
&
status
);
if
(
ret
)
if
(
ACPI_FAILURE
(
rv
))
status
=
acpi_get_handle
(
handle
,
(
char
*
)
method
,
pr_warning
(
"Error reading Wireless status
\n
"
);
ret
);
else
else
{
return
(
status
&
mask
)
?
1
:
0
;
acpi_handle
dummy
;
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
status
=
acpi_get_handle
(
handle
,
(
char
*
)
method
,
&
dummy
);
}
if
(
status
!=
AE_OK
)
{
if
(
ret
)
pr_warning
(
"Error finding %s
\n
"
,
method
);
return
-
ENODEV
;
}
return
0
;
}
}
static
int
read_gps_status
(
void
)
/* Generic LED function */
static
int
asus_led_set
(
struct
asus_laptop
*
asus
,
const
char
*
method
,
int
value
)
{
{
unsigned
long
long
status
;
if
(
!
strcmp
(
method
,
METHOD_MLED
))
acpi_status
rv
=
AE_OK
;
value
=
!
value
;
else
if
(
!
strcmp
(
method
,
METHOD_GLED
))
rv
=
acpi_evaluate_integer
(
gps_status_handle
,
NULL
,
NULL
,
&
status
);
value
=
!
value
+
1
;
if
(
ACPI_FAILURE
(
rv
))
pr_warning
(
"Error reading GPS status
\n
"
);
else
else
return
status
?
1
:
0
;
value
=
!!
value
;
return
(
hotk
->
status
&
GPS_ON
)
?
1
:
0
;
return
write_acpi_int
(
asus
->
handle
,
method
,
value
)
;
}
}
/* Generic LED functions */
/*
static
int
read_status
(
int
mask
)
* LEDs
*/
/* /sys/class/led handlers */
static
void
asus_led_cdev_set
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
{
{
/* There is a special method for both wireless devices */
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
if
(
mask
==
BT_ON
||
mask
==
WL_ON
)
struct
asus_laptop
*
asus
=
led
->
asus
;
return
read_wireless_status
(
mask
);
else
if
(
mask
==
GPS_ON
)
return
read_gps_status
();
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
led
->
wk
=
!!
value
;
queue_work
(
asus
->
led_workqueue
,
&
led
->
work
);
}
}
static
void
write_status
(
acpi_handle
handle
,
int
out
,
int
mas
k
)
static
void
asus_led_cdev_update
(
struct
work_struct
*
wor
k
)
{
{
hotk
->
status
=
(
out
)
?
(
hotk
->
status
|
mask
)
:
(
hotk
->
status
&
~
mask
);
struct
asus_led
*
led
=
container_of
(
work
,
struct
asus_led
,
work
);
struct
asus_laptop
*
asus
=
led
->
asus
;
switch
(
mask
)
{
case
MLED_ON
:
out
=
!
(
out
&
0x1
);
break
;
case
GLED_ON
:
out
=
(
out
&
0x1
)
+
1
;
break
;
case
GPS_ON
:
handle
=
(
out
)
?
gps_on_handle
:
gps_off_handle
;
out
=
0x02
;
break
;
default:
out
&=
0x1
;
break
;
}
if
(
write_acpi_int
(
handle
,
NULL
,
out
,
NULL
))
asus_led_set
(
asus
,
led
->
method
,
led
->
wk
);
pr_warning
(
" write failed %x
\n
"
,
mask
);
}
}
/* /sys/class/led handlers */
static
enum
led_brightness
asus_led_cdev_get
(
struct
led_classdev
*
led_cdev
)
#define ASUS_LED_HANDLER(object, mask) \
{
static void object##_led_set(struct led_classdev *led_cdev, \
return
led_cdev
->
brightness
;
enum led_brightness value) \
}
{ \
object##_led_wk = (value > 0) ? 1 : 0; \
queue_work(led_workqueue, &object##_led_work); \
} \
static void object##_led_update(struct work_struct *ignored) \
{ \
int value = object##_led_wk; \
write_status(object##_set_handle, value, (mask)); \
} \
static enum led_brightness object##_led_get( \
struct led_classdev *led_cdev) \
{ \
return led_cdev->brightness; \
}
ASUS_LED_HANDLER
(
mled
,
MLED_ON
);
ASUS_LED_HANDLER
(
pled
,
PLED_ON
);
ASUS_LED_HANDLER
(
rled
,
RLED_ON
);
ASUS_LED_HANDLER
(
tled
,
TLED_ON
);
ASUS_LED_HANDLER
(
gled
,
GLED_ON
);
/*
/*
* Keyboard backlight
* Keyboard backlight
(also a LED)
*/
*/
static
int
get_kled_lvl
(
void
)
static
int
asus_kled_lvl
(
struct
asus_laptop
*
asus
)
{
{
unsigned
long
long
kblv
;
unsigned
long
long
kblv
;
struct
acpi_object_list
params
;
struct
acpi_object_list
params
;
...
@@ -468,75 +397,183 @@ static int get_kled_lvl(void)
...
@@ -468,75 +397,183 @@ static int get_kled_lvl(void)
in_obj
.
type
=
ACPI_TYPE_INTEGER
;
in_obj
.
type
=
ACPI_TYPE_INTEGER
;
in_obj
.
integer
.
value
=
2
;
in_obj
.
integer
.
value
=
2
;
rv
=
acpi_evaluate_integer
(
kled_get_handle
,
NULL
,
&
params
,
&
kblv
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
METHOD_KBD_LIGHT_GET
,
&
params
,
&
kblv
);
if
(
ACPI_FAILURE
(
rv
))
{
if
(
ACPI_FAILURE
(
rv
))
{
pr_warning
(
"Error reading kled level
\n
"
);
pr_warning
(
"Error reading kled level
\n
"
);
return
0
;
return
-
ENODEV
;
}
}
return
kblv
;
return
kblv
;
}
}
static
int
set_kled_lvl
(
int
kblv
)
static
int
asus_kled_set
(
struct
asus_laptop
*
asus
,
int
kblv
)
{
{
if
(
kblv
>
0
)
if
(
kblv
>
0
)
kblv
=
(
1
<<
7
)
|
(
kblv
&
0x7F
);
kblv
=
(
1
<<
7
)
|
(
kblv
&
0x7F
);
else
else
kblv
=
0
;
kblv
=
0
;
if
(
write_acpi_int
(
kled_set_handle
,
NULL
,
kblv
,
NULL
))
{
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_KBD_LIGHT_SET
,
kblv
))
{
pr_warning
(
"Keyboard LED display write failed
\n
"
);
pr_warning
(
"Keyboard LED display write failed
\n
"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
return
0
;
return
0
;
}
}
static
void
kled_led
_set
(
struct
led_classdev
*
led_cdev
,
static
void
asus_kled_cdev
_set
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
enum
led_brightness
value
)
{
{
kled_led_wk
=
value
;
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
queue_work
(
led_workqueue
,
&
kled_led_work
);
struct
asus_laptop
*
asus
=
led
->
asus
;
led
->
wk
=
value
;
queue_work
(
asus
->
led_workqueue
,
&
led
->
work
);
}
}
static
void
kled_led_update
(
struct
work_struct
*
ignored
)
static
void
asus_kled_cdev_update
(
struct
work_struct
*
work
)
{
{
set_kled_lvl
(
kled_led_wk
);
struct
asus_led
*
led
=
container_of
(
work
,
struct
asus_led
,
work
);
struct
asus_laptop
*
asus
=
led
->
asus
;
asus_kled_set
(
asus
,
led
->
wk
);
}
}
static
enum
led_brightness
kled_led
_get
(
struct
led_classdev
*
led_cdev
)
static
enum
led_brightness
asus_kled_cdev
_get
(
struct
led_classdev
*
led_cdev
)
{
{
return
get_kled_lvl
();
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
struct
asus_laptop
*
asus
=
led
->
asus
;
return
asus_kled_lvl
(
asus
);
}
}
static
int
get_lcd_state
(
void
)
static
void
asus_led_exit
(
struct
asus_laptop
*
asus
)
{
{
return
read_status
(
LCD_ON
);
if
(
asus
->
mled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
mled
.
led
);
if
(
asus
->
tled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
tled
.
led
);
if
(
asus
->
pled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
pled
.
led
);
if
(
asus
->
rled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
rled
.
led
);
if
(
asus
->
gled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
gled
.
led
);
if
(
asus
->
kled
.
led
.
dev
)
led_classdev_unregister
(
&
asus
->
kled
.
led
);
if
(
asus
->
led_workqueue
)
{
destroy_workqueue
(
asus
->
led_workqueue
);
asus
->
led_workqueue
=
NULL
;
}
}
}
static
int
set_lcd_state
(
int
value
)
/* Ugly macro, need to fix that later */
static
int
asus_led_register
(
struct
asus_laptop
*
asus
,
struct
asus_led
*
led
,
const
char
*
name
,
const
char
*
method
)
{
struct
led_classdev
*
led_cdev
=
&
led
->
led
;
if
(
!
method
||
acpi_check_handle
(
asus
->
handle
,
method
,
NULL
))
return
0
;
/* Led not present */
led
->
asus
=
asus
;
led
->
method
=
method
;
INIT_WORK
(
&
led
->
work
,
asus_led_cdev_update
);
led_cdev
->
name
=
name
;
led_cdev
->
brightness_set
=
asus_led_cdev_set
;
led_cdev
->
brightness_get
=
asus_led_cdev_get
;
led_cdev
->
max_brightness
=
1
;
return
led_classdev_register
(
&
asus
->
platform_device
->
dev
,
led_cdev
);
}
static
int
asus_led_init
(
struct
asus_laptop
*
asus
)
{
int
r
;
/*
* Functions that actually update the LED's are called from a
* workqueue. By doing this as separate work rather than when the LED
* subsystem asks, we avoid messing with the Asus ACPI stuff during a
* potentially bad time, such as a timer interrupt.
*/
asus
->
led_workqueue
=
create_singlethread_workqueue
(
"led_workqueue"
);
if
(
!
asus
->
led_workqueue
)
return
-
ENOMEM
;
r
=
asus_led_register
(
asus
,
&
asus
->
mled
,
"asus::mail"
,
METHOD_MLED
);
if
(
r
)
goto
error
;
r
=
asus_led_register
(
asus
,
&
asus
->
tled
,
"asus::touchpad"
,
METHOD_TLED
);
if
(
r
)
goto
error
;
r
=
asus_led_register
(
asus
,
&
asus
->
rled
,
"asus::record"
,
METHOD_RLED
);
if
(
r
)
goto
error
;
r
=
asus_led_register
(
asus
,
&
asus
->
pled
,
"asus::phone"
,
METHOD_PLED
);
if
(
r
)
goto
error
;
r
=
asus_led_register
(
asus
,
&
asus
->
gled
,
"asus::gaming"
,
METHOD_GLED
);
if
(
r
)
goto
error
;
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_KBD_LIGHT_SET
,
NULL
)
&&
!
acpi_check_handle
(
asus
->
handle
,
METHOD_KBD_LIGHT_GET
,
NULL
))
{
struct
asus_led
*
led
=
&
asus
->
kled
;
struct
led_classdev
*
cdev
=
&
led
->
led
;
led
->
asus
=
asus
;
INIT_WORK
(
&
led
->
work
,
asus_kled_cdev_update
);
cdev
->
name
=
"asus::kbd_backlight"
;
cdev
->
brightness_set
=
asus_kled_cdev_set
;
cdev
->
brightness_get
=
asus_kled_cdev_get
;
cdev
->
max_brightness
=
3
;
r
=
led_classdev_register
(
&
asus
->
platform_device
->
dev
,
cdev
);
}
error:
if
(
r
)
asus_led_exit
(
asus
);
return
r
;
}
/*
* Backlight device
*/
static
int
asus_lcd_status
(
struct
asus_laptop
*
asus
)
{
return
asus
->
lcd_state
;
}
static
int
asus_lcd_set
(
struct
asus_laptop
*
asus
,
int
value
)
{
{
int
lcd
=
0
;
int
lcd
=
0
;
acpi_status
status
=
0
;
acpi_status
status
=
0
;
lcd
=
value
?
1
:
0
;
lcd
=
!!
value
;
if
(
lcd
==
get_lcd_state
(
))
if
(
lcd
==
asus_lcd_status
(
asus
))
return
0
;
return
0
;
if
(
lcd_switch_handle
)
{
if
(
!
lcd_switch_handle
)
status
=
acpi_evaluate_object
(
lcd_switch_handle
,
return
-
ENODEV
;
NULL
,
NULL
,
NULL
);
status
=
acpi_evaluate_object
(
lcd_switch_handle
,
NULL
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
{
pr_warning
(
"Error switching LCD
\n
"
);
pr_warning
(
"Error switching LCD
\n
"
);
return
-
ENODEV
;
}
}
write_status
(
NULL
,
lcd
,
LCD_ON
)
;
asus
->
lcd_state
=
lcd
;
return
0
;
return
0
;
}
}
static
void
lcd_blank
(
int
blank
)
static
void
lcd_blank
(
struct
asus_laptop
*
asus
,
int
blank
)
{
{
struct
backlight_device
*
bd
=
asus_backlight_device
;
struct
backlight_device
*
bd
=
asus
->
backlight_device
;
asus
->
lcd_state
=
(
blank
==
FB_BLANK_UNBLANK
);
if
(
bd
)
{
if
(
bd
)
{
bd
->
props
.
power
=
blank
;
bd
->
props
.
power
=
blank
;
...
@@ -544,44 +581,91 @@ static void lcd_blank(int blank)
...
@@ -544,44 +581,91 @@ static void lcd_blank(int blank)
}
}
}
}
static
int
read_brightness
(
struct
backlight_device
*
bd
)
static
int
asus_
read_brightness
(
struct
backlight_device
*
bd
)
{
{
struct
asus_laptop
*
asus
=
bl_get_data
(
bd
);
unsigned
long
long
value
;
unsigned
long
long
value
;
acpi_status
rv
=
AE_OK
;
acpi_status
rv
=
AE_OK
;
rv
=
acpi_evaluate_integer
(
brightness_get_handle
,
NULL
,
NULL
,
&
value
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
METHOD_BRIGHTNESS_GET
,
NULL
,
&
value
);
if
(
ACPI_FAILURE
(
rv
))
if
(
ACPI_FAILURE
(
rv
))
pr_warning
(
"Error reading brightness
\n
"
);
pr_warning
(
"Error reading brightness
\n
"
);
return
value
;
return
value
;
}
}
static
int
set_brightness
(
struct
backlight_device
*
bd
,
int
value
)
static
int
asus_
set_brightness
(
struct
backlight_device
*
bd
,
int
value
)
{
{
int
ret
=
0
;
struct
asus_laptop
*
asus
=
bl_get_data
(
bd
);
value
=
(
0
<
value
)
?
((
15
<
value
)
?
15
:
value
)
:
0
;
/* 0 <= value <= 15 */
if
(
write_acpi_int
(
brightness_set_handle
,
NULL
,
value
,
NULL
))
{
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_BRIGHTNESS_SET
,
value
))
{
pr_warning
(
"Error changing brightness
\n
"
);
pr_warning
(
"Error changing brightness
\n
"
);
ret
=
-
EIO
;
ret
urn
-
EIO
;
}
}
return
0
;
return
ret
;
}
}
static
int
update_bl_status
(
struct
backlight_device
*
bd
)
static
int
update_bl_status
(
struct
backlight_device
*
bd
)
{
{
struct
asus_laptop
*
asus
=
bl_get_data
(
bd
);
int
rv
;
int
rv
;
int
value
=
bd
->
props
.
brightness
;
int
value
=
bd
->
props
.
brightness
;
rv
=
set_brightness
(
bd
,
value
);
rv
=
asus_
set_brightness
(
bd
,
value
);
if
(
rv
)
if
(
rv
)
return
rv
;
return
rv
;
value
=
(
bd
->
props
.
power
==
FB_BLANK_UNBLANK
)
?
1
:
0
;
value
=
(
bd
->
props
.
power
==
FB_BLANK_UNBLANK
)
?
1
:
0
;
return
set_lcd_state
(
value
);
return
asus_lcd_set
(
asus
,
value
);
}
static
struct
backlight_ops
asusbl_ops
=
{
.
get_brightness
=
asus_read_brightness
,
.
update_status
=
update_bl_status
,
};
static
int
asus_backlight_notify
(
struct
asus_laptop
*
asus
)
{
struct
backlight_device
*
bd
=
asus
->
backlight_device
;
int
old
=
bd
->
props
.
brightness
;
backlight_force_update
(
bd
,
BACKLIGHT_UPDATE_HOTKEY
);
return
old
;
}
static
int
asus_backlight_init
(
struct
asus_laptop
*
asus
)
{
struct
backlight_device
*
bd
;
struct
device
*
dev
=
&
asus
->
platform_device
->
dev
;
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_BRIGHTNESS_GET
,
NULL
)
&&
!
acpi_check_handle
(
asus
->
handle
,
METHOD_BRIGHTNESS_SET
,
NULL
)
&&
lcd_switch_handle
)
{
bd
=
backlight_device_register
(
ASUS_LAPTOP_FILE
,
dev
,
asus
,
&
asusbl_ops
);
if
(
IS_ERR
(
bd
))
{
pr_err
(
"Could not register asus backlight device
\n
"
);
asus
->
backlight_device
=
NULL
;
return
PTR_ERR
(
bd
);
}
asus
->
backlight_device
=
bd
;
bd
->
props
.
max_brightness
=
15
;
bd
->
props
.
power
=
FB_BLANK_UNBLANK
;
bd
->
props
.
brightness
=
asus_read_brightness
(
bd
);
backlight_update_status
(
bd
);
}
return
0
;
}
static
void
asus_backlight_exit
(
struct
asus_laptop
*
asus
)
{
if
(
asus
->
backlight_device
)
backlight_device_unregister
(
asus
->
backlight_device
);
asus
->
backlight_device
=
NULL
;
}
}
/*
/*
...
@@ -596,25 +680,26 @@ static int update_bl_status(struct backlight_device *bd)
...
@@ -596,25 +680,26 @@ static int update_bl_status(struct backlight_device *bd)
static
ssize_t
show_infos
(
struct
device
*
dev
,
static
ssize_t
show_infos
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
page
)
struct
device_attribute
*
attr
,
char
*
page
)
{
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
len
=
0
;
int
len
=
0
;
unsigned
long
long
temp
;
unsigned
long
long
temp
;
char
buf
[
16
];
/* enough for all info */
char
buf
[
16
];
/* enough for all info */
acpi_status
rv
=
AE_OK
;
acpi_status
rv
=
AE_OK
;
/*
/*
* We use the easy way, we don't care of off and count,
so we don't set eof
* We use the easy way, we don't care of off and count,
* to 1
*
so we don't set eof
to 1
*/
*/
len
+=
sprintf
(
page
,
ASUS_
HOTK
_NAME
" "
ASUS_LAPTOP_VERSION
"
\n
"
);
len
+=
sprintf
(
page
,
ASUS_
LAPTOP
_NAME
" "
ASUS_LAPTOP_VERSION
"
\n
"
);
len
+=
sprintf
(
page
+
len
,
"Model reference : %s
\n
"
,
hotk
->
name
);
len
+=
sprintf
(
page
+
len
,
"Model reference : %s
\n
"
,
asus
->
name
);
/*
/*
* The SFUN method probably allows the original driver to get the list
* The SFUN method probably allows the original driver to get the list
* of features supported by a given model. For now, 0x0100 or 0x0800
* of features supported by a given model. For now, 0x0100 or 0x0800
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
* The significance of others is yet to be found.
* The significance of others is yet to be found.
*/
*/
rv
=
acpi_evaluate_integer
(
hotk
->
handle
,
"SFUN"
,
NULL
,
&
temp
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
"SFUN"
,
NULL
,
&
temp
);
if
(
!
ACPI_FAILURE
(
rv
))
if
(
!
ACPI_FAILURE
(
rv
))
len
+=
sprintf
(
page
+
len
,
"SFUN value : %#x
\n
"
,
len
+=
sprintf
(
page
+
len
,
"SFUN value : %#x
\n
"
,
(
uint
)
temp
);
(
uint
)
temp
);
...
@@ -624,7 +709,7 @@ static ssize_t show_infos(struct device *dev,
...
@@ -624,7 +709,7 @@ static ssize_t show_infos(struct device *dev,
* The significance of others is yet to be found.
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
* If we don't find the method, we assume the device are present.
*/
*/
rv
=
acpi_evaluate_integer
(
hotk
->
handle
,
"HRWS"
,
NULL
,
&
temp
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
"HRWS"
,
NULL
,
&
temp
);
if
(
!
ACPI_FAILURE
(
rv
))
if
(
!
ACPI_FAILURE
(
rv
))
len
+=
sprintf
(
page
+
len
,
"HRWS value : %#x
\n
"
,
len
+=
sprintf
(
page
+
len
,
"HRWS value : %#x
\n
"
,
(
uint
)
temp
);
(
uint
)
temp
);
...
@@ -635,26 +720,26 @@ static ssize_t show_infos(struct device *dev,
...
@@ -635,26 +720,26 @@ static ssize_t show_infos(struct device *dev,
* Note: since not all the laptops provide this method, errors are
* Note: since not all the laptops provide this method, errors are
* silently ignored.
* silently ignored.
*/
*/
rv
=
acpi_evaluate_integer
(
hotk
->
handle
,
"ASYM"
,
NULL
,
&
temp
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
"ASYM"
,
NULL
,
&
temp
);
if
(
!
ACPI_FAILURE
(
rv
))
if
(
!
ACPI_FAILURE
(
rv
))
len
+=
sprintf
(
page
+
len
,
"ASYM value : %#x
\n
"
,
len
+=
sprintf
(
page
+
len
,
"ASYM value : %#x
\n
"
,
(
uint
)
temp
);
(
uint
)
temp
);
if
(
asus_info
)
{
if
(
asus
->
dsdt
_info
)
{
snprintf
(
buf
,
16
,
"%d"
,
asus_info
->
length
);
snprintf
(
buf
,
16
,
"%d"
,
asus
->
dsdt
_info
->
length
);
len
+=
sprintf
(
page
+
len
,
"DSDT length : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"DSDT length : %s
\n
"
,
buf
);
snprintf
(
buf
,
16
,
"%d"
,
asus_info
->
checksum
);
snprintf
(
buf
,
16
,
"%d"
,
asus
->
dsdt
_info
->
checksum
);
len
+=
sprintf
(
page
+
len
,
"DSDT checksum : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"DSDT checksum : %s
\n
"
,
buf
);
snprintf
(
buf
,
16
,
"%d"
,
asus_info
->
revision
);
snprintf
(
buf
,
16
,
"%d"
,
asus
->
dsdt
_info
->
revision
);
len
+=
sprintf
(
page
+
len
,
"DSDT revision : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"DSDT revision : %s
\n
"
,
buf
);
snprintf
(
buf
,
7
,
"%s"
,
asus_info
->
oem_id
);
snprintf
(
buf
,
7
,
"%s"
,
asus
->
dsdt
_info
->
oem_id
);
len
+=
sprintf
(
page
+
len
,
"OEM id : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"OEM id : %s
\n
"
,
buf
);
snprintf
(
buf
,
9
,
"%s"
,
asus_info
->
oem_table_id
);
snprintf
(
buf
,
9
,
"%s"
,
asus
->
dsdt
_info
->
oem_table_id
);
len
+=
sprintf
(
page
+
len
,
"OEM table id : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"OEM table id : %s
\n
"
,
buf
);
snprintf
(
buf
,
16
,
"%x"
,
asus_info
->
oem_revision
);
snprintf
(
buf
,
16
,
"%x"
,
asus
->
dsdt
_info
->
oem_revision
);
len
+=
sprintf
(
page
+
len
,
"OEM revision : 0x%s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"OEM revision : 0x%s
\n
"
,
buf
);
snprintf
(
buf
,
5
,
"%s"
,
asus_info
->
asl_compiler_id
);
snprintf
(
buf
,
5
,
"%s"
,
asus
->
dsdt
_info
->
asl_compiler_id
);
len
+=
sprintf
(
page
+
len
,
"ASL comp vendor id : %s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"ASL comp vendor id : %s
\n
"
,
buf
);
snprintf
(
buf
,
16
,
"%x"
,
asus_info
->
asl_compiler_revision
);
snprintf
(
buf
,
16
,
"%x"
,
asus
->
dsdt
_info
->
asl_compiler_revision
);
len
+=
sprintf
(
page
+
len
,
"ASL comp revision : 0x%s
\n
"
,
buf
);
len
+=
sprintf
(
page
+
len
,
"ASL comp revision : 0x%s
\n
"
,
buf
);
}
}
...
@@ -672,8 +757,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
...
@@ -672,8 +757,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
return
count
;
return
count
;
}
}
static
ssize_t
store_status
(
const
char
*
buf
,
size_t
count
,
static
ssize_t
sysfs_acpi_set
(
struct
asus_laptop
*
asus
,
acpi_handle
handle
,
int
mask
)
const
char
*
buf
,
size_t
count
,
const
char
*
method
)
{
{
int
rv
,
value
;
int
rv
,
value
;
int
out
=
0
;
int
out
=
0
;
...
@@ -682,8 +768,8 @@ static ssize_t store_status(const char *buf, size_t count,
...
@@ -682,8 +768,8 @@ static ssize_t store_status(const char *buf, size_t count,
if
(
rv
>
0
)
if
(
rv
>
0
)
out
=
value
?
1
:
0
;
out
=
value
?
1
:
0
;
write_status
(
handle
,
out
,
mask
);
if
(
write_acpi_int
(
asus
->
handle
,
method
,
value
))
return
-
ENODEV
;
return
rv
;
return
rv
;
}
}
...
@@ -693,67 +779,116 @@ static ssize_t store_status(const char *buf, size_t count,
...
@@ -693,67 +779,116 @@ static ssize_t store_status(const char *buf, size_t count,
static
ssize_t
show_ledd
(
struct
device
*
dev
,
static
ssize_t
show_ledd
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"0x%08x
\n
"
,
hotk
->
ledd_status
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"0x%08x
\n
"
,
asus
->
ledd_status
);
}
}
static
ssize_t
store_ledd
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_ledd
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
{
if
(
rv
>
0
)
{
if
(
write_acpi_int
(
ledd_set_handle
,
NULL
,
value
,
NULL
))
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_LEDD
,
value
))
pr_warning
(
"LED display write failed
\n
"
);
pr_warning
(
"LED display write failed
\n
"
);
else
else
hotk
->
ledd_status
=
(
u32
)
value
;
asus
->
ledd_status
=
(
u32
)
value
;
}
}
return
rv
;
return
rv
;
}
}
/*
* Wireless
*/
static
int
asus_wireless_status
(
struct
asus_laptop
*
asus
,
int
mask
)
{
unsigned
long
long
status
;
acpi_status
rv
=
AE_OK
;
if
(
!
asus
->
have_rsts
)
return
(
asus
->
wireless_status
&
mask
)
?
1
:
0
;
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
METHOD_WL_STATUS
,
NULL
,
&
status
);
if
(
ACPI_FAILURE
(
rv
))
{
pr_warning
(
"Error reading Wireless status
\n
"
);
return
-
EINVAL
;
}
return
!!
(
status
&
mask
);
}
/*
/*
* WLAN
* WLAN
*/
*/
static
int
asus_wlan_set
(
struct
asus_laptop
*
asus
,
int
status
)
{
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_WLAN
,
!!
status
))
{
pr_warning
(
"Error setting wlan status to %d"
,
status
);
return
-
EIO
;
}
return
0
;
}
static
ssize_t
show_wlan
(
struct
device
*
dev
,
static
ssize_t
show_wlan
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
read_status
(
WL_ON
));
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%d
\n
"
,
asus_wireless_status
(
asus
,
WL_RSTS
));
}
}
static
ssize_t
store_wlan
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_wlan
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
return
store_status
(
buf
,
count
,
wl_switch_handle
,
WL_ON
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sysfs_acpi_set
(
asus
,
buf
,
count
,
METHOD_WLAN
);
}
}
/*
/*
* Bluetooth
* Bluetooth
*/
*/
static
int
asus_bluetooth_set
(
struct
asus_laptop
*
asus
,
int
status
)
{
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_BLUETOOTH
,
!!
status
))
{
pr_warning
(
"Error setting bluetooth status to %d"
,
status
);
return
-
EIO
;
}
return
0
;
}
static
ssize_t
show_bluetooth
(
struct
device
*
dev
,
static
ssize_t
show_bluetooth
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
read_status
(
BT_ON
));
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%d
\n
"
,
asus_wireless_status
(
asus
,
BT_RSTS
));
}
}
static
ssize_t
store_bluetooth
(
struct
device
*
dev
,
static
ssize_t
store_bluetooth
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
size_t
count
)
{
{
return
store_status
(
buf
,
count
,
bt_switch_handle
,
BT_ON
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sysfs_acpi_set
(
asus
,
buf
,
count
,
METHOD_BLUETOOTH
);
}
}
/*
/*
* Display
* Display
*/
*/
static
void
set_display
(
int
value
)
static
void
asus_set_display
(
struct
asus_laptop
*
asus
,
int
value
)
{
{
/* no sanity check needed for now */
/* no sanity check needed for now */
if
(
write_acpi_int
(
display_set_handle
,
NULL
,
value
,
NULL
))
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_SWITCH_DISPLAY
,
value
))
pr_warning
(
"Error setting display
\n
"
);
pr_warning
(
"Error setting display
\n
"
);
return
;
return
;
}
}
static
int
read_display
(
void
)
static
int
read_display
(
struct
asus_laptop
*
asus
)
{
{
unsigned
long
long
value
=
0
;
unsigned
long
long
value
=
0
;
acpi_status
rv
=
AE_OK
;
acpi_status
rv
=
AE_OK
;
...
@@ -769,7 +904,7 @@ static int read_display(void)
...
@@ -769,7 +904,7 @@ static int read_display(void)
pr_warning
(
"Error reading display status
\n
"
);
pr_warning
(
"Error reading display status
\n
"
);
}
}
value
&=
0x0F
;
/* needed for some models, shouldn't hurt others */
value
&=
0x0F
;
/* needed for some models, shouldn't hurt others */
return
value
;
return
value
;
}
}
...
@@ -781,7 +916,11 @@ static int read_display(void)
...
@@ -781,7 +916,11 @@ static int read_display(void)
static
ssize_t
show_disp
(
struct
device
*
dev
,
static
ssize_t
show_disp
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
read_display
());
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
if
(
!
display_get_handle
)
return
-
ENODEV
;
return
sprintf
(
buf
,
"%d
\n
"
,
read_display
(
asus
));
}
}
/*
/*
...
@@ -794,65 +933,72 @@ static ssize_t show_disp(struct device *dev,
...
@@ -794,65 +933,72 @@ static ssize_t show_disp(struct device *dev,
static
ssize_t
store_disp
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_disp
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
if
(
rv
>
0
)
set_display
(
value
);
asus_set_display
(
asus
,
value
);
return
rv
;
return
rv
;
}
}
/*
/*
* Light Sens
* Light Sens
*/
*/
static
void
set_light_sens_switch
(
int
value
)
static
void
asus_als_switch
(
struct
asus_laptop
*
asus
,
int
value
)
{
{
if
(
write_acpi_int
(
ls_switch_handle
,
NULL
,
value
,
NULL
))
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_ALS_CONTROL
,
value
))
pr_warning
(
"Error setting light sensor switch
\n
"
);
pr_warning
(
"Error setting light sensor switch
\n
"
);
hotk
->
light_switch
=
value
;
asus
->
light_switch
=
value
;
}
}
static
ssize_t
show_lssw
(
struct
device
*
dev
,
static
ssize_t
show_lssw
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
hotk
->
light_switch
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%d
\n
"
,
asus
->
light_switch
);
}
}
static
ssize_t
store_lssw
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_lssw
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
if
(
rv
>
0
)
set_light_sens_switch
(
value
?
1
:
0
);
asus_als_switch
(
asus
,
value
?
1
:
0
);
return
rv
;
return
rv
;
}
}
static
void
set_light_sens_level
(
int
value
)
static
void
asus_als_level
(
struct
asus_laptop
*
asus
,
int
value
)
{
{
if
(
write_acpi_int
(
ls_level_handle
,
NULL
,
value
,
NULL
))
if
(
write_acpi_int
(
asus
->
handle
,
METHOD_ALS_LEVEL
,
value
))
pr_warning
(
"Error setting light sensor level
\n
"
);
pr_warning
(
"Error setting light sensor level
\n
"
);
hotk
->
light_level
=
value
;
asus
->
light_level
=
value
;
}
}
static
ssize_t
show_lslvl
(
struct
device
*
dev
,
static
ssize_t
show_lslvl
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
hotk
->
light_level
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%d
\n
"
,
asus
->
light_level
);
}
}
static
ssize_t
store_lslvl
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_lslvl
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
{
if
(
rv
>
0
)
{
value
=
(
0
<
value
)
?
((
15
<
value
)
?
15
:
value
)
:
0
;
value
=
(
0
<
value
)
?
((
15
<
value
)
?
15
:
value
)
:
0
;
/* 0 <= value <= 15 */
/* 0 <= value <= 15 */
set_light_sens_level
(
value
);
asus_als_level
(
asus
,
value
);
}
}
return
rv
;
return
rv
;
...
@@ -861,197 +1007,309 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
...
@@ -861,197 +1007,309 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
/*
/*
* GPS
* GPS
*/
*/
static
int
asus_gps_status
(
struct
asus_laptop
*
asus
)
{
unsigned
long
long
status
;
acpi_status
rv
=
AE_OK
;
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
METHOD_GPS_STATUS
,
NULL
,
&
status
);
if
(
ACPI_FAILURE
(
rv
))
{
pr_warning
(
"Error reading GPS status
\n
"
);
return
-
ENODEV
;
}
return
!!
status
;
}
static
int
asus_gps_switch
(
struct
asus_laptop
*
asus
,
int
status
)
{
const
char
*
meth
=
status
?
METHOD_GPS_ON
:
METHOD_GPS_OFF
;
if
(
write_acpi_int
(
asus
->
handle
,
meth
,
0x02
))
return
-
ENODEV
;
return
0
;
}
static
ssize_t
show_gps
(
struct
device
*
dev
,
static
ssize_t
show_gps
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buf
)
struct
device_attribute
*
attr
,
char
*
buf
)
{
{
return
sprintf
(
buf
,
"%d
\n
"
,
read_status
(
GPS_ON
));
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
return
sprintf
(
buf
,
"%d
\n
"
,
asus_gps_status
(
asus
));
}
}
static
ssize_t
store_gps
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
static
ssize_t
store_gps
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
return
store_status
(
buf
,
count
,
NULL
,
GPS_ON
);
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
int
ret
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
<=
0
)
return
-
EINVAL
;
ret
=
asus_gps_switch
(
asus
,
!!
value
);
if
(
ret
)
return
ret
;
rfkill_set_sw_state
(
asus
->
gps_rfkill
,
!
value
);
return
rv
;
}
}
/*
/*
*
Hotkey functions
*
rfkill
*/
*/
static
struct
key_entry
*
asus_get_entry_by_scancode
(
int
code
)
static
int
asus_gps_rfkill_set
(
void
*
data
,
bool
blocked
)
{
{
struct
key_entry
*
key
;
acpi_handle
handle
=
data
;
for
(
key
=
asus_keymap
;
key
->
type
!=
KE_END
;
key
++
)
if
(
code
==
key
->
code
)
return
key
;
return
NULL
;
return
asus_gps_switch
(
handle
,
!
blocked
)
;
}
}
static
struct
key_entry
*
asus_get_entry_by_keycode
(
int
code
)
static
const
struct
rfkill_ops
asus_gps_rfkill_ops
=
{
{
.
set_block
=
asus_gps_rfkill_set
,
struct
key_entry
*
key
;
};
for
(
key
=
asus_keymap
;
key
->
type
!=
KE_END
;
key
++
)
if
(
code
==
key
->
keycode
&&
key
->
type
==
KE_KEY
)
return
key
;
return
NULL
;
static
void
asus_rfkill_exit
(
struct
asus_laptop
*
asus
)
{
if
(
asus
->
gps_rfkill
)
{
rfkill_unregister
(
asus
->
gps_rfkill
);
rfkill_destroy
(
asus
->
gps_rfkill
);
asus
->
gps_rfkill
=
NULL
;
}
}
}
static
int
asus_
getkeycode
(
struct
input_dev
*
dev
,
int
scancode
,
int
*
keycode
)
static
int
asus_
rfkill_init
(
struct
asus_laptop
*
asus
)
{
{
struct
key_entry
*
key
=
asus_get_entry_by_scancode
(
scancode
)
;
int
result
;
if
(
key
&&
key
->
type
==
KE_KEY
)
{
if
(
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_ON
,
NULL
)
||
*
keycode
=
key
->
keycode
;
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_OFF
,
NULL
)
||
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_STATUS
,
NULL
))
return
0
;
return
0
;
asus
->
gps_rfkill
=
rfkill_alloc
(
"asus-gps"
,
&
asus
->
platform_device
->
dev
,
RFKILL_TYPE_GPS
,
&
asus_gps_rfkill_ops
,
NULL
);
if
(
!
asus
->
gps_rfkill
)
return
-
EINVAL
;
result
=
rfkill_register
(
asus
->
gps_rfkill
);
if
(
result
)
{
rfkill_destroy
(
asus
->
gps_rfkill
);
asus
->
gps_rfkill
=
NULL
;
}
}
return
-
EINVAL
;
return
result
;
}
}
static
int
asus_setkeycode
(
struct
input_dev
*
dev
,
int
scancode
,
int
keycode
)
/*
* Input device (i.e. hotkeys)
*/
static
void
asus_input_notify
(
struct
asus_laptop
*
asus
,
int
event
)
{
{
struct
key_entry
*
key
;
if
(
asus
->
inputdev
)
int
old_keycode
;
sparse_keymap_report_event
(
asus
->
inputdev
,
event
,
1
,
true
);
}
if
(
keycode
<
0
||
keycode
>
KEY_MAX
)
static
int
asus_input_init
(
struct
asus_laptop
*
asus
)
return
-
EINVAL
;
{
struct
input_dev
*
input
;
int
error
;
key
=
asus_get_entry_by_scancode
(
scancode
);
input
=
input_allocate_device
();
if
(
key
&&
key
->
type
==
KE_KEY
)
{
if
(
!
input
)
{
old_keycode
=
key
->
keycode
;
pr_info
(
"Unable to allocate input device
\n
"
);
key
->
keycode
=
keycode
;
set_bit
(
keycode
,
dev
->
keybit
);
if
(
!
asus_get_entry_by_keycode
(
old_keycode
))
clear_bit
(
old_keycode
,
dev
->
keybit
);
return
0
;
return
0
;
}
}
input
->
name
=
"Asus Laptop extra buttons"
;
input
->
phys
=
ASUS_LAPTOP_FILE
"/input0"
;
input
->
id
.
bustype
=
BUS_HOST
;
input
->
dev
.
parent
=
&
asus
->
platform_device
->
dev
;
input_set_drvdata
(
input
,
asus
);
error
=
sparse_keymap_setup
(
input
,
asus_keymap
,
NULL
);
if
(
error
)
{
pr_err
(
"Unable to setup input device keymap
\n
"
);
goto
err_keymap
;
}
error
=
input_register_device
(
input
);
if
(
error
)
{
pr_info
(
"Unable to register input device
\n
"
);
goto
err_device
;
}
asus
->
inputdev
=
input
;
return
0
;
return
-
EINVAL
;
err_keymap:
sparse_keymap_free
(
input
);
err_device:
input_free_device
(
input
);
return
error
;
}
}
static
void
asus_
hotk_notify
(
struct
acpi_device
*
device
,
u32
event
)
static
void
asus_
input_exit
(
struct
asus_laptop
*
asus
)
{
{
static
struct
key_entry
*
key
;
if
(
asus
->
inputdev
)
{
u16
count
;
sparse_keymap_free
(
asus
->
inputdev
);
input_unregister_device
(
asus
->
inputdev
);
}
}
/* TODO Find a better way to handle events count. */
/*
if
(
!
hotk
)
* ACPI driver
return
;
*/
static
void
asus_acpi_notify
(
struct
acpi_device
*
device
,
u32
event
)
{
struct
asus_laptop
*
asus
=
acpi_driver_data
(
device
);
u16
count
;
/*
/*
* We need to tell the backlight device when the backlight power is
* We need to tell the backlight device when the backlight power is
* switched
* switched
*/
*/
if
(
event
==
ATKD_LCD_ON
)
{
if
(
event
==
ATKD_LCD_ON
)
write_status
(
NULL
,
1
,
LCD_ON
);
lcd_blank
(
asus
,
FB_BLANK_UNBLANK
);
lcd_blank
(
FB_BLANK_UNBLANK
);
else
if
(
event
==
ATKD_LCD_OFF
)
}
else
if
(
event
==
ATKD_LCD_OFF
)
{
lcd_blank
(
asus
,
FB_BLANK_POWERDOWN
);
write_status
(
NULL
,
0
,
LCD_ON
);
lcd_blank
(
FB_BLANK_POWERDOWN
);
}
count
=
hotk
->
event_count
[
event
%
128
]
++
;
/* TODO Find a better way to handle events count. */
acpi_bus_generate_proc_event
(
hotk
->
device
,
event
,
count
);
count
=
asus
->
event_count
[
event
%
128
]
++
;
acpi_bus_generate_netlink_event
(
hotk
->
device
->
pnp
.
device_class
,
acpi_bus_generate_proc_event
(
asus
->
device
,
event
,
count
);
dev_name
(
&
hotk
->
device
->
dev
),
event
,
acpi_bus_generate_netlink_event
(
asus
->
device
->
pnp
.
device_class
,
dev_name
(
&
asus
->
device
->
dev
),
event
,
count
);
count
);
if
(
hotk
->
inputdev
)
{
/* Brightness events are special */
key
=
asus_get_entry_by_scancode
(
event
);
if
(
event
>=
ATKD_BR_MIN
&&
event
<=
ATKD_BR_MAX
)
{
if
(
!
key
)
return
;
/* Ignore them completely if the acpi video driver is used */
if
(
asus
->
backlight_device
!=
NULL
)
{
switch
(
key
->
type
)
{
/* Update the backlight device. */
case
KE_KEY
:
asus_backlight_notify
(
asus
);
input_report_key
(
hotk
->
inputdev
,
key
->
keycode
,
1
);
input_sync
(
hotk
->
inputdev
);
input_report_key
(
hotk
->
inputdev
,
key
->
keycode
,
0
);
input_sync
(
hotk
->
inputdev
);
break
;
}
}
return
;
}
}
asus_input_notify
(
asus
,
event
);
}
}
#define ASUS_CREATE_DEVICE_ATTR(_name) \
static
DEVICE_ATTR
(
infos
,
S_IRUGO
,
show_infos
,
NULL
);
struct device_attribute dev_attr_##_name = { \
static
DEVICE_ATTR
(
wlan
,
S_IRUGO
|
S_IWUSR
,
show_wlan
,
store_wlan
);
.attr = { \
static
DEVICE_ATTR
(
bluetooth
,
S_IRUGO
|
S_IWUSR
,
show_bluetooth
,
.name = __stringify(_name), \
store_bluetooth
);
.mode = 0 }, \
static
DEVICE_ATTR
(
display
,
S_IRUGO
|
S_IWUSR
,
show_disp
,
store_disp
);
.show = NULL, \
static
DEVICE_ATTR
(
ledd
,
S_IRUGO
|
S_IWUSR
,
show_ledd
,
store_ledd
);
.store = NULL, \
static
DEVICE_ATTR
(
ls_level
,
S_IRUGO
|
S_IWUSR
,
show_lslvl
,
store_lslvl
);
static
DEVICE_ATTR
(
ls_switch
,
S_IRUGO
|
S_IWUSR
,
show_lssw
,
store_lssw
);
static
DEVICE_ATTR
(
gps
,
S_IRUGO
|
S_IWUSR
,
show_gps
,
store_gps
);
static
void
asus_sysfs_exit
(
struct
asus_laptop
*
asus
)
{
struct
platform_device
*
device
=
asus
->
platform_device
;
device_remove_file
(
&
device
->
dev
,
&
dev_attr_infos
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_wlan
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_bluetooth
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_display
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_ledd
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_ls_switch
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_ls_level
);
device_remove_file
(
&
device
->
dev
,
&
dev_attr_gps
);
}
static
int
asus_sysfs_init
(
struct
asus_laptop
*
asus
)
{
struct
platform_device
*
device
=
asus
->
platform_device
;
int
err
;
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_infos
);
if
(
err
)
return
err
;
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_WLAN
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_wlan
);
if
(
err
)
return
err
;
}
}
#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store) \
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_BLUETOOTH
,
NULL
))
{
do { \
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_bluetooth
);
dev_attr_##_name.attr.mode = _mode; \
if
(
err
)
dev_attr_##_name.show = _show; \
return
err
;
dev_attr_##_name.store = _store; \
}
} while(0)
static
ASUS_CREATE_DEVICE_ATTR
(
infos
);
static
ASUS_CREATE_DEVICE_ATTR
(
wlan
);
static
ASUS_CREATE_DEVICE_ATTR
(
bluetooth
);
static
ASUS_CREATE_DEVICE_ATTR
(
display
);
static
ASUS_CREATE_DEVICE_ATTR
(
ledd
);
static
ASUS_CREATE_DEVICE_ATTR
(
ls_switch
);
static
ASUS_CREATE_DEVICE_ATTR
(
ls_level
);
static
ASUS_CREATE_DEVICE_ATTR
(
gps
);
static
struct
attribute
*
asuspf_attributes
[]
=
{
&
dev_attr_infos
.
attr
,
&
dev_attr_wlan
.
attr
,
&
dev_attr_bluetooth
.
attr
,
&
dev_attr_display
.
attr
,
&
dev_attr_ledd
.
attr
,
&
dev_attr_ls_switch
.
attr
,
&
dev_attr_ls_level
.
attr
,
&
dev_attr_gps
.
attr
,
NULL
};
static
struct
attribute_group
asuspf_attribute_group
=
{
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_SWITCH_DISPLAY
,
NULL
))
{
.
attrs
=
asuspf_attributes
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_display
);
};
if
(
err
)
return
err
;
}
static
struct
platform_driver
asuspf_driver
=
{
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_LEDD
,
NULL
))
{
.
driver
=
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_ledd
);
.
name
=
ASUS_HOTK_FILE
,
if
(
err
)
.
owner
=
THIS_MODULE
,
return
err
;
}
}
};
static
struct
platform_device
*
asuspf_device
;
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_CONTROL
,
NULL
)
&&
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_LEVEL
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_ls_switch
);
if
(
err
)
return
err
;
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_ls_level
);
if
(
err
)
return
err
;
}
static
void
asus_hotk_add_fs
(
void
)
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_ON
,
NULL
)
&&
{
!
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_OFF
,
NULL
)
&&
ASUS_SET_DEVICE_ATTR
(
infos
,
0444
,
show_infos
,
NULL
);
!
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_STATUS
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_gps
);
if
(
err
)
return
err
;
}
if
(
wl_switch_handle
)
return
err
;
ASUS_SET_DEVICE_ATTR
(
wlan
,
0644
,
show_wlan
,
store_wlan
);
}
static
int
asus_platform_init
(
struct
asus_laptop
*
asus
)
{
int
err
;
if
(
bt_switch_handle
)
asus
->
platform_device
=
platform_device_alloc
(
ASUS_LAPTOP_FILE
,
-
1
);
ASUS_SET_DEVICE_ATTR
(
bluetooth
,
0644
,
if
(
!
asus
->
platform_device
)
show_bluetooth
,
store_bluetooth
);
return
-
ENOMEM
;
platform_set_drvdata
(
asus
->
platform_device
,
asus
);
if
(
display_set_handle
&&
display_get_handle
)
err
=
platform_device_add
(
asus
->
platform_device
);
ASUS_SET_DEVICE_ATTR
(
display
,
0644
,
show_disp
,
store_disp
);
if
(
err
)
else
if
(
display_set_handle
)
goto
fail_platform_device
;
ASUS_SET_DEVICE_ATTR
(
display
,
0200
,
NULL
,
store_disp
);
if
(
ledd_set_handle
)
err
=
asus_sysfs_init
(
asus
);
ASUS_SET_DEVICE_ATTR
(
ledd
,
0644
,
show_ledd
,
store_ledd
);
if
(
err
)
goto
fail_sysfs
;
return
0
;
if
(
ls_switch_handle
&&
ls_level_handle
)
{
fail_sysfs:
ASUS_SET_DEVICE_ATTR
(
ls_level
,
0644
,
show_lslvl
,
store_lslvl
);
asus_sysfs_exit
(
asus
);
ASUS_SET_DEVICE_ATTR
(
ls_switch
,
0644
,
show_lssw
,
store_lssw
);
platform_device_del
(
asus
->
platform_device
);
}
fail_platform_device:
platform_device_put
(
asus
->
platform_device
);
return
err
;
}
if
(
gps_status_handle
&&
gps_on_handle
&&
gps_off_handle
)
static
void
asus_platform_exit
(
struct
asus_laptop
*
asus
)
ASUS_SET_DEVICE_ATTR
(
gps
,
0644
,
show_gps
,
store_gps
);
{
asus_sysfs_exit
(
asus
);
platform_device_unregister
(
asus
->
platform_device
);
}
}
static
struct
platform_driver
platform_driver
=
{
.
driver
=
{
.
name
=
ASUS_LAPTOP_FILE
,
.
owner
=
THIS_MODULE
,
}
};
static
int
asus_handle_init
(
char
*
name
,
acpi_handle
*
handle
,
static
int
asus_handle_init
(
char
*
name
,
acpi_handle
*
handle
,
char
**
paths
,
int
num_paths
)
char
**
paths
,
int
num_paths
)
{
{
...
@@ -1073,10 +1331,11 @@ static int asus_handle_init(char *name, acpi_handle * handle,
...
@@ -1073,10 +1331,11 @@ static int asus_handle_init(char *name, acpi_handle * handle,
ARRAY_SIZE(object##_paths))
ARRAY_SIZE(object##_paths))
/*
/*
* This function is used to initialize the hotk with right values. In this
* This function is used to initialize the context with right values. In this
* method, we can make all the detection we want, and modify the hotk struct
* method, we can make all the detection we want, and modify the asus_laptop
* struct
*/
*/
static
int
asus_
hotk_get_info
(
void
)
static
int
asus_
laptop_get_info
(
struct
asus_laptop
*
asus
)
{
{
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
struct
acpi_buffer
buffer
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
union
acpi_object
*
model
=
NULL
;
union
acpi_object
*
model
=
NULL
;
...
@@ -1089,22 +1348,21 @@ static int asus_hotk_get_info(void)
...
@@ -1089,22 +1348,21 @@ static int asus_hotk_get_info(void)
* models, but late enough to allow acpi_bus_register_driver() to fail
* models, but late enough to allow acpi_bus_register_driver() to fail
* before doing anything ACPI-specific. Should we encounter a machine,
* before doing anything ACPI-specific. Should we encounter a machine,
* which needs special handling (i.e. its hotkey device has a different
* which needs special handling (i.e. its hotkey device has a different
* HID), this bit will be moved. A global variable asus_info contains
* HID), this bit will be moved.
* the DSDT header.
*/
*/
status
=
acpi_get_table
(
ACPI_SIG_DSDT
,
1
,
&
asus_info
);
status
=
acpi_get_table
(
ACPI_SIG_DSDT
,
1
,
&
asus
->
dsdt
_info
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
pr_warning
(
"Couldn't get the DSDT table header
\n
"
);
pr_warning
(
"Couldn't get the DSDT table header
\n
"
);
/* We have to write 0 on init this far for all ASUS models */
/* We have to write 0 on init this far for all ASUS models */
if
(
write_acpi_int
(
hotk
->
handle
,
"INIT"
,
0
,
&
buffer
))
{
if
(
write_acpi_int
_ret
(
asus
->
handle
,
"INIT"
,
0
,
&
buffer
))
{
pr_err
(
"Hotkey initialization failed
\n
"
);
pr_err
(
"Hotkey initialization failed
\n
"
);
return
-
ENODEV
;
return
-
ENODEV
;
}
}
/* This needs to be called for some laptops to init properly */
/* This needs to be called for some laptops to init properly */
status
=
status
=
acpi_evaluate_integer
(
hotk
->
handle
,
"BSTS"
,
NULL
,
&
bsts_result
);
acpi_evaluate_integer
(
asus
->
handle
,
"BSTS"
,
NULL
,
&
bsts_result
);
if
(
ACPI_FAILURE
(
status
))
if
(
ACPI_FAILURE
(
status
))
pr_warning
(
"Error calling BSTS
\n
"
);
pr_warning
(
"Error calling BSTS
\n
"
);
else
if
(
bsts_result
)
else
if
(
bsts_result
)
...
@@ -1112,8 +1370,8 @@ static int asus_hotk_get_info(void)
...
@@ -1112,8 +1370,8 @@ static int asus_hotk_get_info(void)
(
uint
)
bsts_result
);
(
uint
)
bsts_result
);
/* This too ... */
/* This too ... */
write_acpi_int
(
hotk
->
handle
,
"CWAP"
,
wapf
,
NULL
);
if
(
write_acpi_int
(
asus
->
handle
,
"CWAP"
,
wapf
))
pr_err
(
"Error calling CWAP(%d)
\n
"
,
wapf
);
/*
/*
* Try to match the object returned by INIT to the specific model.
* Try to match the object returned by INIT to the specific model.
* Handle every possible object (or the lack of thereof) the DSDT
* Handle every possible object (or the lack of thereof) the DSDT
...
@@ -1134,397 +1392,210 @@ static int asus_hotk_get_info(void)
...
@@ -1134,397 +1392,210 @@ static int asus_hotk_get_info(void)
break
;
break
;
}
}
}
}
hotk
->
name
=
kstrdup
(
string
,
GFP_KERNEL
);
asus
->
name
=
kstrdup
(
string
,
GFP_KERNEL
);
if
(
!
hotk
->
name
)
if
(
!
asus
->
name
)
return
-
ENOMEM
;
return
-
ENOMEM
;
if
(
*
string
)
if
(
*
string
)
pr_notice
(
" %s model detected
\n
"
,
string
);
pr_notice
(
" %s model detected
\n
"
,
string
);
ASUS_HANDLE_INIT
(
mled_set
);
ASUS_HANDLE_INIT
(
tled_set
);
ASUS_HANDLE_INIT
(
rled_set
);
ASUS_HANDLE_INIT
(
pled_set
);
ASUS_HANDLE_INIT
(
gled_set
);
ASUS_HANDLE_INIT
(
ledd_set
);
ASUS_HANDLE_INIT
(
kled_set
);
ASUS_HANDLE_INIT
(
kled_get
);
/*
/*
* The HWRS method return informations about the hardware.
* The HWRS method return informations about the hardware.
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
* The significance of others is yet to be found.
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
*/
status
=
status
=
acpi_evaluate_integer
(
hotk
->
handle
,
"HRWS"
,
NULL
,
&
hwrs_result
);
acpi_evaluate_integer
(
asus
->
handle
,
"HRWS"
,
NULL
,
&
hwrs_result
);
if
(
ACPI_FAILURE
(
status
))
if
(
!
ACPI_FAILURE
(
status
))
hwrs_result
=
WL_HWRS
|
BT_HWRS
;
pr_notice
(
" HRWS returned %x"
,
(
int
)
hwrs_result
);
if
(
hwrs_result
&
WL_HWRS
)
ASUS_HANDLE_INIT
(
wl_switch
);
if
(
hwrs_result
&
BT_HWRS
)
ASUS_HANDLE_INIT
(
bt_switch
);
ASUS_HANDLE_INIT
(
wireless_status
);
ASUS_HANDLE_INIT
(
brightness_set
);
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_WL_STATUS
,
NULL
))
ASUS_HANDLE_INIT
(
brightness_get
)
;
asus
->
have_rsts
=
true
;
/* Scheduled for removal */
ASUS_HANDLE_INIT
(
lcd_switch
);
ASUS_HANDLE_INIT
(
lcd_switch
);
ASUS_HANDLE_INIT
(
display_set
);
ASUS_HANDLE_INIT
(
display_get
);
ASUS_HANDLE_INIT
(
display_get
);
/*
* There is a lot of models with "ALSL", but a few get
* a real light sens, so we need to check it.
*/
if
(
!
ASUS_HANDLE_INIT
(
ls_switch
))
ASUS_HANDLE_INIT
(
ls_level
);
ASUS_HANDLE_INIT
(
gps_on
);
ASUS_HANDLE_INIT
(
gps_off
);
ASUS_HANDLE_INIT
(
gps_status
);
kfree
(
model
);
kfree
(
model
);
return
AE_OK
;
return
AE_OK
;
}
}
static
int
asus_input_init
(
void
)
static
bool
asus_device_present
;
{
const
struct
key_entry
*
key
;
int
result
;
hotk
->
inputdev
=
input_allocate_device
();
static
int
__devinit
asus_acpi_init
(
struct
asus_laptop
*
asus
)
if
(
!
hotk
->
inputdev
)
{
pr_info
(
"Unable to allocate input device
\n
"
);
return
0
;
}
hotk
->
inputdev
->
name
=
"Asus Laptop extra buttons"
;
hotk
->
inputdev
->
phys
=
ASUS_HOTK_FILE
"/input0"
;
hotk
->
inputdev
->
id
.
bustype
=
BUS_HOST
;
hotk
->
inputdev
->
getkeycode
=
asus_getkeycode
;
hotk
->
inputdev
->
setkeycode
=
asus_setkeycode
;
for
(
key
=
asus_keymap
;
key
->
type
!=
KE_END
;
key
++
)
{
switch
(
key
->
type
)
{
case
KE_KEY
:
set_bit
(
EV_KEY
,
hotk
->
inputdev
->
evbit
);
set_bit
(
key
->
keycode
,
hotk
->
inputdev
->
keybit
);
break
;
}
}
result
=
input_register_device
(
hotk
->
inputdev
);
if
(
result
)
{
pr_info
(
"Unable to register input device
\n
"
);
input_free_device
(
hotk
->
inputdev
);
}
return
result
;
}
static
int
asus_hotk_check
(
void
)
{
{
int
result
=
0
;
int
result
=
0
;
result
=
acpi_bus_get_status
(
hotk
->
device
);
result
=
acpi_bus_get_status
(
asus
->
device
);
if
(
result
)
if
(
result
)
return
result
;
return
result
;
if
(
!
asus
->
device
->
status
.
present
)
{
if
(
hotk
->
device
->
status
.
present
)
{
result
=
asus_hotk_get_info
();
}
else
{
pr_err
(
"Hotkey device not present, aborting
\n
"
);
pr_err
(
"Hotkey device not present, aborting
\n
"
);
return
-
E
INVAL
;
return
-
E
NODEV
;
}
}
return
result
;
result
=
asus_laptop_get_info
(
asus
);
}
static
int
asus_hotk_found
;
static
int
asus_hotk_add
(
struct
acpi_device
*
device
)
{
int
result
;
pr_notice
(
"Asus Laptop Support version %s
\n
"
,
ASUS_LAPTOP_VERSION
);
hotk
=
kzalloc
(
sizeof
(
struct
asus_hotk
),
GFP_KERNEL
);
if
(
!
hotk
)
return
-
ENOMEM
;
hotk
->
handle
=
device
->
handle
;
strcpy
(
acpi_device_name
(
device
),
ASUS_HOTK_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ASUS_HOTK_CLASS
);
device
->
driver_data
=
hotk
;
hotk
->
device
=
device
;
result
=
asus_hotk_check
();
if
(
result
)
if
(
result
)
goto
end
;
return
result
;
asus_hotk_add_fs
();
asus_hotk_found
=
1
;
/* WLED and BLED are on by default */
/* WLED and BLED are on by default */
write_status
(
bt_switch_handle
,
1
,
BT_ON
);
if
(
bluetooth_status
>=
0
)
write_status
(
wl_switch_handle
,
1
,
WL_ON
);
asus_bluetooth_set
(
asus
,
!!
bluetooth_status
);
/* If the h/w switch is off, we need to check the real status */
write_status
(
NULL
,
read_status
(
BT_ON
),
BT_ON
);
write_status
(
NULL
,
read_status
(
WL_ON
),
WL_ON
);
/* LCD Backlight is on by default */
if
(
wlan_status
>=
0
)
write_status
(
NULL
,
1
,
LCD_ON
);
asus_wlan_set
(
asus
,
!!
wlan_status
);
/* Keyboard Backlight is on by default */
/* Keyboard Backlight is on by default */
if
(
kled_set_handle
)
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_KBD_LIGHT_SET
,
NULL
)
)
set_kled_lvl
(
1
);
asus_kled_set
(
asus
,
1
);
/* LED display is off by default */
/* LED display is off by default */
hotk
->
ledd_status
=
0xFFF
;
asus
->
ledd_status
=
0xFFF
;
/* Set initial values of light sensor and level */
/* Set initial values of light sensor and level */
hotk
->
light_switch
=
0
;
/* Default to light sensor disabled */
asus
->
light_switch
=
0
;
/* Default to light sensor disabled */
hotk
->
light_level
=
5
;
/* level 5 for sensor sensitivity */
asus
->
light_level
=
5
;
/* level 5 for sensor sensitivity */
if
(
ls_switch_handle
)
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_CONTROL
,
NULL
)
&&
set_light_sens_switch
(
hotk
->
light_switch
);
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_LEVEL
,
NULL
))
{
asus_als_switch
(
asus
,
asus
->
light_switch
);
if
(
ls_level_handle
)
asus_als_level
(
asus
,
asus
->
light_level
);
set_light_sens_level
(
hotk
->
light_level
);
/* GPS is on by default */
write_status
(
NULL
,
1
,
GPS_ON
);
end:
if
(
result
)
{
kfree
(
hotk
->
name
);
kfree
(
hotk
);
}
}
asus
->
lcd_state
=
1
;
/* LCD should be on when the module load */
return
result
;
return
result
;
}
}
static
int
asus_hotk_remove
(
struct
acpi_device
*
device
,
int
type
)
static
int
__devinit
asus_acpi_add
(
struct
acpi_device
*
device
)
{
kfree
(
hotk
->
name
);
kfree
(
hotk
);
return
0
;
}
static
void
asus_backlight_exit
(
void
)
{
{
if
(
asus_backlight_device
)
struct
asus_laptop
*
asus
;
backlight_device_unregister
(
asus_backlight_device
);
int
result
;
}
#define ASUS_LED_UNREGISTER(object) \
if (object##_led.dev) \
led_classdev_unregister(&object##_led)
static
void
asus_led_exit
(
void
)
pr_notice
(
"Asus Laptop Support version %s
\n
"
,
{
ASUS_LAPTOP_VERSION
);
destroy_workqueue
(
led_workqueue
);
asus
=
kzalloc
(
sizeof
(
struct
asus_laptop
),
GFP_KERNEL
);
ASUS_LED_UNREGISTER
(
mled
);
if
(
!
asus
)
ASUS_LED_UNREGISTER
(
tled
)
;
return
-
ENOMEM
;
ASUS_LED_UNREGISTER
(
pled
)
;
asus
->
handle
=
device
->
handle
;
ASUS_LED_UNREGISTER
(
rled
);
strcpy
(
acpi_device_name
(
device
),
ASUS_LAPTOP_DEVICE_NAME
);
ASUS_LED_UNREGISTER
(
gled
);
strcpy
(
acpi_device_class
(
device
),
ASUS_LAPTOP_CLASS
);
ASUS_LED_UNREGISTER
(
kled
)
;
device
->
driver_data
=
asus
;
}
asus
->
device
=
device
;
static
void
asus_input_exit
(
void
)
result
=
asus_acpi_init
(
asus
);
{
if
(
result
)
if
(
hotk
->
inputdev
)
goto
fail_platform
;
input_unregister_device
(
hotk
->
inputdev
);
}
static
void
__exit
asus_laptop_exit
(
void
)
/*
{
* Register the platform device first. It is used as a parent for the
asus_backlight_exit
();
* sub-devices below.
asus_led_exit
();
*/
asus_input_exit
();
result
=
asus_platform_init
(
asus
);
if
(
result
)
goto
fail_platform
;
acpi_bus_unregister_driver
(
&
asus_hotk_driver
);
if
(
!
acpi_video_backlight_support
())
{
sysfs_remove_group
(
&
asuspf_device
->
dev
.
kobj
,
&
asuspf_attribute_group
);
result
=
asus_backlight_init
(
asus
);
platform_device_unregister
(
asuspf_device
);
if
(
result
)
platform_driver_unregister
(
&
asuspf_driver
);
goto
fail_backlight
;
}
}
else
pr_info
(
"Backlight controlled by ACPI video driver
\n
"
);
static
int
asus_backlight_init
(
struct
device
*
dev
)
result
=
asus_input_init
(
asus
);
{
if
(
result
)
struct
backlight_device
*
bd
;
goto
fail_input
;
if
(
brightness_set_handle
&&
lcd_switch_handle
)
{
result
=
asus_led_init
(
asus
);
bd
=
backlight_device_register
(
ASUS_HOTK_FILE
,
dev
,
if
(
result
)
NULL
,
&
asusbl_ops
);
goto
fail_led
;
if
(
IS_ERR
(
bd
))
{
pr_err
(
"Could not register asus backlight device
\n
"
);
asus_backlight_device
=
NULL
;
return
PTR_ERR
(
bd
);
}
asus_backlight_device
=
bd
;
result
=
asus_rfkill_init
(
asus
);
if
(
result
)
goto
fail_rfkill
;
bd
->
props
.
max_brightness
=
15
;
asus_device_present
=
true
;
bd
->
props
.
brightness
=
read_brightness
(
NULL
);
bd
->
props
.
power
=
FB_BLANK_UNBLANK
;
backlight_update_status
(
bd
);
}
return
0
;
return
0
;
}
static
int
asus_led_register
(
acpi_handle
handle
,
fail_rfkill:
struct
led_classdev
*
ldev
,
struct
device
*
dev
)
asus_led_exit
(
asus
);
{
fail_led:
if
(
!
handle
)
asus_input_exit
(
asus
);
return
0
;
fail_input:
asus_backlight_exit
(
asus
);
fail_backlight:
asus_platform_exit
(
asus
);
fail_platform:
kfree
(
asus
->
name
);
kfree
(
asus
);
return
led_classdev_register
(
dev
,
ldev
)
;
return
result
;
}
}
#define ASUS_LED_REGISTER(object, device) \
static
int
asus_acpi_remove
(
struct
acpi_device
*
device
,
int
type
)
asus_led_register(object##_set_handle, &object##_led, device)
static
int
asus_led_init
(
struct
device
*
dev
)
{
{
int
rv
;
struct
asus_laptop
*
asus
=
acpi_driver_data
(
device
);
rv
=
ASUS_LED_REGISTER
(
mled
,
dev
);
if
(
rv
)
goto
out
;
rv
=
ASUS_LED_REGISTER
(
tled
,
dev
);
if
(
rv
)
goto
out1
;
rv
=
ASUS_LED_REGISTER
(
rled
,
dev
);
if
(
rv
)
goto
out2
;
rv
=
ASUS_LED_REGISTER
(
pled
,
dev
);
if
(
rv
)
goto
out3
;
rv
=
ASUS_LED_REGISTER
(
gled
,
dev
);
if
(
rv
)
goto
out4
;
if
(
kled_set_handle
&&
kled_get_handle
)
asus_backlight_exit
(
asus
);
rv
=
ASUS_LED_REGISTER
(
kled
,
dev
);
asus_rfkill_exit
(
asus
);
if
(
rv
)
asus_led_exit
(
asus
);
goto
out5
;
asus_input_exit
(
asus
);
asus_platform_exit
(
asus
);
led_workqueue
=
create_singlethread_workqueue
(
"led_workqueue"
);
if
(
!
led_workqueue
)
goto
out6
;
kfree
(
asus
->
name
);
kfree
(
asus
);
return
0
;
return
0
;
out6:
rv
=
-
ENOMEM
;
ASUS_LED_UNREGISTER
(
kled
);
out5:
ASUS_LED_UNREGISTER
(
gled
);
out4:
ASUS_LED_UNREGISTER
(
pled
);
out3:
ASUS_LED_UNREGISTER
(
rled
);
out2:
ASUS_LED_UNREGISTER
(
tled
);
out1:
ASUS_LED_UNREGISTER
(
mled
);
out:
return
rv
;
}
}
static
const
struct
acpi_device_id
asus_device_ids
[]
=
{
{
"ATK0100"
,
0
},
{
"ATK0101"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
asus_device_ids
);
static
struct
acpi_driver
asus_acpi_driver
=
{
.
name
=
ASUS_LAPTOP_NAME
,
.
class
=
ASUS_LAPTOP_CLASS
,
.
owner
=
THIS_MODULE
,
.
ids
=
asus_device_ids
,
.
flags
=
ACPI_DRIVER_ALL_NOTIFY_EVENTS
,
.
ops
=
{
.
add
=
asus_acpi_add
,
.
remove
=
asus_acpi_remove
,
.
notify
=
asus_acpi_notify
,
},
};
static
int
__init
asus_laptop_init
(
void
)
static
int
__init
asus_laptop_init
(
void
)
{
{
int
result
;
int
result
;
result
=
acpi_bus_register_driver
(
&
asus_hotk
_driver
);
result
=
platform_driver_register
(
&
platform
_driver
);
if
(
result
<
0
)
if
(
result
<
0
)
return
result
;
return
result
;
/*
result
=
acpi_bus_register_driver
(
&
asus_acpi_driver
);
* This is a bit of a kludge. We only want this module loaded
if
(
result
<
0
)
* for ASUS systems, but there's currently no way to probe the
goto
fail_acpi_driver
;
* ACPI namespace for ASUS HIDs. So we just return failure if
if
(
!
asus_device_present
)
{
* we didn't find one, which will cause the module to be
result
=
-
ENODEV
;
* unloaded.
goto
fail_no_device
;
*/
if
(
!
asus_hotk_found
)
{
acpi_bus_unregister_driver
(
&
asus_hotk_driver
);
return
-
ENODEV
;
}
result
=
asus_input_init
();
if
(
result
)
goto
fail_input
;
/* Register platform stuff */
result
=
platform_driver_register
(
&
asuspf_driver
);
if
(
result
)
goto
fail_platform_driver
;
asuspf_device
=
platform_device_alloc
(
ASUS_HOTK_FILE
,
-
1
);
if
(
!
asuspf_device
)
{
result
=
-
ENOMEM
;
goto
fail_platform_device1
;
}
}
result
=
platform_device_add
(
asuspf_device
);
if
(
result
)
goto
fail_platform_device2
;
result
=
sysfs_create_group
(
&
asuspf_device
->
dev
.
kobj
,
&
asuspf_attribute_group
);
if
(
result
)
goto
fail_sysfs
;
result
=
asus_led_init
(
&
asuspf_device
->
dev
);
if
(
result
)
goto
fail_led
;
if
(
!
acpi_video_backlight_support
())
{
result
=
asus_backlight_init
(
&
asuspf_device
->
dev
);
if
(
result
)
goto
fail_backlight
;
}
else
pr_info
(
"Brightness ignored, must be controlled by "
"ACPI video driver
\n
"
);
return
0
;
return
0
;
fail_backlight:
fail_no_device:
asus_led_exit
();
acpi_bus_unregister_driver
(
&
asus_acpi_driver
);
fail_acpi_driver:
fail_led:
platform_driver_unregister
(
&
platform_driver
);
sysfs_remove_group
(
&
asuspf_device
->
dev
.
kobj
,
&
asuspf_attribute_group
);
fail_sysfs:
platform_device_del
(
asuspf_device
);
fail_platform_device2:
platform_device_put
(
asuspf_device
);
fail_platform_device1:
platform_driver_unregister
(
&
asuspf_driver
);
fail_platform_driver:
asus_input_exit
();
fail_input:
return
result
;
return
result
;
}
}
static
void
__exit
asus_laptop_exit
(
void
)
{
acpi_bus_unregister_driver
(
&
asus_acpi_driver
);
platform_driver_unregister
(
&
platform_driver
);
}
module_init
(
asus_laptop_init
);
module_init
(
asus_laptop_init
);
module_exit
(
asus_laptop_exit
);
module_exit
(
asus_laptop_exit
);
drivers/platform/x86/eeepc-laptop.c
View file @
db38a291
...
@@ -578,6 +578,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
...
@@ -578,6 +578,8 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
struct
pci_dev
*
dev
;
struct
pci_dev
*
dev
;
struct
pci_bus
*
bus
;
struct
pci_bus
*
bus
;
bool
blocked
=
eeepc_wlan_rfkill_blocked
(
eeepc
);
bool
blocked
=
eeepc_wlan_rfkill_blocked
(
eeepc
);
bool
absent
;
u32
l
;
if
(
eeepc
->
wlan_rfkill
)
if
(
eeepc
->
wlan_rfkill
)
rfkill_set_sw_state
(
eeepc
->
wlan_rfkill
,
blocked
);
rfkill_set_sw_state
(
eeepc
->
wlan_rfkill
,
blocked
);
...
@@ -591,6 +593,22 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
...
@@ -591,6 +593,22 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
goto
out_unlock
;
goto
out_unlock
;
}
}
if
(
pci_bus_read_config_dword
(
bus
,
0
,
PCI_VENDOR_ID
,
&
l
))
{
pr_err
(
"Unable to read PCI config space?
\n
"
);
goto
out_unlock
;
}
absent
=
(
l
==
0xffffffff
);
if
(
blocked
!=
absent
)
{
pr_warning
(
"BIOS says wireless lan is %s, "
"but the pci device is %s
\n
"
,
blocked
?
"blocked"
:
"unblocked"
,
absent
?
"absent"
:
"present"
);
pr_warning
(
"skipped wireless hotplug as probably "
"inappropriate for this model
\n
"
);
goto
out_unlock
;
}
if
(
!
blocked
)
{
if
(
!
blocked
)
{
dev
=
pci_get_slot
(
bus
,
0
);
dev
=
pci_get_slot
(
bus
,
0
);
if
(
dev
)
{
if
(
dev
)
{
...
@@ -1277,7 +1295,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
...
@@ -1277,7 +1295,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
* hotplug code. In fact, current hotplug code seems to unplug another
* hotplug code. In fact, current hotplug code seems to unplug another
* device...
* device...
*/
*/
if
(
strcmp
(
model
,
"1005HA"
)
==
0
||
strcmp
(
model
,
"1201N"
)
==
0
)
{
if
(
strcmp
(
model
,
"1005HA"
)
==
0
||
strcmp
(
model
,
"1201N"
)
==
0
||
strcmp
(
model
,
"1005PE"
)
==
0
)
{
eeepc
->
hotplug_disabled
=
true
;
eeepc
->
hotplug_disabled
=
true
;
pr_info
(
"wlan hotplug disabled
\n
"
);
pr_info
(
"wlan hotplug disabled
\n
"
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment