提交 baaca1a6 编写于 作者: L Linus Torvalds

Merge branch 'for_linus' of...

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()
  ...
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.
What: /sys/devices/platform/eeepc-wmi/cpufv
What: /sys/devices/platform/<platform>/cpufv
Date: Oct 2010
KernelVersion: 2.6.37
Contact: "Corentin Chary" <corentincj@iksaif.net>
......@@ -8,3 +8,24 @@ Description:
* 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.
......@@ -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.
......@@ -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(&params, &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(&params, &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 @@ static int asus_led_init(struct asus_laptop *asus)
/*
* 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;
......
/*
* 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);
此差异已折叠。
/*
* 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[] = {
......
/*
* 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)) {
......
此差异已折叠。
......@@ -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 @@ static int __devinit hp_wmi_bios_setup(struct platform_device *device)
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();
......
/*
* 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);
此差异已折叠。
......@@ -485,7 +485,7 @@ EXPORT_SYMBOL(rar_lock);
*
* The register_rar function is to used by other device drivers
* to ensure that this driver is ready. As we cannot be sure of
* the compile/execute order of drivers in ther kernel, it is
* the compile/execute order of drivers in the kernel, it is
* best to give this driver a callback function to call when
* it is ready to give out addresses. The callback function
* would have those steps that continue the initialization of
......
......@@ -9,7 +9,7 @@
* as published by the Free Software Foundation; version 2
* of the License.
*
* SCU runing in ARC processor communicates with other entity running in IA
* SCU running in ARC processor communicates with other entity running in IA
* core through IPC mechanism which in turn messaging between IA core ad SCU.
* SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and
* SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
......
......@@ -51,6 +51,8 @@
* laptop as MSI S270. YMMV.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -60,6 +62,8 @@
#include <linux/platform_device.h>
#include <linux/rfkill.h>
#include <linux/i8042.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#define MSI_DRIVER_VERSION "0.5"
......@@ -78,6 +82,9 @@
#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d
#define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0)
#define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4
#define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4)
static int msi_laptop_resume(struct platform_device *device);
#define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
......@@ -90,6 +97,14 @@ static int auto_brightness;
module_param(auto_brightness, int, 0);
MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
static const struct key_entry msi_laptop_keymap[] = {
{KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */
{KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */
{KE_END, 0}
};
static struct input_dev *msi_laptop_input_dev;
static bool old_ec_model;
static int wlan_s, bluetooth_s, threeg_s;
static int threeg_exists;
......@@ -432,8 +447,7 @@ static struct platform_device *msipf_device;
static int dmi_check_cb(const struct dmi_system_id *id)
{
printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n",
id->ident);
pr_info("Identified laptop model '%s'.\n", id->ident);
return 1;
}
......@@ -605,6 +619,21 @@ static void msi_update_rfkill(struct work_struct *ignored)
}
static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill);
static void msi_send_touchpad_key(struct work_struct *ignored)
{
u8 rdata;
int result;
result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata);
if (result < 0)
return;
sparse_keymap_report_event(msi_laptop_input_dev,
(rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ?
KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true);
}
static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key);
static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
struct serio *port)
{
......@@ -613,12 +642,17 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
if (str & 0x20)
return false;
/* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/
/* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/
if (unlikely(data == 0xe0)) {
extended = true;
return false;
} else if (unlikely(extended)) {
extended = false;
switch (data) {
case 0xE4:
schedule_delayed_work(&msi_touchpad_work,
round_jiffies_relative(0.5 * HZ));
break;
case 0x54:
case 0x62:
case 0x76:
......@@ -626,7 +660,6 @@ static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str,
round_jiffies_relative(0.5 * HZ));
break;
}
extended = false;
}
return false;
......@@ -731,6 +764,42 @@ static int msi_laptop_resume(struct platform_device *device)
return 0;
}
static int __init msi_laptop_input_setup(void)
{
int err;
msi_laptop_input_dev = input_allocate_device();
if (!msi_laptop_input_dev)
return -ENOMEM;
msi_laptop_input_dev->name = "MSI Laptop hotkeys";
msi_laptop_input_dev->phys = "msi-laptop/input0";
msi_laptop_input_dev->id.bustype = BUS_HOST;
err = sparse_keymap_setup(msi_laptop_input_dev,
msi_laptop_keymap, NULL);
if (err)
goto err_free_dev;
err = input_register_device(msi_laptop_input_dev);
if (err)
goto err_free_keymap;
return 0;
err_free_keymap:
sparse_keymap_free(msi_laptop_input_dev);
err_free_dev:
input_free_device(msi_laptop_input_dev);
return err;
}
static void msi_laptop_input_destroy(void)
{
sparse_keymap_free(msi_laptop_input_dev);
input_unregister_device(msi_laptop_input_dev);
}
static int load_scm_model_init(struct platform_device *sdev)
{
u8 data;
......@@ -759,16 +828,23 @@ static int load_scm_model_init(struct platform_device *sdev)
if (result < 0)
goto fail_rfkill;
/* setup input device */
result = msi_laptop_input_setup();
if (result)
goto fail_input;
result = i8042_install_filter(msi_laptop_i8042_filter);
if (result) {
printk(KERN_ERR
"msi-laptop: Unable to install key filter\n");
pr_err("Unable to install key filter\n");
goto fail_filter;
}
return 0;
fail_filter:
msi_laptop_input_destroy();
fail_input:
rfkill_cleanup();
fail_rfkill:
......@@ -799,7 +875,7 @@ static int __init msi_init(void)
/* Register backlight stuff */
if (acpi_video_backlight_support()) {
printk(KERN_INFO "MSI: Brightness ignored, must be controlled "
pr_info("Brightness ignored, must be controlled "
"by ACPI video driver\n");
} else {
struct backlight_properties props;
......@@ -854,7 +930,7 @@ static int __init msi_init(void)
if (auto_brightness != 2)
set_auto_brightness(auto_brightness);
printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n");
return 0;
......@@ -886,6 +962,7 @@ static void __exit msi_cleanup(void)
{
if (load_scm_model) {
i8042_remove_filter(msi_laptop_i8042_filter);
msi_laptop_input_destroy();
cancel_delayed_work_sync(&msi_rfkill_work);
rfkill_cleanup();
}
......@@ -901,7 +978,7 @@ static void __exit msi_cleanup(void)
if (auto_brightness != 2)
set_auto_brightness(1);
printk(KERN_INFO "msi-laptop: driver unloaded.\n");
pr_info("driver unloaded.\n");
}
module_init(msi_init);
......
此差异已折叠。
此差异已折叠。
......@@ -2407,7 +2407,7 @@ static void hotkey_compare_and_issue_event(struct tp_nvram_state *oldn,
* This code is supposed to duplicate the IBM firmware behaviour:
* - Pressing MUTE issues mute hotkey message, even when already mute
* - Pressing Volume up/down issues volume up/down hotkey messages,
* even when already at maximum or minumum volume
* even when already at maximum or minimum volume
* - The act of unmuting issues volume up/down notification,
* depending which key was used to unmute
*
......@@ -2990,7 +2990,7 @@ static void tpacpi_send_radiosw_update(void)
* rfkill input events, or we will race the rfkill core input
* handler.
*
* tpacpi_inputdev_send_mutex works as a syncronization point
* tpacpi_inputdev_send_mutex works as a synchronization point
* for the above.
*
* We optimize to avoid numerous calls to hotkey_get_wlsw.
......
/*
* OLPC XO-1.5 ebook switch driver
* (based on generic ACPI button driver)
*
* Copyright (C) 2009 Paul Fox <pgf@laptop.org>
* Copyright (C) 2010 One Laptop per Child
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/input.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#define MODULE_NAME "xo15-ebook"
#define PREFIX MODULE_NAME ": "
#define XO15_EBOOK_CLASS MODULE_NAME
#define XO15_EBOOK_TYPE_UNKNOWN 0x00
#define XO15_EBOOK_NOTIFY_STATUS 0x80
#define XO15_EBOOK_SUBCLASS "ebook"
#define XO15_EBOOK_HID "XO15EBK"
#define XO15_EBOOK_DEVICE_NAME "EBook Switch"
ACPI_MODULE_NAME(MODULE_NAME);
MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
MODULE_LICENSE("GPL");
static const struct acpi_device_id ebook_device_ids[] = {
{ XO15_EBOOK_HID, 0 },
{ "", 0 },
};
MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
struct ebook_switch {
struct input_dev *input;
char phys[32]; /* for input device */
};
static int ebook_send_state(struct acpi_device *device)
{
struct ebook_switch *button = acpi_driver_data(device);
unsigned long long state;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state);
if (ACPI_FAILURE(status))
return -EIO;
/* input layer checks if event is redundant */
input_report_switch(button->input, SW_TABLET_MODE, !state);
input_sync(button->input);
return 0;
}
static void ebook_switch_notify(struct acpi_device *device, u32 event)
{
switch (event) {
case ACPI_FIXED_HARDWARE_EVENT:
case XO15_EBOOK_NOTIFY_STATUS:
ebook_send_state(device);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
break;
}
}
static int ebook_switch_resume(struct acpi_device *device)
{
return ebook_send_state(device);
}
static int ebook_switch_add(struct acpi_device *device)
{
struct ebook_switch *button;
struct input_dev *input;
const char *hid = acpi_device_hid(device);
char *name, *class;
int error;
button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL);
if (!button)
return -ENOMEM;
device->driver_data = button;
button->input = input = input_allocate_device();
if (!input) {
error = -ENOMEM;
goto err_free_button;
}
name = acpi_device_name(device);
class = acpi_device_class(device);
if (strcmp(hid, XO15_EBOOK_HID)) {
printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid);
error = -ENODEV;
goto err_free_input;
}
strcpy(name, XO15_EBOOK_DEVICE_NAME);
sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
input->name = name;
input->phys = button->phys;
input->id.bustype = BUS_HOST;
input->dev.parent = &device->dev;
input->evbit[0] = BIT_MASK(EV_SW);
set_bit(SW_TABLET_MODE, input->swbit);
error = input_register_device(input);
if (error)
goto err_free_input;
ebook_send_state(device);
if (device->wakeup.flags.valid) {
/* Button's GPE is run-wake GPE */
acpi_enable_gpe(device->wakeup.gpe_device,
device->wakeup.gpe_number);
device_set_wakeup_enable(&device->dev, true);
}
return 0;
err_free_input:
input_free_device(input);
err_free_button:
kfree(button);
return error;
}
static int ebook_switch_remove(struct acpi_device *device, int type)
{
struct ebook_switch *button = acpi_driver_data(device);
input_unregister_device(button->input);
kfree(button);
return 0;
}
static struct acpi_driver xo15_ebook_driver = {
.name = MODULE_NAME,
.class = XO15_EBOOK_CLASS,
.ids = ebook_device_ids,
.ops = {
.add = ebook_switch_add,
.resume = ebook_switch_resume,
.remove = ebook_switch_remove,
.notify = ebook_switch_notify,
},
};
static int __init xo15_ebook_init(void)
{
return acpi_bus_register_driver(&xo15_ebook_driver);
}
static void __exit xo15_ebook_exit(void)
{
acpi_bus_unregister_driver(&xo15_ebook_driver);
}
module_init(xo15_ebook_init);
module_exit(xo15_ebook_exit);
此差异已折叠。
......@@ -40,6 +40,7 @@
/* events the user application reading /dev/sonypi can use */
#define SONYPI_EVENT_IGNORE 0
#define SONYPI_EVENT_JOGDIAL_DOWN 1
#define SONYPI_EVENT_JOGDIAL_UP 2
#define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册