You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (81 commits) xo15-ebook: Remove device.wakeup_count ips: use interruptible waits in ips-monitor acer-wmi: does not poll device status when WMI event is available acer-wmi: does not set persistence state by rfkill_init_sw_state platform-drivers: x86: fix common misspellings acer-wmi: use pr_<level> for messages asus-wmi: potential NULL dereference in show_call() asus-wmi: signedness bug in read_brightness() platform-driver-x86: samsung-laptop: make dmi_check_cb to return 1 instead of 0 platform-driver-x86: fix wrong merge for compal-laptop.c msi-laptop: use pr_<level> for messages Platform: add Samsung Laptop platform driver acer-wmi: Fix WMI ID acer-wmi: deactive mail led when power off msi-laptop: send out touchpad on/off key acer-wmi: set the touchpad toggle key code to KEY_TOUCHPAD_TOGGLE platform-driver-x86: intel_mid_thermal: fix unterminated platform_device_id table sony-laptop: potential null dereference sony-laptop: handle allocation failures sony-laptop: return negative on failure in sony_nc_add() ...
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
What: /sys/devices/platform/samsung/performance_level
|
||||
Date: January 1, 2010
|
||||
KernelVersion: 2.6.33
|
||||
Contact: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
Description: Some Samsung laptops have different "performance levels"
|
||||
that are can be modified by a function key, and by this
|
||||
sysfs file. These values don't always make a whole lot
|
||||
of sense, but some users like to modify them to keep
|
||||
their fans quiet at all costs. Reading from this file
|
||||
will show the current performance level. Writing to the
|
||||
file can change this value.
|
||||
Valid options:
|
||||
"silent"
|
||||
"normal"
|
||||
"overclock"
|
||||
Note that not all laptops support all of these options.
|
||||
Specifically, not all support the "overclock" option,
|
||||
and it's still unknown if this value even changes
|
||||
anything, other than making the user feel a bit better.
|
||||
@@ -0,0 +1,31 @@
|
||||
What: /sys/devices/platform/<platform>/cpufv
|
||||
Date: Oct 2010
|
||||
KernelVersion: 2.6.37
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Change CPU clock configuration (write-only).
|
||||
There are three available clock configuration:
|
||||
* 0 -> Super Performance Mode
|
||||
* 1 -> High Performance Mode
|
||||
* 2 -> Power Saving Mode
|
||||
|
||||
What: /sys/devices/platform/<platform>/camera
|
||||
Date: Jan 2010
|
||||
KernelVersion: 2.6.39
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the camera. 1 means on, 0 means off.
|
||||
|
||||
What: /sys/devices/platform/<platform>/cardr
|
||||
Date: Jan 2010
|
||||
KernelVersion: 2.6.39
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the card reader. 1 means on, 0 means off.
|
||||
|
||||
What: /sys/devices/platform/<platform>/touchpad
|
||||
Date: Jan 2010
|
||||
KernelVersion: 2.6.39
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Control the card touchpad. 1 means on, 0 means off.
|
||||
@@ -1,10 +0,0 @@
|
||||
What: /sys/devices/platform/eeepc-wmi/cpufv
|
||||
Date: Oct 2010
|
||||
KernelVersion: 2.6.37
|
||||
Contact: "Corentin Chary" <corentincj@iksaif.net>
|
||||
Description:
|
||||
Change CPU clock configuration (write-only).
|
||||
There are three available clock configuration:
|
||||
* 0 -> Super Performance Mode
|
||||
* 1 -> High Performance Mode
|
||||
* 2 -> Power Saving Mode
|
||||
@@ -14,7 +14,8 @@ Some models report hotkeys through the SNC or SPIC devices, such events are
|
||||
reported both through the ACPI subsystem as acpi events and through the INPUT
|
||||
subsystem. See the logs of acpid or /proc/acpi/event and
|
||||
/proc/bus/input/devices to find out what those events are and which input
|
||||
devices are created by the driver.
|
||||
devices are created by the driver. Additionally, loading the driver with the
|
||||
debug option will report all events in the kernel log.
|
||||
|
||||
Backlight control:
|
||||
------------------
|
||||
@@ -64,6 +65,16 @@ powers off the sound card,
|
||||
# echo "1" > /sys/devices/platform/sony-laptop/audiopower
|
||||
powers on the sound card.
|
||||
|
||||
|
||||
RFkill control:
|
||||
---------------
|
||||
More recent Vaio models expose a consistent set of ACPI methods to
|
||||
control radio frequency emitting devices. If you are a lucky owner of
|
||||
such a laptop you will find the necessary rfkill devices under
|
||||
/sys/class/rfkill. Check those starting with sony-* in
|
||||
# grep . /sys/class/rfkill/*/{state,name}
|
||||
|
||||
|
||||
Development:
|
||||
------------
|
||||
|
||||
@@ -75,8 +86,21 @@ pass the option 'debug=1'.
|
||||
REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS.
|
||||
|
||||
In your kernel logs you will find the list of all ACPI methods
|
||||
the SNC device has on your laptop. You can see the GCDP/GCDP methods
|
||||
used to pwer on/off the CD drive, but there are others.
|
||||
the SNC device has on your laptop.
|
||||
|
||||
* For new models you will see a long list of meaningless method names,
|
||||
reading the DSDT table source should reveal that:
|
||||
(1) the SNC device uses an internal capability lookup table
|
||||
(2) SN00 is used to find values in the lookup table
|
||||
(3) SN06 and SN07 are used to call into the real methods based on
|
||||
offsets you can obtain iterating the table using SN00
|
||||
(4) SN02 used to enable events.
|
||||
Some values in the capability lookup table are more or less known, see
|
||||
the code for all sony_call_snc_handle calls, others are more obscure.
|
||||
|
||||
* For old models you can see the GCDP/GCDP methods used to pwer on/off
|
||||
the CD drive, but there are others and they are usually different from
|
||||
model to model.
|
||||
|
||||
I HAVE NO IDEA WHAT THOSE METHODS DO.
|
||||
|
||||
@@ -108,9 +132,8 @@ Bugs/Limitations:
|
||||
laptop, including permanent damage.
|
||||
|
||||
* The sony-laptop and sonypi drivers do not interact at all. In the
|
||||
future, sonypi could use sony-laptop to do (part of) its business.
|
||||
future, sonypi will be removed and replaced by sony-laptop.
|
||||
|
||||
* spicctrl, which is the userspace tool used to communicate with the
|
||||
sonypi driver (through /dev/sonypi) does not try to use the
|
||||
sony-laptop driver. In the future, spicctrl could try sonypi first,
|
||||
and if it isn't present, try sony-laptop instead.
|
||||
sonypi driver (through /dev/sonypi) is deprecated as well since all
|
||||
its features are now available under the sysfs tree via sony-laptop.
|
||||
|
||||
+3
-27
@@ -1157,14 +1157,14 @@ S: Maintained
|
||||
F: Documentation/hwmon/asc7621
|
||||
F: drivers/hwmon/asc7621.c
|
||||
|
||||
ASUS ACPI EXTRAS DRIVER
|
||||
ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
M: Karol Kozimor <sziwan@users.sourceforge.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/asus_acpi.c
|
||||
F: drivers/platform/x86/asus*.c
|
||||
F: drivers/platform/x86/eeepc*.c
|
||||
|
||||
ASUS ASB100 HARDWARE MONITOR DRIVER
|
||||
M: "Mark M. Hoffman" <mhoffman@lightlink.com>
|
||||
@@ -1172,14 +1172,6 @@ L: lm-sensors@lm-sensors.org
|
||||
S: Maintained
|
||||
F: drivers/hwmon/asb100.c
|
||||
|
||||
ASUS LAPTOP EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/asus-laptop.c
|
||||
|
||||
ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
|
||||
M: Dan Williams <dan.j.williams@intel.com>
|
||||
W: http://sourceforge.net/projects/xscaleiop
|
||||
@@ -2414,22 +2406,6 @@ T: git git://git.alsa-project.org/alsa-kernel.git
|
||||
S: Maintained
|
||||
F: sound/usb/misc/ua101.c
|
||||
|
||||
EEEPC LAPTOP EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/eeepc-laptop.c
|
||||
|
||||
EEEPC WMI EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/eeepc-wmi.c
|
||||
|
||||
EFIFB FRAMEBUFFER DRIVER
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
M: Peter Jones <pjones@redhat.com>
|
||||
|
||||
@@ -101,6 +101,19 @@ config DELL_WMI
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called dell-wmi.
|
||||
|
||||
config DELL_WMI_AIO
|
||||
tristate "WMI Hotkeys for Dell All-In-One series"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
select INPUT_SPARSEKMAP
|
||||
---help---
|
||||
Say Y here if you want to support WMI-based hotkeys on Dell
|
||||
All-In-One machines.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called dell-wmi.
|
||||
|
||||
|
||||
config FUJITSU_LAPTOP
|
||||
tristate "Fujitsu Laptop Extras"
|
||||
depends on ACPI
|
||||
@@ -438,23 +451,53 @@ config EEEPC_LAPTOP
|
||||
Bluetooth, backlight and allows powering on/off some other
|
||||
devices.
|
||||
|
||||
If you have an Eee PC laptop, say Y or M here.
|
||||
If you have an Eee PC laptop, say Y or M here. If this driver
|
||||
doesn't work on your Eee PC, try eeepc-wmi instead.
|
||||
|
||||
config EEEPC_WMI
|
||||
tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)"
|
||||
config ASUS_WMI
|
||||
tristate "ASUS WMI Driver (EXPERIMENTAL)"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on HWMON
|
||||
depends on EXPERIMENTAL
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on HOTPLUG_PCI
|
||||
select INPUT_SPARSEKMAP
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---help---
|
||||
Say Y here if you want to support WMI-based hotkeys on Eee PC laptops.
|
||||
Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new
|
||||
Asus Notebooks).
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called eeepc-wmi.
|
||||
be called asus-wmi.
|
||||
|
||||
config ASUS_NB_WMI
|
||||
tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
|
||||
depends on ASUS_WMI
|
||||
---help---
|
||||
This is a driver for newer Asus notebooks. It adds extra features
|
||||
like wireless radio and bluetooth control, leds, hotkeys, backlight...
|
||||
|
||||
For more informations, see
|
||||
<file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
|
||||
|
||||
If you have an ACPI-WMI compatible Asus Notebook, say Y or M
|
||||
here.
|
||||
|
||||
config EEEPC_WMI
|
||||
tristate "Eee PC WMI Driver (EXPERIMENTAL)"
|
||||
depends on ASUS_WMI
|
||||
---help---
|
||||
This is a driver for newer Eee PC laptops. It adds extra features
|
||||
like wireless radio and bluetooth control, leds, hotkeys, backlight...
|
||||
|
||||
For more informations, see
|
||||
<file:Documentation/ABI/testing/sysfs-platform-asus-wmi>
|
||||
|
||||
If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M
|
||||
here.
|
||||
|
||||
config ACPI_WMI
|
||||
tristate "WMI"
|
||||
@@ -616,6 +659,21 @@ config GPIO_INTEL_PMIC
|
||||
Say Y here to support GPIO via the SCU IPC interface
|
||||
on Intel MID platforms.
|
||||
|
||||
config INTEL_MID_POWER_BUTTON
|
||||
tristate "power button driver for Intel MID platforms"
|
||||
depends on INTEL_SCU_IPC && INPUT
|
||||
help
|
||||
This driver handles the power button on the Intel MID platforms.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config INTEL_MFLD_THERMAL
|
||||
tristate "Thermal driver for Intel Medfield platform"
|
||||
depends on INTEL_SCU_IPC && THERMAL
|
||||
help
|
||||
Say Y here to enable thermal driver support for the Intel Medfield
|
||||
platform.
|
||||
|
||||
config RAR_REGISTER
|
||||
bool "Restricted Access Region Register Driver"
|
||||
depends on PCI && X86_MRST
|
||||
@@ -672,4 +730,26 @@ config XO1_RFKILL
|
||||
Support for enabling/disabling the WLAN interface on the OLPC XO-1
|
||||
laptop.
|
||||
|
||||
config XO15_EBOOK
|
||||
tristate "OLPC XO-1.5 ebook switch"
|
||||
depends on ACPI && INPUT
|
||||
---help---
|
||||
Support for the ebook switch on the OLPC XO-1.5 laptop.
|
||||
|
||||
This switch is triggered as the screen is rotated and folded down to
|
||||
convert the device into ebook form.
|
||||
|
||||
config SAMSUNG_LAPTOP
|
||||
tristate "Samsung Laptop driver"
|
||||
depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
|
||||
---help---
|
||||
This module implements a driver for a wide range of different
|
||||
Samsung laptops. It offers control over the different
|
||||
function keys, wireless LED, LCD backlight level, and
|
||||
sometimes provides a "performance_control" sysfs file to allow
|
||||
the performance level of the laptop to be changed.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called samsung-laptop.
|
||||
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# x86 Platform-Specific Drivers
|
||||
#
|
||||
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
|
||||
obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
|
||||
obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
|
||||
obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
|
||||
obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o
|
||||
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
|
||||
@@ -10,6 +12,7 @@ obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o
|
||||
obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o
|
||||
obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o
|
||||
obj-$(CONFIG_DELL_WMI) += dell-wmi.o
|
||||
obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o
|
||||
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
|
||||
obj-$(CONFIG_ACERHDF) += acerhdf.o
|
||||
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
|
||||
@@ -29,9 +32,13 @@ obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
|
||||
obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
|
||||
obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o
|
||||
obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
|
||||
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
|
||||
obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
|
||||
obj-$(CONFIG_INTEL_IPS) += intel_ips.o
|
||||
obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
|
||||
obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
|
||||
obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
|
||||
obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
|
||||
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
|
||||
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -46,12 +48,6 @@ MODULE_AUTHOR("Carlos Corbacho");
|
||||
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define ACER_LOGPREFIX "acer-wmi: "
|
||||
#define ACER_ERR KERN_ERR ACER_LOGPREFIX
|
||||
#define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
|
||||
#define ACER_INFO KERN_INFO ACER_LOGPREFIX
|
||||
#define ACER_WARNING KERN_WARNING ACER_LOGPREFIX
|
||||
|
||||
/*
|
||||
* Magic Number
|
||||
* Meaning is unknown - this number is required for writing to ACPI for AMW0
|
||||
@@ -84,7 +80,7 @@ MODULE_LICENSE("GPL");
|
||||
#define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
|
||||
#define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
|
||||
#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3"
|
||||
#define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
|
||||
#define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A"
|
||||
#define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531"
|
||||
|
||||
/*
|
||||
@@ -93,7 +89,7 @@ MODULE_LICENSE("GPL");
|
||||
#define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026"
|
||||
|
||||
MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
|
||||
MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
|
||||
MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3");
|
||||
MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026");
|
||||
|
||||
enum acer_wmi_event_ids {
|
||||
@@ -108,7 +104,7 @@ static const struct key_entry acer_wmi_keymap[] = {
|
||||
{KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
|
||||
{KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
|
||||
{KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */
|
||||
{KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */
|
||||
{KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */
|
||||
{KE_END, 0}
|
||||
};
|
||||
|
||||
@@ -221,6 +217,7 @@ struct acer_debug {
|
||||
static struct rfkill *wireless_rfkill;
|
||||
static struct rfkill *bluetooth_rfkill;
|
||||
static struct rfkill *threeg_rfkill;
|
||||
static bool rfkill_inited;
|
||||
|
||||
/* Each low-level interface must define at least some of the following */
|
||||
struct wmi_interface {
|
||||
@@ -845,7 +842,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||
has_type_aa = true;
|
||||
type_aa = (struct hotkey_function_type_aa *) header;
|
||||
|
||||
printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n",
|
||||
pr_info("Function bitmap for Communication Button: 0x%x\n",
|
||||
type_aa->commun_func_bitmap);
|
||||
|
||||
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
|
||||
@@ -991,6 +988,7 @@ static int __devinit acer_led_init(struct device *dev)
|
||||
|
||||
static void acer_led_exit(void)
|
||||
{
|
||||
set_u32(LED_OFF, ACER_CAP_MAILLED);
|
||||
led_classdev_unregister(&mail_led);
|
||||
}
|
||||
|
||||
@@ -1036,7 +1034,7 @@ static int __devinit acer_backlight_init(struct device *dev)
|
||||
bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops,
|
||||
&props);
|
||||
if (IS_ERR(bd)) {
|
||||
printk(ACER_ERR "Could not register Acer backlight device\n");
|
||||
pr_err("Could not register Acer backlight device\n");
|
||||
acer_backlight_device = NULL;
|
||||
return PTR_ERR(bd);
|
||||
}
|
||||
@@ -1083,8 +1081,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
|
||||
return AE_ERROR;
|
||||
}
|
||||
if (obj->buffer.length != 8) {
|
||||
printk(ACER_WARNING "Unknown buffer length %d\n",
|
||||
obj->buffer.length);
|
||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||
kfree(obj);
|
||||
return AE_ERROR;
|
||||
}
|
||||
@@ -1093,7 +1090,7 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
|
||||
kfree(obj);
|
||||
|
||||
if (return_value.error_code || return_value.ec_return_value)
|
||||
printk(ACER_WARNING "Get Device Status failed: "
|
||||
pr_warning("Get Device Status failed: "
|
||||
"0x%x - 0x%x\n", return_value.error_code,
|
||||
return_value.ec_return_value);
|
||||
else
|
||||
@@ -1161,9 +1158,13 @@ static int acer_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
acpi_status status;
|
||||
u32 cap = (unsigned long)data;
|
||||
status = set_u32(!blocked, cap);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
if (rfkill_inited) {
|
||||
status = set_u32(!blocked, cap);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1187,14 +1188,16 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
status = get_device_status(&state, cap);
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_init_sw_state(rfkill_dev, !state);
|
||||
|
||||
err = rfkill_register(rfkill_dev);
|
||||
if (err) {
|
||||
rfkill_destroy(rfkill_dev);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
if (ACPI_SUCCESS(status))
|
||||
rfkill_set_sw_state(rfkill_dev, !state);
|
||||
|
||||
return rfkill_dev;
|
||||
}
|
||||
|
||||
@@ -1229,14 +1232,19 @@ static int acer_rfkill_init(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
|
||||
rfkill_inited = true;
|
||||
|
||||
if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
|
||||
schedule_delayed_work(&acer_rfkill_work,
|
||||
round_jiffies_relative(HZ));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acer_rfkill_exit(void)
|
||||
{
|
||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||
if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
|
||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||
|
||||
rfkill_unregister(wireless_rfkill);
|
||||
rfkill_destroy(wireless_rfkill);
|
||||
@@ -1309,7 +1317,7 @@ static void acer_wmi_notify(u32 value, void *context)
|
||||
|
||||
status = wmi_get_event_data(value, &response);
|
||||
if (status != AE_OK) {
|
||||
printk(ACER_WARNING "bad event status 0x%x\n", status);
|
||||
pr_warning("bad event status 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1318,14 +1326,12 @@ static void acer_wmi_notify(u32 value, void *context)
|
||||
if (!obj)
|
||||
return;
|
||||
if (obj->type != ACPI_TYPE_BUFFER) {
|
||||
printk(ACER_WARNING "Unknown response received %d\n",
|
||||
obj->type);
|
||||
pr_warning("Unknown response received %d\n", obj->type);
|
||||
kfree(obj);
|
||||
return;
|
||||
}
|
||||
if (obj->buffer.length != 8) {
|
||||
printk(ACER_WARNING "Unknown buffer length %d\n",
|
||||
obj->buffer.length);
|
||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||
kfree(obj);
|
||||
return;
|
||||
}
|
||||
@@ -1335,13 +1341,26 @@ static void acer_wmi_notify(u32 value, void *context)
|
||||
|
||||
switch (return_value.function) {
|
||||
case WMID_HOTKEY_EVENT:
|
||||
if (return_value.device_state) {
|
||||
u16 device_state = return_value.device_state;
|
||||
pr_debug("deivces states: 0x%x\n", device_state);
|
||||
if (has_cap(ACER_CAP_WIRELESS))
|
||||
rfkill_set_sw_state(wireless_rfkill,
|
||||
!(device_state & ACER_WMID3_GDS_WIRELESS));
|
||||
if (has_cap(ACER_CAP_BLUETOOTH))
|
||||
rfkill_set_sw_state(bluetooth_rfkill,
|
||||
!(device_state & ACER_WMID3_GDS_BLUETOOTH));
|
||||
if (has_cap(ACER_CAP_THREEG))
|
||||
rfkill_set_sw_state(threeg_rfkill,
|
||||
!(device_state & ACER_WMID3_GDS_THREEG));
|
||||
}
|
||||
if (!sparse_keymap_report_event(acer_wmi_input_dev,
|
||||
return_value.key_num, 1, true))
|
||||
printk(ACER_WARNING "Unknown key number - 0x%x\n",
|
||||
pr_warning("Unknown key number - 0x%x\n",
|
||||
return_value.key_num);
|
||||
break;
|
||||
default:
|
||||
printk(ACER_WARNING "Unknown function number - %d - %d\n",
|
||||
pr_warning("Unknown function number - %d - %d\n",
|
||||
return_value.function, return_value.key_num);
|
||||
break;
|
||||
}
|
||||
@@ -1370,8 +1389,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
|
||||
return AE_ERROR;
|
||||
}
|
||||
if (obj->buffer.length != 4) {
|
||||
printk(ACER_WARNING "Unknown buffer length %d\n",
|
||||
obj->buffer.length);
|
||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||
kfree(obj);
|
||||
return AE_ERROR;
|
||||
}
|
||||
@@ -1396,11 +1414,11 @@ static int acer_wmi_enable_ec_raw(void)
|
||||
status = wmid3_set_lm_mode(¶ms, &return_value);
|
||||
|
||||
if (return_value.error_code || return_value.ec_return_value)
|
||||
printk(ACER_WARNING "Enabling EC raw mode failed: "
|
||||
pr_warning("Enabling EC raw mode failed: "
|
||||
"0x%x - 0x%x\n", return_value.error_code,
|
||||
return_value.ec_return_value);
|
||||
else
|
||||
printk(ACER_INFO "Enabled EC raw mode");
|
||||
pr_info("Enabled EC raw mode");
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -1419,7 +1437,7 @@ static int acer_wmi_enable_lm(void)
|
||||
status = wmid3_set_lm_mode(¶ms, &return_value);
|
||||
|
||||
if (return_value.error_code || return_value.ec_return_value)
|
||||
printk(ACER_WARNING "Enabling Launch Manager failed: "
|
||||
pr_warning("Enabling Launch Manager failed: "
|
||||
"0x%x - 0x%x\n", return_value.error_code,
|
||||
return_value.ec_return_value);
|
||||
|
||||
@@ -1553,6 +1571,7 @@ pm_message_t state)
|
||||
|
||||
if (has_cap(ACER_CAP_MAILLED)) {
|
||||
get_u32(&value, ACER_CAP_MAILLED);
|
||||
set_u32(LED_OFF, ACER_CAP_MAILLED);
|
||||
data->mailled = value;
|
||||
}
|
||||
|
||||
@@ -1580,6 +1599,17 @@ static int acer_platform_resume(struct platform_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acer_platform_shutdown(struct platform_device *device)
|
||||
{
|
||||
struct acer_data *data = &interface->data;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (has_cap(ACER_CAP_MAILLED))
|
||||
set_u32(LED_OFF, ACER_CAP_MAILLED);
|
||||
}
|
||||
|
||||
static struct platform_driver acer_platform_driver = {
|
||||
.driver = {
|
||||
.name = "acer-wmi",
|
||||
@@ -1589,6 +1619,7 @@ static struct platform_driver acer_platform_driver = {
|
||||
.remove = acer_platform_remove,
|
||||
.suspend = acer_platform_suspend,
|
||||
.resume = acer_platform_resume,
|
||||
.shutdown = acer_platform_shutdown,
|
||||
};
|
||||
|
||||
static struct platform_device *acer_platform_device;
|
||||
@@ -1636,7 +1667,7 @@ static int create_debugfs(void)
|
||||
{
|
||||
interface->debug.root = debugfs_create_dir("acer-wmi", NULL);
|
||||
if (!interface->debug.root) {
|
||||
printk(ACER_ERR "Failed to create debugfs directory");
|
||||
pr_err("Failed to create debugfs directory");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -1657,11 +1688,10 @@ static int __init acer_wmi_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n");
|
||||
pr_info("Acer Laptop ACPI-WMI Extras\n");
|
||||
|
||||
if (dmi_check_system(acer_blacklist)) {
|
||||
printk(ACER_INFO "Blacklisted hardware detected - "
|
||||
"not loading\n");
|
||||
pr_info("Blacklisted hardware detected - not loading\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1678,12 +1708,11 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
if (wmi_has_guid(WMID_GUID2) && interface) {
|
||||
if (ACPI_FAILURE(WMID_set_capabilities())) {
|
||||
printk(ACER_ERR "Unable to detect available WMID "
|
||||
"devices\n");
|
||||
pr_err("Unable to detect available WMID devices\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (!wmi_has_guid(WMID_GUID2) && interface) {
|
||||
printk(ACER_ERR "No WMID device detection method found\n");
|
||||
pr_err("No WMID device detection method found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1691,8 +1720,7 @@ static int __init acer_wmi_init(void)
|
||||
interface = &AMW0_interface;
|
||||
|
||||
if (ACPI_FAILURE(AMW0_set_capabilities())) {
|
||||
printk(ACER_ERR "Unable to detect available AMW0 "
|
||||
"devices\n");
|
||||
pr_err("Unable to detect available AMW0 devices\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
@@ -1701,8 +1729,7 @@ static int __init acer_wmi_init(void)
|
||||
AMW0_find_mailled();
|
||||
|
||||
if (!interface) {
|
||||
printk(ACER_INFO "No or unsupported WMI interface, unable to "
|
||||
"load\n");
|
||||
pr_err("No or unsupported WMI interface, unable to load\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1710,22 +1737,22 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
|
||||
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
printk(ACER_INFO "Brightness must be controlled by "
|
||||
pr_info("Brightness must be controlled by "
|
||||
"generic video driver\n");
|
||||
}
|
||||
|
||||
if (wmi_has_guid(WMID_GUID3)) {
|
||||
if (ec_raw_mode) {
|
||||
if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
|
||||
printk(ACER_ERR "Cannot enable EC raw mode\n");
|
||||
pr_err("Cannot enable EC raw mode\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (ACPI_FAILURE(acer_wmi_enable_lm())) {
|
||||
printk(ACER_ERR "Cannot enable Launch Manager mode\n");
|
||||
pr_err("Cannot enable Launch Manager mode\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
} else if (ec_raw_mode) {
|
||||
printk(ACER_INFO "No WMID EC raw mode enable method\n");
|
||||
pr_info("No WMID EC raw mode enable method\n");
|
||||
}
|
||||
|
||||
if (wmi_has_guid(ACERWMID_EVENT_GUID)) {
|
||||
@@ -1736,7 +1763,7 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
err = platform_driver_register(&acer_platform_driver);
|
||||
if (err) {
|
||||
printk(ACER_ERR "Unable to register platform driver.\n");
|
||||
pr_err("Unable to register platform driver.\n");
|
||||
goto error_platform_register;
|
||||
}
|
||||
|
||||
@@ -1791,7 +1818,7 @@ static void __exit acer_wmi_exit(void)
|
||||
platform_device_unregister(acer_platform_device);
|
||||
platform_driver_unregister(&acer_platform_driver);
|
||||
|
||||
printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
|
||||
pr_info("Acer Laptop WMI Extras unloaded\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
|
||||
* Eric Burghard - LED display support for W1N
|
||||
* Josh Green - Light Sens support
|
||||
* Thomas Tuttle - His first patch for led support was very helpfull
|
||||
* Thomas Tuttle - His first patch for led support was very helpful
|
||||
* Sam Lin - GPS support
|
||||
*/
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
||||
@@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
|
||||
#define METHOD_BRIGHTNESS_SET "SPLV"
|
||||
#define METHOD_BRIGHTNESS_GET "GPLV"
|
||||
|
||||
/* Backlight */
|
||||
static acpi_handle lcd_switch_handle;
|
||||
static char *lcd_switch_paths[] = {
|
||||
"\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
|
||||
"\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
|
||||
"\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
|
||||
"\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
|
||||
"\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
|
||||
"\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
|
||||
"\\_SB.PCI0.PX40.Q10", /* S1x */
|
||||
"\\Q10"}; /* A2x, L2D, L3D, M2E */
|
||||
|
||||
/* Display */
|
||||
#define METHOD_SWITCH_DISPLAY "SDSP"
|
||||
|
||||
static acpi_handle display_get_handle;
|
||||
static char *display_get_paths[] = {
|
||||
/* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
|
||||
"\\_SB.PCI0.P0P1.VGA.GETD",
|
||||
/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
|
||||
"\\_SB.PCI0.P0P2.VGA.GETD",
|
||||
/* A6V A6Q */
|
||||
"\\_SB.PCI0.P0P3.VGA.GETD",
|
||||
/* A6T, A6M */
|
||||
"\\_SB.PCI0.P0PA.VGA.GETD",
|
||||
/* L3C */
|
||||
"\\_SB.PCI0.PCI1.VGAC.NMAP",
|
||||
/* Z96F */
|
||||
"\\_SB.PCI0.VGA.GETD",
|
||||
/* A2D */
|
||||
"\\ACTD",
|
||||
/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
|
||||
"\\ADVG",
|
||||
/* P30 */
|
||||
"\\DNXT",
|
||||
/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
|
||||
"\\INFB",
|
||||
/* A3F A6F A3N A3L M6N W3N W6A */
|
||||
"\\SSTE"};
|
||||
|
||||
#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
|
||||
#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
|
||||
|
||||
@@ -246,7 +210,6 @@ struct asus_laptop {
|
||||
|
||||
int wireless_status;
|
||||
bool have_rsts;
|
||||
int lcd_state;
|
||||
|
||||
struct rfkill *gps_rfkill;
|
||||
|
||||
@@ -559,48 +522,6 @@ error:
|
||||
/*
|
||||
* Backlight device
|
||||
*/
|
||||
static int asus_lcd_status(struct asus_laptop *asus)
|
||||
{
|
||||
return asus->lcd_state;
|
||||
}
|
||||
|
||||
static int asus_lcd_set(struct asus_laptop *asus, int value)
|
||||
{
|
||||
int lcd = 0;
|
||||
acpi_status status = 0;
|
||||
|
||||
lcd = !!value;
|
||||
|
||||
if (lcd == asus_lcd_status(asus))
|
||||
return 0;
|
||||
|
||||
if (!lcd_switch_handle)
|
||||
return -ENODEV;
|
||||
|
||||
status = acpi_evaluate_object(lcd_switch_handle,
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_warning("Error switching LCD\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
asus->lcd_state = lcd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lcd_blank(struct asus_laptop *asus, int blank)
|
||||
{
|
||||
struct backlight_device *bd = asus->backlight_device;
|
||||
|
||||
asus->lcd_state = (blank == FB_BLANK_UNBLANK);
|
||||
|
||||
if (bd) {
|
||||
bd->props.power = blank;
|
||||
backlight_update_status(bd);
|
||||
}
|
||||
}
|
||||
|
||||
static int asus_read_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_laptop *asus = bl_get_data(bd);
|
||||
@@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
|
||||
|
||||
static int update_bl_status(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_laptop *asus = bl_get_data(bd);
|
||||
int rv;
|
||||
int value = bd->props.brightness;
|
||||
|
||||
rv = asus_set_brightness(bd, value);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
|
||||
return asus_lcd_set(asus, value);
|
||||
return asus_set_brightness(bd, value);
|
||||
}
|
||||
|
||||
static const struct backlight_ops asusbl_ops = {
|
||||
@@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
|
||||
struct backlight_properties props;
|
||||
|
||||
if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
|
||||
acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) ||
|
||||
!lcd_switch_handle)
|
||||
acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
|
||||
return 0;
|
||||
|
||||
memset(&props, 0, sizeof(struct backlight_properties));
|
||||
@@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value)
|
||||
return;
|
||||
}
|
||||
|
||||
static int read_display(struct asus_laptop *asus)
|
||||
{
|
||||
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
|
||||
*/
|
||||
if (display_get_handle) {
|
||||
rv = acpi_evaluate_integer(display_get_handle, NULL,
|
||||
NULL, &value);
|
||||
if (ACPI_FAILURE(rv))
|
||||
pr_warning("Error reading display status\n");
|
||||
}
|
||||
|
||||
value &= 0x0F; /* needed for some models, shouldn't hurt others */
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, *this* one could be more user-friendly, but so far, no-one has
|
||||
* complained. The significance of bits is the same as in store_disp()
|
||||
*/
|
||||
static ssize_t show_disp(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct asus_laptop *asus = dev_get_drvdata(dev);
|
||||
|
||||
if (!display_get_handle)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n", read_display(asus));
|
||||
}
|
||||
|
||||
/*
|
||||
* Experimental support for display switching. As of now: 1 should activate
|
||||
* the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
|
||||
@@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
|
||||
struct asus_laptop *asus = acpi_driver_data(device);
|
||||
u16 count;
|
||||
|
||||
/*
|
||||
* We need to tell the backlight device when the backlight power is
|
||||
* switched
|
||||
*/
|
||||
if (event == ATKD_LCD_ON)
|
||||
lcd_blank(asus, FB_BLANK_UNBLANK);
|
||||
else if (event == ATKD_LCD_OFF)
|
||||
lcd_blank(asus, FB_BLANK_POWERDOWN);
|
||||
|
||||
/* TODO Find a better way to handle events count. */
|
||||
count = asus->event_count[event % 128]++;
|
||||
acpi_bus_generate_proc_event(asus->device, event, count);
|
||||
@@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
|
||||
show_bluetooth, store_bluetooth);
|
||||
static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
|
||||
static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
|
||||
static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp);
|
||||
static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
|
||||
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
|
||||
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
|
||||
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
|
||||
@@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = {
|
||||
}
|
||||
};
|
||||
|
||||
static int asus_handle_init(char *name, acpi_handle * handle,
|
||||
char **paths, int num_paths)
|
||||
{
|
||||
int i;
|
||||
acpi_status status;
|
||||
|
||||
for (i = 0; i < num_paths; i++) {
|
||||
status = acpi_get_handle(NULL, paths[i], handle);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return 0;
|
||||
}
|
||||
|
||||
*handle = NULL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#define ASUS_HANDLE_INIT(object) \
|
||||
asus_handle_init(#object, &object##_handle, object##_paths, \
|
||||
ARRAY_SIZE(object##_paths))
|
||||
|
||||
/*
|
||||
* This function is used to initialize the context with right values. In this
|
||||
* method, we can make all the detection we want, and modify the asus_laptop
|
||||
@@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
|
||||
if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
|
||||
asus->have_rsts = true;
|
||||
|
||||
/* Scheduled for removal */
|
||||
ASUS_HANDLE_INIT(lcd_switch);
|
||||
ASUS_HANDLE_INIT(display_get);
|
||||
|
||||
kfree(model);
|
||||
|
||||
return AE_OK;
|
||||
@@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
|
||||
asus_als_level(asus, asus->light_level);
|
||||
}
|
||||
|
||||
asus->lcd_state = 1; /* LCD should be on when the module load */
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __devinit asus_dmi_check(void)
|
||||
{
|
||||
const char *model;
|
||||
|
||||
model = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
/* On L1400B WLED control the sound card, don't mess with it ... */
|
||||
if (strncmp(model, "L1400B", 6) == 0) {
|
||||
wlan_status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool asus_device_present;
|
||||
|
||||
static int __devinit asus_acpi_add(struct acpi_device *device)
|
||||
@@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
|
||||
device->driver_data = asus;
|
||||
asus->device = device;
|
||||
|
||||
asus_dmi_check();
|
||||
|
||||
result = asus_acpi_init(asus);
|
||||
if (result)
|
||||
goto fail_platform;
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Asus Notebooks WMI hotkey driver
|
||||
*
|
||||
* Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
|
||||
#include "asus-wmi.h"
|
||||
|
||||
#define ASUS_NB_WMI_FILE "asus-nb-wmi"
|
||||
|
||||
MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>");
|
||||
MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
|
||||
|
||||
MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
|
||||
|
||||
static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
|
||||
{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
|
||||
{ KE_KEY, 0x32, { KEY_MUTE } },
|
||||
{ KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
|
||||
{ KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
|
||||
{ KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
|
||||
{ KE_KEY, 0x41, { KEY_NEXTSONG } },
|
||||
{ KE_KEY, 0x43, { KEY_STOPCD } },
|
||||
{ KE_KEY, 0x45, { KEY_PLAYPAUSE } },
|
||||
{ KE_KEY, 0x4c, { KEY_MEDIA } },
|
||||
{ KE_KEY, 0x50, { KEY_EMAIL } },
|
||||
{ KE_KEY, 0x51, { KEY_WWW } },
|
||||
{ KE_KEY, 0x55, { KEY_CALC } },
|
||||
{ KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
|
||||
{ KE_KEY, 0x5D, { KEY_WLAN } },
|
||||
{ KE_KEY, 0x5E, { KEY_WLAN } },
|
||||
{ KE_KEY, 0x5F, { KEY_WLAN } },
|
||||
{ KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
|
||||
{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },
|
||||
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } },
|
||||
{ KE_KEY, 0x82, { KEY_CAMERA } },
|
||||
{ KE_KEY, 0x88, { KEY_RFKILL } },
|
||||
{ KE_KEY, 0x8A, { KEY_PROG1 } },
|
||||
{ KE_KEY, 0x95, { KEY_MEDIA } },
|
||||
{ KE_KEY, 0x99, { KEY_PHONE } },
|
||||
{ KE_KEY, 0xb5, { KEY_CALC } },
|
||||
{ KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
|
||||
{ KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
|
||||
{ KE_END, 0},
|
||||
};
|
||||
|
||||
static struct asus_wmi_driver asus_nb_wmi_driver = {
|
||||
.name = ASUS_NB_WMI_FILE,
|
||||
.owner = THIS_MODULE,
|
||||
.event_guid = ASUS_NB_WMI_EVENT_GUID,
|
||||
.keymap = asus_nb_wmi_keymap,
|
||||
.input_name = "Asus WMI hotkeys",
|
||||
.input_phys = ASUS_NB_WMI_FILE "/input0",
|
||||
};
|
||||
|
||||
|
||||
static int __init asus_nb_wmi_init(void)
|
||||
{
|
||||
return asus_wmi_register_driver(&asus_nb_wmi_driver);
|
||||
}
|
||||
|
||||
static void __exit asus_nb_wmi_exit(void)
|
||||
{
|
||||
asus_wmi_unregister_driver(&asus_nb_wmi_driver);
|
||||
}
|
||||
|
||||
module_init(asus_nb_wmi_init);
|
||||
module_exit(asus_nb_wmi_exit);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Asus PC WMI hotkey driver
|
||||
*
|
||||
* Copyright(C) 2010 Intel Corporation.
|
||||
* Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
|
||||
*
|
||||
* Portions based on wistron_btns.c:
|
||||
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
|
||||
* Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
|
||||
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _ASUS_WMI_H_
|
||||
#define _ASUS_WMI_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct module;
|
||||
struct key_entry;
|
||||
struct asus_wmi;
|
||||
|
||||
struct asus_wmi_driver {
|
||||
bool hotplug_wireless;
|
||||
|
||||
const char *name;
|
||||
struct module *owner;
|
||||
|
||||
const char *event_guid;
|
||||
|
||||
const struct key_entry *keymap;
|
||||
const char *input_name;
|
||||
const char *input_phys;
|
||||
|
||||
int (*probe) (struct platform_device *device);
|
||||
void (*quirks) (struct asus_wmi_driver *driver);
|
||||
|
||||
struct platform_driver platform_driver;
|
||||
struct platform_device *platform_device;
|
||||
};
|
||||
|
||||
int asus_wmi_register_driver(struct asus_wmi_driver *driver);
|
||||
void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
|
||||
|
||||
#endif /* !_ASUS_WMI_H_ */
|
||||
@@ -201,7 +201,7 @@ static bool extra_features;
|
||||
* into 0x4F and read a few bytes from the output, like so:
|
||||
* u8 writeData = 0x33;
|
||||
* ec_transaction(0x4F, &writeData, 1, buffer, 32, 0);
|
||||
* That address is labled "fan1 table information" in the service manual.
|
||||
* That address is labelled "fan1 table information" in the service manual.
|
||||
* It should be clear which value in 'buffer' changes). This seems to be
|
||||
* related to fan speed. It isn't a proper 'realtime' fan speed value
|
||||
* though, because physically stopping or speeding up the fan doesn't
|
||||
@@ -275,7 +275,7 @@ static int set_backlight_level(int level)
|
||||
|
||||
ec_write(BACKLIGHT_LEVEL_ADDR, level);
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_backlight_level(void)
|
||||
@@ -763,7 +763,7 @@ static int dmi_check_cb(const struct dmi_system_id *id)
|
||||
printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n",
|
||||
id->ident);
|
||||
extra_features = false;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int dmi_check_cb_extra(const struct dmi_system_id *id)
|
||||
@@ -772,7 +772,7 @@ static int dmi_check_cb_extra(const struct dmi_system_id *id)
|
||||
"enabling extra features\n",
|
||||
id->ident);
|
||||
extra_features = true;
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dmi_system_id __initdata compal_dmi_table[] = {
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* WMI hotkeys support for Dell All-In-One series
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4"
|
||||
#define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8"
|
||||
|
||||
static const char *dell_wmi_aio_guids[] = {
|
||||
EVENT_GUID1,
|
||||
EVENT_GUID2,
|
||||
NULL
|
||||
};
|
||||
|
||||
MODULE_ALIAS("wmi:"EVENT_GUID1);
|
||||
MODULE_ALIAS("wmi:"EVENT_GUID2);
|
||||
|
||||
static const struct key_entry dell_wmi_aio_keymap[] = {
|
||||
{ KE_KEY, 0xc0, { KEY_VOLUMEUP } },
|
||||
{ KE_KEY, 0xc1, { KEY_VOLUMEDOWN } },
|
||||
{ KE_END, 0 }
|
||||
};
|
||||
|
||||
static struct input_dev *dell_wmi_aio_input_dev;
|
||||
|
||||
static void dell_wmi_aio_notify(u32 value, void *context)
|
||||
{
|
||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
acpi_status status;
|
||||
|
||||
status = wmi_get_event_data(value, &response);
|
||||
if (status != AE_OK) {
|
||||
pr_info("bad event status 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)response.pointer;
|
||||
if (obj) {
|
||||
unsigned int scancode;
|
||||
|
||||
switch (obj->type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
/* Most All-In-One correctly return integer scancode */
|
||||
scancode = obj->integer.value;
|
||||
sparse_keymap_report_event(dell_wmi_aio_input_dev,
|
||||
scancode, 1, true);
|
||||
break;
|
||||
case ACPI_TYPE_BUFFER:
|
||||
/* Broken machines return the scancode in a buffer */
|
||||
if (obj->buffer.pointer && obj->buffer.length > 0) {
|
||||
scancode = obj->buffer.pointer[0];
|
||||
sparse_keymap_report_event(
|
||||
dell_wmi_aio_input_dev,
|
||||
scancode, 1, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
kfree(obj);
|
||||
}
|
||||
|
||||
static int __init dell_wmi_aio_input_setup(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
dell_wmi_aio_input_dev = input_allocate_device();
|
||||
|
||||
if (!dell_wmi_aio_input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys";
|
||||
dell_wmi_aio_input_dev->phys = "wmi/input0";
|
||||
dell_wmi_aio_input_dev->id.bustype = BUS_HOST;
|
||||
|
||||
err = sparse_keymap_setup(dell_wmi_aio_input_dev,
|
||||
dell_wmi_aio_keymap, NULL);
|
||||
if (err) {
|
||||
pr_err("Unable to setup input device keymap\n");
|
||||
goto err_free_dev;
|
||||
}
|
||||
err = input_register_device(dell_wmi_aio_input_dev);
|
||||
if (err) {
|
||||
pr_info("Unable to register input device\n");
|
||||
goto err_free_keymap;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_free_keymap:
|
||||
sparse_keymap_free(dell_wmi_aio_input_dev);
|
||||
err_free_dev:
|
||||
input_free_device(dell_wmi_aio_input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const char *dell_wmi_aio_find(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; dell_wmi_aio_guids[i] != NULL; i++)
|
||||
if (wmi_has_guid(dell_wmi_aio_guids[i]))
|
||||
return dell_wmi_aio_guids[i];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int __init dell_wmi_aio_init(void)
|
||||
{
|
||||
int err;
|
||||
const char *guid;
|
||||
|
||||
guid = dell_wmi_aio_find();
|
||||
if (!guid) {
|
||||
pr_warning("No known WMI GUID found\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
err = dell_wmi_aio_input_setup();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL);
|
||||
if (err) {
|
||||
pr_err("Unable to register notify handler - %d\n", err);
|
||||
sparse_keymap_free(dell_wmi_aio_input_dev);
|
||||
input_unregister_device(dell_wmi_aio_input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dell_wmi_aio_exit(void)
|
||||
{
|
||||
const char *guid;
|
||||
|
||||
guid = dell_wmi_aio_find();
|
||||
wmi_remove_notify_handler(guid);
|
||||
sparse_keymap_free(dell_wmi_aio_input_dev);
|
||||
input_unregister_device(dell_wmi_aio_input_dev);
|
||||
}
|
||||
|
||||
module_init(dell_wmi_aio_init);
|
||||
module_exit(dell_wmi_aio_exit);
|
||||
@@ -1322,7 +1322,7 @@ static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
/* Some BIOSes do not report cm although it is avaliable.
|
||||
/* Some BIOSes do not report cm although it is available.
|
||||
Check if cm_getv[cm] works and, if yes, assume cm should be set. */
|
||||
if (!(eeepc->cm_supported & (1 << cm))
|
||||
&& !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+273
-39
@@ -2,6 +2,7 @@
|
||||
* HP WMI hotkeys
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat <mjg@redhat.com>
|
||||
* Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
|
||||
*
|
||||
* Portions based on wistron_btns.c:
|
||||
* Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
|
||||
@@ -51,6 +52,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
|
||||
#define HPWMI_HARDWARE_QUERY 0x4
|
||||
#define HPWMI_WIRELESS_QUERY 0x5
|
||||
#define HPWMI_HOTKEY_QUERY 0xc
|
||||
#define HPWMI_WIRELESS2_QUERY 0x1b
|
||||
|
||||
#define PREFIX "HP WMI: "
|
||||
#define UNIMP "Unimplemented "
|
||||
@@ -86,7 +88,46 @@ struct bios_args {
|
||||
struct bios_return {
|
||||
u32 sigpass;
|
||||
u32 return_code;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum hp_return_value {
|
||||
HPWMI_RET_WRONG_SIGNATURE = 0x02,
|
||||
HPWMI_RET_UNKNOWN_COMMAND = 0x03,
|
||||
HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
|
||||
HPWMI_RET_INVALID_PARAMETERS = 0x05,
|
||||
};
|
||||
|
||||
enum hp_wireless2_bits {
|
||||
HPWMI_POWER_STATE = 0x01,
|
||||
HPWMI_POWER_SOFT = 0x02,
|
||||
HPWMI_POWER_BIOS = 0x04,
|
||||
HPWMI_POWER_HARD = 0x08,
|
||||
};
|
||||
|
||||
#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
|
||||
!= (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
|
||||
#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
|
||||
|
||||
struct bios_rfkill2_device_state {
|
||||
u8 radio_type;
|
||||
u8 bus_type;
|
||||
u16 vendor_id;
|
||||
u16 product_id;
|
||||
u16 subsys_vendor_id;
|
||||
u16 subsys_product_id;
|
||||
u8 rfkill_id;
|
||||
u8 power;
|
||||
u8 unknown[4];
|
||||
};
|
||||
|
||||
/* 7 devices fit into the 128 byte buffer */
|
||||
#define HPWMI_MAX_RFKILL2_DEVICES 7
|
||||
|
||||
struct bios_rfkill2_state {
|
||||
u8 unknown[7];
|
||||
u8 count;
|
||||
u8 pad[8];
|
||||
struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
|
||||
};
|
||||
|
||||
static const struct key_entry hp_wmi_keymap[] = {
|
||||
@@ -108,6 +149,15 @@ static struct rfkill *wifi_rfkill;
|
||||
static struct rfkill *bluetooth_rfkill;
|
||||
static struct rfkill *wwan_rfkill;
|
||||
|
||||
struct rfkill2_device {
|
||||
u8 id;
|
||||
int num;
|
||||
struct rfkill *rfkill;
|
||||
};
|
||||
|
||||
static int rfkill2_count;
|
||||
static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
|
||||
|
||||
static const struct dev_pm_ops hp_wmi_pm_ops = {
|
||||
.resume = hp_wmi_resume_handler,
|
||||
.restore = hp_wmi_resume_handler,
|
||||
@@ -129,7 +179,8 @@ static struct platform_driver hp_wmi_driver = {
|
||||
* query: The commandtype -> What should be queried
|
||||
* write: The command -> 0 read, 1 write, 3 ODM specific
|
||||
* buffer: Buffer used as input and/or output
|
||||
* buffersize: Size of buffer
|
||||
* insize: Size of input buffer
|
||||
* outsize: Size of output buffer
|
||||
*
|
||||
* returns zero on success
|
||||
* an HP WMI query specific error code (which is positive)
|
||||
@@ -140,25 +191,29 @@ static struct platform_driver hp_wmi_driver = {
|
||||
* size. E.g. Battery info query (0x7) is defined to have 1 byte input
|
||||
* and 128 byte output. The caller would do:
|
||||
* buffer = kzalloc(128, GFP_KERNEL);
|
||||
* ret = hp_wmi_perform_query(0x7, 0, buffer, 128)
|
||||
* ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
|
||||
*/
|
||||
static int hp_wmi_perform_query(int query, int write, u32 *buffer,
|
||||
int buffersize)
|
||||
static int hp_wmi_perform_query(int query, int write, void *buffer,
|
||||
int insize, int outsize)
|
||||
{
|
||||
struct bios_return bios_return;
|
||||
acpi_status status;
|
||||
struct bios_return *bios_return;
|
||||
int actual_outsize;
|
||||
union acpi_object *obj;
|
||||
struct bios_args args = {
|
||||
.signature = 0x55434553,
|
||||
.command = write ? 0x2 : 0x1,
|
||||
.commandtype = query,
|
||||
.datasize = buffersize,
|
||||
.data = *buffer,
|
||||
.datasize = insize,
|
||||
.data = 0,
|
||||
};
|
||||
struct acpi_buffer input = { sizeof(struct bios_args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
|
||||
if (WARN_ON(insize > sizeof(args.data)))
|
||||
return -EINVAL;
|
||||
memcpy(&args.data, buffer, insize);
|
||||
|
||||
wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
|
||||
|
||||
obj = output.pointer;
|
||||
|
||||
@@ -169,10 +224,26 @@ static int hp_wmi_perform_query(int query, int write, u32 *buffer,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bios_return = *((struct bios_return *)obj->buffer.pointer);
|
||||
bios_return = (struct bios_return *)obj->buffer.pointer;
|
||||
|
||||
memcpy(buffer, &bios_return.value, sizeof(bios_return.value));
|
||||
if (bios_return->return_code) {
|
||||
if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
|
||||
printk(KERN_WARNING PREFIX "query 0x%x returned "
|
||||
"error 0x%x\n",
|
||||
query, bios_return->return_code);
|
||||
kfree(obj);
|
||||
return bios_return->return_code;
|
||||
}
|
||||
|
||||
if (!outsize) {
|
||||
/* ignore output data */
|
||||
kfree(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
|
||||
memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
|
||||
memset(buffer + actual_outsize, 0, outsize - actual_outsize);
|
||||
kfree(obj);
|
||||
return 0;
|
||||
}
|
||||
@@ -181,7 +252,7 @@ static int hp_wmi_display_state(void)
|
||||
{
|
||||
int state = 0;
|
||||
int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
|
||||
sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return state;
|
||||
@@ -191,7 +262,7 @@ static int hp_wmi_hddtemp_state(void)
|
||||
{
|
||||
int state = 0;
|
||||
int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
|
||||
sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return state;
|
||||
@@ -201,7 +272,7 @@ static int hp_wmi_als_state(void)
|
||||
{
|
||||
int state = 0;
|
||||
int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
|
||||
sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return state;
|
||||
@@ -211,7 +282,7 @@ static int hp_wmi_dock_state(void)
|
||||
{
|
||||
int state = 0;
|
||||
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
|
||||
sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
@@ -223,7 +294,7 @@ static int hp_wmi_tablet_state(void)
|
||||
{
|
||||
int state = 0;
|
||||
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
|
||||
sizeof(state));
|
||||
sizeof(state), sizeof(state));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -237,7 +308,7 @@ static int hp_wmi_set_block(void *data, bool blocked)
|
||||
int ret;
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
|
||||
&query, sizeof(query));
|
||||
&query, sizeof(query), 0);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
@@ -252,7 +323,8 @@ static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
|
||||
int wireless = 0;
|
||||
int mask;
|
||||
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
|
||||
&wireless, sizeof(wireless));
|
||||
&wireless, sizeof(wireless),
|
||||
sizeof(wireless));
|
||||
/* TBD: Pass error */
|
||||
|
||||
mask = 0x200 << (r * 8);
|
||||
@@ -268,7 +340,8 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
|
||||
int wireless = 0;
|
||||
int mask;
|
||||
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
|
||||
&wireless, sizeof(wireless));
|
||||
&wireless, sizeof(wireless),
|
||||
sizeof(wireless));
|
||||
/* TBD: Pass error */
|
||||
|
||||
mask = 0x800 << (r * 8);
|
||||
@@ -279,6 +352,51 @@ static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
|
||||
{
|
||||
int rfkill_id = (int)(long)data;
|
||||
char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
|
||||
|
||||
if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
|
||||
buffer, sizeof(buffer), 0))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops hp_wmi_rfkill2_ops = {
|
||||
.set_block = hp_wmi_rfkill2_set_block,
|
||||
};
|
||||
|
||||
static int hp_wmi_rfkill2_refresh(void)
|
||||
{
|
||||
int err, i;
|
||||
struct bios_rfkill2_state state;
|
||||
|
||||
err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
|
||||
0, sizeof(state));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < rfkill2_count; i++) {
|
||||
int num = rfkill2[i].num;
|
||||
struct bios_rfkill2_device_state *devstate;
|
||||
devstate = &state.device[num];
|
||||
|
||||
if (num >= state.count ||
|
||||
devstate->rfkill_id != rfkill2[i].id) {
|
||||
printk(KERN_WARNING PREFIX "power configuration of "
|
||||
"the wireless devices unexpectedly changed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
rfkill_set_states(rfkill2[i].rfkill,
|
||||
IS_SWBLOCKED(devstate->power),
|
||||
IS_HWBLOCKED(devstate->power));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@@ -329,7 +447,7 @@ static ssize_t set_als(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
u32 tmp = simple_strtoul(buf, NULL, 10);
|
||||
int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
|
||||
sizeof(tmp));
|
||||
sizeof(tmp), sizeof(tmp));
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
|
||||
@@ -402,6 +520,7 @@ static void hp_wmi_notify(u32 value, void *context)
|
||||
case HPWMI_BEZEL_BUTTON:
|
||||
ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
|
||||
&key_code,
|
||||
sizeof(key_code),
|
||||
sizeof(key_code));
|
||||
if (ret)
|
||||
break;
|
||||
@@ -412,6 +531,11 @@ static void hp_wmi_notify(u32 value, void *context)
|
||||
key_code);
|
||||
break;
|
||||
case HPWMI_WIRELESS:
|
||||
if (rfkill2_count) {
|
||||
hp_wmi_rfkill2_refresh();
|
||||
break;
|
||||
}
|
||||
|
||||
if (wifi_rfkill)
|
||||
rfkill_set_states(wifi_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WIFI),
|
||||
@@ -502,32 +626,16 @@ static void cleanup_sysfs(struct platform_device *device)
|
||||
device_remove_file(&device->dev, &dev_attr_tablet);
|
||||
}
|
||||
|
||||
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
|
||||
static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
|
||||
{
|
||||
int err;
|
||||
int wireless = 0;
|
||||
|
||||
err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
|
||||
sizeof(wireless));
|
||||
sizeof(wireless), sizeof(wireless));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = device_create_file(&device->dev, &dev_attr_display);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_hddtemp);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_als);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_dock);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_tablet);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
|
||||
if (wireless & 0x1) {
|
||||
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
@@ -573,14 +681,131 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
|
||||
return 0;
|
||||
register_wwan_err:
|
||||
rfkill_destroy(wwan_rfkill);
|
||||
wwan_rfkill = NULL;
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
register_bluetooth_error:
|
||||
rfkill_destroy(bluetooth_rfkill);
|
||||
bluetooth_rfkill = NULL;
|
||||
if (wifi_rfkill)
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
register_wifi_error:
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
wifi_rfkill = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
|
||||
{
|
||||
int err, i;
|
||||
struct bios_rfkill2_state state;
|
||||
err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
|
||||
0, sizeof(state));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
|
||||
printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < state.count; i++) {
|
||||
struct rfkill *rfkill;
|
||||
enum rfkill_type type;
|
||||
char *name;
|
||||
switch (state.device[i].radio_type) {
|
||||
case HPWMI_WIFI:
|
||||
type = RFKILL_TYPE_WLAN;
|
||||
name = "hp-wifi";
|
||||
break;
|
||||
case HPWMI_BLUETOOTH:
|
||||
type = RFKILL_TYPE_BLUETOOTH;
|
||||
name = "hp-bluetooth";
|
||||
break;
|
||||
case HPWMI_WWAN:
|
||||
type = RFKILL_TYPE_WWAN;
|
||||
name = "hp-wwan";
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
|
||||
state.device[i].radio_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!state.device[i].vendor_id) {
|
||||
printk(KERN_WARNING PREFIX "zero device %d while %d "
|
||||
"reported\n", i, state.count);
|
||||
continue;
|
||||
}
|
||||
|
||||
rfkill = rfkill_alloc(name, &device->dev, type,
|
||||
&hp_wmi_rfkill2_ops, (void *)(long)i);
|
||||
if (!rfkill) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
|
||||
rfkill2[rfkill2_count].num = i;
|
||||
rfkill2[rfkill2_count].rfkill = rfkill;
|
||||
|
||||
rfkill_init_sw_state(rfkill,
|
||||
IS_SWBLOCKED(state.device[i].power));
|
||||
rfkill_set_hw_state(rfkill,
|
||||
IS_HWBLOCKED(state.device[i].power));
|
||||
|
||||
if (!(state.device[i].power & HPWMI_POWER_BIOS))
|
||||
printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
|
||||
name);
|
||||
|
||||
err = rfkill_register(rfkill);
|
||||
if (err) {
|
||||
rfkill_destroy(rfkill);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rfkill2_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
for (; rfkill2_count > 0; rfkill2_count--) {
|
||||
rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
|
||||
rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devinit hp_wmi_bios_setup(struct platform_device *device)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* clear detected rfkill devices */
|
||||
wifi_rfkill = NULL;
|
||||
bluetooth_rfkill = NULL;
|
||||
wwan_rfkill = NULL;
|
||||
rfkill2_count = 0;
|
||||
|
||||
if (hp_wmi_rfkill_setup(device))
|
||||
hp_wmi_rfkill2_setup(device);
|
||||
|
||||
err = device_create_file(&device->dev, &dev_attr_display);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_hddtemp);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_als);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_dock);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
err = device_create_file(&device->dev, &dev_attr_tablet);
|
||||
if (err)
|
||||
goto add_sysfs_error;
|
||||
return 0;
|
||||
|
||||
add_sysfs_error:
|
||||
cleanup_sysfs(device);
|
||||
return err;
|
||||
@@ -588,8 +813,14 @@ add_sysfs_error:
|
||||
|
||||
static int __exit hp_wmi_bios_remove(struct platform_device *device)
|
||||
{
|
||||
int i;
|
||||
cleanup_sysfs(device);
|
||||
|
||||
for (i = 0; i < rfkill2_count; i++) {
|
||||
rfkill_unregister(rfkill2[i].rfkill);
|
||||
rfkill_destroy(rfkill2[i].rfkill);
|
||||
}
|
||||
|
||||
if (wifi_rfkill) {
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
@@ -622,6 +853,9 @@ static int hp_wmi_resume_handler(struct device *device)
|
||||
input_sync(hp_wmi_input_dev);
|
||||
}
|
||||
|
||||
if (rfkill2_count)
|
||||
hp_wmi_rfkill2_refresh();
|
||||
|
||||
if (wifi_rfkill)
|
||||
rfkill_set_states(wifi_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WIFI),
|
||||
|
||||
@@ -459,6 +459,8 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
|
||||
if (test_bit(vpc_bit, &vpc1)) {
|
||||
if (vpc_bit == 9)
|
||||
ideapad_sync_rfk_state(adevice);
|
||||
else if (vpc_bit == 4)
|
||||
read_ec_data(handle, 0x12, &vpc2);
|
||||
else
|
||||
ideapad_input_report(priv, vpc_bit);
|
||||
}
|
||||
|
||||
@@ -1111,7 +1111,7 @@ static int ips_monitor(void *data)
|
||||
last_msecs = jiffies_to_msecs(jiffies);
|
||||
expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD);
|
||||
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
mod_timer(&timer, expire);
|
||||
schedule();
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Power button driver for Medfield.
|
||||
*
|
||||
* Copyright (C) 2010 Intel Corp
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
|
||||
#define DRIVER_NAME "msic_power_btn"
|
||||
|
||||
#define MSIC_IRQ_STAT 0x02
|
||||
#define MSIC_IRQ_PB (1 << 0)
|
||||
#define MSIC_PB_CONFIG 0x3e
|
||||
#define MSIC_PB_STATUS 0x3f
|
||||
#define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
|
||||
|
||||
struct mfld_pb_priv {
|
||||
struct input_dev *input;
|
||||
unsigned int irq;
|
||||
};
|
||||
|
||||
static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
|
||||
{
|
||||
struct mfld_pb_priv *priv = dev_id;
|
||||
int ret;
|
||||
u8 pbstat;
|
||||
|
||||
ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat);
|
||||
if (ret < 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL));
|
||||
input_sync(priv->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit mfld_pb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mfld_pb_priv *priv;
|
||||
struct input_dev *input;
|
||||
int irq;
|
||||
int error;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return -EINVAL;
|
||||
|
||||
priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL);
|
||||
input = input_allocate_device();
|
||||
if (!priv || !input) {
|
||||
error = -ENOMEM;
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
priv->input = input;
|
||||
priv->irq = irq;
|
||||
|
||||
input->name = pdev->name;
|
||||
input->phys = "power-button/input0";
|
||||
input->id.bustype = BUS_HOST;
|
||||
input->dev.parent = &pdev->dev;
|
||||
|
||||
input_set_capability(input, EV_KEY, KEY_POWER);
|
||||
|
||||
error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr,
|
||||
0, DRIVER_NAME, priv);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to request irq %d for mfld power button\n",
|
||||
irq);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev,
|
||||
"unable to register input dev, error %d\n", error);
|
||||
goto err_free_irq;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
return 0;
|
||||
|
||||
err_free_irq:
|
||||
free_irq(priv->irq, priv);
|
||||
err_free_mem:
|
||||
input_free_device(input);
|
||||
kfree(priv);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __devexit mfld_pb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mfld_pb_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(priv->irq, priv);
|
||||
input_unregister_device(priv->input);
|
||||
kfree(priv);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mfld_pb_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = mfld_pb_probe,
|
||||
.remove = __devexit_p(mfld_pb_remove),
|
||||
};
|
||||
|
||||
static int __init mfld_pb_init(void)
|
||||
{
|
||||
return platform_driver_register(&mfld_pb_driver);
|
||||
}
|
||||
module_init(mfld_pb_init);
|
||||
|
||||
static void __exit mfld_pb_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mfld_pb_driver);
|
||||
}
|
||||
module_exit(mfld_pb_exit);
|
||||
|
||||
MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user