Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: toshiba_acpi: Add full hotkey support hp-wmi: Add support for tablet rotation key dell-laptop: Add another Dell laptop to the DMI whitelist classmate-laptop: use a single MODULE_DEVICE_TABLE to get correct aliases dell-laptop: Pay attention to which devices the hardware switch controls dell-laptop: Use buffer with 32-bit physical address dell-laptop: Blacklist machines not supporting dell-laptop dell-laptop: Block software state changes when rfkill hard blocked dell-laptop: Fix small memory leak dell-laptop: Fix platform device unregistration dell-laptop: Update rfkill state on kill switch compal-laptop: Replace sysfs support with rfkill support compal-laptop: Add support for known Compal made Dell laptops MAINTAINERS: update drivers/platform/x86 information
This commit is contained in:
commit
98723153dc
7 changed files with 579 additions and 200 deletions
29
MAINTAINERS
29
MAINTAINERS
|
@ -221,6 +221,7 @@ F: drivers/net/acenic*
|
|||
|
||||
ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
|
||||
M: Peter Feuerer <peter@piie.net>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://piie.net/?section=acerhdf
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/acerhdf.c
|
||||
|
@ -228,6 +229,7 @@ F: drivers/platform/x86/acerhdf.c
|
|||
ACER WMI LAPTOP EXTRAS
|
||||
M: Carlos Corbacho <carlos@strangeworlds.co.uk>
|
||||
L: aceracpi@googlegroups.com (subscribers-only)
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://code.google.com/p/aceracpi
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/acer-wmi.c
|
||||
|
@ -288,7 +290,7 @@ F: drivers/acpi/video.c
|
|||
|
||||
ACPI WMI DRIVER
|
||||
M: Carlos Corbacho <carlos@strangeworlds.co.uk>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://www.lesswatts.org/projects/acpi/
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/wmi.c
|
||||
|
@ -968,6 +970,7 @@ ASUS ACPI EXTRAS DRIVER
|
|||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
M: Karol Kozimor <sziwan@users.sourceforge.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/asus_acpi.c
|
||||
|
@ -981,6 +984,7 @@ F: drivers/hwmon/asb100.c
|
|||
ASUS LAPTOP EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/asus-laptop.c
|
||||
|
@ -1473,6 +1477,7 @@ F: drivers/scsi/fnic/
|
|||
CMPC ACPI DRIVER
|
||||
M: Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
|
||||
M: Daniel Oliveira Nascimento <don@syst.com.br>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/platform/x86/classmate-laptop.c
|
||||
|
||||
|
@ -1516,6 +1521,7 @@ F: drivers/pci/hotplug/cpcihp_generic.c
|
|||
|
||||
COMPAL LAPTOP SUPPORT
|
||||
M: Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/compal-laptop.c
|
||||
|
||||
|
@ -1746,6 +1752,7 @@ F: drivers/net/defxx.*
|
|||
|
||||
DELL LAPTOP DRIVER
|
||||
M: Matthew Garrett <mjg59@srcf.ucam.org>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/dell-laptop.c
|
||||
|
||||
|
@ -2028,6 +2035,7 @@ F: drivers/edac/r82600_edac.c
|
|||
EEEPC LAPTOP EXTRAS DRIVER
|
||||
M: Corentin Chary <corentincj@iksaif.net>
|
||||
L: acpi4asus-user@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://acpi4asus.sf.net
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/eeepc-laptop.c
|
||||
|
@ -2306,7 +2314,7 @@ F: arch/frv/
|
|||
|
||||
FUJITSU LAPTOP EXTRAS
|
||||
M: Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/fujitsu-laptop.c
|
||||
|
||||
|
@ -2584,6 +2592,7 @@ F: drivers/net/wireless/hostap/
|
|||
|
||||
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
|
||||
M: Carlos Corbacho <carlos@strangeworlds.co.uk>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Odd Fixes
|
||||
F: drivers/platform/x86/tc1100-wmi.c
|
||||
|
||||
|
@ -2794,7 +2803,7 @@ F: drivers/video/i810/
|
|||
|
||||
INTEL MENLOW THERMAL DRIVER
|
||||
M: Sujith Thomas <sujith.thomas@intel.com>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://www.lesswatts.org/projects/acpi/
|
||||
S: Supported
|
||||
F: drivers/platform/x86/intel_menlow.c
|
||||
|
@ -3660,6 +3669,7 @@ F: drivers/char/mxser.*
|
|||
|
||||
MSI LAPTOP SUPPORT
|
||||
M: Lennart Poettering <mzxreary@0pointer.de>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: https://tango.0pointer.de/mailman/listinfo/s270-linux
|
||||
W: http://0pointer.de/lennart/tchibo.html
|
||||
S: Maintained
|
||||
|
@ -3667,6 +3677,7 @@ F: drivers/platform/x86/msi-laptop.c
|
|||
|
||||
MSI WMI SUPPORT
|
||||
M: Anisse Astier <anisse@astier.eu>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Supported
|
||||
F: drivers/platform/x86/msi-wmi.c
|
||||
|
||||
|
@ -4119,6 +4130,7 @@ F: drivers/i2c/busses/i2c-pasemi.c
|
|||
|
||||
PANASONIC LAPTOP ACPI EXTRAS DRIVER
|
||||
M: Harald Welte <laforge@gnumonks.org>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/panasonic-laptop.c
|
||||
|
||||
|
@ -5064,7 +5076,7 @@ F: include/linux/ssb/
|
|||
|
||||
SONY VAIO CONTROL DEVICE DRIVER
|
||||
M: Mattia Dongili <malattia@linux.it>
|
||||
L: linux-acpi@vger.kernel.org
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
|
||||
S: Maintained
|
||||
F: Documentation/laptops/sony-laptop.txt
|
||||
|
@ -5270,6 +5282,7 @@ F: arch/xtensa/
|
|||
THINKPAD ACPI EXTRAS DRIVER
|
||||
M: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
|
||||
L: ibm-acpi-devel@lists.sourceforge.net
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
W: http://ibm-acpi.sourceforge.net
|
||||
W: http://thinkwiki.org/wiki/Ibm-acpi
|
||||
T: git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
|
||||
|
@ -5323,10 +5336,12 @@ F: security/tomoyo/
|
|||
|
||||
TOPSTAR LAPTOP EXTRAS DRIVER
|
||||
M: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/topstar-laptop.c
|
||||
|
||||
TOSHIBA ACPI EXTRAS DRIVER
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Orphan
|
||||
F: drivers/platform/x86/toshiba_acpi.c
|
||||
|
||||
|
@ -6054,6 +6069,12 @@ S: Maintained
|
|||
F: Documentation/x86/
|
||||
F: arch/x86/
|
||||
|
||||
X86 PLATFORM DRIVERS
|
||||
M: Matthew Garrett <mjg@redhat.com>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86
|
||||
|
||||
XEN HYPERVISOR INTERFACE
|
||||
M: Jeremy Fitzhardinge <jeremy@xensource.com>
|
||||
M: Chris Wright <chrisw@sous-sol.org>
|
||||
|
|
|
@ -79,6 +79,7 @@ config DELL_LAPTOP
|
|||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on RFKILL || RFKILL = n
|
||||
depends on POWER_SUPPLY
|
||||
depends on SERIO_I8042
|
||||
default n
|
||||
---help---
|
||||
This driver adds support for rfkill and backlight control to Dell
|
||||
|
|
|
@ -34,6 +34,11 @@ struct cmpc_accel {
|
|||
#define CMPC_ACCEL_SENSITIVITY_DEFAULT 5
|
||||
|
||||
|
||||
#define CMPC_ACCEL_HID "ACCE0000"
|
||||
#define CMPC_TABLET_HID "TBLT0000"
|
||||
#define CMPC_BL_HID "IPML200"
|
||||
#define CMPC_KEYS_HID "FnBT0000"
|
||||
|
||||
/*
|
||||
* Generic input device code.
|
||||
*/
|
||||
|
@ -282,10 +287,9 @@ static int cmpc_accel_remove(struct acpi_device *acpi, int type)
|
|||
}
|
||||
|
||||
static const struct acpi_device_id cmpc_accel_device_ids[] = {
|
||||
{"ACCE0000", 0},
|
||||
{CMPC_ACCEL_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids);
|
||||
|
||||
static struct acpi_driver cmpc_accel_acpi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -366,10 +370,9 @@ static int cmpc_tablet_resume(struct acpi_device *acpi)
|
|||
}
|
||||
|
||||
static const struct acpi_device_id cmpc_tablet_device_ids[] = {
|
||||
{"TBLT0000", 0},
|
||||
{CMPC_TABLET_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids);
|
||||
|
||||
static struct acpi_driver cmpc_tablet_acpi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -477,17 +480,16 @@ static int cmpc_bl_remove(struct acpi_device *acpi, int type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id cmpc_device_ids[] = {
|
||||
{"IPML200", 0},
|
||||
static const struct acpi_device_id cmpc_bl_device_ids[] = {
|
||||
{CMPC_BL_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
|
||||
|
||||
static struct acpi_driver cmpc_bl_acpi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cmpc",
|
||||
.class = "cmpc",
|
||||
.ids = cmpc_device_ids,
|
||||
.ids = cmpc_bl_device_ids,
|
||||
.ops = {
|
||||
.add = cmpc_bl_add,
|
||||
.remove = cmpc_bl_remove
|
||||
|
@ -540,10 +542,9 @@ static int cmpc_keys_remove(struct acpi_device *acpi, int type)
|
|||
}
|
||||
|
||||
static const struct acpi_device_id cmpc_keys_device_ids[] = {
|
||||
{"FnBT0000", 0},
|
||||
{CMPC_KEYS_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids);
|
||||
|
||||
static struct acpi_driver cmpc_keys_acpi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -607,3 +608,13 @@ static void cmpc_exit(void)
|
|||
|
||||
module_init(cmpc_init);
|
||||
module_exit(cmpc_exit);
|
||||
|
||||
static const struct acpi_device_id cmpc_device_ids[] = {
|
||||
{CMPC_ACCEL_HID, 0},
|
||||
{CMPC_TABLET_HID, 0},
|
||||
{CMPC_BL_HID, 0},
|
||||
{CMPC_KEYS_HID, 0},
|
||||
{"", 0}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
|
||||
|
|
|
@ -26,17 +26,8 @@
|
|||
/*
|
||||
* comapl-laptop.c - Compal laptop support.
|
||||
*
|
||||
* This driver exports a few files in /sys/devices/platform/compal-laptop/:
|
||||
*
|
||||
* wlan - wlan subsystem state: contains 0 or 1 (rw)
|
||||
*
|
||||
* bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
|
||||
*
|
||||
* raw - raw value taken from embedded controller register (ro)
|
||||
*
|
||||
* In addition to these platform device attributes the driver
|
||||
* registers itself in the Linux backlight control subsystem and is
|
||||
* available to userspace under /sys/class/backlight/compal-laptop/.
|
||||
* The driver registers itself with the rfkill subsystem and
|
||||
* the Linux backlight control subsystem.
|
||||
*
|
||||
* This driver might work on other laptops produced by Compal. If you
|
||||
* want to try it you can pass force=1 as argument to the module which
|
||||
|
@ -51,6 +42,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
||||
#define COMPAL_DRIVER_VERSION "0.2.6"
|
||||
|
||||
|
@ -63,6 +55,10 @@
|
|||
#define WLAN_MASK 0x01
|
||||
#define BT_MASK 0x02
|
||||
|
||||
static struct rfkill *wifi_rfkill;
|
||||
static struct rfkill *bt_rfkill;
|
||||
static struct platform_device *compal_device;
|
||||
|
||||
static int force;
|
||||
module_param(force, bool, 0);
|
||||
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
|
||||
|
@ -88,65 +84,75 @@ static int get_lcd_level(void)
|
|||
return (int) result;
|
||||
}
|
||||
|
||||
static int set_wlan_state(int state)
|
||||
static int compal_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
unsigned long radio = (unsigned long) data;
|
||||
u8 result, value;
|
||||
|
||||
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
|
||||
|
||||
if ((result & KILLSWITCH_MASK) == 0)
|
||||
return -EINVAL;
|
||||
else {
|
||||
if (state)
|
||||
value = (u8) (result | WLAN_MASK);
|
||||
else
|
||||
value = (u8) (result & ~WLAN_MASK);
|
||||
ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
|
||||
}
|
||||
if (!blocked)
|
||||
value = (u8) (result | radio);
|
||||
else
|
||||
value = (u8) (result & ~radio);
|
||||
ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_bluetooth_state(int state)
|
||||
{
|
||||
u8 result, value;
|
||||
|
||||
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
|
||||
|
||||
if ((result & KILLSWITCH_MASK) == 0)
|
||||
return -EINVAL;
|
||||
else {
|
||||
if (state)
|
||||
value = (u8) (result | BT_MASK);
|
||||
else
|
||||
value = (u8) (result & ~BT_MASK);
|
||||
ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_wireless_state(int *wlan, int *bluetooth)
|
||||
static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
|
||||
{
|
||||
u8 result;
|
||||
bool hw_blocked;
|
||||
|
||||
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
|
||||
|
||||
if (wlan) {
|
||||
if ((result & KILLSWITCH_MASK) == 0)
|
||||
*wlan = 0;
|
||||
else
|
||||
*wlan = result & WLAN_MASK;
|
||||
}
|
||||
hw_blocked = !(result & KILLSWITCH_MASK);
|
||||
rfkill_set_hw_state(rfkill, hw_blocked);
|
||||
}
|
||||
|
||||
if (bluetooth) {
|
||||
if ((result & KILLSWITCH_MASK) == 0)
|
||||
*bluetooth = 0;
|
||||
else
|
||||
*bluetooth = (result & BT_MASK) >> 1;
|
||||
static const struct rfkill_ops compal_rfkill_ops = {
|
||||
.poll = compal_rfkill_poll,
|
||||
.set_block = compal_rfkill_set,
|
||||
};
|
||||
|
||||
static int setup_rfkill(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
|
||||
RFKILL_TYPE_WLAN, &compal_rfkill_ops,
|
||||
(void *) WLAN_MASK);
|
||||
if (!wifi_rfkill)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rfkill_register(wifi_rfkill);
|
||||
if (ret)
|
||||
goto err_wifi;
|
||||
|
||||
bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
|
||||
(void *) BT_MASK);
|
||||
if (!bt_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
goto err_allocate_bt;
|
||||
}
|
||||
ret = rfkill_register(bt_rfkill);
|
||||
if (ret)
|
||||
goto err_register_bt;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_bt:
|
||||
rfkill_destroy(bt_rfkill);
|
||||
|
||||
err_allocate_bt:
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
|
||||
err_wifi:
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Backlight device stuff */
|
||||
|
@ -169,86 +175,6 @@ static struct backlight_ops compalbl_ops = {
|
|||
|
||||
static struct backlight_device *compalbl_device;
|
||||
|
||||
/* Platform device */
|
||||
|
||||
static ssize_t show_wlan(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret, enabled;
|
||||
|
||||
ret = get_wireless_state(&enabled, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", enabled);
|
||||
}
|
||||
|
||||
static ssize_t show_raw(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
u8 result;
|
||||
|
||||
ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
|
||||
|
||||
return sprintf(buf, "%i\n", result);
|
||||
}
|
||||
|
||||
static ssize_t show_bluetooth(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int ret, enabled;
|
||||
|
||||
ret = get_wireless_state(NULL, &enabled);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%i\n", enabled);
|
||||
}
|
||||
|
||||
static ssize_t store_wlan_state(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int state, ret;
|
||||
|
||||
if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
|
||||
return -EINVAL;
|
||||
|
||||
ret = set_wlan_state(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t store_bluetooth_state(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int state, ret;
|
||||
|
||||
if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
|
||||
return -EINVAL;
|
||||
|
||||
ret = set_bluetooth_state(state);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
|
||||
static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
|
||||
static DEVICE_ATTR(raw, 0444, show_raw, NULL);
|
||||
|
||||
static struct attribute *compal_attributes[] = {
|
||||
&dev_attr_bluetooth.attr,
|
||||
&dev_attr_wlan.attr,
|
||||
&dev_attr_raw.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group compal_attribute_group = {
|
||||
.attrs = compal_attributes
|
||||
};
|
||||
|
||||
static struct platform_driver compal_driver = {
|
||||
.driver = {
|
||||
|
@ -257,8 +183,6 @@ static struct platform_driver compal_driver = {
|
|||
}
|
||||
};
|
||||
|
||||
static struct platform_device *compal_device;
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static int dmi_check_cb(const struct dmi_system_id *id)
|
||||
|
@ -310,6 +234,47 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
|
|||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 9",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 10v",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Dell Inspiron 11z",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 12",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
|
||||
},
|
||||
.callback = dmi_check_cb
|
||||
},
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -348,23 +313,21 @@ static int __init compal_init(void)
|
|||
|
||||
ret = platform_device_add(compal_device);
|
||||
if (ret)
|
||||
goto fail_platform_device1;
|
||||
goto fail_platform_device;
|
||||
|
||||
ret = sysfs_create_group(&compal_device->dev.kobj,
|
||||
&compal_attribute_group);
|
||||
ret = setup_rfkill();
|
||||
if (ret)
|
||||
goto fail_platform_device2;
|
||||
goto fail_rfkill;
|
||||
|
||||
printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
|
||||
" successfully loaded.\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_platform_device2:
|
||||
|
||||
fail_rfkill:
|
||||
platform_device_del(compal_device);
|
||||
|
||||
fail_platform_device1:
|
||||
fail_platform_device:
|
||||
|
||||
platform_device_put(compal_device);
|
||||
|
||||
|
@ -382,10 +345,13 @@ static int __init compal_init(void)
|
|||
static void __exit compal_cleanup(void)
|
||||
{
|
||||
|
||||
sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
|
||||
platform_device_unregister(compal_device);
|
||||
platform_driver_unregister(&compal_driver);
|
||||
backlight_device_unregister(compalbl_device);
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
rfkill_unregister(bt_rfkill);
|
||||
rfkill_destroy(bt_rfkill);
|
||||
|
||||
printk(KERN_INFO "compal-laptop: driver unloaded.\n");
|
||||
}
|
||||
|
@ -403,3 +369,8 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
|
|||
MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
|
||||
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <linux/rfkill.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/i8042.h>
|
||||
#include "../../firmware/dcdbas.h"
|
||||
|
||||
#define BRIGHTNESS_TOKEN 0x7d
|
||||
|
@ -79,9 +81,73 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
|
|||
DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Computer Corporation",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
|
||||
DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct dmi_system_id __devinitdata dell_blacklist[] = {
|
||||
/* Supported by compal-laptop */
|
||||
{
|
||||
.ident = "Dell Mini 9",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 10v",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Inspiron 11z",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Dell Mini 12",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct calling_interface_buffer *buffer;
|
||||
struct page *bufferpage;
|
||||
DEFINE_MUTEX(buffer_mutex);
|
||||
|
||||
static int hwswitch_state;
|
||||
|
||||
static void get_buffer(void)
|
||||
{
|
||||
mutex_lock(&buffer_mutex);
|
||||
memset(buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
}
|
||||
|
||||
static void release_buffer(void)
|
||||
{
|
||||
mutex_unlock(&buffer_mutex);
|
||||
}
|
||||
|
||||
static void __init parse_da_table(const struct dmi_header *dm)
|
||||
{
|
||||
/* Final token is a terminator, so we don't want to copy it */
|
||||
|
@ -160,6 +226,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
|
|||
/* Derived from information in DellWirelessCtl.cpp:
|
||||
Class 17, select 11 is radio control. It returns an array of 32-bit values.
|
||||
|
||||
Input byte 0 = 0: Wireless information
|
||||
|
||||
result[0]: return code
|
||||
result[1]:
|
||||
Bit 0: Hardware switch supported
|
||||
|
@ -180,33 +248,62 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
|
|||
Bits 20-31: Reserved
|
||||
result[2]: NVRAM size in bytes
|
||||
result[3]: NVRAM format version number
|
||||
|
||||
Input byte 0 = 2: Wireless switch configuration
|
||||
result[0]: return code
|
||||
result[1]:
|
||||
Bit 0: Wifi controlled by switch
|
||||
Bit 1: Bluetooth controlled by switch
|
||||
Bit 2: WWAN controlled by switch
|
||||
Bits 3-6: Reserved
|
||||
Bit 7: Wireless switch config locked
|
||||
Bit 8: Wifi locator enabled
|
||||
Bits 9-14: Reserved
|
||||
Bit 15: Wifi locator setting locked
|
||||
Bits 16-31: Reserved
|
||||
*/
|
||||
|
||||
static int dell_rfkill_set(void *data, bool blocked)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int disable = blocked ? 1 : 0;
|
||||
unsigned long radio = (unsigned long)data;
|
||||
int hwswitch_bit = (unsigned long)data - 1;
|
||||
int ret = 0;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer.input[0] = (1 | (radio<<8) | (disable << 16));
|
||||
dell_send_request(&buffer, 17, 11);
|
||||
get_buffer();
|
||||
dell_send_request(buffer, 17, 11);
|
||||
|
||||
return 0;
|
||||
/* If the hardware switch controls this radio, and the hardware
|
||||
switch is disabled, don't allow changing the software state */
|
||||
if ((hwswitch_state & BIT(hwswitch_bit)) &&
|
||||
!(buffer->output[1] & BIT(16))) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer->input[0] = (1 | (radio<<8) | (disable << 16));
|
||||
dell_send_request(buffer, 17, 11);
|
||||
|
||||
out:
|
||||
release_buffer();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int status;
|
||||
int bit = (unsigned long)data + 16;
|
||||
int hwswitch_bit = (unsigned long)data - 1;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
dell_send_request(&buffer, 17, 11);
|
||||
status = buffer.output[1];
|
||||
get_buffer();
|
||||
dell_send_request(buffer, 17, 11);
|
||||
status = buffer->output[1];
|
||||
release_buffer();
|
||||
|
||||
rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
|
||||
rfkill_set_hw_state(rfkill, !(status & BIT(16)));
|
||||
|
||||
if (hwswitch_state & (BIT(hwswitch_bit)))
|
||||
rfkill_set_hw_state(rfkill, !(status & BIT(16)));
|
||||
}
|
||||
|
||||
static const struct rfkill_ops dell_rfkill_ops = {
|
||||
|
@ -214,15 +311,36 @@ static const struct rfkill_ops dell_rfkill_ops = {
|
|||
.query = dell_rfkill_query,
|
||||
};
|
||||
|
||||
static void dell_update_rfkill(struct work_struct *ignored)
|
||||
{
|
||||
if (wifi_rfkill)
|
||||
dell_rfkill_query(wifi_rfkill, (void *)1);
|
||||
if (bluetooth_rfkill)
|
||||
dell_rfkill_query(bluetooth_rfkill, (void *)2);
|
||||
if (wwan_rfkill)
|
||||
dell_rfkill_query(wwan_rfkill, (void *)3);
|
||||
}
|
||||
static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
|
||||
|
||||
|
||||
static int __init dell_setup_rfkill(void)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
dell_send_request(&buffer, 17, 11);
|
||||
status = buffer.output[1];
|
||||
if (dmi_check_system(dell_blacklist)) {
|
||||
printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - "
|
||||
"not enabling rfkill\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
get_buffer();
|
||||
dell_send_request(buffer, 17, 11);
|
||||
status = buffer->output[1];
|
||||
buffer->input[0] = 0x2;
|
||||
dell_send_request(buffer, 17, 11);
|
||||
hwswitch_state = buffer->output[1];
|
||||
release_buffer();
|
||||
|
||||
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
|
||||
wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
|
||||
|
@ -298,39 +416,49 @@ static void dell_cleanup_rfkill(void)
|
|||
|
||||
static int dell_send_intensity(struct backlight_device *bd)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int ret = 0;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
buffer.input[1] = bd->props.brightness;
|
||||
get_buffer();
|
||||
buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
buffer->input[1] = bd->props.brightness;
|
||||
|
||||
if (buffer.input[0] == -1)
|
||||
return -ENODEV;
|
||||
if (buffer->input[0] == -1) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
dell_send_request(&buffer, 1, 2);
|
||||
dell_send_request(buffer, 1, 2);
|
||||
else
|
||||
dell_send_request(&buffer, 1, 1);
|
||||
dell_send_request(buffer, 1, 1);
|
||||
|
||||
out:
|
||||
release_buffer();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dell_get_intensity(struct backlight_device *bd)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int ret = 0;
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
get_buffer();
|
||||
buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
|
||||
if (buffer.input[0] == -1)
|
||||
return -ENODEV;
|
||||
if (buffer->input[0] == -1) {
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (power_supply_is_system_supplied() > 0)
|
||||
dell_send_request(&buffer, 0, 2);
|
||||
dell_send_request(buffer, 0, 2);
|
||||
else
|
||||
dell_send_request(&buffer, 0, 1);
|
||||
dell_send_request(buffer, 0, 1);
|
||||
|
||||
return buffer.output[1];
|
||||
out:
|
||||
release_buffer();
|
||||
if (ret)
|
||||
return ret;
|
||||
return buffer->output[1];
|
||||
}
|
||||
|
||||
static struct backlight_ops dell_ops = {
|
||||
|
@ -338,9 +466,32 @@ static struct backlight_ops dell_ops = {
|
|||
.update_status = dell_send_intensity,
|
||||
};
|
||||
|
||||
bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
|
||||
struct serio *port)
|
||||
{
|
||||
static bool extended;
|
||||
|
||||
if (str & 0x20)
|
||||
return false;
|
||||
|
||||
if (unlikely(data == 0xe0)) {
|
||||
extended = true;
|
||||
return false;
|
||||
} else if (unlikely(extended)) {
|
||||
switch (data) {
|
||||
case 0x8:
|
||||
schedule_delayed_work(&dell_rfkill_work,
|
||||
round_jiffies_relative(HZ));
|
||||
break;
|
||||
}
|
||||
extended = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __init dell_init(void)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int max_intensity = 0;
|
||||
int ret;
|
||||
|
||||
|
@ -366,6 +517,17 @@ static int __init dell_init(void)
|
|||
if (ret)
|
||||
goto fail_platform_device2;
|
||||
|
||||
/*
|
||||
* Allocate buffer below 4GB for SMI data--only 32-bit physical addr
|
||||
* is passed to SMI handler.
|
||||
*/
|
||||
bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
|
||||
|
||||
if (!bufferpage)
|
||||
goto fail_buffer;
|
||||
buffer = page_address(bufferpage);
|
||||
mutex_init(&buffer_mutex);
|
||||
|
||||
ret = dell_setup_rfkill();
|
||||
|
||||
if (ret) {
|
||||
|
@ -373,6 +535,13 @@ static int __init dell_init(void)
|
|||
goto fail_rfkill;
|
||||
}
|
||||
|
||||
ret = i8042_install_filter(dell_laptop_i8042_filter);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING
|
||||
"dell-laptop: Unable to install key filter\n");
|
||||
goto fail_filter;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
/* In the event of an ACPI backlight being available, don't
|
||||
* register the platform controller.
|
||||
|
@ -381,13 +550,13 @@ static int __init dell_init(void)
|
|||
return 0;
|
||||
#endif
|
||||
|
||||
memset(&buffer, 0, sizeof(struct calling_interface_buffer));
|
||||
buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
|
||||
if (buffer.input[0] != -1) {
|
||||
dell_send_request(&buffer, 0, 2);
|
||||
max_intensity = buffer.output[3];
|
||||
get_buffer();
|
||||
buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
|
||||
if (buffer->input[0] != -1) {
|
||||
dell_send_request(buffer, 0, 2);
|
||||
max_intensity = buffer->output[3];
|
||||
}
|
||||
release_buffer();
|
||||
|
||||
if (max_intensity) {
|
||||
dell_backlight_device = backlight_device_register(
|
||||
|
@ -410,8 +579,12 @@ static int __init dell_init(void)
|
|||
return 0;
|
||||
|
||||
fail_backlight:
|
||||
i8042_remove_filter(dell_laptop_i8042_filter);
|
||||
fail_filter:
|
||||
dell_cleanup_rfkill();
|
||||
fail_rfkill:
|
||||
free_page((unsigned long)bufferpage);
|
||||
fail_buffer:
|
||||
platform_device_del(platform_device);
|
||||
fail_platform_device2:
|
||||
platform_device_put(platform_device);
|
||||
|
@ -424,8 +597,16 @@ static int __init dell_init(void)
|
|||
|
||||
static void __exit dell_exit(void)
|
||||
{
|
||||
cancel_delayed_work_sync(&dell_rfkill_work);
|
||||
i8042_remove_filter(dell_laptop_i8042_filter);
|
||||
backlight_device_unregister(dell_backlight_device);
|
||||
dell_cleanup_rfkill();
|
||||
if (platform_device) {
|
||||
platform_device_del(platform_device);
|
||||
platform_driver_unregister(&platform_driver);
|
||||
}
|
||||
kfree(da_tokens);
|
||||
free_page((unsigned long)buffer);
|
||||
}
|
||||
|
||||
module_init(dell_init);
|
||||
|
@ -435,3 +616,4 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
|||
MODULE_DESCRIPTION("Dell laptop driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
|
||||
MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
|
||||
|
|
|
@ -89,6 +89,7 @@ static struct key_entry hp_wmi_keymap[] = {
|
|||
{KE_KEY, 0x20e6, KEY_PROG1},
|
||||
{KE_KEY, 0x2142, KEY_MEDIA},
|
||||
{KE_KEY, 0x213b, KEY_INFO},
|
||||
{KE_KEY, 0x2169, KEY_DIRECTION},
|
||||
{KE_KEY, 0x231b, KEY_HELP},
|
||||
{KE_END, 0}
|
||||
};
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include <linux/backlight.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -62,9 +63,10 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
/* Toshiba ACPI method paths */
|
||||
#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
|
||||
#define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
|
||||
#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
|
||||
#define TOSH_INTERFACE_1 "\\_SB_.VALD"
|
||||
#define TOSH_INTERFACE_2 "\\_SB_.VALZ"
|
||||
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
|
||||
#define GHCI_METHOD ".GHCI"
|
||||
|
||||
/* Toshiba HCI interface definitions
|
||||
*
|
||||
|
@ -116,6 +118,36 @@ static const struct acpi_device_id toshiba_device_ids[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
|
||||
|
||||
struct key_entry {
|
||||
char type;
|
||||
u16 code;
|
||||
u16 keycode;
|
||||
};
|
||||
|
||||
enum {KE_KEY, KE_END};
|
||||
|
||||
static struct key_entry toshiba_acpi_keymap[] = {
|
||||
{KE_KEY, 0x101, KEY_MUTE},
|
||||
{KE_KEY, 0x13b, KEY_COFFEE},
|
||||
{KE_KEY, 0x13c, KEY_BATTERY},
|
||||
{KE_KEY, 0x13d, KEY_SLEEP},
|
||||
{KE_KEY, 0x13e, KEY_SUSPEND},
|
||||
{KE_KEY, 0x13f, KEY_SWITCHVIDEOMODE},
|
||||
{KE_KEY, 0x140, KEY_BRIGHTNESSDOWN},
|
||||
{KE_KEY, 0x141, KEY_BRIGHTNESSUP},
|
||||
{KE_KEY, 0x142, KEY_WLAN},
|
||||
{KE_KEY, 0x143, KEY_PROG1},
|
||||
{KE_KEY, 0xb05, KEY_PROG2},
|
||||
{KE_KEY, 0xb06, KEY_WWW},
|
||||
{KE_KEY, 0xb07, KEY_MAIL},
|
||||
{KE_KEY, 0xb30, KEY_STOP},
|
||||
{KE_KEY, 0xb31, KEY_PREVIOUSSONG},
|
||||
{KE_KEY, 0xb32, KEY_NEXTSONG},
|
||||
{KE_KEY, 0xb33, KEY_PLAYPAUSE},
|
||||
{KE_KEY, 0xb5a, KEY_MEDIA},
|
||||
{KE_END, 0, 0},
|
||||
};
|
||||
|
||||
/* utility
|
||||
*/
|
||||
|
||||
|
@ -251,6 +283,8 @@ static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
|
|||
struct toshiba_acpi_dev {
|
||||
struct platform_device *p_dev;
|
||||
struct rfkill *bt_rfk;
|
||||
struct input_dev *hotkey_dev;
|
||||
acpi_handle handle;
|
||||
|
||||
const char *bt_name;
|
||||
|
||||
|
@ -711,8 +745,159 @@ static struct backlight_ops toshiba_backlight_data = {
|
|||
.update_status = set_lcd_status,
|
||||
};
|
||||
|
||||
static struct key_entry *toshiba_acpi_get_entry_by_scancode(int code)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
||||
for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
|
||||
if (code == key->code)
|
||||
return key;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct key_entry *toshiba_acpi_get_entry_by_keycode(int code)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
||||
for (key = toshiba_acpi_keymap; key->type != KE_END; key++)
|
||||
if (code == key->keycode && key->type == KE_KEY)
|
||||
return key;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int toshiba_acpi_getkeycode(struct input_dev *dev, int scancode,
|
||||
int *keycode)
|
||||
{
|
||||
struct key_entry *key = toshiba_acpi_get_entry_by_scancode(scancode);
|
||||
|
||||
if (key && key->type == KE_KEY) {
|
||||
*keycode = key->keycode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int toshiba_acpi_setkeycode(struct input_dev *dev, int scancode,
|
||||
int keycode)
|
||||
{
|
||||
struct key_entry *key;
|
||||
int old_keycode;
|
||||
|
||||
if (keycode < 0 || keycode > KEY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
key = toshiba_acpi_get_entry_by_scancode(scancode);
|
||||
if (key && key->type == KE_KEY) {
|
||||
old_keycode = key->keycode;
|
||||
key->keycode = keycode;
|
||||
set_bit(keycode, dev->keybit);
|
||||
if (!toshiba_acpi_get_entry_by_keycode(old_keycode))
|
||||
clear_bit(old_keycode, dev->keybit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_notify(acpi_handle handle, u32 event, void *context)
|
||||
{
|
||||
u32 hci_result, value;
|
||||
struct key_entry *key;
|
||||
|
||||
if (event != 0x80)
|
||||
return;
|
||||
do {
|
||||
hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
|
||||
if (hci_result == HCI_SUCCESS) {
|
||||
if (value == 0x100)
|
||||
continue;
|
||||
else if (value & 0x80) {
|
||||
key = toshiba_acpi_get_entry_by_scancode
|
||||
(value & ~0x80);
|
||||
if (!key) {
|
||||
printk(MY_INFO "Unknown key %x\n",
|
||||
value & ~0x80);
|
||||
continue;
|
||||
}
|
||||
input_report_key(toshiba_acpi.hotkey_dev,
|
||||
key->keycode, 1);
|
||||
input_sync(toshiba_acpi.hotkey_dev);
|
||||
input_report_key(toshiba_acpi.hotkey_dev,
|
||||
key->keycode, 0);
|
||||
input_sync(toshiba_acpi.hotkey_dev);
|
||||
}
|
||||
} else if (hci_result == HCI_NOT_SUPPORTED) {
|
||||
/* This is a workaround for an unresolved issue on
|
||||
* some machines where system events sporadically
|
||||
* become disabled. */
|
||||
hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
|
||||
printk(MY_NOTICE "Re-enabled hotkeys\n");
|
||||
}
|
||||
} while (hci_result != HCI_EMPTY);
|
||||
}
|
||||
|
||||
static int toshiba_acpi_setup_keyboard(char *device)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_handle handle;
|
||||
int result;
|
||||
const struct key_entry *key;
|
||||
|
||||
status = acpi_get_handle(NULL, device, &handle);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(MY_INFO "Unable to get notification device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
toshiba_acpi.handle = handle;
|
||||
|
||||
status = acpi_evaluate_object(handle, "ENAB", NULL, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(MY_INFO "Unable to enable hotkeys\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_acpi_notify, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(MY_INFO "Unable to install hotkey notification\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
toshiba_acpi.hotkey_dev = input_allocate_device();
|
||||
if (!toshiba_acpi.hotkey_dev) {
|
||||
printk(MY_INFO "Unable to register input device\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
toshiba_acpi.hotkey_dev->name = "Toshiba input device";
|
||||
toshiba_acpi.hotkey_dev->phys = device;
|
||||
toshiba_acpi.hotkey_dev->id.bustype = BUS_HOST;
|
||||
toshiba_acpi.hotkey_dev->getkeycode = toshiba_acpi_getkeycode;
|
||||
toshiba_acpi.hotkey_dev->setkeycode = toshiba_acpi_setkeycode;
|
||||
|
||||
for (key = toshiba_acpi_keymap; key->type != KE_END; key++) {
|
||||
set_bit(EV_KEY, toshiba_acpi.hotkey_dev->evbit);
|
||||
set_bit(key->keycode, toshiba_acpi.hotkey_dev->keybit);
|
||||
}
|
||||
|
||||
result = input_register_device(toshiba_acpi.hotkey_dev);
|
||||
if (result) {
|
||||
printk(MY_INFO "Unable to register input device\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void toshiba_acpi_exit(void)
|
||||
{
|
||||
if (toshiba_acpi.hotkey_dev)
|
||||
input_unregister_device(toshiba_acpi.hotkey_dev);
|
||||
|
||||
if (toshiba_acpi.bt_rfk) {
|
||||
rfkill_unregister(toshiba_acpi.bt_rfk);
|
||||
rfkill_destroy(toshiba_acpi.bt_rfk);
|
||||
|
@ -726,6 +911,9 @@ static void toshiba_acpi_exit(void)
|
|||
if (toshiba_proc_dir)
|
||||
remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
|
||||
|
||||
acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY,
|
||||
toshiba_acpi_notify);
|
||||
|
||||
platform_device_unregister(toshiba_acpi.p_dev);
|
||||
|
||||
return;
|
||||
|
@ -742,11 +930,15 @@ static int __init toshiba_acpi_init(void)
|
|||
return -ENODEV;
|
||||
|
||||
/* simple device detection: look for HCI method */
|
||||
if (is_valid_acpi_path(METHOD_HCI_1))
|
||||
method_hci = METHOD_HCI_1;
|
||||
else if (is_valid_acpi_path(METHOD_HCI_2))
|
||||
method_hci = METHOD_HCI_2;
|
||||
else
|
||||
if (is_valid_acpi_path(TOSH_INTERFACE_1 GHCI_METHOD)) {
|
||||
method_hci = TOSH_INTERFACE_1 GHCI_METHOD;
|
||||
if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_1))
|
||||
printk(MY_INFO "Unable to activate hotkeys\n");
|
||||
} else if (is_valid_acpi_path(TOSH_INTERFACE_2 GHCI_METHOD)) {
|
||||
method_hci = TOSH_INTERFACE_2 GHCI_METHOD;
|
||||
if (toshiba_acpi_setup_keyboard(TOSH_INTERFACE_2))
|
||||
printk(MY_INFO "Unable to activate hotkeys\n");
|
||||
} else
|
||||
return -ENODEV;
|
||||
|
||||
printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
|
||||
|
|
Loading…
Reference in a new issue