mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 21:30:43 +00:00
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platform driver updates from Matthew Garrett: "Some significant updates to samsung-laptop, additional hardware support for Toshibas, misc updates to various hardware and a new backlight driver for some Apple machines." Fix up trivial conflicts: geode Geos update happening next to net5501 support, and MSIC thermal platform support added twice. * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (77 commits) acer-wmi: add quirk table for video backlight vendor mode drivers/platform/x86/amilo-rfkill.c::amilo_rfkill_probe() avoid NULL deref samsung-laptop: unregister ACPI video module for some well known laptops acer-wmi: No wifi rfkill on Sony machines thinkpad-acpi: recognize Lenovo as version string in newer V-series BIOS asus-wmi: don't update power and brightness when using scalar eeepc-wmi: split et2012 specific hacks eeepc-wmi: refine quirks handling asus-nb-wmi: set panel_power correctly asus-wmi: move WAPF variable into quirks_entry asus-wmi: store backlight power status for AIO machine asus-wmi: add scalar board brightness adj. support samsung-laptop: cleanup return type: mode_t vs umode_t drivers, samsung-laptop: fix usage of isalnum drivers, samsung-laptop: fix initialization of sabi_data in sabi_set_commandb asus-wmi: on/off bit is not set when reading the value eeepc-wmi: add extra keymaps for EP121 asus-nb-wmi: ignore useless keys acer-wmi: support Lenovo ideapad S205 Brazos wifi switch acer-wmi: fix out of input parameter size when set ...
This commit is contained in:
commit
61e5191c9d
@ -17,3 +17,21 @@ Description: Some Samsung laptops have different "performance levels"
|
||||
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/samsung/battery_life_extender
|
||||
Date: December 1, 2011
|
||||
KernelVersion: 3.3
|
||||
Contact: Corentin Chary <corentin.chary@gmail.com>
|
||||
Description: Max battery charge level can be modified, battery cycle
|
||||
life can be extended by reducing the max battery charge
|
||||
level.
|
||||
0 means normal battery mode (100% charge)
|
||||
1 means battery life extender mode (80% charge)
|
||||
|
||||
What: /sys/devices/platform/samsung/usb_charge
|
||||
Date: December 1, 2011
|
||||
KernelVersion: 3.3
|
||||
Contact: Corentin Chary <corentin.chary@gmail.com>
|
||||
Description: Use your USB ports to charge devices, even
|
||||
when your laptop is powered off.
|
||||
1 means enabled, 0 means disabled.
|
||||
|
@ -45,7 +45,7 @@ Status
|
||||
Usage
|
||||
-----
|
||||
|
||||
Try "modprobe asus_acpi". Check your dmesg (simply type dmesg). You should
|
||||
Try "modprobe asus-laptop". Check your dmesg (simply type dmesg). You should
|
||||
see some lines like this :
|
||||
|
||||
Asus Laptop Extras version 0.42
|
||||
|
@ -17,6 +17,11 @@ subsystem. See the logs of acpid or /proc/acpi/event and
|
||||
devices are created by the driver. Additionally, loading the driver with the
|
||||
debug option will report all events in the kernel log.
|
||||
|
||||
The "scancodes" passed to the input system (that can be remapped with udev)
|
||||
are indexes to the table "sony_laptop_input_keycode_map" in the sony-laptop.c
|
||||
module. For example the "FN/E" key combination (EJECTCD on some models)
|
||||
generates the scancode 20 (0x14).
|
||||
|
||||
Backlight control:
|
||||
------------------
|
||||
If your laptop model supports it, you will find sysfs files in the
|
||||
|
@ -5776,6 +5776,12 @@ F: drivers/media/common/saa7146*
|
||||
F: drivers/media/video/*7146*
|
||||
F: include/media/*7146*
|
||||
|
||||
SAMSUNG LAPTOP DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/samsung-laptop.c
|
||||
|
||||
SAMSUNG AUDIO (ASoC) DRIVERS
|
||||
M: Sangbeom Kim <sbkim73@samsung.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
|
@ -2125,6 +2125,13 @@ config NET5501
|
||||
---help---
|
||||
This option enables system support for the Soekris Engineering net5501.
|
||||
|
||||
config GEOS
|
||||
bool "Traverse Technologies GEOS System Support (LEDS, GPIO, etc)"
|
||||
select GPIOLIB
|
||||
depends on DMI
|
||||
---help---
|
||||
This option enables system support for the Traverse Technologies GEOS.
|
||||
|
||||
endif # X86_32
|
||||
|
||||
config AMD_NB
|
||||
|
@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_ALIX) += alix.o
|
||||
obj-$(CONFIG_NET5501) += net5501.o
|
||||
obj-$(CONFIG_GEOS) += geos.o
|
||||
|
128
arch/x86/platform/geode/geos.c
Normal file
128
arch/x86/platform/geode/geos.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* System Specific setup for Traverse Technologies GEOS.
|
||||
* At the moment this means setup of GPIO control of LEDs.
|
||||
*
|
||||
* Copyright (C) 2008 Constantin Baranov <const@mimas.ru>
|
||||
* Copyright (C) 2011 Ed Wildgoose <kernel@wildgooses.com>
|
||||
* and Philip Prindeville <philipp@redfish-solutions.com>
|
||||
*
|
||||
* TODO: There are large similarities with leds-net5501.c
|
||||
* by Alessandro Zummo <a.zummo@towertech.it>
|
||||
* In the future leds-net5501.c should be migrated over to platform
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio_keys.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#include <asm/geode.h>
|
||||
|
||||
static struct gpio_keys_button geos_gpio_buttons[] = {
|
||||
{
|
||||
.code = KEY_RESTART,
|
||||
.gpio = 3,
|
||||
.active_low = 1,
|
||||
.desc = "Reset button",
|
||||
.type = EV_KEY,
|
||||
.wakeup = 0,
|
||||
.debounce_interval = 100,
|
||||
.can_disable = 0,
|
||||
}
|
||||
};
|
||||
static struct gpio_keys_platform_data geos_buttons_data = {
|
||||
.buttons = geos_gpio_buttons,
|
||||
.nbuttons = ARRAY_SIZE(geos_gpio_buttons),
|
||||
.poll_interval = 20,
|
||||
};
|
||||
|
||||
static struct platform_device geos_buttons_dev = {
|
||||
.name = "gpio-keys-polled",
|
||||
.id = 1,
|
||||
.dev = {
|
||||
.platform_data = &geos_buttons_data,
|
||||
}
|
||||
};
|
||||
|
||||
static struct gpio_led geos_leds[] = {
|
||||
{
|
||||
.name = "geos:1",
|
||||
.gpio = 6,
|
||||
.default_trigger = "default-on",
|
||||
.active_low = 1,
|
||||
},
|
||||
{
|
||||
.name = "geos:2",
|
||||
.gpio = 25,
|
||||
.default_trigger = "default-off",
|
||||
.active_low = 1,
|
||||
},
|
||||
{
|
||||
.name = "geos:3",
|
||||
.gpio = 27,
|
||||
.default_trigger = "default-off",
|
||||
.active_low = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpio_led_platform_data geos_leds_data = {
|
||||
.num_leds = ARRAY_SIZE(geos_leds),
|
||||
.leds = geos_leds,
|
||||
};
|
||||
|
||||
static struct platform_device geos_leds_dev = {
|
||||
.name = "leds-gpio",
|
||||
.id = -1,
|
||||
.dev.platform_data = &geos_leds_data,
|
||||
};
|
||||
|
||||
static struct __initdata platform_device *geos_devs[] = {
|
||||
&geos_buttons_dev,
|
||||
&geos_leds_dev,
|
||||
};
|
||||
|
||||
static void __init register_geos(void)
|
||||
{
|
||||
/* Setup LED control through leds-gpio driver */
|
||||
platform_add_devices(geos_devs, ARRAY_SIZE(geos_devs));
|
||||
}
|
||||
|
||||
static int __init geos_init(void)
|
||||
{
|
||||
const char *vendor, *product;
|
||||
|
||||
if (!is_geode())
|
||||
return 0;
|
||||
|
||||
vendor = dmi_get_system_info(DMI_SYS_VENDOR);
|
||||
if (!vendor || strcmp(vendor, "Traverse Technologies"))
|
||||
return 0;
|
||||
|
||||
product = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||
if (!product || strcmp(product, "Geos"))
|
||||
return 0;
|
||||
|
||||
printk(KERN_INFO "%s: system is recognized as \"%s %s\"\n",
|
||||
KBUILD_MODNAME, vendor, product);
|
||||
|
||||
register_geos();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(geos_init);
|
||||
|
||||
MODULE_AUTHOR("Philip Prindeville <philipp@redfish-solutions.com>");
|
||||
MODULE_DESCRIPTION("Traverse Technologies Geos System Setup");
|
||||
MODULE_LICENSE("GPL");
|
@ -445,6 +445,16 @@ int ec_transaction(u8 command,
|
||||
|
||||
EXPORT_SYMBOL(ec_transaction);
|
||||
|
||||
/* Get the handle to the EC device */
|
||||
acpi_handle ec_get_handle(void)
|
||||
{
|
||||
if (!first_ec)
|
||||
return NULL;
|
||||
return first_ec->handle;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ec_get_handle);
|
||||
|
||||
void acpi_ec_block_transactions(void)
|
||||
{
|
||||
struct acpi_ec *ec = first_ec;
|
||||
|
@ -23,7 +23,7 @@
|
||||
* Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
|
||||
* are available, video.ko should be used to handle the device.
|
||||
*
|
||||
* Otherwise vendor specific drivers like thinkpad_acpi, asus_acpi,
|
||||
* Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
|
||||
* sony_acpi,... can take care about backlight brightness.
|
||||
*
|
||||
* If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
|
||||
|
@ -26,6 +26,10 @@ config ACER_WMI
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on ACPI_WMI
|
||||
select INPUT_SPARSEKMAP
|
||||
# Acer WMI depends on ACPI_VIDEO when ACPI is enabled
|
||||
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
|
||||
select VIDEO_OUTPUT_CONTROL if ACPI
|
||||
select ACPI_VIDEO if ACPI
|
||||
---help---
|
||||
This is a driver for newer Acer (and Wistron) laptops. It adds
|
||||
wireless radio and bluetooth control, and on some laptops,
|
||||
@ -54,7 +58,6 @@ config ACERHDF
|
||||
config ASUS_LAPTOP
|
||||
tristate "Asus Laptop Extras"
|
||||
depends on ACPI
|
||||
depends on !ACPI_ASUS
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
@ -460,10 +463,9 @@ config INTEL_MENLOW
|
||||
If unsure, say N.
|
||||
|
||||
config EEEPC_LAPTOP
|
||||
tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
|
||||
tristate "Eee PC Hotkey Driver"
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
depends on EXPERIMENTAL
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on HOTPLUG_PCI
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
@ -482,11 +484,10 @@ config EEEPC_LAPTOP
|
||||
doesn't work on your Eee PC, try eeepc-wmi instead.
|
||||
|
||||
config ASUS_WMI
|
||||
tristate "ASUS WMI Driver (EXPERIMENTAL)"
|
||||
tristate "ASUS WMI Driver"
|
||||
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
|
||||
@ -501,7 +502,7 @@ config ASUS_WMI
|
||||
be called asus-wmi.
|
||||
|
||||
config ASUS_NB_WMI
|
||||
tristate "Asus Notebook WMI Driver (EXPERIMENTAL)"
|
||||
tristate "Asus Notebook WMI Driver"
|
||||
depends on ASUS_WMI
|
||||
---help---
|
||||
This is a driver for newer Asus notebooks. It adds extra features
|
||||
@ -514,7 +515,7 @@ config ASUS_NB_WMI
|
||||
here.
|
||||
|
||||
config EEEPC_WMI
|
||||
tristate "Eee PC WMI Driver (EXPERIMENTAL)"
|
||||
tristate "Eee PC WMI Driver"
|
||||
depends on ASUS_WMI
|
||||
---help---
|
||||
This is a driver for newer Eee PC laptops. It adds extra features
|
||||
@ -559,38 +560,6 @@ config MSI_WMI
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called msi-wmi.
|
||||
|
||||
config ACPI_ASUS
|
||||
tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
|
||||
depends on ACPI
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver provides support for extra features of ACPI-compatible
|
||||
ASUS laptops. As some of Medion laptops are made by ASUS, it may also
|
||||
support some Medion laptops (such as 9675 for example). It makes all
|
||||
the extra buttons generate standard ACPI events that go through
|
||||
/proc/acpi/events, and (on some models) adds support for changing the
|
||||
display brightness and output, switching the LCD backlight on and off,
|
||||
and most importantly, allows you to blink those fancy LEDs intended
|
||||
for reporting mail and wireless status.
|
||||
|
||||
Note: display switching code is currently considered EXPERIMENTAL,
|
||||
toying with these values may even lock your machine.
|
||||
|
||||
All settings are changed via /proc/acpi/asus directory entries. Owner
|
||||
and group for these entries can be set with asus_uid and asus_gid
|
||||
parameters.
|
||||
|
||||
More information and a userspace daemon for handling the extra buttons
|
||||
at <http://acpi4asus.sf.net>.
|
||||
|
||||
If you have an ACPI-compatible ASUS laptop, say Y or M here. This
|
||||
driver is still under development, so if your laptop is unsupported or
|
||||
something works not quite as expected, please use the mailing list
|
||||
available on the above page (acpi4asus-user@lists.sourceforge.net).
|
||||
|
||||
NOTE: This driver is deprecated and will probably be removed soon,
|
||||
use asus-laptop instead.
|
||||
|
||||
config TOPSTAR_LAPTOP
|
||||
tristate "Topstar Laptop Extras"
|
||||
depends on ACPI
|
||||
@ -604,6 +573,7 @@ config TOPSTAR_LAPTOP
|
||||
config ACPI_TOSHIBA
|
||||
tristate "Toshiba Laptop Extras"
|
||||
depends on ACPI
|
||||
depends on ACPI_WMI
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
@ -746,13 +716,18 @@ config XO15_EBOOK
|
||||
|
||||
config SAMSUNG_LAPTOP
|
||||
tristate "Samsung Laptop driver"
|
||||
depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86
|
||||
depends on X86
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---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.
|
||||
function keys, wireless LED, LCD backlight level.
|
||||
|
||||
It may also provide some sysfs files described in
|
||||
<file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called samsung-laptop.
|
||||
@ -781,4 +756,14 @@ config SAMSUNG_Q10
|
||||
This driver provides support for backlight control on Samsung Q10
|
||||
and related laptops, including Dell Latitude X200.
|
||||
|
||||
config APPLE_GMUX
|
||||
tristate "Apple Gmux Driver"
|
||||
depends on PNP
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
---help---
|
||||
This driver provides support for the gmux device found on many
|
||||
Apple laptops, which controls the display mux for the hybrid
|
||||
graphics as well as the backlight. Currently only backlight
|
||||
control is supported by the driver.
|
||||
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
@ -29,9 +29,12 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
|
||||
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
|
||||
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
|
||||
# toshiba_acpi must link after wmi to ensure that wmi devices are found
|
||||
# before toshiba_acpi initializes
|
||||
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
|
||||
@ -46,3 +49,4 @@ obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
|
||||
obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
|
||||
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
|
||||
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
|
||||
obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/video.h>
|
||||
|
||||
MODULE_AUTHOR("Carlos Corbacho");
|
||||
MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
|
||||
@ -105,13 +106,19 @@ static const struct key_entry acer_wmi_keymap[] = {
|
||||
{KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
|
||||
{KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
|
||||
{KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
|
||||
{KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */
|
||||
{KE_IGNORE, 0x41, {KEY_MUTE} },
|
||||
{KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
|
||||
{KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
|
||||
{KE_IGNORE, 0x43, {KEY_NEXTSONG} },
|
||||
{KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
|
||||
{KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
|
||||
{KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
|
||||
{KE_IGNORE, 0x45, {KEY_STOP} },
|
||||
{KE_IGNORE, 0x50, {KEY_STOP} },
|
||||
{KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
|
||||
{KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
|
||||
{KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
|
||||
{KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
|
||||
{KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
|
||||
{KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
|
||||
@ -153,7 +160,14 @@ struct lm_return_value {
|
||||
u16 reserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wmid3_gds_input_param { /* Get Device Status input parameter */
|
||||
struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
|
||||
u8 function_num; /* Function Number */
|
||||
u8 hotkey_number; /* Hotkey Number */
|
||||
u16 devices; /* Set Device */
|
||||
u8 volume_value; /* Volume Value */
|
||||
} __attribute__((packed));
|
||||
|
||||
struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
|
||||
u8 function_num; /* Function Number */
|
||||
u8 hotkey_number; /* Hotkey Number */
|
||||
u16 devices; /* Get Device */
|
||||
@ -171,6 +185,11 @@ struct hotkey_function_type_aa {
|
||||
u8 length;
|
||||
u16 handle;
|
||||
u16 commun_func_bitmap;
|
||||
u16 application_func_bitmap;
|
||||
u16 media_func_bitmap;
|
||||
u16 display_func_bitmap;
|
||||
u16 others_func_bitmap;
|
||||
u8 commun_fn_key_number;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
@ -207,6 +226,7 @@ static int force_series;
|
||||
static bool ec_raw_mode;
|
||||
static bool has_type_aa;
|
||||
static u16 commun_func_bitmap;
|
||||
static u8 commun_fn_key_number;
|
||||
|
||||
module_param(mailled, int, 0444);
|
||||
module_param(brightness, int, 0444);
|
||||
@ -466,6 +486,15 @@ static struct dmi_system_id acer_quirks[] = {
|
||||
},
|
||||
.driver_data = &quirk_lenovo_ideapad_s205,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Lenovo Ideapad S205 (Brazos)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
|
||||
},
|
||||
.driver_data = &quirk_lenovo_ideapad_s205,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Lenovo 3000 N200",
|
||||
@ -478,6 +507,25 @@ static struct dmi_system_id acer_quirks[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
|
||||
{
|
||||
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
pr_info("Brightness must be controlled by generic video driver\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dmi_system_id video_vendor_dmi_table[] = {
|
||||
{
|
||||
.callback = video_set_backlight_video_vendor,
|
||||
.ident = "Acer TravelMate 4750",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
/* Find which quirks are needed for a particular vendor/ model pair */
|
||||
static void find_quirks(void)
|
||||
{
|
||||
@ -536,8 +584,7 @@ struct acpi_buffer *result)
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status AMW0_get_u32(u32 *value, u32 cap,
|
||||
struct wmi_interface *iface)
|
||||
static acpi_status AMW0_get_u32(u32 *value, u32 cap)
|
||||
{
|
||||
int err;
|
||||
u8 result;
|
||||
@ -607,7 +654,7 @@ struct wmi_interface *iface)
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
||||
static acpi_status AMW0_set_u32(u32 value, u32 cap)
|
||||
{
|
||||
struct wmab_args args;
|
||||
|
||||
@ -692,6 +739,7 @@ static const struct acpi_device_id norfkill_ids[] = {
|
||||
{ "VPC2004", 0},
|
||||
{ "IBM0068", 0},
|
||||
{ "LEN0068", 0},
|
||||
{ "SNY5001", 0}, /* sony-laptop in charge */
|
||||
{ "", 0},
|
||||
};
|
||||
|
||||
@ -827,8 +875,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status WMID_get_u32(u32 *value, u32 cap,
|
||||
struct wmi_interface *iface)
|
||||
static acpi_status WMID_get_u32(u32 *value, u32 cap)
|
||||
{
|
||||
acpi_status status;
|
||||
u8 tmp;
|
||||
@ -864,7 +911,7 @@ struct wmi_interface *iface)
|
||||
return status;
|
||||
}
|
||||
|
||||
static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
||||
static acpi_status WMID_set_u32(u32 value, u32 cap)
|
||||
{
|
||||
u32 method_id = 0;
|
||||
char param;
|
||||
@ -912,13 +959,13 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
|
||||
struct wmid3_gds_return_value return_value;
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
struct wmid3_gds_input_param params = {
|
||||
struct wmid3_gds_get_input_param params = {
|
||||
.function_num = 0x1,
|
||||
.hotkey_number = 0x01,
|
||||
.hotkey_number = commun_fn_key_number,
|
||||
.devices = device,
|
||||
};
|
||||
struct acpi_buffer input = {
|
||||
sizeof(struct wmid3_gds_input_param),
|
||||
sizeof(struct wmid3_gds_get_input_param),
|
||||
¶ms
|
||||
};
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
@ -981,19 +1028,28 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
u16 devices;
|
||||
struct wmid3_gds_input_param params = {
|
||||
struct wmid3_gds_get_input_param get_params = {
|
||||
.function_num = 0x1,
|
||||
.hotkey_number = 0x01,
|
||||
.hotkey_number = commun_fn_key_number,
|
||||
.devices = commun_func_bitmap,
|
||||
};
|
||||
struct acpi_buffer input = {
|
||||
sizeof(struct wmid3_gds_input_param),
|
||||
¶ms
|
||||
struct acpi_buffer get_input = {
|
||||
sizeof(struct wmid3_gds_get_input_param),
|
||||
&get_params
|
||||
};
|
||||
struct wmid3_gds_set_input_param set_params = {
|
||||
.function_num = 0x2,
|
||||
.hotkey_number = commun_fn_key_number,
|
||||
.devices = commun_func_bitmap,
|
||||
};
|
||||
struct acpi_buffer set_input = {
|
||||
sizeof(struct wmid3_gds_set_input_param),
|
||||
&set_params
|
||||
};
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
|
||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
@ -1006,7 +1062,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||
return AE_ERROR;
|
||||
}
|
||||
if (obj->buffer.length != 8) {
|
||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||
pr_warn("Unknown buffer length %d\n", obj->buffer.length);
|
||||
kfree(obj);
|
||||
return AE_ERROR;
|
||||
}
|
||||
@ -1015,18 +1071,16 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||
kfree(obj);
|
||||
|
||||
if (return_value.error_code || return_value.ec_return_value) {
|
||||
pr_warning("Get Current Device Status failed: "
|
||||
"0x%x - 0x%x\n", return_value.error_code,
|
||||
pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
|
||||
return_value.error_code,
|
||||
return_value.ec_return_value);
|
||||
return status;
|
||||
}
|
||||
|
||||
devices = return_value.devices;
|
||||
params.function_num = 0x2;
|
||||
params.hotkey_number = 0x01;
|
||||
params.devices = (value) ? (devices | device) : (devices & ~device);
|
||||
set_params.devices = (value) ? (devices | device) : (devices & ~device);
|
||||
|
||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
|
||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
@ -1039,7 +1093,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||
return AE_ERROR;
|
||||
}
|
||||
if (obj->buffer.length != 4) {
|
||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||
pr_warn("Unknown buffer length %d\n", obj->buffer.length);
|
||||
kfree(obj);
|
||||
return AE_ERROR;
|
||||
}
|
||||
@ -1048,8 +1102,8 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||
kfree(obj);
|
||||
|
||||
if (return_value.error_code || return_value.ec_return_value)
|
||||
pr_warning("Set Device Status failed: "
|
||||
"0x%x - 0x%x\n", return_value.error_code,
|
||||
pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
|
||||
return_value.error_code,
|
||||
return_value.ec_return_value);
|
||||
|
||||
return status;
|
||||
@ -1096,6 +1150,8 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||
interface->capability |= ACER_CAP_THREEG;
|
||||
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
|
||||
interface->capability |= ACER_CAP_BLUETOOTH;
|
||||
|
||||
commun_fn_key_number = type_aa->commun_fn_key_number;
|
||||
}
|
||||
|
||||
static acpi_status WMID_set_capabilities(void)
|
||||
@ -1154,15 +1210,15 @@ static acpi_status get_u32(u32 *value, u32 cap)
|
||||
|
||||
switch (interface->type) {
|
||||
case ACER_AMW0:
|
||||
status = AMW0_get_u32(value, cap, interface);
|
||||
status = AMW0_get_u32(value, cap);
|
||||
break;
|
||||
case ACER_AMW0_V2:
|
||||
if (cap == ACER_CAP_MAILLED) {
|
||||
status = AMW0_get_u32(value, cap, interface);
|
||||
status = AMW0_get_u32(value, cap);
|
||||
break;
|
||||
}
|
||||
case ACER_WMID:
|
||||
status = WMID_get_u32(value, cap, interface);
|
||||
status = WMID_get_u32(value, cap);
|
||||
break;
|
||||
case ACER_WMID_v2:
|
||||
if (cap & (ACER_CAP_WIRELESS |
|
||||
@ -1170,7 +1226,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
|
||||
ACER_CAP_THREEG))
|
||||
status = wmid_v2_get_u32(value, cap);
|
||||
else if (wmi_has_guid(WMID_GUID2))
|
||||
status = WMID_get_u32(value, cap, interface);
|
||||
status = WMID_get_u32(value, cap);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1184,10 +1240,10 @@ static acpi_status set_u32(u32 value, u32 cap)
|
||||
if (interface->capability & cap) {
|
||||
switch (interface->type) {
|
||||
case ACER_AMW0:
|
||||
return AMW0_set_u32(value, cap, interface);
|
||||
return AMW0_set_u32(value, cap);
|
||||
case ACER_AMW0_V2:
|
||||
if (cap == ACER_CAP_MAILLED)
|
||||
return AMW0_set_u32(value, cap, interface);
|
||||
return AMW0_set_u32(value, cap);
|
||||
|
||||
/*
|
||||
* On some models, some WMID methods don't toggle
|
||||
@ -1197,21 +1253,21 @@ static acpi_status set_u32(u32 value, u32 cap)
|
||||
*/
|
||||
if (cap == ACER_CAP_WIRELESS ||
|
||||
cap == ACER_CAP_BLUETOOTH) {
|
||||
status = WMID_set_u32(value, cap, interface);
|
||||
status = WMID_set_u32(value, cap);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
return AMW0_set_u32(value, cap, interface);
|
||||
return AMW0_set_u32(value, cap);
|
||||
}
|
||||
case ACER_WMID:
|
||||
return WMID_set_u32(value, cap, interface);
|
||||
return WMID_set_u32(value, cap);
|
||||
case ACER_WMID_v2:
|
||||
if (cap & (ACER_CAP_WIRELESS |
|
||||
ACER_CAP_BLUETOOTH |
|
||||
ACER_CAP_THREEG))
|
||||
return wmid_v2_set_u32(value, cap);
|
||||
else if (wmi_has_guid(WMID_GUID2))
|
||||
return WMID_set_u32(value, cap, interface);
|
||||
return WMID_set_u32(value, cap);
|
||||
default:
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
@ -1488,8 +1544,8 @@ static ssize_t show_bool_threeg(struct device *dev,
|
||||
u32 result; \
|
||||
acpi_status status;
|
||||
|
||||
pr_info("This threeg sysfs will be removed in 2012"
|
||||
" - used by: %s\n", current->comm);
|
||||
pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
|
||||
current->comm);
|
||||
status = get_u32(&result, ACER_CAP_THREEG);
|
||||
if (ACPI_SUCCESS(status))
|
||||
return sprintf(buf, "%u\n", result);
|
||||
@ -1501,8 +1557,8 @@ static ssize_t set_bool_threeg(struct device *dev,
|
||||
{
|
||||
u32 tmp = simple_strtoul(buf, NULL, 10);
|
||||
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
|
||||
pr_info("This threeg sysfs will be removed in 2012"
|
||||
" - used by: %s\n", current->comm);
|
||||
pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
|
||||
current->comm);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EINVAL;
|
||||
return count;
|
||||
@ -1513,8 +1569,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
|
||||
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
pr_info("This interface sysfs will be removed in 2012"
|
||||
" - used by: %s\n", current->comm);
|
||||
pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
|
||||
current->comm);
|
||||
switch (interface->type) {
|
||||
case ACER_AMW0:
|
||||
return sprintf(buf, "AMW0\n");
|
||||
@ -1981,9 +2037,13 @@ static int __init acer_wmi_init(void)
|
||||
set_quirks();
|
||||
|
||||
if (acpi_video_backlight_support()) {
|
||||
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
pr_info("Brightness must be controlled by "
|
||||
"generic video driver\n");
|
||||
if (dmi_check_system(video_vendor_dmi_table)) {
|
||||
acpi_video_unregister();
|
||||
} else {
|
||||
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||
pr_info("Brightness must be controlled by "
|
||||
"acpi video driver\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (wmi_has_guid(WMID_GUID3)) {
|
||||
@ -2008,7 +2068,7 @@ static int __init acer_wmi_init(void)
|
||||
|
||||
err = platform_driver_register(&acer_platform_driver);
|
||||
if (err) {
|
||||
pr_err("Unable to register platform driver.\n");
|
||||
pr_err("Unable to register platform driver\n");
|
||||
goto error_platform_register;
|
||||
}
|
||||
|
||||
|
@ -244,12 +244,11 @@ static void acerhdf_change_fanstate(int state)
|
||||
unsigned char cmd;
|
||||
|
||||
if (verbose)
|
||||
pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ?
|
||||
"OFF" : "ON");
|
||||
pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
|
||||
|
||||
if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
|
||||
pr_err("invalid fan state %d requested, setting to auto!\n",
|
||||
state);
|
||||
state);
|
||||
state = ACERHDF_FAN_AUTO;
|
||||
}
|
||||
|
||||
@ -264,19 +263,18 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
|
||||
{
|
||||
if (fanon > ACERHDF_MAX_FANON) {
|
||||
pr_err("fanon temperature too high, set to %d\n",
|
||||
ACERHDF_MAX_FANON);
|
||||
ACERHDF_MAX_FANON);
|
||||
fanon = ACERHDF_MAX_FANON;
|
||||
}
|
||||
|
||||
if (kernelmode && prev_interval != interval) {
|
||||
if (interval > ACERHDF_MAX_INTERVAL) {
|
||||
pr_err("interval too high, set to %d\n",
|
||||
ACERHDF_MAX_INTERVAL);
|
||||
ACERHDF_MAX_INTERVAL);
|
||||
interval = ACERHDF_MAX_INTERVAL;
|
||||
}
|
||||
if (verbose)
|
||||
pr_notice("interval changed to: %d\n",
|
||||
interval);
|
||||
pr_notice("interval changed to: %d\n", interval);
|
||||
thermal->polling_delay = interval*1000;
|
||||
prev_interval = interval;
|
||||
}
|
||||
@ -587,8 +585,8 @@ static int acerhdf_check_hardware(void)
|
||||
}
|
||||
|
||||
if (!bios_cfg) {
|
||||
pr_err("unknown (unsupported) BIOS version %s/%s/%s, "
|
||||
"please report, aborting!\n", vendor, product, version);
|
||||
pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
|
||||
vendor, product, version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -598,8 +596,7 @@ static int acerhdf_check_hardware(void)
|
||||
*/
|
||||
if (!kernelmode) {
|
||||
pr_notice("Fan control off, to enable do:\n");
|
||||
pr_notice("echo -n \"enabled\" > "
|
||||
"/sys/class/thermal/thermal_zone0/mode\n");
|
||||
pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -97,9 +97,12 @@ static struct rfkill *amilo_rfkill_dev;
|
||||
|
||||
static int __devinit amilo_rfkill_probe(struct platform_device *device)
|
||||
{
|
||||
int rc;
|
||||
const struct dmi_system_id *system_id =
|
||||
dmi_first_match(amilo_rfkill_id_table);
|
||||
int rc;
|
||||
|
||||
if (!system_id)
|
||||
return -ENXIO;
|
||||
|
||||
amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
|
244
drivers/platform/x86/apple-gmux.c
Normal file
244
drivers/platform/x86/apple-gmux.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Gmux driver for Apple laptops
|
||||
*
|
||||
* Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/pnp.h>
|
||||
#include <linux/apple_bl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <acpi/video.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
struct apple_gmux_data {
|
||||
unsigned long iostart;
|
||||
unsigned long iolen;
|
||||
|
||||
struct backlight_device *bdev;
|
||||
};
|
||||
|
||||
/*
|
||||
* gmux port offsets. Many of these are not yet used, but may be in the
|
||||
* future, and it's useful to have them documented here anyhow.
|
||||
*/
|
||||
#define GMUX_PORT_VERSION_MAJOR 0x04
|
||||
#define GMUX_PORT_VERSION_MINOR 0x05
|
||||
#define GMUX_PORT_VERSION_RELEASE 0x06
|
||||
#define GMUX_PORT_SWITCH_DISPLAY 0x10
|
||||
#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11
|
||||
#define GMUX_PORT_INTERRUPT_ENABLE 0x14
|
||||
#define GMUX_PORT_INTERRUPT_STATUS 0x16
|
||||
#define GMUX_PORT_SWITCH_DDC 0x28
|
||||
#define GMUX_PORT_SWITCH_EXTERNAL 0x40
|
||||
#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41
|
||||
#define GMUX_PORT_DISCRETE_POWER 0x50
|
||||
#define GMUX_PORT_MAX_BRIGHTNESS 0x70
|
||||
#define GMUX_PORT_BRIGHTNESS 0x74
|
||||
|
||||
#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
|
||||
|
||||
#define GMUX_INTERRUPT_ENABLE 0xff
|
||||
#define GMUX_INTERRUPT_DISABLE 0x00
|
||||
|
||||
#define GMUX_INTERRUPT_STATUS_ACTIVE 0
|
||||
#define GMUX_INTERRUPT_STATUS_DISPLAY (1 << 0)
|
||||
#define GMUX_INTERRUPT_STATUS_POWER (1 << 2)
|
||||
#define GMUX_INTERRUPT_STATUS_HOTPLUG (1 << 3)
|
||||
|
||||
#define GMUX_BRIGHTNESS_MASK 0x00ffffff
|
||||
#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
|
||||
|
||||
static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
|
||||
{
|
||||
return inb(gmux_data->iostart + port);
|
||||
}
|
||||
|
||||
static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
|
||||
u8 val)
|
||||
{
|
||||
outb(val, gmux_data->iostart + port);
|
||||
}
|
||||
|
||||
static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
|
||||
{
|
||||
return inl(gmux_data->iostart + port);
|
||||
}
|
||||
|
||||
static int gmux_get_brightness(struct backlight_device *bd)
|
||||
{
|
||||
struct apple_gmux_data *gmux_data = bl_get_data(bd);
|
||||
return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
|
||||
GMUX_BRIGHTNESS_MASK;
|
||||
}
|
||||
|
||||
static int gmux_update_status(struct backlight_device *bd)
|
||||
{
|
||||
struct apple_gmux_data *gmux_data = bl_get_data(bd);
|
||||
u32 brightness = bd->props.brightness;
|
||||
|
||||
/*
|
||||
* Older gmux versions require writing out lower bytes first then
|
||||
* setting the upper byte to 0 to flush the values. Newer versions
|
||||
* accept a single u32 write, but the old method also works, so we
|
||||
* just use the old method for all gmux versions.
|
||||
*/
|
||||
gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
|
||||
gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
|
||||
gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
|
||||
gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct backlight_ops gmux_bl_ops = {
|
||||
.get_brightness = gmux_get_brightness,
|
||||
.update_status = gmux_update_status,
|
||||
};
|
||||
|
||||
static int __devinit gmux_probe(struct pnp_dev *pnp,
|
||||
const struct pnp_device_id *id)
|
||||
{
|
||||
struct apple_gmux_data *gmux_data;
|
||||
struct resource *res;
|
||||
struct backlight_properties props;
|
||||
struct backlight_device *bdev;
|
||||
u8 ver_major, ver_minor, ver_release;
|
||||
int ret = -ENXIO;
|
||||
|
||||
gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
|
||||
if (!gmux_data)
|
||||
return -ENOMEM;
|
||||
pnp_set_drvdata(pnp, gmux_data);
|
||||
|
||||
res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
|
||||
if (!res) {
|
||||
pr_err("Failed to find gmux I/O resource\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
gmux_data->iostart = res->start;
|
||||
gmux_data->iolen = res->end - res->start;
|
||||
|
||||
if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
|
||||
pr_err("gmux I/O region too small (%lu < %u)\n",
|
||||
gmux_data->iolen, GMUX_MIN_IO_LEN);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (!request_region(gmux_data->iostart, gmux_data->iolen,
|
||||
"Apple gmux")) {
|
||||
pr_err("gmux I/O already in use\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
/*
|
||||
* On some machines the gmux is in ACPI even thought the machine
|
||||
* doesn't really have a gmux. Check for invalid version information
|
||||
* to detect this.
|
||||
*/
|
||||
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
|
||||
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
|
||||
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
|
||||
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
|
||||
pr_info("gmux device not present\n");
|
||||
ret = -ENODEV;
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
|
||||
ver_release);
|
||||
|
||||
memset(&props, 0, sizeof(props));
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
|
||||
|
||||
/*
|
||||
* Currently it's assumed that the maximum brightness is less than
|
||||
* 2^24 for compatibility with old gmux versions. Cap the max
|
||||
* brightness at this value, but print a warning if the hardware
|
||||
* reports something higher so that it can be fixed.
|
||||
*/
|
||||
if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
|
||||
props.max_brightness = GMUX_MAX_BRIGHTNESS;
|
||||
|
||||
bdev = backlight_device_register("gmux_backlight", &pnp->dev,
|
||||
gmux_data, &gmux_bl_ops, &props);
|
||||
if (IS_ERR(bdev)) {
|
||||
ret = PTR_ERR(bdev);
|
||||
goto err_release;
|
||||
}
|
||||
|
||||
gmux_data->bdev = bdev;
|
||||
bdev->props.brightness = gmux_get_brightness(bdev);
|
||||
backlight_update_status(bdev);
|
||||
|
||||
/*
|
||||
* The backlight situation on Macs is complicated. If the gmux is
|
||||
* present it's the best choice, because it always works for
|
||||
* backlight control and supports more levels than other options.
|
||||
* Disable the other backlight choices.
|
||||
*/
|
||||
acpi_video_unregister();
|
||||
apple_bl_unregister();
|
||||
|
||||
return 0;
|
||||
|
||||
err_release:
|
||||
release_region(gmux_data->iostart, gmux_data->iolen);
|
||||
err_free:
|
||||
kfree(gmux_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __devexit gmux_remove(struct pnp_dev *pnp)
|
||||
{
|
||||
struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
|
||||
|
||||
backlight_device_unregister(gmux_data->bdev);
|
||||
release_region(gmux_data->iostart, gmux_data->iolen);
|
||||
kfree(gmux_data);
|
||||
|
||||
acpi_video_register();
|
||||
apple_bl_register();
|
||||
}
|
||||
|
||||
static const struct pnp_device_id gmux_device_ids[] = {
|
||||
{"APP000B", 0},
|
||||
{"", 0}
|
||||
};
|
||||
|
||||
static struct pnp_driver gmux_pnp_driver = {
|
||||
.name = "apple-gmux",
|
||||
.probe = gmux_probe,
|
||||
.remove = __devexit_p(gmux_remove),
|
||||
.id_table = gmux_device_ids,
|
||||
};
|
||||
|
||||
static int __init apple_gmux_init(void)
|
||||
{
|
||||
return pnp_register_driver(&gmux_pnp_driver);
|
||||
}
|
||||
|
||||
static void __exit apple_gmux_exit(void)
|
||||
{
|
||||
pnp_unregister_driver(&gmux_pnp_driver);
|
||||
}
|
||||
|
||||
module_init(apple_gmux_init);
|
||||
module_exit(apple_gmux_exit);
|
||||
|
||||
MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
|
||||
MODULE_DESCRIPTION("Apple Gmux Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(pnp, gmux_device_ids);
|
@ -81,6 +81,19 @@ static uint wapf = 1;
|
||||
module_param(wapf, uint, 0444);
|
||||
MODULE_PARM_DESC(wapf, "WAPF value");
|
||||
|
||||
static char *wled_type = "unknown";
|
||||
static char *bled_type = "unknown";
|
||||
|
||||
module_param(wled_type, charp, 0444);
|
||||
MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
|
||||
"(unknown, led or rfkill). "
|
||||
"default is unknown");
|
||||
|
||||
module_param(bled_type, charp, 0444);
|
||||
MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
|
||||
"(unknown, led or rfkill). "
|
||||
"default is unknown");
|
||||
|
||||
static int wlan_status = 1;
|
||||
static int bluetooth_status = 1;
|
||||
static int wimax_status = -1;
|
||||
@ -137,6 +150,11 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
|
||||
#define WM_RSTS 0x08 /* internal wimax */
|
||||
#define WW_RSTS 0x20 /* internal wwan */
|
||||
|
||||
/* WLED and BLED type */
|
||||
#define TYPE_UNKNOWN 0
|
||||
#define TYPE_LED 1
|
||||
#define TYPE_RFKILL 2
|
||||
|
||||
/* LED */
|
||||
#define METHOD_MLED "MLED"
|
||||
#define METHOD_TLED "TLED"
|
||||
@ -218,8 +236,9 @@ struct asus_led {
|
||||
/*
|
||||
* Same thing for rfkill
|
||||
*/
|
||||
struct asus_pega_rfkill {
|
||||
int control_id; /* type of control. Maps to PEGA_* values */
|
||||
struct asus_rfkill {
|
||||
/* type of control. Maps to PEGA_* values or *_RSTS */
|
||||
int control_id;
|
||||
struct rfkill *rfkill;
|
||||
struct asus_laptop *asus;
|
||||
};
|
||||
@ -240,6 +259,8 @@ struct asus_laptop {
|
||||
struct key_entry *keymap;
|
||||
struct input_polled_dev *pega_accel_poll;
|
||||
|
||||
struct asus_led wled;
|
||||
struct asus_led bled;
|
||||
struct asus_led mled;
|
||||
struct asus_led tled;
|
||||
struct asus_led rled;
|
||||
@ -248,6 +269,8 @@ struct asus_laptop {
|
||||
struct asus_led kled;
|
||||
struct workqueue_struct *led_workqueue;
|
||||
|
||||
int wled_type;
|
||||
int bled_type;
|
||||
int wireless_status;
|
||||
bool have_rsts;
|
||||
bool is_pega_lucid;
|
||||
@ -256,11 +279,11 @@ struct asus_laptop {
|
||||
int pega_acc_y;
|
||||
int pega_acc_z;
|
||||
|
||||
struct rfkill *gps_rfkill;
|
||||
|
||||
struct asus_pega_rfkill wlanrfk;
|
||||
struct asus_pega_rfkill btrfk;
|
||||
struct asus_pega_rfkill wwanrfk;
|
||||
struct asus_rfkill wlan;
|
||||
struct asus_rfkill bluetooth;
|
||||
struct asus_rfkill wwan;
|
||||
struct asus_rfkill wimax;
|
||||
struct asus_rfkill gps;
|
||||
|
||||
acpi_handle handle; /* the handle of the hotk device */
|
||||
u32 ledd_status; /* status of the LED display */
|
||||
@ -274,6 +297,7 @@ static const struct key_entry asus_keymap[] = {
|
||||
{KE_KEY, 0x02, { KEY_SCREENLOCK } },
|
||||
{KE_KEY, 0x05, { KEY_WLAN } },
|
||||
{KE_KEY, 0x08, { KEY_F13 } },
|
||||
{KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
|
||||
{KE_KEY, 0x17, { KEY_ZOOM } },
|
||||
{KE_KEY, 0x1f, { KEY_BATTERY } },
|
||||
/* End of Lenovo SL Specific keycodes */
|
||||
@ -299,6 +323,8 @@ static const struct key_entry asus_keymap[] = {
|
||||
{KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
|
||||
{KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
|
||||
{KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
|
||||
{KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
|
||||
{KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
|
||||
{KE_KEY, 0x7E, { KEY_BLUETOOTH } },
|
||||
{KE_KEY, 0x7D, { KEY_BLUETOOTH } },
|
||||
{KE_KEY, 0x82, { KEY_CAMERA } },
|
||||
@ -601,6 +627,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
|
||||
|
||||
static void asus_led_exit(struct asus_laptop *asus)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(asus->wled.led.dev))
|
||||
led_classdev_unregister(&asus->wled.led);
|
||||
if (!IS_ERR_OR_NULL(asus->bled.led.dev))
|
||||
led_classdev_unregister(&asus->bled.led);
|
||||
if (!IS_ERR_OR_NULL(asus->mled.led.dev))
|
||||
led_classdev_unregister(&asus->mled.led);
|
||||
if (!IS_ERR_OR_NULL(asus->tled.led.dev))
|
||||
@ -642,7 +672,7 @@ static int asus_led_register(struct asus_laptop *asus,
|
||||
|
||||
static int asus_led_init(struct asus_laptop *asus)
|
||||
{
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
/*
|
||||
* The Pegatron Lucid has no physical leds, but all methods are
|
||||
@ -661,6 +691,16 @@ static int asus_led_init(struct asus_laptop *asus)
|
||||
if (!asus->led_workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
if (asus->wled_type == TYPE_LED)
|
||||
r = asus_led_register(asus, &asus->wled, "asus::wlan",
|
||||
METHOD_WLAN);
|
||||
if (r)
|
||||
goto error;
|
||||
if (asus->bled_type == TYPE_LED)
|
||||
r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
|
||||
METHOD_BLUETOOTH);
|
||||
if (r)
|
||||
goto error;
|
||||
r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
|
||||
if (r)
|
||||
goto error;
|
||||
@ -963,7 +1003,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
|
||||
return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
|
||||
}
|
||||
|
||||
/*
|
||||
/*e
|
||||
* Bluetooth
|
||||
*/
|
||||
static int asus_bluetooth_set(struct asus_laptop *asus, int status)
|
||||
@ -1228,7 +1268,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
|
||||
ret = asus_gps_switch(asus, !!value);
|
||||
if (ret)
|
||||
return ret;
|
||||
rfkill_set_sw_state(asus->gps_rfkill, !value);
|
||||
rfkill_set_sw_state(asus->gps.rfkill, !value);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -1246,46 +1286,127 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
|
||||
.set_block = asus_gps_rfkill_set,
|
||||
};
|
||||
|
||||
static int asus_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
struct asus_rfkill *rfk = data;
|
||||
struct asus_laptop *asus = rfk->asus;
|
||||
|
||||
if (rfk->control_id == WL_RSTS)
|
||||
return asus_wlan_set(asus, !blocked);
|
||||
else if (rfk->control_id == BT_RSTS)
|
||||
return asus_bluetooth_set(asus, !blocked);
|
||||
else if (rfk->control_id == WM_RSTS)
|
||||
return asus_wimax_set(asus, !blocked);
|
||||
else if (rfk->control_id == WW_RSTS)
|
||||
return asus_wwan_set(asus, !blocked);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct rfkill_ops asus_rfkill_ops = {
|
||||
.set_block = asus_rfkill_set,
|
||||
};
|
||||
|
||||
static void asus_rfkill_terminate(struct asus_rfkill *rfk)
|
||||
{
|
||||
if (!rfk->rfkill)
|
||||
return ;
|
||||
|
||||
rfkill_unregister(rfk->rfkill);
|
||||
rfkill_destroy(rfk->rfkill);
|
||||
rfk->rfkill = NULL;
|
||||
}
|
||||
|
||||
static void asus_rfkill_exit(struct asus_laptop *asus)
|
||||
{
|
||||
if (asus->gps_rfkill) {
|
||||
rfkill_unregister(asus->gps_rfkill);
|
||||
rfkill_destroy(asus->gps_rfkill);
|
||||
asus->gps_rfkill = NULL;
|
||||
asus_rfkill_terminate(&asus->wwan);
|
||||
asus_rfkill_terminate(&asus->bluetooth);
|
||||
asus_rfkill_terminate(&asus->wlan);
|
||||
asus_rfkill_terminate(&asus->gps);
|
||||
}
|
||||
|
||||
static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
|
||||
const char *name, int control_id, int type,
|
||||
const struct rfkill_ops *ops)
|
||||
{
|
||||
int result;
|
||||
|
||||
rfk->control_id = control_id;
|
||||
rfk->asus = asus;
|
||||
rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
|
||||
type, ops, rfk);
|
||||
if (!rfk->rfkill)
|
||||
return -EINVAL;
|
||||
|
||||
result = rfkill_register(rfk->rfkill);
|
||||
if (result) {
|
||||
rfkill_destroy(rfk->rfkill);
|
||||
rfk->rfkill = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int asus_rfkill_init(struct asus_laptop *asus)
|
||||
{
|
||||
int result;
|
||||
int result = 0;
|
||||
|
||||
if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) ||
|
||||
acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) ||
|
||||
acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
|
||||
return 0;
|
||||
if (asus->is_pega_lucid)
|
||||
return -ENODEV;
|
||||
|
||||
asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
|
||||
RFKILL_TYPE_GPS,
|
||||
&asus_gps_rfkill_ops, asus);
|
||||
if (!asus->gps_rfkill)
|
||||
return -EINVAL;
|
||||
if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
|
||||
!acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
|
||||
!acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
|
||||
result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
|
||||
-1, RFKILL_TYPE_GPS,
|
||||
&asus_gps_rfkill_ops);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
result = rfkill_register(asus->gps_rfkill);
|
||||
if (result) {
|
||||
rfkill_destroy(asus->gps_rfkill);
|
||||
asus->gps_rfkill = NULL;
|
||||
}
|
||||
|
||||
if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
|
||||
asus->wled_type == TYPE_RFKILL)
|
||||
result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
|
||||
WL_RSTS, RFKILL_TYPE_WLAN,
|
||||
&asus_rfkill_ops);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
|
||||
asus->bled_type == TYPE_RFKILL)
|
||||
result = asus_rfkill_setup(asus, &asus->bluetooth,
|
||||
"asus-bluetooth", BT_RSTS,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&asus_rfkill_ops);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
|
||||
result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
|
||||
WW_RSTS, RFKILL_TYPE_WWAN,
|
||||
&asus_rfkill_ops);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
|
||||
result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
|
||||
WM_RSTS, RFKILL_TYPE_WIMAX,
|
||||
&asus_rfkill_ops);
|
||||
if (result)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
if (result)
|
||||
asus_rfkill_exit(asus);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int pega_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
struct asus_pega_rfkill *pega_rfk = data;
|
||||
|
||||
int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
|
||||
pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
|
||||
struct asus_rfkill *rfk = data;
|
||||
|
||||
int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1293,43 +1414,11 @@ static const struct rfkill_ops pega_rfkill_ops = {
|
||||
.set_block = pega_rfkill_set,
|
||||
};
|
||||
|
||||
static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
|
||||
static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
|
||||
const char *name, int controlid, int rfkill_type)
|
||||
{
|
||||
pr_warn("Terminating %d\n", pega_rfk->control_id);
|
||||
if (pega_rfk->rfkill) {
|
||||
rfkill_unregister(pega_rfk->rfkill);
|
||||
rfkill_destroy(pega_rfk->rfkill);
|
||||
pega_rfk->rfkill = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void pega_rfkill_exit(struct asus_laptop *asus)
|
||||
{
|
||||
pega_rfkill_terminate(&asus->wwanrfk);
|
||||
pega_rfkill_terminate(&asus->btrfk);
|
||||
pega_rfkill_terminate(&asus->wlanrfk);
|
||||
}
|
||||
|
||||
static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
|
||||
const char *name, int controlid, int rfkill_type)
|
||||
{
|
||||
int result;
|
||||
|
||||
pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
|
||||
pega_rfk->control_id = controlid;
|
||||
pega_rfk->asus = asus;
|
||||
pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
|
||||
rfkill_type, &pega_rfkill_ops, pega_rfk);
|
||||
if (!pega_rfk->rfkill)
|
||||
return -EINVAL;
|
||||
|
||||
result = rfkill_register(pega_rfk->rfkill);
|
||||
if (result) {
|
||||
rfkill_destroy(pega_rfk->rfkill);
|
||||
pega_rfk->rfkill = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
|
||||
&pega_rfkill_ops);
|
||||
}
|
||||
|
||||
static int pega_rfkill_init(struct asus_laptop *asus)
|
||||
@ -1339,22 +1428,22 @@ static int pega_rfkill_init(struct asus_laptop *asus)
|
||||
if(!asus->is_pega_lucid)
|
||||
return -ENODEV;
|
||||
|
||||
ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
|
||||
ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
|
||||
PEGA_WLAN, RFKILL_TYPE_WLAN);
|
||||
if(ret)
|
||||
return ret;
|
||||
ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
|
||||
if(ret)
|
||||
goto err_btrfk;
|
||||
ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
|
||||
if(ret)
|
||||
goto err_wwanrfk;
|
||||
goto exit;
|
||||
|
||||
pr_warn("Pega rfkill init succeeded\n");
|
||||
return 0;
|
||||
err_wwanrfk:
|
||||
pega_rfkill_terminate(&asus->btrfk);
|
||||
err_btrfk:
|
||||
pega_rfkill_terminate(&asus->wlanrfk);
|
||||
ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
|
||||
PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
|
||||
if(ret)
|
||||
goto exit;
|
||||
|
||||
ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
|
||||
PEGA_WWAN, RFKILL_TYPE_WWAN);
|
||||
|
||||
exit:
|
||||
if (ret)
|
||||
asus_rfkill_exit(asus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1364,8 +1453,10 @@ err_btrfk:
|
||||
*/
|
||||
static void asus_input_notify(struct asus_laptop *asus, int event)
|
||||
{
|
||||
if (asus->inputdev)
|
||||
sparse_keymap_report_event(asus->inputdev, event, 1, true);
|
||||
if (!asus->inputdev)
|
||||
return ;
|
||||
if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
|
||||
pr_info("Unknown key %x pressed\n", event);
|
||||
}
|
||||
|
||||
static int asus_input_init(struct asus_laptop *asus)
|
||||
@ -1375,7 +1466,7 @@ static int asus_input_init(struct asus_laptop *asus)
|
||||
|
||||
input = input_allocate_device();
|
||||
if (!input) {
|
||||
pr_info("Unable to allocate input device\n");
|
||||
pr_warn("Unable to allocate input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
input->name = "Asus Laptop extra buttons";
|
||||
@ -1390,7 +1481,7 @@ static int asus_input_init(struct asus_laptop *asus)
|
||||
}
|
||||
error = input_register_device(input);
|
||||
if (error) {
|
||||
pr_info("Unable to register input device\n");
|
||||
pr_warn("Unable to register input device\n");
|
||||
goto err_free_keymap;
|
||||
}
|
||||
|
||||
@ -1688,7 +1779,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* WLED and BLED are on by default */
|
||||
if (!strcmp(bled_type, "led"))
|
||||
asus->bled_type = TYPE_LED;
|
||||
else if (!strcmp(bled_type, "rfkill"))
|
||||
asus->bled_type = TYPE_RFKILL;
|
||||
|
||||
if (!strcmp(wled_type, "led"))
|
||||
asus->wled_type = TYPE_LED;
|
||||
else if (!strcmp(wled_type, "rfkill"))
|
||||
asus->wled_type = TYPE_RFKILL;
|
||||
|
||||
if (bluetooth_status >= 0)
|
||||
asus_bluetooth_set(asus, !!bluetooth_status);
|
||||
|
||||
@ -1786,7 +1886,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
|
||||
goto fail_led;
|
||||
|
||||
result = asus_rfkill_init(asus);
|
||||
if (result)
|
||||
if (result && result != -ENODEV)
|
||||
goto fail_rfkill;
|
||||
|
||||
result = pega_accel_init(asus);
|
||||
@ -1828,7 +1928,6 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
|
||||
asus_led_exit(asus);
|
||||
asus_input_exit(asus);
|
||||
pega_accel_exit(asus);
|
||||
pega_rfkill_exit(asus);
|
||||
asus_platform_exit(asus);
|
||||
|
||||
kfree(asus->name);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include "asus-wmi.h"
|
||||
|
||||
@ -51,9 +52,14 @@ static uint wapf;
|
||||
module_param(wapf, uint, 0444);
|
||||
MODULE_PARM_DESC(wapf, "WAPF value");
|
||||
|
||||
static struct quirk_entry quirk_asus_unknown = {
|
||||
};
|
||||
|
||||
static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
|
||||
{
|
||||
driver->wapf = wapf;
|
||||
driver->quirks = &quirk_asus_unknown;
|
||||
driver->quirks->wapf = wapf;
|
||||
driver->panel_power = FB_BLANK_UNBLANK;
|
||||
}
|
||||
|
||||
static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
@ -70,6 +76,8 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
|
||||
{ KE_KEY, 0x50, { KEY_EMAIL } },
|
||||
{ KE_KEY, 0x51, { KEY_WWW } },
|
||||
{ KE_KEY, 0x55, { KEY_CALC } },
|
||||
{ KE_IGNORE, 0x57, }, /* Battery mode */
|
||||
{ KE_IGNORE, 0x58, }, /* AC mode */
|
||||
{ KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
|
||||
{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
|
||||
{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
|
||||
@ -99,7 +107,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
|
||||
.keymap = asus_nb_wmi_keymap,
|
||||
.input_name = "Asus WMI hotkeys",
|
||||
.input_phys = ASUS_NB_WMI_FILE "/input0",
|
||||
.quirks = asus_nb_wmi_quirks,
|
||||
.detect_quirks = asus_nb_wmi_quirks,
|
||||
};
|
||||
|
||||
|
||||
|
@ -411,7 +411,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
|
||||
|
||||
if (retval >= 0) {
|
||||
if (level)
|
||||
*level = retval & 0x80 ? retval & 0x7F : 0;
|
||||
*level = retval & 0x7F;
|
||||
if (env)
|
||||
*env = (retval >> 8) & 0x7F;
|
||||
retval = 0;
|
||||
@ -784,7 +784,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
|
||||
arfkill->dev_id = dev_id;
|
||||
arfkill->asus = asus;
|
||||
|
||||
if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless)
|
||||
if (dev_id == ASUS_WMI_DEVID_WLAN &&
|
||||
asus->driver->quirks->hotplug_wireless)
|
||||
*rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
|
||||
&asus_rfkill_wlan_ops, arfkill);
|
||||
else
|
||||
@ -895,7 +896,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
|
||||
if (result && result != -ENODEV)
|
||||
goto exit;
|
||||
|
||||
if (!asus->driver->hotplug_wireless)
|
||||
if (!asus->driver->quirks->hotplug_wireless)
|
||||
goto exit;
|
||||
|
||||
result = asus_setup_pci_hotplug(asus);
|
||||
@ -1075,7 +1076,12 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
|
||||
*/
|
||||
static int read_backlight_power(struct asus_wmi *asus)
|
||||
{
|
||||
int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);
|
||||
int ret;
|
||||
if (asus->driver->quirks->store_backlight_power)
|
||||
ret = !asus->driver->panel_power;
|
||||
else
|
||||
ret = asus_wmi_get_devstate_simple(asus,
|
||||
ASUS_WMI_DEVID_BACKLIGHT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@ -1116,26 +1122,51 @@ static int read_brightness(struct backlight_device *bd)
|
||||
return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
|
||||
}
|
||||
|
||||
static u32 get_scalar_command(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_wmi *asus = bl_get_data(bd);
|
||||
u32 ctrl_param = 0;
|
||||
|
||||
if ((asus->driver->brightness < bd->props.brightness) ||
|
||||
bd->props.brightness == bd->props.max_brightness)
|
||||
ctrl_param = 0x00008001;
|
||||
else if ((asus->driver->brightness > bd->props.brightness) ||
|
||||
bd->props.brightness == 0)
|
||||
ctrl_param = 0x00008000;
|
||||
|
||||
asus->driver->brightness = bd->props.brightness;
|
||||
|
||||
return ctrl_param;
|
||||
}
|
||||
|
||||
static int update_bl_status(struct backlight_device *bd)
|
||||
{
|
||||
struct asus_wmi *asus = bl_get_data(bd);
|
||||
u32 ctrl_param;
|
||||
int power, err;
|
||||
|
||||
ctrl_param = bd->props.brightness;
|
||||
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
|
||||
ctrl_param, NULL);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
int power, err = 0;
|
||||
|
||||
power = read_backlight_power(asus);
|
||||
if (power != -ENODEV && bd->props.power != power) {
|
||||
ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
|
||||
ctrl_param, NULL);
|
||||
if (asus->driver->quirks->store_backlight_power)
|
||||
asus->driver->panel_power = bd->props.power;
|
||||
|
||||
/* When using scalar brightness, updating the brightness
|
||||
* will mess with the backlight power */
|
||||
if (asus->driver->quirks->scalar_panel_brightness)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (asus->driver->quirks->scalar_panel_brightness)
|
||||
ctrl_param = get_scalar_command(bd);
|
||||
else
|
||||
ctrl_param = bd->props.brightness;
|
||||
|
||||
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
|
||||
ctrl_param, NULL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1196,10 +1227,15 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
|
||||
|
||||
asus->backlight_device = bd;
|
||||
|
||||
if (asus->driver->quirks->store_backlight_power)
|
||||
asus->driver->panel_power = power;
|
||||
|
||||
bd->props.brightness = read_brightness(bd);
|
||||
bd->props.power = power;
|
||||
backlight_update_status(bd);
|
||||
|
||||
asus->driver->brightness = bd->props.brightness;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1441,9 +1477,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
|
||||
|
||||
/* CWAP allow to define the behavior of the Fn+F2 key,
|
||||
* this method doesn't seems to be present on Eee PCs */
|
||||
if (asus->driver->wapf >= 0)
|
||||
if (asus->driver->quirks->wapf >= 0)
|
||||
asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
|
||||
asus->driver->wapf, NULL);
|
||||
asus->driver->quirks->wapf, NULL);
|
||||
|
||||
return asus_wmi_sysfs_init(asus->platform_device);
|
||||
}
|
||||
@ -1622,8 +1658,8 @@ static int asus_wmi_add(struct platform_device *pdev)
|
||||
wdrv->platform_device = pdev;
|
||||
platform_set_drvdata(asus->platform_device, asus);
|
||||
|
||||
if (wdrv->quirks)
|
||||
wdrv->quirks(asus->driver);
|
||||
if (wdrv->detect_quirks)
|
||||
wdrv->detect_quirks(asus->driver);
|
||||
|
||||
err = asus_wmi_platform_init(asus);
|
||||
if (err)
|
||||
|
@ -35,9 +35,16 @@ struct module;
|
||||
struct key_entry;
|
||||
struct asus_wmi;
|
||||
|
||||
struct quirk_entry {
|
||||
bool hotplug_wireless;
|
||||
bool scalar_panel_brightness;
|
||||
bool store_backlight_power;
|
||||
int wapf;
|
||||
};
|
||||
|
||||
struct asus_wmi_driver {
|
||||
bool hotplug_wireless;
|
||||
int wapf;
|
||||
int brightness;
|
||||
int panel_power;
|
||||
|
||||
const char *name;
|
||||
struct module *owner;
|
||||
@ -47,13 +54,14 @@ struct asus_wmi_driver {
|
||||
const struct key_entry *keymap;
|
||||
const char *input_name;
|
||||
const char *input_phys;
|
||||
struct quirk_entry *quirks;
|
||||
/* Returns new code, value, and autorelease values in arguments.
|
||||
* Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
|
||||
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
|
||||
unsigned int *value, bool *autorelease);
|
||||
|
||||
int (*probe) (struct platform_device *device);
|
||||
void (*quirks) (struct asus_wmi_driver *driver);
|
||||
void (*detect_quirks) (struct asus_wmi_driver *driver);
|
||||
|
||||
struct platform_driver platform_driver;
|
||||
struct platform_device *platform_device;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -882,6 +882,7 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
|
||||
|
||||
static void initialize_power_supply_data(struct compal_data *data)
|
||||
{
|
||||
@ -1097,16 +1098,3 @@ MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
|
||||
MODULE_DESCRIPTION("Compal Laptop Support");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
|
||||
MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
|
||||
|
@ -117,6 +117,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, dell_device_table);
|
||||
|
||||
static struct dmi_system_id __devinitdata dell_blacklist[] = {
|
||||
/* Supported by compal-laptop */
|
||||
@ -184,6 +185,33 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
|
||||
},
|
||||
.driver_data = &quirk_dell_vostro_v130,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Dell Vostro 3555",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
|
||||
},
|
||||
.driver_data = &quirk_dell_vostro_v130,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Dell Inspiron N311z",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
|
||||
},
|
||||
.driver_data = &quirk_dell_vostro_v130,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Dell Inspiron M5110",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
|
||||
},
|
||||
.driver_data = &quirk_dell_vostro_v130,
|
||||
},
|
||||
};
|
||||
|
||||
static struct calling_interface_buffer *buffer;
|
||||
@ -236,9 +264,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
switch (dm->type) {
|
||||
case 0xd4: /* Indexed IO */
|
||||
break;
|
||||
case 0xd5: /* Protected Area Type 1 */
|
||||
break;
|
||||
case 0xd6: /* Protected Area Type 2 */
|
||||
break;
|
||||
case 0xda: /* Calling interface */
|
||||
@ -615,6 +641,7 @@ static void touchpad_led_set(struct led_classdev *led_cdev,
|
||||
static struct led_classdev touchpad_led = {
|
||||
.name = "dell-laptop::touchpad",
|
||||
.brightness_set = touchpad_led_set,
|
||||
.flags = LED_CORE_SUSPENDRESUME,
|
||||
};
|
||||
|
||||
static int __devinit touchpad_led_init(struct device *dev)
|
||||
@ -794,6 +821,3 @@ module_exit(dell_exit);
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
MODULE_DESCRIPTION("Dell laptop driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
|
||||
MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
|
||||
MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
|
||||
|
@ -1251,6 +1251,14 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
|
||||
/*
|
||||
* ACPI driver
|
||||
*/
|
||||
static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
|
||||
{
|
||||
if (!eeepc->inputdev)
|
||||
return ;
|
||||
if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
|
||||
pr_info("Unknown key %x pressed\n", event);
|
||||
}
|
||||
|
||||
static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
struct eeepc_laptop *eeepc = acpi_driver_data(device);
|
||||
@ -1287,12 +1295,11 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
|
||||
* event will be desired value (or else ignored)
|
||||
*/
|
||||
}
|
||||
sparse_keymap_report_event(eeepc->inputdev, event,
|
||||
1, true);
|
||||
eeepc_input_notify(eeepc, event);
|
||||
}
|
||||
} else {
|
||||
/* Everything else is a bona-fide keypress event */
|
||||
sparse_keymap_report_event(eeepc->inputdev, event, 1, true);
|
||||
eeepc_input_notify(eeepc, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/fb.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
||||
#include "asus-wmi.h"
|
||||
@ -84,9 +85,81 @@ static const struct key_entry eeepc_wmi_keymap[] = {
|
||||
{ KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
|
||||
{ KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
|
||||
{ KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
|
||||
{ KE_KEY, 0xf3, { KEY_MENU } },
|
||||
{ KE_KEY, 0xf5, { KEY_HOMEPAGE } },
|
||||
{ KE_KEY, 0xf6, { KEY_ESC } },
|
||||
{ KE_END, 0},
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_asus_unknown = {
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_asus_1000h = {
|
||||
.hotplug_wireless = true,
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_asus_et2012_type1 = {
|
||||
.store_backlight_power = true,
|
||||
};
|
||||
|
||||
static struct quirk_entry quirk_asus_et2012_type3 = {
|
||||
.scalar_panel_brightness = true,
|
||||
.store_backlight_power = true,
|
||||
};
|
||||
|
||||
static struct quirk_entry *quirks;
|
||||
|
||||
static void et2012_quirks(void)
|
||||
{
|
||||
const struct dmi_device *dev = NULL;
|
||||
char oemstring[30];
|
||||
|
||||
while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
|
||||
if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
|
||||
if (oemstring[18] == '1')
|
||||
quirks = &quirk_asus_et2012_type1;
|
||||
else if (oemstring[18] == '3')
|
||||
quirks = &quirk_asus_et2012_type3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int dmi_matched(const struct dmi_system_id *dmi)
|
||||
{
|
||||
char *model;
|
||||
|
||||
quirks = dmi->driver_data;
|
||||
|
||||
model = (char *)dmi->matches[1].substr;
|
||||
if (unlikely(strncmp(model, "ET2012", 6) == 0))
|
||||
et2012_quirks();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct dmi_system_id asus_quirks[] = {
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "ASUSTeK Computer INC. 1000H",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
|
||||
},
|
||||
.driver_data = &quirk_asus_1000h,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "ASUSTeK Computer INC. ET2012E/I",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
|
||||
},
|
||||
.driver_data = &quirk_asus_unknown,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
|
||||
unsigned int *value, bool *autorelease)
|
||||
{
|
||||
@ -141,33 +214,16 @@ static int eeepc_wmi_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void eeepc_dmi_check(struct asus_wmi_driver *driver)
|
||||
{
|
||||
const char *model;
|
||||
|
||||
model = dmi_get_system_info(DMI_PRODUCT_NAME);
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Whitelist for wlan hotplug
|
||||
*
|
||||
* Asus 1000H needs the current hotplug code to handle
|
||||
* Fn+F2 correctly. We may add other Asus here later, but
|
||||
* it seems that most of the laptops supported by asus-wmi
|
||||
* don't need to be on this list
|
||||
*/
|
||||
if (strcmp(model, "1000H") == 0) {
|
||||
driver->hotplug_wireless = true;
|
||||
pr_info("wlan hotplug enabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
|
||||
{
|
||||
driver->hotplug_wireless = hotplug_wireless;
|
||||
driver->wapf = -1;
|
||||
eeepc_dmi_check(driver);
|
||||
quirks = &quirk_asus_unknown;
|
||||
quirks->hotplug_wireless = hotplug_wireless;
|
||||
|
||||
dmi_check_system(asus_quirks);
|
||||
|
||||
driver->quirks = quirks;
|
||||
driver->quirks->wapf = -1;
|
||||
driver->panel_power = FB_BLANK_UNBLANK;
|
||||
}
|
||||
|
||||
static struct asus_wmi_driver asus_wmi_driver = {
|
||||
@ -179,7 +235,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
|
||||
.input_phys = EEEPC_WMI_FILE "/input0",
|
||||
.key_filter = eeepc_wmi_key_filter,
|
||||
.probe = eeepc_wmi_probe,
|
||||
.quirks = eeepc_wmi_quirks,
|
||||
.detect_quirks = eeepc_wmi_quirks,
|
||||
};
|
||||
|
||||
|
||||
|
@ -375,7 +375,7 @@ static ssize_t hdaps_variance_show(struct device *dev,
|
||||
static ssize_t hdaps_temp1_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u8 temp;
|
||||
u8 uninitialized_var(temp);
|
||||
int ret;
|
||||
|
||||
ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
|
||||
@ -388,7 +388,7 @@ static ssize_t hdaps_temp1_show(struct device *dev,
|
||||
static ssize_t hdaps_temp2_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u8 temp;
|
||||
u8 uninitialized_var(temp);
|
||||
int ret;
|
||||
|
||||
ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
|
||||
|
@ -142,17 +142,7 @@ static struct platform_driver mfld_pb_driver = {
|
||||
.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_platform_driver(mfld_pb_driver);
|
||||
|
||||
MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
|
||||
|
@ -549,6 +549,7 @@ static int mid_thermal_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id therm_id_table[] = {
|
||||
{ DRIVER_NAME, 1 },
|
||||
{ "msic_thermal", 1 },
|
||||
{ }
|
||||
};
|
||||
|
||||
@ -564,18 +565,7 @@ static struct platform_driver mid_thermal_driver = {
|
||||
.id_table = therm_id_table,
|
||||
};
|
||||
|
||||
static int __init mid_thermal_module_init(void)
|
||||
{
|
||||
return platform_driver_register(&mid_thermal_driver);
|
||||
}
|
||||
|
||||
static void __exit mid_thermal_module_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mid_thermal_driver);
|
||||
}
|
||||
|
||||
module_init(mid_thermal_module_init);
|
||||
module_exit(mid_thermal_module_exit);
|
||||
module_platform_driver(mid_thermal_driver);
|
||||
|
||||
MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
|
||||
MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
|
||||
|
@ -313,6 +313,7 @@ static struct dmi_system_id __initdata oaktrail_dmi_table[] = {
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, oaktrail_dmi_table);
|
||||
|
||||
static int __init oaktrail_init(void)
|
||||
{
|
||||
@ -394,4 +395,3 @@ MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)");
|
||||
MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -127,7 +127,7 @@ MODULE_PARM_DESC(minor,
|
||||
"default is -1 (automatic)");
|
||||
#endif
|
||||
|
||||
static int kbd_backlight; /* = 1 */
|
||||
static int kbd_backlight = 1;
|
||||
module_param(kbd_backlight, int, 0444);
|
||||
MODULE_PARM_DESC(kbd_backlight,
|
||||
"set this to 0 to disable keyboard backlight, "
|
||||
@ -347,6 +347,7 @@ static void sony_laptop_report_input_event(u8 event)
|
||||
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
|
||||
struct input_dev *key_dev = sony_laptop_input.key_dev;
|
||||
struct sony_laptop_keypress kp = { NULL };
|
||||
int scancode = -1;
|
||||
|
||||
if (event == SONYPI_EVENT_FNKEY_RELEASED ||
|
||||
event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
|
||||
@ -380,8 +381,8 @@ static void sony_laptop_report_input_event(u8 event)
|
||||
dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
|
||||
break;
|
||||
}
|
||||
if (sony_laptop_input_index[event] != -1) {
|
||||
kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
|
||||
if ((scancode = sony_laptop_input_index[event]) != -1) {
|
||||
kp.key = sony_laptop_input_keycode_map[scancode];
|
||||
if (kp.key != KEY_UNKNOWN)
|
||||
kp.dev = key_dev;
|
||||
}
|
||||
@ -389,9 +390,11 @@ static void sony_laptop_report_input_event(u8 event)
|
||||
}
|
||||
|
||||
if (kp.dev) {
|
||||
/* if we have a scancode we emit it so we can always
|
||||
remap the key */
|
||||
if (scancode != -1)
|
||||
input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
|
||||
input_report_key(kp.dev, kp.key, 1);
|
||||
/* we emit the scancode so we can always remap the key */
|
||||
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
|
||||
input_sync(kp.dev);
|
||||
|
||||
/* schedule key release */
|
||||
@ -466,7 +469,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
|
||||
jog_dev->name = "Sony Vaio Jogdial";
|
||||
jog_dev->id.bustype = BUS_ISA;
|
||||
jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
||||
key_dev->dev.parent = &acpi_device->dev;
|
||||
jog_dev->dev.parent = &acpi_device->dev;
|
||||
|
||||
input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
|
||||
input_set_capability(jog_dev, EV_REL, REL_WHEEL);
|
||||
|
@ -8658,7 +8658,7 @@ static int __must_check __init get_thinkpad_model_data(
|
||||
}
|
||||
|
||||
s = dmi_get_system_info(DMI_PRODUCT_VERSION);
|
||||
if (s && !strnicmp(s, "ThinkPad", 8)) {
|
||||
if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
|
||||
tp->model_str = kstrdup(s, GFP_KERNEL);
|
||||
if (!tp->model_str)
|
||||
return -ENOMEM;
|
||||
|
@ -52,6 +52,8 @@
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i8042.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@ -61,6 +63,11 @@ MODULE_AUTHOR("John Belmonte");
|
||||
MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
|
||||
|
||||
/* Scan code for Fn key on TOS1900 models */
|
||||
#define TOS1900_FN_SCAN 0x6e
|
||||
|
||||
/* Toshiba ACPI method paths */
|
||||
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
|
||||
|
||||
@ -95,6 +102,8 @@ MODULE_LICENSE("GPL");
|
||||
#define HCI_WIRELESS 0x0056
|
||||
|
||||
/* field definitions */
|
||||
#define HCI_HOTKEY_DISABLE 0x0b
|
||||
#define HCI_HOTKEY_ENABLE 0x09
|
||||
#define HCI_LCD_BRIGHTNESS_BITS 3
|
||||
#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
|
||||
#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
|
||||
@ -111,6 +120,7 @@ struct toshiba_acpi_dev {
|
||||
const char *method_hci;
|
||||
struct rfkill *bt_rfk;
|
||||
struct input_dev *hotkey_dev;
|
||||
struct work_struct hotkey_work;
|
||||
struct backlight_device *backlight_dev;
|
||||
struct led_classdev led_dev;
|
||||
|
||||
@ -118,14 +128,18 @@ struct toshiba_acpi_dev {
|
||||
int last_key_event;
|
||||
int key_event_valid;
|
||||
|
||||
int illumination_supported:1;
|
||||
int video_supported:1;
|
||||
int fan_supported:1;
|
||||
int system_event_supported:1;
|
||||
unsigned int illumination_supported:1;
|
||||
unsigned int video_supported:1;
|
||||
unsigned int fan_supported:1;
|
||||
unsigned int system_event_supported:1;
|
||||
unsigned int ntfy_supported:1;
|
||||
unsigned int info_supported:1;
|
||||
|
||||
struct mutex mutex;
|
||||
};
|
||||
|
||||
static struct toshiba_acpi_dev *toshiba_acpi;
|
||||
|
||||
static const struct acpi_device_id toshiba_device_ids[] = {
|
||||
{"TOS6200", 0},
|
||||
{"TOS6208", 0},
|
||||
@ -138,6 +152,8 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
|
||||
{ KE_KEY, 0x101, { KEY_MUTE } },
|
||||
{ KE_KEY, 0x102, { KEY_ZOOMOUT } },
|
||||
{ KE_KEY, 0x103, { KEY_ZOOMIN } },
|
||||
{ KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, 0x139, { KEY_ZOOMRESET } },
|
||||
{ KE_KEY, 0x13b, { KEY_COFFEE } },
|
||||
{ KE_KEY, 0x13c, { KEY_BATTERY } },
|
||||
{ KE_KEY, 0x13d, { KEY_SLEEP } },
|
||||
@ -146,7 +162,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
|
||||
{ KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
|
||||
{ KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
|
||||
{ KE_KEY, 0x142, { KEY_WLAN } },
|
||||
{ KE_KEY, 0x143, { KEY_PROG1 } },
|
||||
{ KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
|
||||
{ KE_KEY, 0x17f, { KEY_FN } },
|
||||
{ KE_KEY, 0xb05, { KEY_PROG2 } },
|
||||
{ KE_KEY, 0xb06, { KEY_WWW } },
|
||||
@ -156,6 +172,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
|
||||
{ KE_KEY, 0xb32, { KEY_NEXTSONG } },
|
||||
{ KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
|
||||
{ KE_KEY, 0xb5a, { KEY_MEDIA } },
|
||||
{ KE_IGNORE, 0x1430, { KEY_RESERVED } },
|
||||
{ KE_END, 0 },
|
||||
};
|
||||
|
||||
@ -847,10 +864,78 @@ static const struct backlight_ops toshiba_backlight_data = {
|
||||
.update_status = set_lcd_status,
|
||||
};
|
||||
|
||||
static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
{
|
||||
if (str & 0x20)
|
||||
return false;
|
||||
|
||||
if (unlikely(data == 0xe0))
|
||||
return false;
|
||||
|
||||
if ((data & 0x7f) == TOS1900_FN_SCAN) {
|
||||
schedule_work(&toshiba_acpi->hotkey_work);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_hotkey_work(struct work_struct *work)
|
||||
{
|
||||
acpi_handle ec_handle = ec_get_handle();
|
||||
acpi_status status;
|
||||
|
||||
if (!ec_handle)
|
||||
return;
|
||||
|
||||
status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("ACPI NTFY method execution failed\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns hotkey scancode, or < 0 on failure.
|
||||
*/
|
||||
static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
|
||||
{
|
||||
struct acpi_buffer buf;
|
||||
union acpi_object out_obj;
|
||||
acpi_status status;
|
||||
|
||||
buf.pointer = &out_obj;
|
||||
buf.length = sizeof(out_obj);
|
||||
|
||||
status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
|
||||
NULL, &buf);
|
||||
if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
|
||||
pr_err("ACPI INFO method execution failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return out_obj.integer.value;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
|
||||
int scancode)
|
||||
{
|
||||
if (scancode == 0x100)
|
||||
return;
|
||||
|
||||
/* act on key press; ignore key release */
|
||||
if (scancode & 0x80)
|
||||
return;
|
||||
|
||||
if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
|
||||
pr_info("Unknown key %x\n", scancode);
|
||||
}
|
||||
|
||||
static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle ec_handle, handle;
|
||||
int error;
|
||||
u32 hci_result;
|
||||
|
||||
dev->hotkey_dev = input_allocate_device();
|
||||
if (!dev->hotkey_dev) {
|
||||
@ -866,21 +951,67 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
|
||||
if (error)
|
||||
goto err_free_dev;
|
||||
|
||||
/*
|
||||
* For some machines the SCI responsible for providing hotkey
|
||||
* notification doesn't fire. We can trigger the notification
|
||||
* whenever the Fn key is pressed using the NTFY method, if
|
||||
* supported, so if it's present set up an i8042 key filter
|
||||
* for this purpose.
|
||||
*/
|
||||
status = AE_ERROR;
|
||||
ec_handle = ec_get_handle();
|
||||
if (ec_handle)
|
||||
status = acpi_get_handle(ec_handle, "NTFY", &handle);
|
||||
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
|
||||
|
||||
error = i8042_install_filter(toshiba_acpi_i8042_filter);
|
||||
if (error) {
|
||||
pr_err("Error installing key filter\n");
|
||||
goto err_free_keymap;
|
||||
}
|
||||
|
||||
dev->ntfy_supported = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine hotkey query interface. Prefer using the INFO
|
||||
* method when it is available.
|
||||
*/
|
||||
status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
dev->info_supported = 1;
|
||||
} else {
|
||||
hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS)
|
||||
dev->system_event_supported = 1;
|
||||
}
|
||||
|
||||
if (!dev->info_supported && !dev->system_event_supported) {
|
||||
pr_warn("No hotkey query interface found\n");
|
||||
goto err_remove_filter;
|
||||
}
|
||||
|
||||
status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_info("Unable to enable hotkeys\n");
|
||||
error = -ENODEV;
|
||||
goto err_free_keymap;
|
||||
goto err_remove_filter;
|
||||
}
|
||||
|
||||
error = input_register_device(dev->hotkey_dev);
|
||||
if (error) {
|
||||
pr_info("Unable to register input device\n");
|
||||
goto err_free_keymap;
|
||||
goto err_remove_filter;
|
||||
}
|
||||
|
||||
hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
|
||||
return 0;
|
||||
|
||||
err_remove_filter:
|
||||
if (dev->ntfy_supported)
|
||||
i8042_remove_filter(toshiba_acpi_i8042_filter);
|
||||
err_free_keymap:
|
||||
sparse_keymap_free(dev->hotkey_dev);
|
||||
err_free_dev:
|
||||
@ -895,6 +1026,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
|
||||
|
||||
remove_toshiba_proc_entries(dev);
|
||||
|
||||
if (dev->ntfy_supported) {
|
||||
i8042_remove_filter(toshiba_acpi_i8042_filter);
|
||||
cancel_work_sync(&dev->hotkey_work);
|
||||
}
|
||||
|
||||
if (dev->hotkey_dev) {
|
||||
input_unregister_device(dev->hotkey_dev);
|
||||
sparse_keymap_free(dev->hotkey_dev);
|
||||
@ -911,6 +1047,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
|
||||
if (dev->illumination_supported)
|
||||
led_classdev_unregister(&dev->led_dev);
|
||||
|
||||
if (toshiba_acpi)
|
||||
toshiba_acpi = NULL;
|
||||
|
||||
kfree(dev);
|
||||
|
||||
return 0;
|
||||
@ -936,12 +1075,14 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev;
|
||||
const char *hci_method;
|
||||
u32 hci_result;
|
||||
u32 dummy;
|
||||
bool bt_present;
|
||||
int ret = 0;
|
||||
struct backlight_properties props;
|
||||
|
||||
if (toshiba_acpi)
|
||||
return -EBUSY;
|
||||
|
||||
pr_info("Toshiba Laptop ACPI Extras version %s\n",
|
||||
TOSHIBA_ACPI_VERSION);
|
||||
|
||||
@ -963,11 +1104,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
|
||||
/* enable event fifo */
|
||||
hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS)
|
||||
dev->system_event_supported = 1;
|
||||
|
||||
props.type = BACKLIGHT_PLATFORM;
|
||||
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
|
||||
dev->backlight_dev = backlight_device_register("toshiba",
|
||||
@ -1024,6 +1160,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
|
||||
|
||||
create_toshiba_proc_entries(dev);
|
||||
|
||||
toshiba_acpi = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
@ -1036,40 +1174,64 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
|
||||
u32 hci_result, value;
|
||||
int retries = 3;
|
||||
int scancode;
|
||||
|
||||
if (!dev->system_event_supported || event != 0x80)
|
||||
if (event != 0x80)
|
||||
return;
|
||||
|
||||
do {
|
||||
hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
|
||||
switch (hci_result) {
|
||||
case HCI_SUCCESS:
|
||||
if (value == 0x100)
|
||||
continue;
|
||||
/* act on key press; ignore key release */
|
||||
if (value & 0x80)
|
||||
continue;
|
||||
|
||||
if (!sparse_keymap_report_event(dev->hotkey_dev,
|
||||
value, 1, true)) {
|
||||
pr_info("Unknown key %x\n",
|
||||
value);
|
||||
if (dev->info_supported) {
|
||||
scancode = toshiba_acpi_query_hotkey(dev);
|
||||
if (scancode < 0)
|
||||
pr_err("Failed to query hotkey event\n");
|
||||
else if (scancode != 0)
|
||||
toshiba_acpi_report_hotkey(dev, scancode);
|
||||
} else if (dev->system_event_supported) {
|
||||
do {
|
||||
hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
|
||||
switch (hci_result) {
|
||||
case HCI_SUCCESS:
|
||||
toshiba_acpi_report_hotkey(dev, (int)value);
|
||||
break;
|
||||
case HCI_NOT_SUPPORTED:
|
||||
/*
|
||||
* This is a workaround for an unresolved
|
||||
* issue on some machines where system events
|
||||
* sporadically become disabled.
|
||||
*/
|
||||
hci_write1(dev, HCI_SYSTEM_EVENT, 1,
|
||||
&hci_result);
|
||||
pr_notice("Re-enabled hotkeys\n");
|
||||
/* fall through */
|
||||
default:
|
||||
retries--;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case HCI_NOT_SUPPORTED:
|
||||
/* This is a workaround for an unresolved issue on
|
||||
* some machines where system events sporadically
|
||||
* become disabled. */
|
||||
hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
|
||||
pr_notice("Re-enabled hotkeys\n");
|
||||
/* fall through */
|
||||
default:
|
||||
retries--;
|
||||
break;
|
||||
}
|
||||
} while (retries && hci_result != HCI_EMPTY);
|
||||
} while (retries && hci_result != HCI_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
|
||||
pm_message_t state)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
|
||||
u32 result;
|
||||
|
||||
if (dev->hotkey_dev)
|
||||
hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
|
||||
{
|
||||
struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
|
||||
u32 result;
|
||||
|
||||
if (dev->hotkey_dev)
|
||||
hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct acpi_driver toshiba_acpi_driver = {
|
||||
.name = "Toshiba ACPI driver",
|
||||
@ -1080,6 +1242,8 @@ static struct acpi_driver toshiba_acpi_driver = {
|
||||
.add = toshiba_acpi_add,
|
||||
.remove = toshiba_acpi_remove,
|
||||
.notify = toshiba_acpi_notify,
|
||||
.suspend = toshiba_acpi_suspend,
|
||||
.resume = toshiba_acpi_resume,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1087,6 +1251,14 @@ static int __init toshiba_acpi_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Machines with this WMI guid aren't supported due to bugs in
|
||||
* their AML. This check relies on wmi initializing before
|
||||
* toshiba_acpi to guarantee guids have been identified.
|
||||
*/
|
||||
if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
|
||||
return -ENODEV;
|
||||
|
||||
toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
|
||||
if (!toshiba_proc_dir) {
|
||||
pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
|
||||
|
@ -67,19 +67,8 @@ static struct platform_driver xo1_rfkill_driver = {
|
||||
.remove = __devexit_p(xo1_rfkill_remove),
|
||||
};
|
||||
|
||||
static int __init xo1_rfkill_init(void)
|
||||
{
|
||||
return platform_driver_register(&xo1_rfkill_driver);
|
||||
}
|
||||
|
||||
static void __exit xo1_rfkill_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&xo1_rfkill_driver);
|
||||
}
|
||||
module_platform_driver(xo1_rfkill_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:xo1-rfkill");
|
||||
|
||||
module_init(xo1_rfkill_init);
|
||||
module_exit(xo1_rfkill_exit);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
static struct backlight_device *apple_backlight_device;
|
||||
|
||||
@ -221,14 +222,32 @@ static struct acpi_driver apple_bl_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
static atomic_t apple_bl_registered = ATOMIC_INIT(0);
|
||||
|
||||
int apple_bl_register(void)
|
||||
{
|
||||
if (atomic_xchg(&apple_bl_registered, 1) == 0)
|
||||
return acpi_bus_register_driver(&apple_bl_driver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apple_bl_register);
|
||||
|
||||
void apple_bl_unregister(void)
|
||||
{
|
||||
if (atomic_xchg(&apple_bl_registered, 0) == 1)
|
||||
acpi_bus_unregister_driver(&apple_bl_driver);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(apple_bl_unregister);
|
||||
|
||||
static int __init apple_bl_init(void)
|
||||
{
|
||||
return acpi_bus_register_driver(&apple_bl_driver);
|
||||
return apple_bl_register();
|
||||
}
|
||||
|
||||
static void __exit apple_bl_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&apple_bl_driver);
|
||||
apple_bl_unregister();
|
||||
}
|
||||
|
||||
module_init(apple_bl_init);
|
||||
|
@ -151,6 +151,7 @@ extern int ec_write(u8 addr, u8 val);
|
||||
extern int ec_transaction(u8 command,
|
||||
const u8 *wdata, unsigned wdata_len,
|
||||
u8 *rdata, unsigned rdata_len);
|
||||
extern acpi_handle ec_get_handle(void);
|
||||
|
||||
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
|
||||
|
||||
|
26
include/linux/apple_bl.h
Normal file
26
include/linux/apple_bl.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* apple_bl exported symbols
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_APPLE_BL_H
|
||||
#define _LINUX_APPLE_BL_H
|
||||
|
||||
#ifdef CONFIG_BACKLIGHT_APPLE
|
||||
|
||||
extern int apple_bl_register(void);
|
||||
extern void apple_bl_unregister(void);
|
||||
|
||||
#else /* !CONFIG_BACKLIGHT_APPLE */
|
||||
|
||||
static inline int apple_bl_register(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void apple_bl_unregister(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_BACKLIGHT_APPLE */
|
||||
|
||||
#endif /* _LINUX_APPLE_BL_H */
|
Loading…
Reference in New Issue
Block a user