Merge branch 'asus' into release
This commit is contained in:
commit
b4549a24b6
9 changed files with 832 additions and 195 deletions
36
Documentation/ABI/stable/sysfs-class-backlight
Normal file
36
Documentation/ABI/stable/sysfs-class-backlight
Normal file
|
@ -0,0 +1,36 @@
|
|||
What: /sys/class/backlight/<backlight>/bl_power
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Control BACKLIGHT power, values are FB_BLANK_* from fb.h
|
||||
- FB_BLANK_UNBLANK (0) : power on.
|
||||
- FB_BLANK_POWERDOWN (4) : power off
|
||||
Users: HAL
|
||||
|
||||
What: /sys/class/backlight/<backlight>/brightness
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Control the brightness for this <backlight>. Values
|
||||
are between 0 and max_brightness. This file will also
|
||||
show the brightness level stored in the driver, which
|
||||
may not be the actual brightness (see actual_brightness).
|
||||
Users: HAL
|
||||
|
||||
What: /sys/class/backlight/<backlight>/actual_brightness
|
||||
Date: March 2006
|
||||
KernelVersion: 2.6.17
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Show the actual brightness by querying the hardware.
|
||||
Users: HAL
|
||||
|
||||
What: /sys/class/backlight/<backlight>/max_brightness
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Maximum brightness for <backlight>.
|
||||
Users: HAL
|
23
Documentation/ABI/testing/sysfs-class-lcd
Normal file
23
Documentation/ABI/testing/sysfs-class-lcd
Normal file
|
@ -0,0 +1,23 @@
|
|||
What: /sys/class/lcd/<lcd>/lcd_power
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Control LCD power, values are FB_BLANK_* from fb.h
|
||||
- FB_BLANK_UNBLANK (0) : power on.
|
||||
- FB_BLANK_POWERDOWN (4) : power off
|
||||
|
||||
What: /sys/class/lcd/<lcd>/contrast
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Current contrast of this LCD device. Value is between 0 and
|
||||
/sys/class/lcd/<lcd>/max_contrast.
|
||||
|
||||
What: /sys/class/lcd/<lcd>/max_contrast
|
||||
Date: April 2005
|
||||
KernelVersion: 2.6.12
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Maximum contrast for this LCD device.
|
28
Documentation/ABI/testing/sysfs-class-led
Normal file
28
Documentation/ABI/testing/sysfs-class-led
Normal file
|
@ -0,0 +1,28 @@
|
|||
What: /sys/class/leds/<led>/brightness
|
||||
Date: March 2006
|
||||
KernelVersion: 2.6.17
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Set the brightness of the LED. Most LEDs don't
|
||||
have hardware brightness support so will just be turned on for
|
||||
non-zero brightness settings. The value is between 0 and
|
||||
/sys/class/leds/<led>/max_brightness.
|
||||
|
||||
What: /sys/class/leds/<led>/max_brightness
|
||||
Date: March 2006
|
||||
KernelVersion: 2.6.17
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Maximum brightness level for this led, default is 255 (LED_FULL).
|
||||
|
||||
What: /sys/class/leds/<led>/trigger
|
||||
Date: March 2006
|
||||
KernelVersion: 2.6.17
|
||||
Contact: Richard Purdie <rpurdie@rpsys.net>
|
||||
Description:
|
||||
Set the trigger for this LED. A trigger is a kernel based source
|
||||
of led events.
|
||||
You can change triggers in a similar manner to the way an IO
|
||||
scheduler is chosen. Trigger specific parameters can appear in
|
||||
/sys/class/leds/<led> once a given trigger is selected.
|
||||
|
52
Documentation/ABI/testing/sysfs-platform-asus-laptop
Normal file
52
Documentation/ABI/testing/sysfs-platform-asus-laptop
Normal file
|
@ -0,0 +1,52 @@
|
|||
What: /sys/devices/platform/asus-laptop/display
|
||||
Date: January 2007
|
||||
KernelVersion: 2.6.20
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
This file allows display switching. The value
|
||||
is composed by 4 bits and defined as follow:
|
||||
4321
|
||||
|||`- LCD
|
||||
||`-- CRT
|
||||
|`--- TV
|
||||
`---- DVI
|
||||
Ex: - 0 (0000b) means no display
|
||||
- 3 (0011b) CRT+LCD.
|
||||
|
||||
What: /sys/devices/platform/asus-laptop/gps
|
||||
Date: January 2007
|
||||
KernelVersion: 2.6.20
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the gps device. 1 means on, 0 means off.
|
||||
Users: Lapsus
|
||||
|
||||
What: /sys/devices/platform/asus-laptop/ledd
|
||||
Date: January 2007
|
||||
KernelVersion: 2.6.20
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
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/
|
||||
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
|
||||
Date: January 2007
|
||||
KernelVersion: 2.6.20
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the bluetooth device. 1 means on, 0 means off.
|
||||
This may control the led, the device or both.
|
||||
Users: Lapsus
|
||||
|
||||
What: /sys/devices/platform/asus-laptop/wlan
|
||||
Date: January 2007
|
||||
KernelVersion: 2.6.20
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the bluetooth device. 1 means on, 0 means off.
|
||||
This may control the led, the device or both.
|
||||
Users: Lapsus
|
50
Documentation/ABI/testing/sysfs-platform-eeepc-laptop
Normal file
50
Documentation/ABI/testing/sysfs-platform-eeepc-laptop
Normal file
|
@ -0,0 +1,50 @@
|
|||
What: /sys/devices/platform/eeepc-laptop/disp
|
||||
Date: May 2008
|
||||
KernelVersion: 2.6.26
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
This file allows display switching.
|
||||
- 1 = LCD
|
||||
- 2 = CRT
|
||||
- 3 = LCD+CRT
|
||||
If you run X11, you should use xrandr instead.
|
||||
|
||||
What: /sys/devices/platform/eeepc-laptop/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
|
||||
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
|
||||
Date: Jun 2009
|
||||
KernelVersion: 2.6.31
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Change CPU clock configuration.
|
||||
On the Eee PC 1000H there are three available clock configuration:
|
||||
* 0 -> Super Performance Mode
|
||||
* 1 -> High Performance Mode
|
||||
* 2 -> Power Saving Mode
|
||||
On Eee PC 701 there is only 2 available clock configurations.
|
||||
Available configuration are listed in available_cpufv file.
|
||||
Reading this file will show the raw hexadecimal value which
|
||||
is defined as follow:
|
||||
| 8 bit | 8 bit |
|
||||
| `---- Current mode
|
||||
`------------ Availables modes
|
||||
For example, 0x301 means: mode 1 selected, 3 available modes.
|
||||
|
||||
What: /sys/devices/platform/eeepc-laptop/available_cpufv
|
||||
Date: Jun 2009
|
||||
KernelVersion: 2.6.31
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
List available cpufv modes.
|
258
Documentation/laptops/asus-laptop.txt
Normal file
258
Documentation/laptops/asus-laptop.txt
Normal file
|
@ -0,0 +1,258 @@
|
|||
Asus Laptop Extras
|
||||
|
||||
Version 0.1
|
||||
August 6, 2009
|
||||
|
||||
Corentin Chary <corentincj@iksaif.net>
|
||||
http://acpi4asus.sf.net/
|
||||
|
||||
This driver provides support for extra features of ACPI-compatible ASUS laptops.
|
||||
It may also support some MEDION, JVC or VICTOR laptops (such as MEDION 9675 or
|
||||
VICTOR XP7210 for example). It makes all the extra buttons generate standard
|
||||
ACPI events that go through /proc/acpi/events and input events (like keyboards).
|
||||
On some models adds support for changing the display brightness and output,
|
||||
switching the LCD backlight on and off, and most importantly, allows you to
|
||||
blink those fancy LEDs intended for reporting mail and wireless status.
|
||||
|
||||
This driver supercedes the old asus_acpi driver.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Kernel 2.6.X sources, configured for your computer, with ACPI support.
|
||||
You also need CONFIG_INPUT and CONFIG_ACPI.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
The features currently supported are the following (see below for
|
||||
detailed description):
|
||||
|
||||
- Fn key combinations
|
||||
- Bluetooth enable and disable
|
||||
- Wlan enable and disable
|
||||
- GPS enable and disable
|
||||
- Video output switching
|
||||
- Ambient Light Sensor on and off
|
||||
- LED control
|
||||
- LED Display control
|
||||
- LCD brightness control
|
||||
- LCD on and off
|
||||
|
||||
A compatibility table by model and feature is maintained on the web
|
||||
site, http://acpi4asus.sf.net/.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
Try "modprobe asus_acpi". Check your dmesg (simply type dmesg). You should
|
||||
see some lines like this :
|
||||
|
||||
Asus Laptop Extras version 0.42
|
||||
L2D model detected.
|
||||
|
||||
If it is not the output you have on your laptop, send it (and the laptop's
|
||||
DSDT) to me.
|
||||
|
||||
That's all, now, all the events generated by the hotkeys of your laptop
|
||||
should be reported in your /proc/acpi/event entry. You can check with
|
||||
"acpi_listen".
|
||||
|
||||
Hotkeys are also reported as input keys (like keyboards) you can check
|
||||
which key are supported using "xev" under X11.
|
||||
|
||||
You can get informations on the version of your DSDT table by reading the
|
||||
/sys/devices/platform/asus-laptop/infos entry. If you have a question or a
|
||||
bug report to do, please include the output of this entry.
|
||||
|
||||
LEDs
|
||||
----
|
||||
|
||||
You can modify LEDs be echoing values to /sys/class/leds/asus::*/brightness :
|
||||
echo 1 > /sys/class/leds/asus::mail/brightness
|
||||
will switch the mail LED on.
|
||||
You can also know if they are on/off by reading their content and use
|
||||
kernel triggers like ide-disk or heartbeat.
|
||||
|
||||
Backlight
|
||||
---------
|
||||
|
||||
You can control lcd backlight power and brightness with
|
||||
/sys/class/backlight/asus-laptop/. Brightness Values are between 0 and 15.
|
||||
|
||||
Wireless devices
|
||||
---------------
|
||||
|
||||
You can turn the internal Bluetooth adapter on/off with the bluetooth entry
|
||||
(only on models with Bluetooth). This usually controls the associated LED.
|
||||
Same for Wlan adapter.
|
||||
|
||||
Display switching
|
||||
-----------------
|
||||
|
||||
Note: the display switching code is currently considered EXPERIMENTAL.
|
||||
|
||||
Switching works for the following models:
|
||||
L3800C
|
||||
A2500H
|
||||
L5800C
|
||||
M5200N
|
||||
W1000N (albeit with some glitches)
|
||||
M6700R
|
||||
A6JC
|
||||
F3J
|
||||
|
||||
Switching doesn't work for the following:
|
||||
M3700N
|
||||
L2X00D (locks the laptop under certain conditions)
|
||||
|
||||
To switch the displays, echo values from 0 to 15 to
|
||||
/sys/devices/platform/asus-laptop/display. The significance of those values
|
||||
is as follows:
|
||||
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
| Bin | Val | DVI | TV | CRT | LCD |
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0000 + 0 + + + + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0001 + 1 + + + + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0010 + 2 + + + X + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0011 + 3 + + + X + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0100 + 4 + + X + + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0101 + 5 + + X + + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0110 + 6 + + X + X + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 0111 + 7 + + X + X + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1000 + 8 + X + + + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1001 + 9 + X + + + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1010 + 10 + X + + X + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1011 + 11 + X + + X + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1100 + 12 + X + X + + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1101 + 13 + X + X + + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1110 + 14 + X + X + X + +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
+ 1111 + 15 + X + X + X + X +
|
||||
+-------+-----+-----+-----+-----+-----+
|
||||
|
||||
In most cases, the appropriate displays must be plugged in for the above
|
||||
combinations to work. TV-Out may need to be initialized at boot time.
|
||||
|
||||
Debugging:
|
||||
1) Check whether the Fn+F8 key:
|
||||
a) does not lock the laptop (try disabling CONFIG_X86_UP_APIC or boot with
|
||||
noapic / nolapic if it does)
|
||||
b) generates events (0x6n, where n is the value corresponding to the
|
||||
configuration above)
|
||||
c) actually works
|
||||
Record the disp value at every configuration.
|
||||
2) Echo values from 0 to 15 to /sys/devices/platform/asus-laptop/display.
|
||||
Record its value, note any change. If nothing changes, try a broader range,
|
||||
up to 65535.
|
||||
3) Send ANY output (both positive and negative reports are needed, unless your
|
||||
machine is already listed above) to the acpi4asus-user mailing list.
|
||||
|
||||
Note: on some machines (e.g. L3C), after the module has been loaded, only 0x6n
|
||||
events are generated and no actual switching occurs. In such a case, a line
|
||||
like:
|
||||
|
||||
echo $((10#$arg-60)) > /sys/devices/platform/asus-laptop/display
|
||||
|
||||
will usually do the trick ($arg is the 0000006n-like event passed to acpid).
|
||||
|
||||
Note: there is currently no reliable way to read display status on xxN
|
||||
(Centrino) models.
|
||||
|
||||
LED display
|
||||
-----------
|
||||
|
||||
Some models like the W1N have a LED display that can be used to display
|
||||
several informations.
|
||||
|
||||
LED display works for the following models:
|
||||
W1000N
|
||||
W1J
|
||||
|
||||
To control the LED display, use the following :
|
||||
|
||||
echo 0x0T000DDD > /sys/devices/platform/asus-laptop/
|
||||
|
||||
where T control the 3 letters display, and DDD the 3 digits display,
|
||||
according to the tables below.
|
||||
|
||||
DDD (digits)
|
||||
000 to 999 = display digits
|
||||
AAA = ---
|
||||
BBB to FFF = turn-off
|
||||
|
||||
T (type)
|
||||
0 = off
|
||||
1 = dvd
|
||||
2 = vcd
|
||||
3 = mp3
|
||||
4 = cd
|
||||
5 = tv
|
||||
6 = cpu
|
||||
7 = vol
|
||||
|
||||
For example "echo 0x01000001 >/sys/devices/platform/asus-laptop/ledd"
|
||||
would display "DVD001".
|
||||
|
||||
Driver options:
|
||||
---------------
|
||||
|
||||
Options can be passed to the asus-laptop driver using the standard
|
||||
module argument syntax (<param>=<value> when passing the option to the
|
||||
module or asus-laptop.<param>=<value> on the kernel boot line when
|
||||
asus-laptop is statically linked into the kernel).
|
||||
|
||||
wapf: WAPF defines the behavior of the Fn+Fx wlan key
|
||||
The significance of values is yet to be found, but
|
||||
most of the time:
|
||||
- 0x0 should do nothing
|
||||
- 0x1 should allow to control the device with Fn+Fx key.
|
||||
- 0x4 should send an ACPI event (0x88) while pressing the Fn+Fx key
|
||||
- 0x5 like 0x1 or 0x4
|
||||
|
||||
The default value is 0x1.
|
||||
|
||||
Unsupported models
|
||||
------------------
|
||||
|
||||
These models will never be supported by this module, as they use a completely
|
||||
different mechanism to handle LEDs and extra stuff (meaning we have no clue
|
||||
how it works):
|
||||
|
||||
- ASUS A1300 (A1B), A1370D
|
||||
- ASUS L7300G
|
||||
- ASUS L8400
|
||||
|
||||
Patches, Errors, Questions:
|
||||
--------------------------
|
||||
|
||||
I appreciate any success or failure
|
||||
reports, especially if they add to or correct the compatibility table.
|
||||
Please include the following information in your report:
|
||||
|
||||
- Asus model name
|
||||
- a copy of your ACPI tables, using the "acpidump" utility
|
||||
- a copy of /sys/devices/platform/asus-laptop/infos
|
||||
- which driver features work and which don't
|
||||
- the observed behavior of non-working features
|
||||
|
||||
Any other comments or patches are also more than welcome.
|
||||
|
||||
acpi4asus-user@lists.sourceforge.net
|
||||
http://sourceforge.net/projects/acpi4asus
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
LED handling under Linux
|
||||
========================
|
||||
|
||||
|
@ -5,10 +6,10 @@ If you're reading this and thinking about keyboard leds, these are
|
|||
handled by the input subsystem and the led class is *not* needed.
|
||||
|
||||
In its simplest form, the LED class just allows control of LEDs from
|
||||
userspace. LEDs appear in /sys/class/leds/. The brightness file will
|
||||
set the brightness of the LED (taking a value 0-255). Most LEDs don't
|
||||
have hardware brightness support so will just be turned on for non-zero
|
||||
brightness settings.
|
||||
userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
|
||||
LED is defined in max_brightness file. The brightness file will set the brightness
|
||||
of the LED (taking a value 0-max_brightness). Most LEDs don't have hardware
|
||||
brightness support so will just be turned on for non-zero brightness settings.
|
||||
|
||||
The class also introduces the optional concept of an LED trigger. A trigger
|
||||
is a kernel based source of led events. Triggers can either be simple or
|
||||
|
|
|
@ -77,15 +77,16 @@
|
|||
* 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 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
|
||||
|
@ -98,7 +99,8 @@ MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
|
|||
MODULE_DESCRIPTION(ASUS_HOTK_NAME);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* WAPF defines the behavior of the Fn+Fx wlan key
|
||||
/*
|
||||
* WAPF defines the behavior of the Fn+Fx wlan key
|
||||
* The significance of values is yet to be found, but
|
||||
* most of the time:
|
||||
* 0x0 will do nothing
|
||||
|
@ -125,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
|
|||
/* LEDD */
|
||||
ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
|
||||
|
||||
/* Bluetooth and WLAN
|
||||
/*
|
||||
* Bluetooth and WLAN
|
||||
* WLED and BLED are not handled like other XLED, because in some dsdt
|
||||
* they also control the WLAN/Bluetooth device.
|
||||
*/
|
||||
|
@ -149,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
|
|||
|
||||
/* Display */
|
||||
ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
|
||||
ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G
|
||||
M6A M6V VX-1 V6J V6V W3Z */
|
||||
"\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
|
||||
S5A M5A z33A W1Jc W2V G1 */
|
||||
"\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
|
||||
"\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
|
||||
"\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
|
||||
"\\_SB.PCI0.VGA.GETD", /* Z96F */
|
||||
"\\ACTD", /* A2D */
|
||||
"\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
|
||||
"\\DNXT", /* P30 */
|
||||
"\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
|
||||
"\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */
|
||||
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 */
|
||||
ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
|
||||
ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
|
||||
|
||||
/* GPS */
|
||||
/* R2H use different handle for GPS on/off */
|
||||
|
@ -172,19 +185,23 @@ 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");
|
||||
|
||||
/* Keyboard light */
|
||||
ASUS_HANDLE(kled_set, ASUS_HOTK_PREFIX "SLKB");
|
||||
ASUS_HANDLE(kled_get, ASUS_HOTK_PREFIX "GLKB");
|
||||
|
||||
/*
|
||||
* This is the main structure, we can use it to store anything interesting
|
||||
* about the hotk device
|
||||
*/
|
||||
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
|
||||
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;
|
||||
};
|
||||
|
@ -237,28 +254,35 @@ static struct backlight_ops asusbl_ops = {
|
|||
.update_status = update_bl_status,
|
||||
};
|
||||
|
||||
/* These functions actually update the LED's, and are called from a
|
||||
/*
|
||||
* 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. */
|
||||
* potentially bad time, such as a timer interrupt.
|
||||
*/
|
||||
static struct workqueue_struct *led_workqueue;
|
||||
|
||||
#define ASUS_LED(object, ledname) \
|
||||
#define ASUS_LED(object, ledname, max) \
|
||||
static void object##_led_set(struct led_classdev *led_cdev, \
|
||||
enum led_brightness value); \
|
||||
static enum led_brightness object##_led_get( \
|
||||
struct led_classdev *led_cdev); \
|
||||
static void object##_led_update(struct work_struct *ignored); \
|
||||
static int object##_led_wk; \
|
||||
static DECLARE_WORK(object##_led_work, object##_led_update); \
|
||||
static struct led_classdev object##_led = { \
|
||||
.name = "asus::" ledname, \
|
||||
.brightness_set = object##_led_set, \
|
||||
.brightness_get = object##_led_get, \
|
||||
.max_brightness = max \
|
||||
}
|
||||
|
||||
ASUS_LED(mled, "mail");
|
||||
ASUS_LED(tled, "touchpad");
|
||||
ASUS_LED(rled, "record");
|
||||
ASUS_LED(pled, "phone");
|
||||
ASUS_LED(gled, "gaming");
|
||||
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;
|
||||
|
@ -278,16 +302,23 @@ static struct key_entry asus_keymap[] = {
|
|||
{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, 0x6B, BTN_TOUCH}, /* Lock Mouse */
|
||||
{KE_KEY, 0x82, KEY_CAMERA},
|
||||
{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},
|
||||
};
|
||||
|
||||
|
@ -301,8 +332,8 @@ static struct key_entry asus_keymap[] = {
|
|||
static int write_acpi_int(acpi_handle handle, const char *method, int val,
|
||||
struct acpi_buffer *output)
|
||||
{
|
||||
struct acpi_object_list params; //list of input parameters (an int here)
|
||||
union acpi_object in_obj; //the only param we use
|
||||
struct acpi_object_list params; /* list of input parameters (an int) */
|
||||
union acpi_object in_obj; /* the only param we use */
|
||||
acpi_status status;
|
||||
|
||||
if (!handle)
|
||||
|
@ -399,6 +430,11 @@ static void write_status(acpi_handle handle, int out, int mask)
|
|||
{ \
|
||||
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);
|
||||
|
@ -407,6 +443,60 @@ ASUS_LED_HANDLER(rled, RLED_ON);
|
|||
ASUS_LED_HANDLER(tled, TLED_ON);
|
||||
ASUS_LED_HANDLER(gled, GLED_ON);
|
||||
|
||||
/*
|
||||
* Keyboard backlight
|
||||
*/
|
||||
static int get_kled_lvl(void)
|
||||
{
|
||||
unsigned long long kblv;
|
||||
struct acpi_object_list params;
|
||||
union acpi_object in_obj;
|
||||
acpi_status rv;
|
||||
|
||||
params.count = 1;
|
||||
params.pointer = &in_obj;
|
||||
in_obj.type = ACPI_TYPE_INTEGER;
|
||||
in_obj.integer.value = 2;
|
||||
|
||||
rv = acpi_evaluate_integer(kled_get_handle, NULL, ¶ms, &kblv);
|
||||
if (ACPI_FAILURE(rv)) {
|
||||
pr_warning("Error reading kled level\n");
|
||||
return 0;
|
||||
}
|
||||
return kblv;
|
||||
}
|
||||
|
||||
static int set_kled_lvl(int kblv)
|
||||
{
|
||||
if (kblv > 0)
|
||||
kblv = (1 << 7) | (kblv & 0x7F);
|
||||
else
|
||||
kblv = 0;
|
||||
|
||||
if (write_acpi_int(kled_set_handle, NULL, kblv, NULL)) {
|
||||
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)
|
||||
{
|
||||
kled_led_wk = value;
|
||||
queue_work(led_workqueue, &kled_led_work);
|
||||
}
|
||||
|
||||
static void kled_led_update(struct work_struct *ignored)
|
||||
{
|
||||
set_kled_lvl(kled_led_wk);
|
||||
}
|
||||
|
||||
static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
return get_kled_lvl();
|
||||
}
|
||||
|
||||
static int get_lcd_state(void)
|
||||
{
|
||||
return read_status(LCD_ON);
|
||||
|
@ -498,7 +588,7 @@ static ssize_t show_infos(struct device *dev,
|
|||
{
|
||||
int len = 0;
|
||||
unsigned long long temp;
|
||||
char buf[16]; //enough for all info
|
||||
char buf[16]; /* enough for all info */
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
/*
|
||||
|
@ -516,7 +606,17 @@ static ssize_t show_infos(struct device *dev,
|
|||
*/
|
||||
rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
|
||||
if (!ACPI_FAILURE(rv))
|
||||
len += sprintf(page + len, "SFUN value : 0x%04x\n",
|
||||
len += sprintf(page + len, "SFUN value : %#x\n",
|
||||
(uint) temp);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
rv = acpi_evaluate_integer(hotk->handle, "HRWS", NULL, &temp);
|
||||
if (!ACPI_FAILURE(rv))
|
||||
len += sprintf(page + len, "HRWS value : %#x\n",
|
||||
(uint) temp);
|
||||
/*
|
||||
* Another value for userspace: the ASYM method returns 0x02 for
|
||||
|
@ -527,7 +627,7 @@ static ssize_t show_infos(struct device *dev,
|
|||
*/
|
||||
rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
|
||||
if (!ACPI_FAILURE(rv))
|
||||
len += sprintf(page + len, "ASYM value : 0x%04x\n",
|
||||
len += sprintf(page + len, "ASYM value : %#x\n",
|
||||
(uint) temp);
|
||||
if (asus_info) {
|
||||
snprintf(buf, 16, "%d", asus_info->length);
|
||||
|
@ -648,8 +748,10 @@ static int read_display(void)
|
|||
unsigned long long value = 0;
|
||||
acpi_status rv = AE_OK;
|
||||
|
||||
/* In most of the case, we know how to set the display, but sometime
|
||||
we can't read it */
|
||||
/*
|
||||
* In most of the case, we know how to set the display, but sometime
|
||||
* we can't read it
|
||||
*/
|
||||
if (display_get_handle) {
|
||||
rv = acpi_evaluate_integer(display_get_handle, NULL,
|
||||
NULL, &value);
|
||||
|
@ -1037,6 +1139,9 @@ static int asus_hotk_get_info(void)
|
|||
|
||||
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.
|
||||
|
@ -1063,8 +1168,10 @@ static int asus_hotk_get_info(void)
|
|||
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. */
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
@ -1168,6 +1275,10 @@ static int asus_hotk_add(struct acpi_device *device)
|
|||
/* LCD Backlight is on by default */
|
||||
write_status(NULL, 1, LCD_ON);
|
||||
|
||||
/* Keyboard Backlight is on by default */
|
||||
if (kled_set_handle)
|
||||
set_kled_lvl(1);
|
||||
|
||||
/* LED display is off by default */
|
||||
hotk->ledd_status = 0xFFF;
|
||||
|
||||
|
@ -1222,6 +1333,7 @@ static void asus_led_exit(void)
|
|||
ASUS_LED_UNREGISTER(pled);
|
||||
ASUS_LED_UNREGISTER(rled);
|
||||
ASUS_LED_UNREGISTER(gled);
|
||||
ASUS_LED_UNREGISTER(kled);
|
||||
}
|
||||
|
||||
static void asus_input_exit(void)
|
||||
|
@ -1301,13 +1413,20 @@ static int asus_led_init(struct device *dev)
|
|||
if (rv)
|
||||
goto out4;
|
||||
|
||||
led_workqueue = create_singlethread_workqueue("led_workqueue");
|
||||
if (!led_workqueue)
|
||||
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;
|
||||
|
||||
return 0;
|
||||
out5:
|
||||
out6:
|
||||
rv = -ENOMEM;
|
||||
ASUS_LED_UNREGISTER(kled);
|
||||
out5:
|
||||
ASUS_LED_UNREGISTER(gled);
|
||||
out4:
|
||||
ASUS_LED_UNREGISTER(pled);
|
||||
|
|
|
@ -142,18 +142,28 @@ struct eeepc_hotk {
|
|||
struct rfkill *wlan_rfkill;
|
||||
struct rfkill *bluetooth_rfkill;
|
||||
struct rfkill *wwan3g_rfkill;
|
||||
struct rfkill *wimax_rfkill;
|
||||
struct hotplug_slot *hotplug_slot;
|
||||
struct work_struct hotplug_work;
|
||||
struct mutex hotplug_lock;
|
||||
};
|
||||
|
||||
/* The actual device the driver binds to */
|
||||
static struct eeepc_hotk *ehotk;
|
||||
|
||||
/* Platform device/driver */
|
||||
static int eeepc_hotk_thaw(struct device *device);
|
||||
static int eeepc_hotk_restore(struct device *device);
|
||||
|
||||
static struct dev_pm_ops eeepc_pm_ops = {
|
||||
.thaw = eeepc_hotk_thaw,
|
||||
.restore = eeepc_hotk_restore,
|
||||
};
|
||||
|
||||
static struct platform_driver platform_driver = {
|
||||
.driver = {
|
||||
.name = EEEPC_HOTK_FILE,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &eeepc_pm_ops,
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -192,7 +202,6 @@ static struct key_entry eeepc_keymap[] = {
|
|||
*/
|
||||
static int eeepc_hotk_add(struct acpi_device *device);
|
||||
static int eeepc_hotk_remove(struct acpi_device *device, int type);
|
||||
static int eeepc_hotk_resume(struct acpi_device *device);
|
||||
static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
|
||||
|
||||
static const struct acpi_device_id eeepc_device_ids[] = {
|
||||
|
@ -209,7 +218,6 @@ static struct acpi_driver eeepc_hotk_driver = {
|
|||
.ops = {
|
||||
.add = eeepc_hotk_add,
|
||||
.remove = eeepc_hotk_remove,
|
||||
.resume = eeepc_hotk_resume,
|
||||
.notify = eeepc_hotk_notify,
|
||||
},
|
||||
};
|
||||
|
@ -579,7 +587,6 @@ static void cmsg_quirks(void)
|
|||
|
||||
static int eeepc_hotk_check(void)
|
||||
{
|
||||
const struct key_entry *key;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
int result;
|
||||
|
||||
|
@ -604,31 +611,6 @@ static int eeepc_hotk_check(void)
|
|||
pr_info("Get control methods supported: 0x%x\n",
|
||||
ehotk->cm_supported);
|
||||
}
|
||||
ehotk->inputdev = input_allocate_device();
|
||||
if (!ehotk->inputdev) {
|
||||
pr_info("Unable to allocate input device\n");
|
||||
return 0;
|
||||
}
|
||||
ehotk->inputdev->name = "Asus EeePC extra buttons";
|
||||
ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
|
||||
ehotk->inputdev->id.bustype = BUS_HOST;
|
||||
ehotk->inputdev->getkeycode = eeepc_getkeycode;
|
||||
ehotk->inputdev->setkeycode = eeepc_setkeycode;
|
||||
|
||||
for (key = eeepc_keymap; key->type != KE_END; key++) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
set_bit(EV_KEY, ehotk->inputdev->evbit);
|
||||
set_bit(key->keycode, ehotk->inputdev->keybit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = input_register_device(ehotk->inputdev);
|
||||
if (result) {
|
||||
pr_info("Unable to register input device\n");
|
||||
input_free_device(ehotk->inputdev);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
pr_err("Hotkey device not present, aborting\n");
|
||||
return -EINVAL;
|
||||
|
@ -661,40 +643,48 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void eeepc_hotplug_work(struct work_struct *work)
|
||||
static void eeepc_rfkill_hotplug(void)
|
||||
{
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
||||
bool blocked;
|
||||
struct pci_bus *bus;
|
||||
bool blocked = eeepc_wlan_rfkill_blocked();
|
||||
|
||||
if (!bus) {
|
||||
pr_warning("Unable to find PCI bus 1?\n");
|
||||
return;
|
||||
}
|
||||
if (ehotk->wlan_rfkill)
|
||||
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
|
||||
|
||||
blocked = eeepc_wlan_rfkill_blocked();
|
||||
if (!blocked) {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
/* Device already present */
|
||||
pci_dev_put(dev);
|
||||
return;
|
||||
mutex_lock(&ehotk->hotplug_lock);
|
||||
|
||||
if (ehotk->hotplug_slot) {
|
||||
bus = pci_find_bus(0, 1);
|
||||
if (!bus) {
|
||||
pr_warning("Unable to find PCI bus 1?\n");
|
||||
goto out_unlock;
|
||||
}
|
||||
dev = pci_scan_single_device(bus, 0);
|
||||
if (dev) {
|
||||
pci_bus_assign_resources(bus);
|
||||
if (pci_bus_add_device(dev))
|
||||
pr_err("Unable to hotplug wifi\n");
|
||||
}
|
||||
} else {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
pci_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
|
||||
if (!blocked) {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
/* Device already present */
|
||||
pci_dev_put(dev);
|
||||
goto out_unlock;
|
||||
}
|
||||
dev = pci_scan_single_device(bus, 0);
|
||||
if (dev) {
|
||||
pci_bus_assign_resources(bus);
|
||||
if (pci_bus_add_device(dev))
|
||||
pr_err("Unable to hotplug wifi\n");
|
||||
}
|
||||
} else {
|
||||
dev = pci_get_slot(bus, 0);
|
||||
if (dev) {
|
||||
pci_remove_bus_device(dev);
|
||||
pci_dev_put(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
|
||||
out_unlock:
|
||||
mutex_unlock(&ehotk->hotplug_lock);
|
||||
}
|
||||
|
||||
static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
||||
|
@ -702,7 +692,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
|
|||
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||
return;
|
||||
|
||||
schedule_work(&ehotk->hotplug_work);
|
||||
eeepc_rfkill_hotplug();
|
||||
}
|
||||
|
||||
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
|
||||
|
@ -839,66 +829,38 @@ static int eeepc_setup_pci_hotplug(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_add(struct acpi_device *device)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
pr_notice(EEEPC_HOTK_NAME "\n");
|
||||
ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
|
||||
if (!ehotk)
|
||||
return -ENOMEM;
|
||||
ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
|
||||
ehotk->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
|
||||
device->driver_data = ehotk;
|
||||
ehotk->device = device;
|
||||
result = eeepc_hotk_check();
|
||||
if (result)
|
||||
goto ehotk_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
ehotk_fail:
|
||||
kfree(ehotk);
|
||||
ehotk = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
kfree(ehotk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_resume(struct acpi_device *device)
|
||||
static int eeepc_hotk_thaw(struct device *device)
|
||||
{
|
||||
if (ehotk->wlan_rfkill) {
|
||||
bool wlan;
|
||||
|
||||
/* Workaround - it seems that _PTS disables the wireless
|
||||
without notification or changing the value read by WLAN.
|
||||
Normally this is fine because the correct value is restored
|
||||
from the non-volatile storage on resume, but we need to do
|
||||
it ourself if case suspend is aborted, or we lose wireless.
|
||||
/*
|
||||
* Work around bios bug - acpi _PTS turns off the wireless led
|
||||
* during suspend. Normally it restores it on resume, but
|
||||
* we should kick it ourselves in case hibernation is aborted.
|
||||
*/
|
||||
wlan = get_acpi(CM_ASL_WLAN);
|
||||
set_acpi(CM_ASL_WLAN, wlan);
|
||||
|
||||
rfkill_set_sw_state(ehotk->wlan_rfkill, wlan != 1);
|
||||
|
||||
schedule_work(&ehotk->hotplug_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_restore(struct device *device)
|
||||
{
|
||||
/* Refresh both wlan rfkill state and pci hotplug */
|
||||
if (ehotk->wlan_rfkill)
|
||||
eeepc_rfkill_hotplug();
|
||||
|
||||
if (ehotk->bluetooth_rfkill)
|
||||
rfkill_set_sw_state(ehotk->bluetooth_rfkill,
|
||||
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
||||
if (ehotk->wwan3g_rfkill)
|
||||
rfkill_set_sw_state(ehotk->wwan3g_rfkill,
|
||||
get_acpi(CM_ASL_3G) != 1);
|
||||
if (ehotk->wimax_rfkill)
|
||||
rfkill_set_sw_state(ehotk->wimax_rfkill,
|
||||
get_acpi(CM_ASL_WIMAX) != 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1019,16 +981,37 @@ static void eeepc_backlight_exit(void)
|
|||
|
||||
static void eeepc_rfkill_exit(void)
|
||||
{
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
if (ehotk->wlan_rfkill)
|
||||
if (ehotk->wlan_rfkill) {
|
||||
rfkill_unregister(ehotk->wlan_rfkill);
|
||||
if (ehotk->bluetooth_rfkill)
|
||||
rfkill_unregister(ehotk->bluetooth_rfkill);
|
||||
if (ehotk->wwan3g_rfkill)
|
||||
rfkill_unregister(ehotk->wwan3g_rfkill);
|
||||
rfkill_destroy(ehotk->wlan_rfkill);
|
||||
ehotk->wlan_rfkill = NULL;
|
||||
}
|
||||
/*
|
||||
* Refresh pci hotplug in case the rfkill state was changed after
|
||||
* eeepc_unregister_rfkill_notifier()
|
||||
*/
|
||||
eeepc_rfkill_hotplug();
|
||||
if (ehotk->hotplug_slot)
|
||||
pci_hp_deregister(ehotk->hotplug_slot);
|
||||
|
||||
if (ehotk->bluetooth_rfkill) {
|
||||
rfkill_unregister(ehotk->bluetooth_rfkill);
|
||||
rfkill_destroy(ehotk->bluetooth_rfkill);
|
||||
ehotk->bluetooth_rfkill = NULL;
|
||||
}
|
||||
if (ehotk->wwan3g_rfkill) {
|
||||
rfkill_unregister(ehotk->wwan3g_rfkill);
|
||||
rfkill_destroy(ehotk->wwan3g_rfkill);
|
||||
ehotk->wwan3g_rfkill = NULL;
|
||||
}
|
||||
if (ehotk->wimax_rfkill) {
|
||||
rfkill_unregister(ehotk->wimax_rfkill);
|
||||
rfkill_destroy(ehotk->wimax_rfkill);
|
||||
ehotk->wimax_rfkill = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void eeepc_input_exit(void)
|
||||
|
@ -1050,19 +1033,6 @@ static void eeepc_hwmon_exit(void)
|
|||
eeepc_hwmon_device = NULL;
|
||||
}
|
||||
|
||||
static void __exit eeepc_laptop_exit(void)
|
||||
{
|
||||
eeepc_backlight_exit();
|
||||
eeepc_rfkill_exit();
|
||||
eeepc_input_exit();
|
||||
eeepc_hwmon_exit();
|
||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
||||
sysfs_remove_group(&platform_device->dev.kobj,
|
||||
&platform_attribute_group);
|
||||
platform_device_unregister(platform_device);
|
||||
platform_driver_unregister(&platform_driver);
|
||||
}
|
||||
|
||||
static int eeepc_new_rfkill(struct rfkill **rfkill,
|
||||
const char *name, struct device *dev,
|
||||
enum rfkill_type type, int cm)
|
||||
|
@ -1094,10 +1064,7 @@ static int eeepc_rfkill_init(struct device *dev)
|
|||
{
|
||||
int result = 0;
|
||||
|
||||
INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work);
|
||||
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
mutex_init(&ehotk->hotplug_lock);
|
||||
|
||||
result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
|
||||
"eeepc-wlan", dev,
|
||||
|
@ -1120,6 +1087,13 @@ static int eeepc_rfkill_init(struct device *dev)
|
|||
if (result && result != -ENODEV)
|
||||
goto exit;
|
||||
|
||||
result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
|
||||
"eeepc-wimax", dev,
|
||||
RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
|
||||
|
||||
if (result && result != -ENODEV)
|
||||
goto exit;
|
||||
|
||||
result = eeepc_setup_pci_hotplug();
|
||||
/*
|
||||
* If we get -EBUSY then something else is handling the PCI hotplug -
|
||||
|
@ -1128,6 +1102,15 @@ static int eeepc_rfkill_init(struct device *dev)
|
|||
if (result == -EBUSY)
|
||||
result = 0;
|
||||
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
|
||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||
/*
|
||||
* Refresh pci hotplug in case the rfkill state was changed during
|
||||
* setup.
|
||||
*/
|
||||
eeepc_rfkill_hotplug();
|
||||
|
||||
exit:
|
||||
if (result && result != -ENODEV)
|
||||
eeepc_rfkill_exit();
|
||||
|
@ -1172,21 +1155,61 @@ static int eeepc_hwmon_init(struct device *dev)
|
|||
return result;
|
||||
}
|
||||
|
||||
static int __init eeepc_laptop_init(void)
|
||||
static int eeepc_input_init(struct device *dev)
|
||||
{
|
||||
const struct key_entry *key;
|
||||
int result;
|
||||
|
||||
ehotk->inputdev = input_allocate_device();
|
||||
if (!ehotk->inputdev) {
|
||||
pr_info("Unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ehotk->inputdev->name = "Asus EeePC extra buttons";
|
||||
ehotk->inputdev->dev.parent = dev;
|
||||
ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
|
||||
ehotk->inputdev->id.bustype = BUS_HOST;
|
||||
ehotk->inputdev->getkeycode = eeepc_getkeycode;
|
||||
ehotk->inputdev->setkeycode = eeepc_setkeycode;
|
||||
|
||||
for (key = eeepc_keymap; key->type != KE_END; key++) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
set_bit(EV_KEY, ehotk->inputdev->evbit);
|
||||
set_bit(key->keycode, ehotk->inputdev->keybit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = input_register_device(ehotk->inputdev);
|
||||
if (result) {
|
||||
pr_info("Unable to register input device\n");
|
||||
input_free_device(ehotk->inputdev);
|
||||
return result;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_add(struct acpi_device *device)
|
||||
{
|
||||
struct device *dev;
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
result = acpi_bus_register_driver(&eeepc_hotk_driver);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (!ehotk) {
|
||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
pr_notice(EEEPC_HOTK_NAME "\n");
|
||||
ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
|
||||
if (!ehotk)
|
||||
return -ENOMEM;
|
||||
ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
|
||||
ehotk->handle = device->handle;
|
||||
strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
|
||||
device->driver_data = ehotk;
|
||||
ehotk->device = device;
|
||||
|
||||
result = eeepc_hotk_check();
|
||||
if (result)
|
||||
goto fail_platform_driver;
|
||||
eeepc_enable_camera();
|
||||
|
||||
/* Register platform stuff */
|
||||
|
@ -1216,6 +1239,10 @@ static int __init eeepc_laptop_init(void)
|
|||
pr_info("Backlight controlled by ACPI video "
|
||||
"driver\n");
|
||||
|
||||
result = eeepc_input_init(dev);
|
||||
if (result)
|
||||
goto fail_input;
|
||||
|
||||
result = eeepc_hwmon_init(dev);
|
||||
if (result)
|
||||
goto fail_hwmon;
|
||||
|
@ -1225,9 +1252,12 @@ static int __init eeepc_laptop_init(void)
|
|||
goto fail_rfkill;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_rfkill:
|
||||
eeepc_hwmon_exit();
|
||||
fail_hwmon:
|
||||
eeepc_input_exit();
|
||||
fail_input:
|
||||
eeepc_backlight_exit();
|
||||
fail_backlight:
|
||||
sysfs_remove_group(&platform_device->dev.kobj,
|
||||
|
@ -1239,9 +1269,49 @@ static int __init eeepc_laptop_init(void)
|
|||
fail_platform_device1:
|
||||
platform_driver_unregister(&platform_driver);
|
||||
fail_platform_driver:
|
||||
eeepc_input_exit();
|
||||
kfree(ehotk);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int eeepc_hotk_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
eeepc_backlight_exit();
|
||||
eeepc_rfkill_exit();
|
||||
eeepc_input_exit();
|
||||
eeepc_hwmon_exit();
|
||||
sysfs_remove_group(&platform_device->dev.kobj,
|
||||
&platform_attribute_group);
|
||||
platform_device_unregister(platform_device);
|
||||
platform_driver_unregister(&platform_driver);
|
||||
|
||||
kfree(ehotk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init eeepc_laptop_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
result = acpi_bus_register_driver(&eeepc_hotk_driver);
|
||||
if (result < 0)
|
||||
return result;
|
||||
if (!ehotk) {
|
||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit eeepc_laptop_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
||||
}
|
||||
|
||||
module_init(eeepc_laptop_init);
|
||||
module_exit(eeepc_laptop_exit);
|
||||
|
|
Loading…
Reference in a new issue