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
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -13,7 +13,7 @@ Description:
Ex: - 0 (0000b) means no display
- 3 (0011b) CRT+LCD.
What: /sys/devices/platform/asus
-
laptop/gps
What: /sys/devices/platform/asus
_
laptop/gps
Date: January 2007
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -21,7 +21,7 @@ Description:
Control the gps device. 1 means on, 0 means off.
Users: Lapsus
What: /sys/devices/platform/asus
-
laptop/ledd
What: /sys/devices/platform/asus
_
laptop/ledd
Date: January 2007
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -29,11 +29,11 @@ Description:
Some models like the W1N have a LED display that can be
used to display several informations.
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.
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
KernelVersion: 2.6.20
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -42,7 +42,7 @@ Description:
This may control the led, the device or both.
Users: Lapsus
What: /sys/devices/platform/asus
-
laptop/wlan
What: /sys/devices/platform/asus
_
laptop/wlan
Date: January 2007
KernelVersion: 2.6.20
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
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -9,21 +9,21 @@ Description:
- 3 = LCD+CRT
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
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
Description:
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
KernelVersion: 2.6.26
Contact: "Corentin Chary" <corentincj@iksaif.net>
Description:
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
KernelVersion: 2.6.31
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
@@ -42,7 +42,7 @@ Description:
`------------ Availables 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
KernelVersion: 2.6.31
Contact: "Corentin Chary" <corentincj@iksaif.net>
...
...
drivers/platform/x86/Kconfig
View file @
db38a291
...
...
@@ -59,6 +59,8 @@ config ASUS_LAPTOP
select NEW_LEDS
select BACKLIGHT_CLASS_DEVICE
depends on INPUT
depends on RFKILL || RFKILL = n
select INPUT_SPARSEKMAP
---help---
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
...
...
drivers/platform/x86/asus-laptop.c
View file @
db38a291
...
...
@@ -45,58 +45,23 @@
#include <linux/fb.h>
#include <linux/leds.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_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"
/*
* Some events we use, same for all Asus
*/
#define ATKD_BR_UP 0x10
#define ATKD_BR_DOWN 0x20
#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
#define ASUS_LAPTOP_NAME "Asus Laptop Support"
#define ASUS_LAPTOP_CLASS "hotkey"
#define ASUS_LAPTOP_DEVICE_NAME "Hotkey"
#define ASUS_LAPTOP_FILE KBUILD_MODNAME
#define ASUS_LAPTOP_PREFIX "\\_SB.ATKD."
MODULE_AUTHOR
(
"Julien Lerouge, Karol Kozimor, Corentin Chary"
);
MODULE_DESCRIPTION
(
ASUS_
HOTK
_NAME
);
MODULE_DESCRIPTION
(
ASUS_
LAPTOP
_NAME
);
MODULE_LICENSE
(
"GPL"
);
/*
...
...
@@ -113,225 +78,209 @@ static uint wapf = 1;
module_param
(
wapf
,
uint
,
0644
);
MODULE_PARM_DESC
(
wapf
,
"WAPF value"
);
#define ASUS_HANDLE(object, paths...) \
static acpi_handle object##_handle = NULL; \
static char *object##_paths[] = { paths }
static
uint
wlan_status
=
1
;
static
uint
bluetooth_status
=
1
;
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 */
ASUS_HANDLE
(
mled_set
,
ASUS_HOTK_PREFIX
"MLED"
);
ASUS_HANDLE
(
tled_set
,
ASUS_HOTK_PREFIX
"TLED"
);
ASUS_HANDLE
(
rled_set
,
ASUS_HOTK_PREFIX
"RLED"
);
/* W1JC */
ASUS_HANDLE
(
pled_set
,
ASUS_HOTK_PREFIX
"PLED"
);
/* A7J */
ASUS_HANDLE
(
gled_set
,
ASUS_HOTK_PREFIX
"GLED"
);
/* G1, G2 (probably) */
#define METHOD_MLED "MLED"
#define METHOD_TLED "TLED"
#define METHOD_RLED "RLED"
/* W1JC */
#define METHOD_PLED "PLED"
/* A7J */
#define METHOD_GLED "GLED"
/* G1, G2 (probably) */
/* LEDD */
ASUS_HANDLE
(
ledd_set
,
ASUS_HOTK_PREFIX
"SLCM"
);
#define METHOD_LEDD "SLCM"
/*
* Bluetooth and WLAN
* WLED and BLED are not handled like other XLED, because in some dsdt
* they also control the WLAN/Bluetooth device.
*/
ASUS_HANDLE
(
wl_switch
,
ASUS_HOTK_PREFIX
"WLED"
);
ASUS_HANDLE
(
bt_switch
,
ASUS_HOTK_PREFIX
"BLED"
);
ASUS_HANDLE
(
wireless_status
,
ASUS_HOTK_PREFIX
"RSTS"
);
/* All new models */
#define METHOD_WLAN "WLED"
#define METHOD_BLUETOOTH "BLED"
#define METHOD_WL_STATUS "RSTS"
/* Brightness */
ASUS_HANDLE
(
brightness_set
,
ASUS_HOTK_PREFIX
"SPLV"
);
ASUS_HANDLE
(
brightness_get
,
ASUS_HOTK_PREFIX
"GPLV"
);
#define METHOD_BRIGHTNESS_SET "SPLV"
#define METHOD_BRIGHTNESS_GET "GPLV"
/* Backlight */
ASUS_HANDLE
(
lcd_switch
,
"
\\
_SB.PCI0.SBRG.EC0._Q10"
,
/* All new models */
"
\\
_SB.PCI0.ISA.EC0._Q10"
,
/* A1x */
"
\\
_SB.PCI0.PX40.ECD0._Q10"
,
/* L3C */
"
\\
_SB.PCI0.PX40.EC0.Q10"
,
/* M1A */
"
\\
_SB.PCI0.LPCB.EC0._Q10"
,
/* P30 */
"
\\
_SB.PCI0.LPCB.EC0._Q0E"
,
/* P30/P35 */
"
\\
_SB.PCI0.PX40.Q10"
,
/* S1x */
"
\\
Q10"
);
/* A2x, L2D, L3D, M2E */
static
acpi_handle
lcd_switch_handle
;
static
const
char
*
lcd_switch_paths
[]
=
{
"
\\
_SB.PCI0.SBRG.EC0._Q10"
,
/* All new models */
"
\\
_SB.PCI0.ISA.EC0._Q10"
,
/* A1x */
"
\\
_SB.PCI0.PX40.ECD0._Q10"
,
/* L3C */
"
\\
_SB.PCI0.PX40.EC0.Q10"
,
/* M1A */
"
\\
_SB.PCI0.LPCB.EC0._Q10"
,
/* P30 */
"
\\
_SB.PCI0.LPCB.EC0._Q0E"
,
/* P30/P35 */
"
\\
_SB.PCI0.PX40.Q10"
,
/* S1x */
"
\\
Q10"
};
/* A2x, L2D, L3D, M2E */
/* Display */
ASUS_HANDLE
(
display_set
,
ASUS_HOTK_PREFIX
"SDSP"
);
ASUS_HANDLE
(
display_get
,
/* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
"
\\
_SB.PCI0.P0P1.VGA.GETD"
,
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
"
\\
_SB.PCI0.P0P2.VGA.GETD"
,
/* A6V A6Q */
"
\\
_SB.PCI0.P0P3.VGA.GETD"
,
/* A6T, A6M */
"
\\
_SB.PCI0.P0PA.VGA.GETD"
,
/* L3C */
"
\\
_SB.PCI0.PCI1.VGAC.NMAP"
,
/* Z96F */
"
\\
_SB.PCI0.VGA.GETD"
,
/* A2D */
"
\\
ACTD"
,
/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
"
\\
ADVG"
,
/* P30 */
"
\\
DNXT"
,
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
"
\\
INFB"
,
/* A3F A6F A3N A3L M6N W3N W6A */
"
\\
SSTE"
);
ASUS_HANDLE
(
ls_switch
,
ASUS_HOTK_PREFIX
"ALSC"
);
/* Z71A Z71V */
ASUS_HANDLE
(
ls_level
,
ASUS_HOTK_PREFIX
"ALSL"
);
/* Z71A Z71V */
#define METHOD_SWITCH_DISPLAY "SDSP"
static
acpi_handle
display_get_handle
;
static
const
char
*
display_get_paths
[]
=
{
/* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
"
\\
_SB.PCI0.P0P1.VGA.GETD"
,
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
"
\\
_SB.PCI0.P0P2.VGA.GETD"
,
/* A6V A6Q */
"
\\
_SB.PCI0.P0P3.VGA.GETD"
,
/* A6T, A6M */
"
\\
_SB.PCI0.P0PA.VGA.GETD"
,
/* L3C */
"
\\
_SB.PCI0.PCI1.VGAC.NMAP"
,
/* Z96F */
"
\\
_SB.PCI0.VGA.GETD"
,
/* A2D */
"
\\
ACTD"
,
/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
"
\\
ADVG"
,
/* P30 */
"
\\
DNXT"
,
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
"
\\
INFB"
,
/* A3F A6F A3N A3L M6N W3N W6A */
"
\\
SSTE"
};
#define METHOD_ALS_CONTROL "ALSC"
/* Z71A Z71V */
#define METHOD_ALS_LEVEL "ALSL"
/* Z71A Z71V */
/* GPS */
/* R2H use different handle for GPS on/off */
ASUS_HANDLE
(
gps_on
,
ASUS_HOTK_PREFIX
"SDON"
);
/* R2H */
ASUS_HANDLE
(
gps_off
,
ASUS_HOTK_PREFIX
"SDOF"
);
/* R2H */
ASUS_HANDLE
(
gps_status
,
ASUS_HOTK_PREFIX
"GPST"
);
#define METHOD_GPS_ON "SDON"
#define METHOD_GPS_OFF "SDOF"
#define METHOD_GPS_STATUS "GPST"
/* Keyboard light */
ASUS_HANDLE
(
kled_set
,
ASUS_HOTK_PREFIX
"SLKB"
);
ASUS_HANDLE
(
kled_get
,
ASUS_HOTK_PREFIX
"GLKB"
);
#define METHOD_KBD_LIGHT_SET "SLKB"
#define METHOD_KBD_LIGHT_GET "GLKB"
/*
* This is the main structure, we can use it to store anything interesting
* about the hotk device
* Define a specific led structure to keep the main structure clean
*/
struct
asus_hotk
{
char
*
name
;
/* laptop name */
struct
acpi_device
*
device
;
/* the device we are in */
acpi_handle
handle
;
/* the handle of the hotk device */
char
status
;
/* status of the hotk, for LEDs, ... */
u32
ledd_status
;
/* status of the LED display */
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
;
struct
asus_led
{
int
wk
;
struct
work_struct
work
;
struct
led_classdev
led
;
struct
asus_laptop
*
asus
;
const
char
*
method
;
};
/*
* This header is made available to allow proper configuration given model,
* revision number , ... this info cannot go in struct asus_hotk because it is
* 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
* This is the main structure, we can use it to store anything interesting
* about the hotk device
*/
static
const
struct
acpi_device_id
asus_device_ids
[]
=
{
{
"ATK0100"
,
0
},
{
"ATK0101"
,
0
},
{
""
,
0
},
};
MODULE_DEVICE_TABLE
(
acpi
,
asus_device_ids
);
struct
asus_laptop
{
char
*
name
;
/* laptop name */
static
int
asus_hotk_add
(
struct
acpi_device
*
device
);
static
int
asus_hotk_remove
(
struct
acpi_device
*
device
,
int
type
);
static
void
asus_hotk_notify
(
struct
acpi_device
*
device
,
u32
event
);
struct
acpi_table_header
*
dsdt_info
;
struct
platform_device
*
platform_device
;
struct
acpi_device
*
device
;
/* the device we are in */
struct
backlight_device
*
backlight_device
;
static
struct
acpi_driver
asus_hotk_driver
=
{
.
name
=
ASUS_HOTK_NAME
,
.
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
,
},
};
struct
input_dev
*
inputdev
;
struct
key_entry
*
keymap
;
/* The backlight device /sys/class/backlight */
static
struct
backlight_device
*
asus_backlight_device
;
struct
asus_led
mled
;
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
;
/*
* The backlight class declaration
*/
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
,
};
int
wireless_status
;
bool
have_rsts
;
int
lcd_state
;
/*
* 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 \
}
struct
rfkill
*
gps_rfkill
;
ASUS_LED
(
mled
,
"mail"
,
1
);
ASUS_LED
(
tled
,
"touchpad"
,
1
);
ASUS_LED
(
rled
,
"record"
,
1
);
ASUS_LED
(
pled
,
"phone"
,
1
);
ASUS_LED
(
gled
,
"gaming"
,
1
);
ASUS_LED
(
kled
,
"kbd_backlight"
,
3
);
struct
key_entry
{
char
type
;
u8
code
;
u16
keycode
;
acpi_handle
handle
;
/* the handle of the hotk device */
u32
ledd_status
;
/* status of the LED display */
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 */
u16
*
keycode_map
;
};
enum
{
KE_KEY
,
KE_END
};
static
struct
key_entry
asus_keymap
[]
=
{
{
KE_KEY
,
0x02
,
KEY_SCREENLOCK
},
{
KE_KEY
,
0x05
,
KEY_WLAN
},
{
KE_KEY
,
0x08
,
KEY_F13
},
{
KE_KEY
,
0x17
,
KEY_ZOOM
},
{
KE_KEY
,
0x1f
,
KEY_BATTERY
},
{
KE_KEY
,
0x30
,
KEY_VOLUMEUP
},
{
KE_KEY
,
0x31
,
KEY_VOLUMEDOWN
},
{
KE_KEY
,
0x32
,
KEY_MUTE
},
{
KE_KEY
,
0x33
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x34
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x40
,
KEY_PREVIOUSSONG
},
{
KE_KEY
,
0x41
,
KEY_NEXTSONG
},
{
KE_KEY
,
0x43
,
KEY_STOPCD
},
{
KE_KEY
,
0x45
,
KEY_PLAYPAUSE
},
{
KE_KEY
,
0x4c
,
KEY_MEDIA
},
{
KE_KEY
,
0x50
,
KEY_EMAIL
},
{
KE_KEY
,
0x51
,
KEY_WWW
},
{
KE_KEY
,
0x55
,
KEY_CALC
},
{
KE_KEY
,
0x5C
,
KEY_SCREENLOCK
},
/* Screenlock */
{
KE_KEY
,
0x5D
,
KEY_WLAN
},
{
KE_KEY
,
0x5E
,
KEY_WLAN
},
{
KE_KEY
,
0x5F
,
KEY_WLAN
},
{
KE_KEY
,
0x60
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x61
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x62
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x63
,
KEY_SWITCHVIDEOMODE
},
{
KE_KEY
,
0x6B
,
KEY_F13
},
/* Lock Touchpad */
{
KE_KEY
,
0x82
,
KEY_CAMERA
},
{
KE_KEY
,
0x88
,
KEY_WLAN
},
{
KE_KEY
,
0x8A
,
KEY_PROG1
},
{
KE_KEY
,
0x95
,
KEY_MEDIA
},
{
KE_KEY
,
0x99
,
KEY_PHONE
},
{
KE_KEY
,
0xc4
,
KEY_KBDILLUMUP
},
{
KE_KEY
,
0xc5
,
KEY_KBDILLUMDOWN
},
static
const
struct
key_entry
asus_keymap
[]
=
{
/* Lenovo SL Specific keycodes */
{
KE_KEY
,
0x02
,
{
KEY_SCREENLOCK
}
},
{
KE_KEY
,
0x05
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x08
,
{
KEY_F13
}
},
{
KE_KEY
,
0x17
,
{
KEY_ZOOM
}
},
{
KE_KEY
,
0x1f
,
{
KEY_BATTERY
}
},
/* End of Lenovo SL Specific keycodes */
{
KE_KEY
,
0x30
,
{
KEY_VOLUMEUP
}
},
{
KE_KEY
,
0x31
,
{
KEY_VOLUMEDOWN
}
},
{
KE_KEY
,
0x32
,
{
KEY_MUTE
}
},
{
KE_KEY
,
0x33
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x34
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x40
,
{
KEY_PREVIOUSSONG
}
},
{
KE_KEY
,
0x41
,
{
KEY_NEXTSONG
}
},
{
KE_KEY
,
0x43
,
{
KEY_STOPCD
}
},
{
KE_KEY
,
0x45
,
{
KEY_PLAYPAUSE
}
},
{
KE_KEY
,
0x4c
,
{
KEY_MEDIA
}
},
{
KE_KEY
,
0x50
,
{
KEY_EMAIL
}
},
{
KE_KEY
,
0x51
,
{
KEY_WWW
}
},
{
KE_KEY
,
0x55
,
{
KEY_CALC
}
},
{
KE_KEY
,
0x5C
,
{
KEY_SCREENLOCK
}
},
/* Screenlock */
{
KE_KEY
,
0x5D
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x5E
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x5F
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x60
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x61
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x62
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x63
,
{
KEY_SWITCHVIDEOMODE
}
},
{
KE_KEY
,
0x6B
,
{
KEY_F13
}
},
/* Lock Touchpad */
{
KE_KEY
,
0x7E
,
{
KEY_BLUETOOTH
}
},
{
KE_KEY
,
0x7D
,
{
KEY_BLUETOOTH
}
},
{
KE_KEY
,
0x82
,
{
KEY_CAMERA
}
},
{
KE_KEY
,
0x88
,
{
KEY_WLAN
}
},
{
KE_KEY
,
0x8A
,
{
KEY_PROG1
}
},
{
KE_KEY
,
0x95
,
{
KEY_MEDIA
}
},
{
KE_KEY
,
0x99
,
{
KEY_PHONE
}
},
{
KE_KEY
,
0xc4
,
{
KEY_KBDILLUMUP
}
},
{
KE_KEY
,
0xc5
,
{
KEY_KBDILLUMDOWN
}
},
{
KE_END
,
0
},
};
/*
* 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
...
...
@@ -339,8 +288,8 @@ static struct key_entry asus_keymap[] = {
*
* returns 0 if write is successful, -1 else.
*/
static
int
write_acpi_int
(
acpi_handle
handle
,
const
char
*
method
,
int
val
,
struct
acpi_buffer
*
output
)
static
int
write_acpi_int
_ret
(
acpi_handle
handle
,
const
char
*
method
,
int
val
,
struct
acpi_buffer
*
output
)
{
struct
acpi_object_list
params
;
/* list of input parameters (an int) */
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,
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
;
acpi_status
rv
=
AE_OK
;
return
write_acpi_int_ret
(
handle
,
method
,
val
,
NULL
);
}
static
int
acpi_check_handle
(
acpi_handle
handle
,
const
char
*
method
,
acpi_handle
*
ret
)
{
acpi_status
status
;
if
(
!
wireless_status_handle
)
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
if
(
method
==
NULL
)
return
-
ENODEV
;
rv
=
acpi_evaluate_integer
(
wireless_status_handle
,
NULL
,
NULL
,
&
status
);
if
(
ACPI_FAILURE
(
rv
))
pr_warning
(
"Error reading Wireless status
\n
"
);
else
return
(
status
&
mask
)
?
1
:
0
;
if
(
ret
)
status
=
acpi_get_handle
(
handle
,
(
char
*
)
method
,
ret
);
else
{
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
;
acpi_status
rv
=
AE_OK
;
rv
=
acpi_evaluate_integer
(
gps_status_handle
,
NULL
,
NULL
,
&
status
);
if
(
ACPI_FAILURE
(
rv
))
pr_warning
(
"Error reading GPS status
\n
"
);
if
(
!
strcmp
(
method
,
METHOD_MLED
))
value
=
!
value
;
else
if
(
!
strcmp
(
method
,
METHOD_GLED
))
value
=
!
value
+
1
;
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 */
if
(
mask
==
BT_ON
||
mask
==
WL_ON
)
return
read_wireless_status
(
mask
);
else
if
(
mask
==
GPS_ON
)
return
read_gps_status
();
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
struct
asus_laptop
*
asus
=
led
->
asus
;
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
);
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
;
}
struct
asus_led
*
led
=
container_of
(
work
,
struct
asus_led
,
work
);
struct
asus_laptop
*
asus
=
led
->
asus
;
if
(
write_acpi_int
(
handle
,
NULL
,
out
,
NULL
))
pr_warning
(
" write failed %x
\n
"
,
mask
);
asus_led_set
(
asus
,
led
->
method
,
led
->
wk
);
}
/* /sys/class/led handlers */
#define ASUS_LED_HANDLER(object, mask) \
static void object##_led_set(struct led_classdev *led_cdev, \
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
);
static
enum
led_brightness
asus_led_cdev_get
(
struct
led_classdev
*
led_cdev
)
{
return
led_cdev
->
brightness
;
}
/*
* 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
;
struct
acpi_object_list
params
;
...
...
@@ -468,75 +397,183 @@ static int get_kled_lvl(void)
in_obj
.
type
=
ACPI_TYPE_INTEGER
;
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
))
{
pr_warning
(
"Error reading kled level
\n
"
);
return
0
;
return
-
ENODEV
;
}
return
kblv
;
}
static
int
set_kled_lvl
(
int
kblv
)
static
int
asus_kled_set
(
struct
asus_laptop
*
asus
,
int
kblv
)
{
if
(
kblv
>
0
)
kblv
=
(
1
<<
7
)
|
(
kblv
&
0x7F
);
else
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
"
);
return
-
EINVAL
;
}
return
0
;
}
static
void
kled_led
_set
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
static
void
asus_kled_cdev
_set
(
struct
led_classdev
*
led_cdev
,
enum
led_brightness
value
)
{
kled_led_wk
=
value
;
queue_work
(
led_workqueue
,
&
kled_led_work
);
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
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
;
acpi_status
status
=
0
;
lcd
=
value
?
1
:
0
;
lcd
=
!!
value
;
if
(
lcd
==
get_lcd_state
(
))
if
(
lcd
==
asus_lcd_status
(
asus
))
return
0
;
if
(
lcd_switch_handle
)
{
status
=
acpi_evaluate_object
(
lcd_switch_handle
,
NULL
,
NULL
,
NULL
);
if
(
!
lcd_switch_handle
)
return
-
ENODEV
;
status
=
acpi_evaluate_object
(
lcd_switch_handle
,
NULL
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
pr_warning
(
"Error switching LCD
\n
"
);
if
(
ACPI_FAILURE
(
status
))
{
pr_warning
(
"Error switching LCD
\n
"
);
return
-
ENODEV
;
}
write_status
(
NULL
,
lcd
,
LCD_ON
)
;
asus
->
lcd_state
=
lcd
;
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
)
{
bd
->
props
.
power
=
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
;
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
))
pr_warning
(
"Error reading brightness
\n
"
);
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
;
value
=
(
0
<
value
)
?
((
15
<
value
)
?
15
:
value
)
:
0
;
/* 0 <= value <= 15 */
struct
asus_laptop
*
asus
=
bl_get_data
(
bd
);
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
"
);
ret
=
-
EIO
;
ret
urn
-
EIO
;
}
return
ret
;
return
0
;
}
static
int
update_bl_status
(
struct
backlight_device
*
bd
)
{
struct
asus_laptop
*
asus
=
bl_get_data
(
bd
);
int
rv
;
int
value
=
bd
->
props
.
brightness
;
rv
=
set_brightness
(
bd
,
value
);
rv
=
asus_
set_brightness
(
bd
,
value
);
if
(
rv
)
return
rv
;
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)
static
ssize_t
show_infos
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
page
)
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
len
=
0
;
unsigned
long
long
temp
;
char
buf
[
16
];
/* enough for all info */
acpi_status
rv
=
AE_OK
;
/*
* We use the easy way, we don't care of off and count,
so we don't set eof
* to 1
* We use the easy way, we don't care of off and count,
*
so we don't set eof
to 1
*/
len
+=
sprintf
(
page
,
ASUS_
HOTK
_NAME
" "
ASUS_LAPTOP_VERSION
"
\n
"
);
len
+=
sprintf
(
page
+
len
,
"Model reference : %s
\n
"
,
hotk
->
name
);
len
+=
sprintf
(
page
,
ASUS_
LAPTOP
_NAME
" "
ASUS_LAPTOP_VERSION
"
\n
"
);
len
+=
sprintf
(
page
+
len
,
"Model reference : %s
\n
"
,
asus
->
name
);
/*
* The SFUN method probably allows the original driver to get the list
* 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.
* 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
))
len
+=
sprintf
(
page
+
len
,
"SFUN value : %#x
\n
"
,
(
uint
)
temp
);
...
...
@@ -624,7 +709,7 @@ static ssize_t show_infos(struct device *dev,
* The significance of others is yet to be found.
* 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
))
len
+=
sprintf
(
page
+
len
,
"HRWS value : %#x
\n
"
,
(
uint
)
temp
);
...
...
@@ -635,26 +720,26 @@ static ssize_t show_infos(struct device *dev,
* Note: since not all the laptops provide this method, errors are
* silently ignored.
*/
rv
=
acpi_evaluate_integer
(
hotk
->
handle
,
"ASYM"
,
NULL
,
&
temp
);
rv
=
acpi_evaluate_integer
(
asus
->
handle
,
"ASYM"
,
NULL
,
&
temp
);
if
(
!
ACPI_FAILURE
(
rv
))
len
+=
sprintf
(
page
+
len
,
"ASYM value : %#x
\n
"
,
(
uint
)
temp
);
if
(
asus_info
)
{
snprintf
(
buf
,
16
,
"%d"
,
asus_info
->
length
);
if
(
asus
->
dsdt
_info
)
{
snprintf
(
buf
,
16
,
"%d"
,
asus
->
dsdt
_info
->
length
);
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
);
snprintf
(
buf
,
16
,
"%d"
,
asus_info
->
revision
);
snprintf
(
buf
,
16
,
"%d"
,
asus
->
dsdt
_info
->
revision
);
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
);
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
);
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
);
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
);
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
);
}
...
...
@@ -672,8 +757,9 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
return
count
;
}
static
ssize_t
store_status
(
const
char
*
buf
,
size_t
count
,
acpi_handle
handle
,
int
mask
)
static
ssize_t
sysfs_acpi_set
(
struct
asus_laptop
*
asus
,
const
char
*
buf
,
size_t
count
,
const
char
*
method
)
{
int
rv
,
value
;
int
out
=
0
;
...
...
@@ -682,8 +768,8 @@ static ssize_t store_status(const char *buf, size_t count,
if
(
rv
>
0
)
out
=
value
?
1
:
0
;
write_status
(
handle
,
out
,
mask
);
if
(
write_acpi_int
(
asus
->
handle
,
method
,
value
))
return
-
ENODEV
;
return
rv
;
}
...
...
@@ -693,67 +779,116 @@ static ssize_t store_status(const char *buf, size_t count,
static
ssize_t
show_ledd
(
struct
device
*
dev
,
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
,
const
char
*
buf
,
size_t
count
)
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
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
"
);
else
hotk
->
ledd_status
=
(
u32
)
value
;
asus
->
ledd_status
=
(
u32
)
value
;
}
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
*/
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
,
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
,
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
*/
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
,
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
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
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
*/
static
void
set_display
(
int
value
)
static
void
asus_set_display
(
struct
asus_laptop
*
asus
,
int
value
)
{
/* 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
"
);
return
;
}
static
int
read_display
(
void
)
static
int
read_display
(
struct
asus_laptop
*
asus
)
{
unsigned
long
long
value
=
0
;
acpi_status
rv
=
AE_OK
;
...
...
@@ -769,7 +904,7 @@ static int read_display(void)
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
;
}
...
...
@@ -781,7 +916,11 @@ static int read_display(void)
static
ssize_t
show_disp
(
struct
device
*
dev
,
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,
static
ssize_t
store_disp
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buf
,
size_t
count
)
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
set_display
(
value
);
asus_set_display
(
asus
,
value
);
return
rv
;
}
/*
* 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
"
);
hotk
->
light_switch
=
value
;
asus
->
light_switch
=
value
;
}
static
ssize_t
show_lssw
(
struct
device
*
dev
,
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
,
const
char
*
buf
,
size_t
count
)
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
set_light_sens_switch
(
value
?
1
:
0
);
asus_als_switch
(
asus
,
value
?
1
:
0
);
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
"
);
hotk
->
light_level
=
value
;
asus
->
light_level
=
value
;
}
static
ssize_t
show_lslvl
(
struct
device
*
dev
,
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
,
const
char
*
buf
,
size_t
count
)
{
struct
asus_laptop
*
asus
=
dev_get_drvdata
(
dev
);
int
rv
,
value
;
rv
=
parse_arg
(
buf
,
count
,
&
value
);
if
(
rv
>
0
)
{
value
=
(
0
<
value
)
?
((
15
<
value
)
?
15
:
value
)
:
0
;
/* 0 <= value <= 15 */
set_light_sens_level
(
value
);
asus_als_level
(
asus
,
value
);
}
return
rv
;
...
...
@@ -861,197 +1007,309 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
/*
* 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
,
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
,
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
;
for
(
key
=
asus_keymap
;
key
->
type
!=
KE_END
;
key
++
)
if
(
code
==
key
->
code
)
return
key
;
acpi_handle
handle
=
data
;
return
NULL
;
return
asus_gps_switch
(
handle
,
!
blocked
)
;
}
static
struct
key_entry
*
asus_get_entry_by_keycode
(
int
code
)
{
struct
key_entry
*
key
;
for
(
key
=
asus_keymap
;
key
->
type
!=
KE_END
;
key
++
)
if
(
code
==
key
->
keycode
&&
key
->
type
==
KE_KEY
)
return
key
;
static
const
struct
rfkill_ops
asus_gps_rfkill_ops
=
{
.
set_block
=
asus_gps_rfkill_set
,
};
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
)
{
*
keycode
=
key
->
keycode
;
if
(
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_ON
,
NULL
)
||
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_OFF
,
NULL
)
||
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_STATUS
,
NULL
))
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
;
int
old_keycode
;
if
(
asus
->
inputdev
)
sparse_keymap_report_event
(
asus
->
inputdev
,
event
,
1
,
true
);
}
if
(
keycode
<
0
||
keycode
>
KEY_MAX
)
return
-
EINVAL
;
static
int
asus_input_init
(
struct
asus_laptop
*
asus
)
{
struct
input_dev
*
input
;
int
error
;
key
=
asus_get_entry_by_scancode
(
scancode
);
if
(
key
&&
key
->
type
==
KE_KEY
)
{
old_keycode
=
key
->
keycode
;
key
->
keycode
=
keycode
;
set_bit
(
keycode
,
dev
->
keybit
);
if
(
!
asus_get_entry_by_keycode
(
old_keycode
))
clear_bit
(
old_keycode
,
dev
->
keybit
);
input
=
input_allocate_device
();
if
(
!
input
)
{
pr_info
(
"Unable to allocate input device
\n
"
);
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
;
u16
count
;
if
(
asus
->
inputdev
)
{
sparse_keymap_free
(
asus
->
inputdev
);
input_unregister_device
(
asus
->
inputdev
);
}
}
/* TODO Find a better way to handle events count. */
if
(
!
hotk
)
return
;
/*
* ACPI driver
*/
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
* switched
*/
if
(
event
==
ATKD_LCD_ON
)
{
write_status
(
NULL
,
1
,
LCD_ON
);
lcd_blank
(
FB_BLANK_UNBLANK
);
}
else
if
(
event
==
ATKD_LCD_OFF
)
{
write_status
(
NULL
,
0
,
LCD_ON
);
lcd_blank
(
FB_BLANK_POWERDOWN
);
}
if
(
event
==
ATKD_LCD_ON
)
lcd_blank
(
asus
,
FB_BLANK_UNBLANK
);
else
if
(
event
==
ATKD_LCD_OFF
)
lcd_blank
(
asus
,
FB_BLANK_POWERDOWN
);
count
=
hotk
->
event_count
[
event
%
128
]
++
;
acpi_bus_generate_proc_event
(
hotk
->
device
,
event
,
count
);
acpi_bus_generate_netlink_event
(
hotk
->
device
->
pnp
.
device_class
,
dev_name
(
&
hotk
->
device
->
dev
),
event
,
/* TODO Find a better way to handle events count. */
count
=
asus
->
event_count
[
event
%
128
]
++
;
acpi_bus_generate_proc_event
(
asus
->
device
,
event
,
count
);
acpi_bus_generate_netlink_event
(
asus
->
device
->
pnp
.
device_class
,
dev_name
(
&
asus
->
device
->
dev
),
event
,
count
);
if
(
hotk
->
inputdev
)
{
key
=
asus_get_entry_by_scancode
(
event
);
if
(
!
key
)
return
;
switch
(
key
->
type
)
{
case
KE_KEY
:
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
;
/* Brightness events are special */
if
(
event
>=
ATKD_BR_MIN
&&
event
<=
ATKD_BR_MAX
)
{
/* Ignore them completely if the acpi video driver is used */
if
(
asus
->
backlight_device
!=
NULL
)
{
/* Update the backlight device. */
asus_backlight_notify
(
asus
);
}
return
;
}
asus_input_notify
(
asus
,
event
);
}
#define ASUS_CREATE_DEVICE_ATTR(_name) \
struct device_attribute dev_attr_##_name = { \
.attr = { \
.name = __stringify(_name), \
.mode = 0 }, \
.show = NULL, \
.store = NULL, \
static
DEVICE_ATTR
(
infos
,
S_IRUGO
,
show_infos
,
NULL
);
static
DEVICE_ATTR
(
wlan
,
S_IRUGO
|
S_IWUSR
,
show_wlan
,
store_wlan
);
static
DEVICE_ATTR
(
bluetooth
,
S_IRUGO
|
S_IWUSR
,
show_bluetooth
,
store_bluetooth
);
static
DEVICE_ATTR
(
display
,
S_IRUGO
|
S_IWUSR
,
show_disp
,
store_disp
);
static
DEVICE_ATTR
(
ledd
,
S_IRUGO
|
S_IWUSR
,
show_ledd
,
store_ledd
);
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) \
do { \
dev_attr_##_name.attr.mode = _mode; \
dev_attr_##_name.show = _show; \
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
};
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_BLUETOOTH
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_bluetooth
);
if
(
err
)
return
err
;
}
static
struct
attribute_group
asuspf_attribute_group
=
{
.
attrs
=
asuspf_attributes
};
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_SWITCH_DISPLAY
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_display
);
if
(
err
)
return
err
;
}
static
struct
platform_driver
asuspf_driver
=
{
.
driver
=
{
.
name
=
ASUS_HOTK_FILE
,
.
owner
=
THIS_MODULE
,
}
};
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_LEDD
,
NULL
))
{
err
=
device_create_file
(
&
device
->
dev
,
&
dev_attr_ledd
);
if
(
err
)
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
)
{
ASUS_SET_DEVICE_ATTR
(
infos
,
0444
,
show_infos
,
NULL
);
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_ON
,
NULL
)
&&
!
acpi_check_handle
(
asus
->
handle
,
METHOD_GPS_OFF
,
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
)
ASUS_SET_DEVICE_ATTR
(
wlan
,
0644
,
show_wlan
,
store_wlan
);
return
err
;
}
static
int
asus_platform_init
(
struct
asus_laptop
*
asus
)
{
int
err
;
if
(
bt_switch_handle
)
ASUS_SET_DEVICE_ATTR
(
bluetooth
,
0644
,
show_bluetooth
,
store_bluetooth
);
asus
->
platform_device
=
platform_device_alloc
(
ASUS_LAPTOP_FILE
,
-
1
);
if
(
!
asus
->
platform_device
)
return
-
ENOMEM
;
platform_set_drvdata
(
asus
->
platform_device
,
asus
);
if
(
display_set_handle
&&
display_get_handle
)
ASUS_SET_DEVICE_ATTR
(
display
,
0644
,
show_disp
,
store_disp
);
else
if
(
display_set_handle
)
ASUS_SET_DEVICE_ATTR
(
display
,
0200
,
NULL
,
store_disp
);
err
=
platform_device_add
(
asus
->
platform_device
);
if
(
err
)
goto
fail_platform_device
;
if
(
ledd_set_handle
)
ASUS_SET_DEVICE_ATTR
(
ledd
,
0644
,
show_ledd
,
store_ledd
);
err
=
asus_sysfs_init
(
asus
);
if
(
err
)
goto
fail_sysfs
;
return
0
;
if
(
ls_switch_handle
&&
ls_level_handle
)
{
ASUS_SET_DEVICE_ATTR
(
ls_level
,
0644
,
show_lslvl
,
store_lslvl
);
ASUS_SET_DEVICE_ATTR
(
ls_switch
,
0644
,
show_lssw
,
store_lssw
);
}
fail_sysfs:
asus_sysfs_exit
(
asus
);
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
)
ASUS_SET_DEVICE_ATTR
(
gps
,
0644
,
show_gps
,
store_gps
);
static
void
asus_platform_exit
(
struct
asus_laptop
*
asus
)
{
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
,
char
**
paths
,
int
num_paths
)
{
...
...
@@ -1073,10 +1331,11 @@ static int asus_handle_init(char *name, acpi_handle * handle,
ARRAY_SIZE(object##_paths))
/*
* This function is used to initialize the hotk with right values. In this
* method, we can make all the detection we want, and modify the hotk struct
* 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 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
};
union
acpi_object
*
model
=
NULL
;
...
...
@@ -1089,22 +1348,21 @@ static int asus_hotk_get_info(void)
* models, but late enough to allow acpi_bus_register_driver() to fail
* before doing anything ACPI-specific. Should we encounter a machine,
* which needs special handling (i.e. its hotkey device has a different
* HID), this bit will be moved. A global variable asus_info contains
* the DSDT header.
* HID), this bit will be moved.
*/
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
))
pr_warning
(
"Couldn't get the DSDT table header
\n
"
);
/* 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
"
);
return
-
ENODEV
;
}
/* This needs to be called for some laptops to init properly */
status
=
acpi_evaluate_integer
(
hotk
->
handle
,
"BSTS"
,
NULL
,
&
bsts_result
);
acpi_evaluate_integer
(
asus
->
handle
,
"BSTS"
,
NULL
,
&
bsts_result
);
if
(
ACPI_FAILURE
(
status
))
pr_warning
(
"Error calling BSTS
\n
"
);
else
if
(
bsts_result
)
...
...
@@ -1112,8 +1370,8 @@ static int asus_hotk_get_info(void)
(
uint
)
bsts_result
);
/* 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.
* Handle every possible object (or the lack of thereof) the DSDT
...
...
@@ -1134,397 +1392,210 @@ static int asus_hotk_get_info(void)
break
;
}
}
hotk
->
name
=
kstrdup
(
string
,
GFP_KERNEL
);
if
(
!
hotk
->
name
)
asus
->
name
=
kstrdup
(
string
,
GFP_KERNEL
);
if
(
!
asus
->
name
)
return
-
ENOMEM
;
if
(
*
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.
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
* The significance of others is yet to be found.
* If we don't find the method, we assume the device are present.
*/
status
=
acpi_evaluate_integer
(
hotk
->
handle
,
"HRWS"
,
NULL
,
&
hwrs_result
);
if
(
ACPI_FAILURE
(
status
))
hwrs_result
=
WL_HWRS
|
BT_HWRS
;
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
);
acpi_evaluate_integer
(
asus
->
handle
,
"HRWS"
,
NULL
,
&
hwrs_result
);
if
(
!
ACPI_FAILURE
(
status
))
pr_notice
(
" HRWS returned %x"
,
(
int
)
hwrs_result
);
ASUS_HANDLE_INIT
(
brightness_set
);
ASUS_HANDLE_INIT
(
brightness_get
)
;
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_WL_STATUS
,
NULL
))
asus
->
have_rsts
=
true
;
/* Scheduled for removal */
ASUS_HANDLE_INIT
(
lcd_switch
);
ASUS_HANDLE_INIT
(
display_set
);
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
);
return
AE_OK
;
}
static
int
asus_input_init
(
void
)
{
const
struct
key_entry
*
key
;
int
result
;
static
bool
asus_device_present
;
hotk
->
inputdev
=
input_allocate_device
();
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
)
static
int
__devinit
asus_acpi_init
(
struct
asus_laptop
*
asus
)
{
int
result
=
0
;
result
=
acpi_bus_get_status
(
hotk
->
device
);
result
=
acpi_bus_get_status
(
asus
->
device
);
if
(
result
)
return
result
;
if
(
hotk
->
device
->
status
.
present
)
{
result
=
asus_hotk_get_info
();
}
else
{
if
(
!
asus
->
device
->
status
.
present
)
{
pr_err
(
"Hotkey device not present, aborting
\n
"
);
return
-
E
INVAL
;
return
-
E
NODEV
;
}
return
result
;
}
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
();
result
=
asus_laptop_get_info
(
asus
);
if
(
result
)
goto
end
;
asus_hotk_add_fs
();
asus_hotk_found
=
1
;
return
result
;
/* WLED and BLED are on by default */
write_status
(
bt_switch_handle
,
1
,
BT_ON
);
write_status
(
wl_switch_handle
,
1
,
WL_ON
);
/* 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
);
if
(
bluetooth_status
>=
0
)
asus_bluetooth_set
(
asus
,
!!
bluetooth_status
);
/* LCD Backlight is on by default */
write_status
(
NULL
,
1
,
LCD_ON
);
if
(
wlan_status
>=
0
)
asus_wlan_set
(
asus
,
!!
wlan_status
);
/* Keyboard Backlight is on by default */
if
(
kled_set_handle
)
set_kled_lvl
(
1
);
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_KBD_LIGHT_SET
,
NULL
)
)
asus_kled_set
(
asus
,
1
);
/* LED display is off by default */
hotk
->
ledd_status
=
0xFFF
;
asus
->
ledd_status
=
0xFFF
;
/* Set initial values of light sensor and level */
hotk
->
light_switch
=
0
;
/* Default to light sensor disabled */
hotk
->
light_level
=
5
;
/* level 5 for sensor sensitivity */
asus
->
light_switch
=
0
;
/* Default to light sensor disabled */
asus
->
light_level
=
5
;
/* level 5 for sensor sensitivity */
if
(
ls_switch_handle
)
set_light_sens_switch
(
hotk
->
light_switch
);
if
(
ls_level_handle
)
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
);
if
(
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_CONTROL
,
NULL
)
&&
!
acpi_check_handle
(
asus
->
handle
,
METHOD_ALS_LEVEL
,
NULL
))
{
asus_als_switch
(
asus
,
asus
->
light_switch
);
asus_als_level
(
asus
,
asus
->
light_level
);
}
asus
->
lcd_state
=
1
;
/* LCD should be on when the module load */
return
result
;
}
static
int
asus_hotk_remove
(
struct
acpi_device
*
device
,
int
type
)
{
kfree
(
hotk
->
name
);
kfree
(
hotk
);
return
0
;
}
static
void
asus_backlight_exit
(
void
)
static
int
__devinit
asus_acpi_add
(
struct
acpi_device
*
device
)
{
if
(
asus_backlight_device
)
backlight_device_unregister
(
asus_backlight_device
);
}
#define ASUS_LED_UNREGISTER(object) \
if (object##_led.dev) \
led_classdev_unregister(&object##_led)
struct
asus_laptop
*
asus
;
int
result
;
static
void
asus_led_exit
(
void
)
{
destroy_workqueue
(
led_workqueue
);
ASUS_LED_UNREGISTER
(
mled
);
ASUS_LED_UNREGISTER
(
tled
)
;
ASUS_LED_UNREGISTER
(
pled
)
;
ASUS_LED_UNREGISTER
(
rled
);
ASUS_LED_UNREGISTER
(
gled
);
ASUS_LED_UNREGISTER
(
kled
)
;
}
pr_notice
(
"Asus Laptop Support version %s
\n
"
,
ASUS_LAPTOP_VERSION
);
asus
=
kzalloc
(
sizeof
(
struct
asus_laptop
),
GFP_KERNEL
);
if
(
!
asus
)
return
-
ENOMEM
;
asus
->
handle
=
device
->
handle
;
strcpy
(
acpi_device_name
(
device
),
ASUS_LAPTOP_DEVICE_NAME
);
strcpy
(
acpi_device_class
(
device
),
ASUS_LAPTOP_CLASS
);
device
->
driver_data
=
asus
;
asus
->
device
=
device
;
static
void
asus_input_exit
(
void
)
{
if
(
hotk
->
inputdev
)
input_unregister_device
(
hotk
->
inputdev
);
}
result
=
asus_acpi_init
(
asus
);
if
(
result
)
goto
fail_platform
;
static
void
__exit
asus_laptop_exit
(
void
)
{
asus_backlight_exit
();
asus_led_exit
();
asus_input_exit
();
/*
* Register the platform device first. It is used as a parent for the
* sub-devices below.
*/
result
=
asus_platform_init
(
asus
);
if
(
result
)
goto
fail_platform
;
acpi_bus_unregister_driver
(
&
asus_hotk_driver
);
sysfs_remove_group
(
&
asuspf_device
->
dev
.
kobj
,
&
asuspf_attribute_group
);
platform_device_unregister
(
asuspf_device
);
platform_driver_unregister
(
&
asuspf_driver
);
}
if
(
!
acpi_video_backlight_support
())
{
result
=
asus_backlight_init
(
asus
);
if
(
result
)
goto
fail_backlight
;
}
else
pr_info
(
"Backlight controlled by ACPI video driver
\n
"
);
static
int
asus_backlight_init
(
struct
device
*
dev
)
{
struct
backlight_device
*
bd
;
result
=
asus_input_init
(
asus
);
if
(
result
)
goto
fail_input
;
if
(
brightness_set_handle
&&
lcd_switch_handle
)
{
bd
=
backlight_device_register
(
ASUS_HOTK_FILE
,
dev
,
NULL
,
&
asusbl_ops
);
if
(
IS_ERR
(
bd
))
{
pr_err
(
"Could not register asus backlight device
\n
"
);
asus_backlight_device
=
NULL
;
return
PTR_ERR
(
bd
);
}
result
=
asus_led_init
(
asus
);
if
(
result
)
goto
fail_led
;
asus_backlight_device
=
bd
;
result
=
asus_rfkill_init
(
asus
);
if
(
result
)
goto
fail_rfkill
;
bd
->
props
.
max_brightness
=
15
;
bd
->
props
.
brightness
=
read_brightness
(
NULL
);
bd
->
props
.
power
=
FB_BLANK_UNBLANK
;
backlight_update_status
(
bd
);
}
asus_device_present
=
true
;
return
0
;
}
static
int
asus_led_register
(
acpi_handle
handle
,
struct
led_classdev
*
ldev
,
struct
device
*
dev
)
{
if
(
!
handle
)
return
0
;
fail_rfkill:
asus_led_exit
(
asus
);
fail_led:
asus_input_exit
(
asus
);
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) \
asus_led_register(object##_set_handle, &object##_led, device)
static
int
asus_led_init
(
struct
device
*
dev
)
static
int
asus_acpi_remove
(
struct
acpi_device
*
device
,
int
type
)
{
int
rv
;
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
;
struct
asus_laptop
*
asus
=
acpi_driver_data
(
device
);
if
(
kled_set_handle
&&
kled_get_handle
)
rv
=
ASUS_LED_REGISTER
(
kled
,
dev
);
if
(
rv
)
goto
out5
;
led_workqueue
=
create_singlethread_workqueue
(
"led_workqueue"
);
if
(
!
led_workqueue
)
goto
out6
;
asus_backlight_exit
(
asus
);
asus_rfkill_exit
(
asus
);
asus_led_exit
(
asus
);
asus_input_exit
(
asus
);
asus_platform_exit
(
asus
);
kfree
(
asus
->
name
);
kfree
(
asus
);
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
)
{
int
result
;
result
=
acpi_bus_register_driver
(
&
asus_hotk
_driver
);
result
=
platform_driver_register
(
&
platform
_driver
);
if
(
result
<
0
)
return
result
;
/*
* This is a bit of a kludge. We only want this module loaded
* for ASUS systems, but there's currently no way to probe the
* ACPI namespace for ASUS HIDs. So we just return failure if
* we didn't find one, which will cause the module to be
* unloaded.
*/
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
=
acpi_bus_register_driver
(
&
asus_acpi_driver
);
if
(
result
<
0
)
goto
fail_acpi_driver
;
if
(
!
asus_device_present
)
{
result
=
-
ENODEV
;
goto
fail_no_device
;
}
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
;
fail_backlight:
asus_led_exit
();
fail_led:
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:
fail_no_device:
acpi_bus_unregister_driver
(
&
asus_acpi_driver
);
fail_acpi_driver:
platform_driver_unregister
(
&
platform_driver
);
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_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)
struct
pci_dev
*
dev
;
struct
pci_bus
*
bus
;
bool
blocked
=
eeepc_wlan_rfkill_blocked
(
eeepc
);
bool
absent
;
u32
l
;
if
(
eeepc
->
wlan_rfkill
)
rfkill_set_sw_state
(
eeepc
->
wlan_rfkill
,
blocked
);
...
...
@@ -591,6 +593,22 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc)
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
)
{
dev
=
pci_get_slot
(
bus
,
0
);
if
(
dev
)
{
...
...
@@ -1277,7 +1295,8 @@ static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
* hotplug code. In fact, current hotplug code seems to unplug another
* 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
;
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