Merge branch 'asus' into release
This commit is contained in:
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
|
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.
|
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
|
In its simplest form, the LED class just allows control of LEDs from
|
||||||
userspace. LEDs appear in /sys/class/leds/. The brightness file will
|
userspace. LEDs appear in /sys/class/leds/. The maximum brightness of the
|
||||||
set the brightness of the LED (taking a value 0-255). Most LEDs don't
|
LED is defined in max_brightness file. The brightness file will set the brightness
|
||||||
have hardware brightness support so will just be turned on for non-zero
|
of the LED (taking a value 0-max_brightness). Most LEDs don't have hardware
|
||||||
brightness settings.
|
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
|
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
|
is a kernel based source of led events. Triggers can either be simple or
|
||||||
|
@@ -77,15 +77,16 @@
|
|||||||
* Flags for hotk status
|
* Flags for hotk status
|
||||||
* WL_ON and BT_ON are also used for wireless_status()
|
* WL_ON and BT_ON are also used for wireless_status()
|
||||||
*/
|
*/
|
||||||
#define WL_ON 0x01 //internal Wifi
|
#define WL_ON 0x01 /* internal Wifi */
|
||||||
#define BT_ON 0x02 //internal Bluetooth
|
#define BT_ON 0x02 /* internal Bluetooth */
|
||||||
#define MLED_ON 0x04 //mail LED
|
#define MLED_ON 0x04 /* mail LED */
|
||||||
#define TLED_ON 0x08 //touchpad LED
|
#define TLED_ON 0x08 /* touchpad LED */
|
||||||
#define RLED_ON 0x10 //Record LED
|
#define RLED_ON 0x10 /* Record LED */
|
||||||
#define PLED_ON 0x20 //Phone LED
|
#define PLED_ON 0x20 /* Phone LED */
|
||||||
#define GLED_ON 0x40 //Gaming LED
|
#define GLED_ON 0x40 /* Gaming LED */
|
||||||
#define LCD_ON 0x80 //LCD backlight
|
#define LCD_ON 0x80 /* LCD backlight */
|
||||||
#define GPS_ON 0x100 //GPS
|
#define GPS_ON 0x100 /* GPS */
|
||||||
|
#define KEY_ON 0x200 /* Keyboard backlight */
|
||||||
|
|
||||||
#define ASUS_LOG ASUS_HOTK_FILE ": "
|
#define ASUS_LOG ASUS_HOTK_FILE ": "
|
||||||
#define ASUS_ERR KERN_ERR ASUS_LOG
|
#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_DESCRIPTION(ASUS_HOTK_NAME);
|
||||||
MODULE_LICENSE("GPL");
|
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
|
* The significance of values is yet to be found, but
|
||||||
* most of the time:
|
* most of the time:
|
||||||
* 0x0 will do nothing
|
* 0x0 will do nothing
|
||||||
@@ -125,7 +127,8 @@ ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED"); /* G1, G2 (probably) */
|
|||||||
/* LEDD */
|
/* LEDD */
|
||||||
ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
|
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
|
* WLED and BLED are not handled like other XLED, because in some dsdt
|
||||||
* they also control the WLAN/Bluetooth device.
|
* they also control the WLAN/Bluetooth device.
|
||||||
*/
|
*/
|
||||||
@@ -149,22 +152,32 @@ ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
|
|||||||
|
|
||||||
/* Display */
|
/* Display */
|
||||||
ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
|
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
|
ASUS_HANDLE(display_get,
|
||||||
M6A M6V VX-1 V6J V6V W3Z */
|
/* 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
|
"\\_SB.PCI0.P0P1.VGA.GETD",
|
||||||
S5A M5A z33A W1Jc W2V G1 */
|
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
|
||||||
"\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
|
"\\_SB.PCI0.P0P2.VGA.GETD",
|
||||||
"\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
|
/* A6V A6Q */
|
||||||
"\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
|
"\\_SB.PCI0.P0P3.VGA.GETD",
|
||||||
"\\_SB.PCI0.VGA.GETD", /* Z96F */
|
/* A6T, A6M */
|
||||||
"\\ACTD", /* A2D */
|
"\\_SB.PCI0.P0PA.VGA.GETD",
|
||||||
"\\ADVG", /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
|
/* L3C */
|
||||||
"\\DNXT", /* P30 */
|
"\\_SB.PCI0.PCI1.VGAC.NMAP",
|
||||||
"\\INFB", /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
|
/* Z96F */
|
||||||
"\\SSTE"); /* A3F A6F A3N A3L M6N W3N W6A */
|
"\\_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_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
|
||||||
ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
|
ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
|
||||||
|
|
||||||
/* GPS */
|
/* GPS */
|
||||||
/* R2H use different handle for GPS on/off */
|
/* 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_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
|
||||||
ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
|
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
|
* This is the main structure, we can use it to store anything interesting
|
||||||
* about the hotk device
|
* about the hotk device
|
||||||
*/
|
*/
|
||||||
struct asus_hotk {
|
struct asus_hotk {
|
||||||
char *name; //laptop name
|
char *name; /* laptop name */
|
||||||
struct acpi_device *device; //the device we are in
|
struct acpi_device *device; /* the device we are in */
|
||||||
acpi_handle handle; //the handle of the hotk device
|
acpi_handle handle; /* the handle of the hotk device */
|
||||||
char status; //status of the hotk, for LEDs, ...
|
char status; /* status of the hotk, for LEDs, ... */
|
||||||
u32 ledd_status; //status of the LED display
|
u32 ledd_status; /* status of the LED display */
|
||||||
u8 light_level; //light sensor level
|
u8 light_level; /* light sensor level */
|
||||||
u8 light_switch; //light sensor switch value
|
u8 light_switch; /* light sensor switch value */
|
||||||
u16 event_count[128]; //count for each event TODO make this better
|
u16 event_count[128]; /* count for each event TODO make this better */
|
||||||
struct input_dev *inputdev;
|
struct input_dev *inputdev;
|
||||||
u16 *keycode_map;
|
u16 *keycode_map;
|
||||||
};
|
};
|
||||||
@@ -237,28 +254,35 @@ static struct backlight_ops asusbl_ops = {
|
|||||||
.update_status = update_bl_status,
|
.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
|
* workqueue. By doing this as separate work rather than when the LED
|
||||||
* subsystem asks, we avoid messing with the Asus ACPI stuff during a
|
* 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;
|
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, \
|
static void object##_led_set(struct led_classdev *led_cdev, \
|
||||||
enum led_brightness value); \
|
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 void object##_led_update(struct work_struct *ignored); \
|
||||||
static int object##_led_wk; \
|
static int object##_led_wk; \
|
||||||
static DECLARE_WORK(object##_led_work, object##_led_update); \
|
static DECLARE_WORK(object##_led_work, object##_led_update); \
|
||||||
static struct led_classdev object##_led = { \
|
static struct led_classdev object##_led = { \
|
||||||
.name = "asus::" ledname, \
|
.name = "asus::" ledname, \
|
||||||
.brightness_set = object##_led_set, \
|
.brightness_set = object##_led_set, \
|
||||||
|
.brightness_get = object##_led_get, \
|
||||||
|
.max_brightness = max \
|
||||||
}
|
}
|
||||||
|
|
||||||
ASUS_LED(mled, "mail");
|
ASUS_LED(mled, "mail", 1);
|
||||||
ASUS_LED(tled, "touchpad");
|
ASUS_LED(tled, "touchpad", 1);
|
||||||
ASUS_LED(rled, "record");
|
ASUS_LED(rled, "record", 1);
|
||||||
ASUS_LED(pled, "phone");
|
ASUS_LED(pled, "phone", 1);
|
||||||
ASUS_LED(gled, "gaming");
|
ASUS_LED(gled, "gaming", 1);
|
||||||
|
ASUS_LED(kled, "kbd_backlight", 3);
|
||||||
|
|
||||||
struct key_entry {
|
struct key_entry {
|
||||||
char type;
|
char type;
|
||||||
@@ -278,16 +302,23 @@ static struct key_entry asus_keymap[] = {
|
|||||||
{KE_KEY, 0x41, KEY_NEXTSONG},
|
{KE_KEY, 0x41, KEY_NEXTSONG},
|
||||||
{KE_KEY, 0x43, KEY_STOPCD},
|
{KE_KEY, 0x43, KEY_STOPCD},
|
||||||
{KE_KEY, 0x45, KEY_PLAYPAUSE},
|
{KE_KEY, 0x45, KEY_PLAYPAUSE},
|
||||||
|
{KE_KEY, 0x4c, KEY_MEDIA},
|
||||||
{KE_KEY, 0x50, KEY_EMAIL},
|
{KE_KEY, 0x50, KEY_EMAIL},
|
||||||
{KE_KEY, 0x51, KEY_WWW},
|
{KE_KEY, 0x51, KEY_WWW},
|
||||||
|
{KE_KEY, 0x55, KEY_CALC},
|
||||||
{KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
|
{KE_KEY, 0x5C, KEY_SCREENLOCK}, /* Screenlock */
|
||||||
{KE_KEY, 0x5D, KEY_WLAN},
|
{KE_KEY, 0x5D, KEY_WLAN},
|
||||||
|
{KE_KEY, 0x5E, KEY_WLAN},
|
||||||
|
{KE_KEY, 0x5F, KEY_WLAN},
|
||||||
|
{KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
|
||||||
{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
|
{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
|
||||||
{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
|
{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
|
||||||
{KE_KEY, 0x82, KEY_CAMERA},
|
{KE_KEY, 0x82, KEY_CAMERA},
|
||||||
{KE_KEY, 0x8A, KEY_PROG1},
|
{KE_KEY, 0x8A, KEY_PROG1},
|
||||||
{KE_KEY, 0x95, KEY_MEDIA},
|
{KE_KEY, 0x95, KEY_MEDIA},
|
||||||
{KE_KEY, 0x99, KEY_PHONE},
|
{KE_KEY, 0x99, KEY_PHONE},
|
||||||
|
{KE_KEY, 0xc4, KEY_KBDILLUMUP},
|
||||||
|
{KE_KEY, 0xc5, KEY_KBDILLUMDOWN},
|
||||||
{KE_END, 0},
|
{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,
|
static int write_acpi_int(acpi_handle handle, const char *method, int val,
|
||||||
struct acpi_buffer *output)
|
struct acpi_buffer *output)
|
||||||
{
|
{
|
||||||
struct acpi_object_list params; //list of input parameters (an int here)
|
struct acpi_object_list params; /* list of input parameters (an int) */
|
||||||
union acpi_object in_obj; //the only param we use
|
union acpi_object in_obj; /* the only param we use */
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
if (!handle)
|
if (!handle)
|
||||||
@@ -399,6 +430,11 @@ static void write_status(acpi_handle handle, int out, int mask)
|
|||||||
{ \
|
{ \
|
||||||
int value = object##_led_wk; \
|
int value = object##_led_wk; \
|
||||||
write_status(object##_set_handle, value, (mask)); \
|
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(mled, MLED_ON);
|
||||||
@@ -407,6 +443,60 @@ ASUS_LED_HANDLER(rled, RLED_ON);
|
|||||||
ASUS_LED_HANDLER(tled, TLED_ON);
|
ASUS_LED_HANDLER(tled, TLED_ON);
|
||||||
ASUS_LED_HANDLER(gled, GLED_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)
|
static int get_lcd_state(void)
|
||||||
{
|
{
|
||||||
return read_status(LCD_ON);
|
return read_status(LCD_ON);
|
||||||
@@ -498,7 +588,7 @@ static ssize_t show_infos(struct device *dev,
|
|||||||
{
|
{
|
||||||
int len = 0;
|
int len = 0;
|
||||||
unsigned long long temp;
|
unsigned long long temp;
|
||||||
char buf[16]; //enough for all info
|
char buf[16]; /* enough for all info */
|
||||||
acpi_status rv = AE_OK;
|
acpi_status rv = AE_OK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -516,7 +606,17 @@ static ssize_t show_infos(struct device *dev,
|
|||||||
*/
|
*/
|
||||||
rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
|
rv = acpi_evaluate_integer(hotk->handle, "SFUN", NULL, &temp);
|
||||||
if (!ACPI_FAILURE(rv))
|
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);
|
(uint) temp);
|
||||||
/*
|
/*
|
||||||
* Another value for userspace: the ASYM method returns 0x02 for
|
* 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);
|
rv = acpi_evaluate_integer(hotk->handle, "ASYM", NULL, &temp);
|
||||||
if (!ACPI_FAILURE(rv))
|
if (!ACPI_FAILURE(rv))
|
||||||
len += sprintf(page + len, "ASYM value : 0x%04x\n",
|
len += sprintf(page + len, "ASYM value : %#x\n",
|
||||||
(uint) temp);
|
(uint) temp);
|
||||||
if (asus_info) {
|
if (asus_info) {
|
||||||
snprintf(buf, 16, "%d", asus_info->length);
|
snprintf(buf, 16, "%d", asus_info->length);
|
||||||
@@ -648,8 +748,10 @@ static int read_display(void)
|
|||||||
unsigned long long value = 0;
|
unsigned long long value = 0;
|
||||||
acpi_status rv = AE_OK;
|
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) {
|
if (display_get_handle) {
|
||||||
rv = acpi_evaluate_integer(display_get_handle, NULL,
|
rv = acpi_evaluate_integer(display_get_handle, NULL,
|
||||||
NULL, &value);
|
NULL, &value);
|
||||||
@@ -1037,6 +1139,9 @@ static int asus_hotk_get_info(void)
|
|||||||
|
|
||||||
ASUS_HANDLE_INIT(ledd_set);
|
ASUS_HANDLE_INIT(ledd_set);
|
||||||
|
|
||||||
|
ASUS_HANDLE_INIT(kled_set);
|
||||||
|
ASUS_HANDLE_INIT(kled_get);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The HWRS method return informations about the hardware.
|
* The HWRS method return informations about the hardware.
|
||||||
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
|
* 0x80 bit is for WLAN, 0x100 for Bluetooth.
|
||||||
@@ -1063,8 +1168,10 @@ static int asus_hotk_get_info(void)
|
|||||||
ASUS_HANDLE_INIT(display_set);
|
ASUS_HANDLE_INIT(display_set);
|
||||||
ASUS_HANDLE_INIT(display_get);
|
ASUS_HANDLE_INIT(display_get);
|
||||||
|
|
||||||
/* There is a lot of models with "ALSL", but a few get
|
/*
|
||||||
a real light sens, so we need to check it. */
|
* 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))
|
if (!ASUS_HANDLE_INIT(ls_switch))
|
||||||
ASUS_HANDLE_INIT(ls_level);
|
ASUS_HANDLE_INIT(ls_level);
|
||||||
|
|
||||||
@@ -1168,6 +1275,10 @@ static int asus_hotk_add(struct acpi_device *device)
|
|||||||
/* LCD Backlight is on by default */
|
/* LCD Backlight is on by default */
|
||||||
write_status(NULL, 1, LCD_ON);
|
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 */
|
/* LED display is off by default */
|
||||||
hotk->ledd_status = 0xFFF;
|
hotk->ledd_status = 0xFFF;
|
||||||
|
|
||||||
@@ -1222,6 +1333,7 @@ static void asus_led_exit(void)
|
|||||||
ASUS_LED_UNREGISTER(pled);
|
ASUS_LED_UNREGISTER(pled);
|
||||||
ASUS_LED_UNREGISTER(rled);
|
ASUS_LED_UNREGISTER(rled);
|
||||||
ASUS_LED_UNREGISTER(gled);
|
ASUS_LED_UNREGISTER(gled);
|
||||||
|
ASUS_LED_UNREGISTER(kled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void asus_input_exit(void)
|
static void asus_input_exit(void)
|
||||||
@@ -1301,13 +1413,20 @@ static int asus_led_init(struct device *dev)
|
|||||||
if (rv)
|
if (rv)
|
||||||
goto out4;
|
goto out4;
|
||||||
|
|
||||||
led_workqueue = create_singlethread_workqueue("led_workqueue");
|
if (kled_set_handle && kled_get_handle)
|
||||||
if (!led_workqueue)
|
rv = ASUS_LED_REGISTER(kled, dev);
|
||||||
|
if (rv)
|
||||||
goto out5;
|
goto out5;
|
||||||
|
|
||||||
|
led_workqueue = create_singlethread_workqueue("led_workqueue");
|
||||||
|
if (!led_workqueue)
|
||||||
|
goto out6;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out5:
|
out6:
|
||||||
rv = -ENOMEM;
|
rv = -ENOMEM;
|
||||||
|
ASUS_LED_UNREGISTER(kled);
|
||||||
|
out5:
|
||||||
ASUS_LED_UNREGISTER(gled);
|
ASUS_LED_UNREGISTER(gled);
|
||||||
out4:
|
out4:
|
||||||
ASUS_LED_UNREGISTER(pled);
|
ASUS_LED_UNREGISTER(pled);
|
||||||
|
@@ -142,18 +142,28 @@ struct eeepc_hotk {
|
|||||||
struct rfkill *wlan_rfkill;
|
struct rfkill *wlan_rfkill;
|
||||||
struct rfkill *bluetooth_rfkill;
|
struct rfkill *bluetooth_rfkill;
|
||||||
struct rfkill *wwan3g_rfkill;
|
struct rfkill *wwan3g_rfkill;
|
||||||
|
struct rfkill *wimax_rfkill;
|
||||||
struct hotplug_slot *hotplug_slot;
|
struct hotplug_slot *hotplug_slot;
|
||||||
struct work_struct hotplug_work;
|
struct mutex hotplug_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The actual device the driver binds to */
|
/* The actual device the driver binds to */
|
||||||
static struct eeepc_hotk *ehotk;
|
static struct eeepc_hotk *ehotk;
|
||||||
|
|
||||||
/* Platform device/driver */
|
/* 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 = {
|
static struct platform_driver platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = EEEPC_HOTK_FILE,
|
.name = EEEPC_HOTK_FILE,
|
||||||
.owner = THIS_MODULE,
|
.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_add(struct acpi_device *device);
|
||||||
static int eeepc_hotk_remove(struct acpi_device *device, int type);
|
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 void eeepc_hotk_notify(struct acpi_device *device, u32 event);
|
||||||
|
|
||||||
static const struct acpi_device_id eeepc_device_ids[] = {
|
static const struct acpi_device_id eeepc_device_ids[] = {
|
||||||
@@ -209,7 +218,6 @@ static struct acpi_driver eeepc_hotk_driver = {
|
|||||||
.ops = {
|
.ops = {
|
||||||
.add = eeepc_hotk_add,
|
.add = eeepc_hotk_add,
|
||||||
.remove = eeepc_hotk_remove,
|
.remove = eeepc_hotk_remove,
|
||||||
.resume = eeepc_hotk_resume,
|
|
||||||
.notify = eeepc_hotk_notify,
|
.notify = eeepc_hotk_notify,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -579,7 +587,6 @@ static void cmsg_quirks(void)
|
|||||||
|
|
||||||
static int eeepc_hotk_check(void)
|
static int eeepc_hotk_check(void)
|
||||||
{
|
{
|
||||||
const struct key_entry *key;
|
|
||||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
@@ -604,31 +611,6 @@ static int eeepc_hotk_check(void)
|
|||||||
pr_info("Get control methods supported: 0x%x\n",
|
pr_info("Get control methods supported: 0x%x\n",
|
||||||
ehotk->cm_supported);
|
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 {
|
} else {
|
||||||
pr_err("Hotkey device not present, aborting\n");
|
pr_err("Hotkey device not present, aborting\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -661,40 +643,48 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eeepc_hotplug_work(struct work_struct *work)
|
static void eeepc_rfkill_hotplug(void)
|
||||||
{
|
{
|
||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus = pci_find_bus(0, 1);
|
struct pci_bus *bus;
|
||||||
bool blocked;
|
bool blocked = eeepc_wlan_rfkill_blocked();
|
||||||
|
|
||||||
if (!bus) {
|
if (ehotk->wlan_rfkill)
|
||||||
pr_warning("Unable to find PCI bus 1?\n");
|
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
blocked = eeepc_wlan_rfkill_blocked();
|
mutex_lock(&ehotk->hotplug_lock);
|
||||||
if (!blocked) {
|
|
||||||
dev = pci_get_slot(bus, 0);
|
if (ehotk->hotplug_slot) {
|
||||||
if (dev) {
|
bus = pci_find_bus(0, 1);
|
||||||
/* Device already present */
|
if (!bus) {
|
||||||
pci_dev_put(dev);
|
pr_warning("Unable to find PCI bus 1?\n");
|
||||||
return;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
dev = pci_scan_single_device(bus, 0);
|
|
||||||
if (dev) {
|
if (!blocked) {
|
||||||
pci_bus_assign_resources(bus);
|
dev = pci_get_slot(bus, 0);
|
||||||
if (pci_bus_add_device(dev))
|
if (dev) {
|
||||||
pr_err("Unable to hotplug wifi\n");
|
/* Device already present */
|
||||||
}
|
pci_dev_put(dev);
|
||||||
} else {
|
goto out_unlock;
|
||||||
dev = pci_get_slot(bus, 0);
|
}
|
||||||
if (dev) {
|
dev = pci_scan_single_device(bus, 0);
|
||||||
pci_remove_bus_device(dev);
|
if (dev) {
|
||||||
pci_dev_put(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)
|
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)
|
if (event != ACPI_NOTIFY_BUS_CHECK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
schedule_work(&ehotk->hotplug_work);
|
eeepc_rfkill_hotplug();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
|
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
|
||||||
@@ -839,66 +829,38 @@ error_slot:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int eeepc_hotk_add(struct acpi_device *device)
|
static int eeepc_hotk_thaw(struct 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)
|
|
||||||
{
|
{
|
||||||
if (ehotk->wlan_rfkill) {
|
if (ehotk->wlan_rfkill) {
|
||||||
bool wlan;
|
bool wlan;
|
||||||
|
|
||||||
/* Workaround - it seems that _PTS disables the wireless
|
/*
|
||||||
without notification or changing the value read by WLAN.
|
* Work around bios bug - acpi _PTS turns off the wireless led
|
||||||
Normally this is fine because the correct value is restored
|
* during suspend. Normally it restores it on resume, but
|
||||||
from the non-volatile storage on resume, but we need to do
|
* we should kick it ourselves in case hibernation is aborted.
|
||||||
it ourself if case suspend is aborted, or we lose wireless.
|
|
||||||
*/
|
*/
|
||||||
wlan = get_acpi(CM_ASL_WLAN);
|
wlan = get_acpi(CM_ASL_WLAN);
|
||||||
set_acpi(CM_ASL_WLAN, 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)
|
if (ehotk->bluetooth_rfkill)
|
||||||
rfkill_set_sw_state(ehotk->bluetooth_rfkill,
|
rfkill_set_sw_state(ehotk->bluetooth_rfkill,
|
||||||
get_acpi(CM_ASL_BLUETOOTH) != 1);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1019,16 +981,37 @@ static void eeepc_backlight_exit(void)
|
|||||||
|
|
||||||
static void eeepc_rfkill_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.P0P6");
|
||||||
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
|
||||||
if (ehotk->wlan_rfkill)
|
if (ehotk->wlan_rfkill) {
|
||||||
rfkill_unregister(ehotk->wlan_rfkill);
|
rfkill_unregister(ehotk->wlan_rfkill);
|
||||||
if (ehotk->bluetooth_rfkill)
|
rfkill_destroy(ehotk->wlan_rfkill);
|
||||||
rfkill_unregister(ehotk->bluetooth_rfkill);
|
ehotk->wlan_rfkill = NULL;
|
||||||
if (ehotk->wwan3g_rfkill)
|
}
|
||||||
rfkill_unregister(ehotk->wwan3g_rfkill);
|
/*
|
||||||
|
* Refresh pci hotplug in case the rfkill state was changed after
|
||||||
|
* eeepc_unregister_rfkill_notifier()
|
||||||
|
*/
|
||||||
|
eeepc_rfkill_hotplug();
|
||||||
if (ehotk->hotplug_slot)
|
if (ehotk->hotplug_slot)
|
||||||
pci_hp_deregister(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)
|
static void eeepc_input_exit(void)
|
||||||
@@ -1050,19 +1033,6 @@ static void eeepc_hwmon_exit(void)
|
|||||||
eeepc_hwmon_device = NULL;
|
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,
|
static int eeepc_new_rfkill(struct rfkill **rfkill,
|
||||||
const char *name, struct device *dev,
|
const char *name, struct device *dev,
|
||||||
enum rfkill_type type, int cm)
|
enum rfkill_type type, int cm)
|
||||||
@@ -1094,10 +1064,7 @@ static int eeepc_rfkill_init(struct device *dev)
|
|||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
INIT_WORK(&ehotk->hotplug_work, eeepc_hotplug_work);
|
mutex_init(&ehotk->hotplug_lock);
|
||||||
|
|
||||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
|
|
||||||
eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
|
|
||||||
|
|
||||||
result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
|
result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
|
||||||
"eeepc-wlan", dev,
|
"eeepc-wlan", dev,
|
||||||
@@ -1120,6 +1087,13 @@ static int eeepc_rfkill_init(struct device *dev)
|
|||||||
if (result && result != -ENODEV)
|
if (result && result != -ENODEV)
|
||||||
goto exit;
|
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();
|
result = eeepc_setup_pci_hotplug();
|
||||||
/*
|
/*
|
||||||
* If we get -EBUSY then something else is handling the 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)
|
if (result == -EBUSY)
|
||||||
result = 0;
|
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:
|
exit:
|
||||||
if (result && result != -ENODEV)
|
if (result && result != -ENODEV)
|
||||||
eeepc_rfkill_exit();
|
eeepc_rfkill_exit();
|
||||||
@@ -1172,21 +1155,61 @@ static int eeepc_hwmon_init(struct device *dev)
|
|||||||
return result;
|
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;
|
struct device *dev;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if (acpi_disabled)
|
if (!device)
|
||||||
return -ENODEV;
|
return -EINVAL;
|
||||||
result = acpi_bus_register_driver(&eeepc_hotk_driver);
|
pr_notice(EEEPC_HOTK_NAME "\n");
|
||||||
if (result < 0)
|
ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
|
||||||
return result;
|
if (!ehotk)
|
||||||
if (!ehotk) {
|
return -ENOMEM;
|
||||||
acpi_bus_unregister_driver(&eeepc_hotk_driver);
|
ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
|
||||||
return -ENODEV;
|
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();
|
eeepc_enable_camera();
|
||||||
|
|
||||||
/* Register platform stuff */
|
/* Register platform stuff */
|
||||||
@@ -1216,6 +1239,10 @@ static int __init eeepc_laptop_init(void)
|
|||||||
pr_info("Backlight controlled by ACPI video "
|
pr_info("Backlight controlled by ACPI video "
|
||||||
"driver\n");
|
"driver\n");
|
||||||
|
|
||||||
|
result = eeepc_input_init(dev);
|
||||||
|
if (result)
|
||||||
|
goto fail_input;
|
||||||
|
|
||||||
result = eeepc_hwmon_init(dev);
|
result = eeepc_hwmon_init(dev);
|
||||||
if (result)
|
if (result)
|
||||||
goto fail_hwmon;
|
goto fail_hwmon;
|
||||||
@@ -1225,9 +1252,12 @@ static int __init eeepc_laptop_init(void)
|
|||||||
goto fail_rfkill;
|
goto fail_rfkill;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail_rfkill:
|
fail_rfkill:
|
||||||
eeepc_hwmon_exit();
|
eeepc_hwmon_exit();
|
||||||
fail_hwmon:
|
fail_hwmon:
|
||||||
|
eeepc_input_exit();
|
||||||
|
fail_input:
|
||||||
eeepc_backlight_exit();
|
eeepc_backlight_exit();
|
||||||
fail_backlight:
|
fail_backlight:
|
||||||
sysfs_remove_group(&platform_device->dev.kobj,
|
sysfs_remove_group(&platform_device->dev.kobj,
|
||||||
@@ -1239,9 +1269,49 @@ fail_platform_device2:
|
|||||||
fail_platform_device1:
|
fail_platform_device1:
|
||||||
platform_driver_unregister(&platform_driver);
|
platform_driver_unregister(&platform_driver);
|
||||||
fail_platform_driver:
|
fail_platform_driver:
|
||||||
eeepc_input_exit();
|
kfree(ehotk);
|
||||||
|
|
||||||
return result;
|
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_init(eeepc_laptop_init);
|
||||||
module_exit(eeepc_laptop_exit);
|
module_exit(eeepc_laptop_exit);
|
||||||
|
Reference in New Issue
Block a user