Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
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
Show 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."
/*
* 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,46 +78,82 @@ 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 */
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 */
"
\\
Q10"
}
;
/* A2x, L2D, L3D, M2E */
/* Display */
ASUS_HANDLE
(
display_set
,
ASUS_HOTK_PREFIX
"SDSP"
);
ASUS_HANDLE
(
display_get
,
#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 */
...
...
@@ -174,164 +175,112 @@ ASUS_HANDLE(display_get,
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
"
\\
INFB"
,
/* A3F A6F A3N A3L M6N W3N W6A */
"
\\
SSTE"
)
;
"
\\
SSTE"
}
;
ASUS_HANDLE
(
ls_switch
,
ASUS_HOTK_PREFIX
"ALSC"
);
/* Z71A Z71V */
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 */
/* 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,7 +288,7 @@ 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
,
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) */
...
...
@@ -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
)
;
}
if
(
!
wireless_status_handle
)
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
static
int
acpi_check_handle
(
acpi_handle
handle
,
const
char
*
method
,
acpi_handle
*
ret
)
{
acpi_status
status
;
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
(
method
==
NULL
)
return
-
ENODEV
;
return
(
hotk
->
status
&
mask
)
?
1
:
0
;
if
(
ret
)
status
=
acpi_get_handle
(
handle
,
(
char
*
)
method
,
ret
);
else
{
acpi_handle
dummy
;
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
);
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
))
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
,
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
asus_kled_cdev_update
(
struct
work_struct
*
work
)
{
struct
asus_led
*
led
=
container_of
(
work
,
struct
asus_led
,
work
);
struct
asus_laptop
*
asus
=
led
->
asus
;
asus_kled_set
(
asus
,
led
->
wk
);
}
static
void
kled_led_update
(
struct
work_struct
*
ignored
)
static
enum
led_brightness
asus_kled_cdev_get
(
struct
led_classdev
*
led_cdev
)
{
set_kled_lvl
(
kled_led_wk
);
struct
asus_led
*
led
=
container_of
(
led_cdev
,
struct
asus_led
,
led
);
struct
asus_laptop
*
asus
=
led
->
asus
;
return
asus_kled_lvl
(
asus
);
}
static
enum
led_brightness
kled_led_get
(
struct
led_classdev
*
led_cdev
)
static
void
asus_led_exit
(
struct
asus_laptop
*
asus
)
{
return
get_kled_lvl
();
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
get_lcd_state
(
void
)
/* 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
read_status
(
LCD_ON
)
;
return
asus
->
lcd_state
;
}
static
int
set_lcd_state
(
int
value
)
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
)
{
if
(
!
lcd_switch_handle
)
return
-
ENODEV
;
status
=
acpi_evaluate_object
(
lcd_switch_handle
,
NULL
,
NULL
,
NULL
);
if
(
ACPI_FAILURE
(
status
))
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
;
...
...
@@ -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
;
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
)
{
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
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
;
}
return
-
EINVAL
;
asus
->
inputdev
=
input
;
return
0
;
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
;
/* Brightness events are special */
if
(
event
>=
ATKD_BR_MIN
&&
event
<=
ATKD_BR_MAX
)
{
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
;
/* 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
;
}
if
(
bt_switch_handle
)
ASUS_SET_DEVICE_ATTR
(
bluetooth
,
0644
,
show_bluetooth
,
store_bluetooth
)
;
static
int
asus_platform_init
(
struct
asus_laptop
*
asus
)
{
int
err
;
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
);
asus
->
platform_device
=
platform_device_alloc
(
ASUS_LAPTOP_FILE
,
-
1
);
if
(
!
asus
->
platform_device
)
return
-
ENOMEM
;
platform_set_drvdata
(
asus
->
platform_device
,
asus
);
if
(
ledd_set_handle
)
ASUS_SET_DEVICE_ATTR
(
ledd
,
0644
,
show_ledd
,
store_ledd
);
err
=
platform_device_add
(
asus
->
platform_device
);
if
(
err
)
goto
fail_platform_device
;
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
);
}
err
=
asus_sysfs_init
(
asus
);
if
(
err
)
goto
fail_sysfs
;
return
0
;
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
;
acpi_evaluate_integer
(
asus
->
handle
,
"HRWS"
,
NULL
,
&
hwrs_result
);
if
(
!
ACPI_FAILURE
(
status
))
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
);
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
;
struct
asus_laptop
*
asus
=
acpi_driver_data
(
device
);
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
)
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