From c215ab9a7530d415707430de8d51a58ca6a41808 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 25 Nov 2011 04:09:37 +0000 Subject: [PATCH 1/4] x86: Add amilo-rfkill driver for some Fujitsu-Siemens Amilo laptops An rfkill driver based on the fsaa1655g and fsam7440 drivers for Fujitsu-Siemens Amilo A1655 and M7440 models found at: http://sourceforge.net/projects/fsaa1655g/ http://sourceforge.net/projects/fsam7440/ This adds DMI matching, replaces the procfs files with rfkill devices, and uses the proper functions to write to the i8042 safely. Signed-off-by: Ben Hutchings Signed-off-by: Matthew Garrett --- drivers/platform/x86/Kconfig | 7 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/amilo-rfkill.c | 173 ++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 drivers/platform/x86/amilo-rfkill.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f995e6e2f78c..c405b278e349 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -143,6 +143,13 @@ config FUJITSU_LAPTOP_DEBUG If you are not sure, say N here. +config AMILO_RFKILL + tristate "Fujitsu-Siemens Amilo rfkill support" + depends on RFKILL + ---help--- + This is a driver for enabling wifi on some Fujitsu-Siemens Amilo + laptops. + config TC1100_WMI tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" depends on !X86_64 diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 293a320d9faa..3acbaad66682 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ACERHDF) += acerhdf.o obj-$(CONFIG_HP_ACCEL) += hp_accel.o obj-$(CONFIG_HP_WMI) += hp-wmi.o +obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c new file mode 100644 index 000000000000..19170bb7700b --- /dev/null +++ b/drivers/platform/x86/amilo-rfkill.c @@ -0,0 +1,173 @@ +/* + * Support for rfkill on some Fujitsu-Siemens Amilo laptops. + * Copyright 2011 Ben Hutchings. + * + * Based in part on the fsam7440 driver, which is: + * Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata. + * and on the fsaa1655g driver, which is: + * Copyright 2006 Martin Večeřa. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * These values were obtained from disassembling and debugging the + * PM.exe program installed in the Fujitsu-Siemens AMILO A1655G + */ +#define A1655_WIFI_COMMAND 0x10C5 +#define A1655_WIFI_ON 0x25 +#define A1655_WIFI_OFF 0x45 + +static int amilo_a1655_rfkill_set_block(void *data, bool blocked) +{ + u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON; + int rc; + + i8042_lock_chip(); + rc = i8042_command(¶m, A1655_WIFI_COMMAND); + i8042_unlock_chip(); + return rc; +} + +static const struct rfkill_ops amilo_a1655_rfkill_ops = { + .set_block = amilo_a1655_rfkill_set_block +}; + +/* + * These values were obtained from disassembling the PM.exe program + * installed in the Fujitsu-Siemens AMILO M 7440 + */ +#define M7440_PORT1 0x118f +#define M7440_PORT2 0x118e +#define M7440_RADIO_ON1 0x12 +#define M7440_RADIO_ON2 0x80 +#define M7440_RADIO_OFF1 0x10 +#define M7440_RADIO_OFF2 0x00 + +static int amilo_m7440_rfkill_set_block(void *data, bool blocked) +{ + u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1; + u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2; + + outb(val1, M7440_PORT1); + outb(val2, M7440_PORT2); + + /* Check whether the state has changed correctly */ + if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2) + return -EIO; + + return 0; +} + +static const struct rfkill_ops amilo_m7440_rfkill_ops = { + .set_block = amilo_m7440_rfkill_set_block +}; + +static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"), + }, + .driver_data = (void *)&amilo_a1655_rfkill_ops + }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"), + }, + .driver_data = (void *)&amilo_m7440_rfkill_ops + }, + {} +}; + +static struct platform_device *amilo_rfkill_pdev; +static struct rfkill *amilo_rfkill_dev; + +static int __devinit amilo_rfkill_probe(struct platform_device *device) +{ + const struct dmi_system_id *system_id = + dmi_first_match(amilo_rfkill_id_table); + int rc; + + amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev, + RFKILL_TYPE_WLAN, + system_id->driver_data, NULL); + if (!amilo_rfkill_dev) + return -ENOMEM; + + rc = rfkill_register(amilo_rfkill_dev); + if (rc) + goto fail; + + return 0; + +fail: + rfkill_destroy(amilo_rfkill_dev); + return rc; +} + +static int amilo_rfkill_remove(struct platform_device *device) +{ + rfkill_unregister(amilo_rfkill_dev); + rfkill_destroy(amilo_rfkill_dev); + return 0; +} + +static struct platform_driver amilo_rfkill_driver = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = amilo_rfkill_probe, + .remove = amilo_rfkill_remove, +}; + +static int __init amilo_rfkill_init(void) +{ + int rc; + + if (dmi_first_match(amilo_rfkill_id_table) == NULL) + return -ENODEV; + + rc = platform_driver_register(&amilo_rfkill_driver); + if (rc) + return rc; + + amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1, + NULL, 0); + if (IS_ERR(amilo_rfkill_pdev)) { + rc = PTR_ERR(amilo_rfkill_pdev); + goto fail; + } + + return 0; + +fail: + platform_driver_unregister(&amilo_rfkill_driver); + return rc; +} + +static void __exit amilo_rfkill_exit(void) +{ + platform_device_unregister(amilo_rfkill_pdev); + platform_driver_unregister(&amilo_rfkill_driver); +} + +MODULE_AUTHOR("Ben Hutchings "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table); + +module_init(amilo_rfkill_init); +module_exit(amilo_rfkill_exit); From 2d24c49080afdb80816f6cedaef0e3999f344c4b Mon Sep 17 00:00:00 2001 From: Robert Gerlach Date: Wed, 18 Jan 2012 14:26:22 +0100 Subject: [PATCH 2/4] Fujitsu tablet extras driver This patch adds support for some of the devices within a wide variety of Fujitsu Tablet Computers, both convertibles and slates. Primarily it allows for the automatic detection of the tablet/notebook mode for convertible tablet pc's, and orientation for docked slates. It also adds support for the application panel buttons usually found next to the tablet screen, and docking station detection for slates. Signed-off-by: Robert Gerlach Signed-off-by: Matthew Garrett --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 17 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/fujitsu-tablet.c | 478 ++++++++++++++++++++++++++ 4 files changed, 502 insertions(+) create mode 100644 drivers/platform/x86/fujitsu-tablet.c diff --git a/MAINTAINERS b/MAINTAINERS index 3321d75c6c7f..95e4e43a12b4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2845,6 +2845,12 @@ S: Maintained F: drivers/media/video/m5mols/ F: include/media/m5mols.h +FUJITSU TABLET EXTRAS +M: Robert Gerlach +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/x86/fujitsu-tablet.c + FUSE: FILESYSTEM IN USERSPACE M: Miklos Szeredi L: fuse-devel@lists.sourceforge.net diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index c405b278e349..15dbd8cc445f 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -143,6 +143,23 @@ config FUJITSU_LAPTOP_DEBUG If you are not sure, say N here. +config FUJITSU_TABLET + tristate "Fujitsu Tablet Extras" + depends on ACPI + depends on INPUT + ---help--- + This is a driver for tablets built by Fujitsu: + + * Lifebook P1510/P1610/P1620/Txxxx + * Stylistic ST5xxx + * Possibly other Fujitsu tablet models + + It adds support for the panel buttons, docking station detection, + tablet/notebook mode detection for convertible and + orientation detection for docked slates. + + If you have a Fujitsu convertible or slate, say Y or M here. + config AMILO_RFKILL tristate "Fujitsu-Siemens Amilo rfkill support" depends on RFKILL diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 3acbaad66682..d328f21e9fdd 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o +obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ACPI_WMI) += wmi.o diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c new file mode 100644 index 000000000000..580d80a73c3a --- /dev/null +++ b/drivers/platform/x86/fujitsu-tablet.c @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2006-2012 Robert Gerlach + * Copyright (C) 2005-2006 Jan Rychter + * + * You can redistribute and/or modify this program under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MODULENAME "fujitsu-tablet" + +#define ACPI_FUJITSU_CLASS "fujitsu" + +#define INVERT_TABLET_MODE_BIT 0x01 +#define FORCE_TABLET_MODE_IF_UNDOCK 0x02 + +#define KEYMAP_LEN 16 + +static const struct acpi_device_id fujitsu_ids[] = { + { .id = "FUJ02BD" }, + { .id = "FUJ02BF" }, + { .id = "" } +}; + +struct fujitsu_config { + unsigned short keymap[KEYMAP_LEN]; + unsigned int quirks; +}; + +static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_SCROLLDOWN, + KEY_SCROLLUP, + KEY_DIRECTION, + KEY_LEFTCTRL, + KEY_BRIGHTNESSUP, + KEY_BRIGHTNESSDOWN, + KEY_BRIGHTNESS_ZERO, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_LEFTALT +}; + +static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PROG1, + KEY_PROG2, + KEY_DIRECTION, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_UP, + KEY_DOWN, + KEY_RESERVED, + KEY_RESERVED, + KEY_LEFTCTRL, + KEY_LEFTALT +}; + +static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_PRINT, + KEY_BACKSPACE, + KEY_SPACE, + KEY_ENTER, + KEY_BRIGHTNESSUP, + KEY_BRIGHTNESSDOWN, + KEY_DOWN, + KEY_UP, + KEY_SCROLLUP, + KEY_SCROLLDOWN, + KEY_LEFTCTRL, + KEY_LEFTALT +}; + +static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initconst = { + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_RESERVED, + KEY_MAIL, + KEY_DIRECTION, + KEY_ESC, + KEY_ENTER, + KEY_BRIGHTNESSUP, + KEY_BRIGHTNESSDOWN, + KEY_DOWN, + KEY_UP, + KEY_SCROLLUP, + KEY_SCROLLDOWN, + KEY_LEFTCTRL, + KEY_LEFTALT +}; + +static struct { + struct input_dev *idev; + struct fujitsu_config config; + unsigned long prev_keymask; + + char phys[21]; + + int irq; + int io_base; + int io_length; +} fujitsu; + +static u8 fujitsu_ack(void) +{ + return inb(fujitsu.io_base + 2); +} + +static u8 fujitsu_status(void) +{ + return inb(fujitsu.io_base + 6); +} + +static u8 fujitsu_read_register(const u8 addr) +{ + outb(addr, fujitsu.io_base); + return inb(fujitsu.io_base + 4); +} + +static void fujitsu_send_state(void) +{ + int state; + int dock, tablet_mode; + + state = fujitsu_read_register(0xdd); + + dock = state & 0x02; + + if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { + tablet_mode = 1; + } else{ + tablet_mode = state & 0x01; + if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT) + tablet_mode = !tablet_mode; + } + + input_report_switch(fujitsu.idev, SW_DOCK, dock); + input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode); + input_sync(fujitsu.idev); +} + +static void fujitsu_reset(void) +{ + int timeout = 50; + + fujitsu_ack(); + + while ((fujitsu_status() & 0x02) && (--timeout)) + msleep(20); + + fujitsu_send_state(); +} + +static int __devinit input_fujitsu_setup(struct device *parent, + const char *name, const char *phys) +{ + struct input_dev *idev; + int error; + int i; + + idev = input_allocate_device(); + if (!idev) + return -ENOMEM; + + idev->dev.parent = parent; + idev->phys = phys; + idev->name = name; + idev->id.bustype = BUS_HOST; + idev->id.vendor = 0x1734; /* Fujitsu Siemens Computer GmbH */ + idev->id.product = 0x0001; + idev->id.version = 0x0101; + + idev->keycode = fujitsu.config.keymap; + idev->keycodesize = sizeof(fujitsu.config.keymap[0]); + idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap); + + __set_bit(EV_REP, idev->evbit); + + for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++) + if (fujitsu.config.keymap[i]) + input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]); + + input_set_capability(idev, EV_MSC, MSC_SCAN); + + input_set_capability(idev, EV_SW, SW_DOCK); + input_set_capability(idev, EV_SW, SW_TABLET_MODE); + + input_set_capability(idev, EV_SW, SW_DOCK); + input_set_capability(idev, EV_SW, SW_TABLET_MODE); + + error = input_register_device(idev); + if (error) { + input_free_device(idev); + return error; + } + + fujitsu.idev = idev; + return 0; +} + +static void input_fujitsu_remove(void) +{ + input_unregister_device(fujitsu.idev); +} + +static irqreturn_t fujitsu_interrupt(int irq, void *dev_id) +{ + unsigned long keymask, changed; + unsigned int keycode; + int pressed; + int i; + + if (unlikely(!(fujitsu_status() & 0x01))) + return IRQ_NONE; + + fujitsu_send_state(); + + keymask = fujitsu_read_register(0xde); + keymask |= fujitsu_read_register(0xdf) << 8; + keymask ^= 0xffff; + + changed = keymask ^ fujitsu.prev_keymask; + if (changed) { + fujitsu.prev_keymask = keymask; + + for_each_set_bit(i, &changed, KEYMAP_LEN) { + keycode = fujitsu.config.keymap[i]; + pressed = keymask & changed & BIT(i); + + if (pressed) + input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i); + + input_report_key(fujitsu.idev, keycode, pressed); + input_sync(fujitsu.idev); + } + } + + fujitsu_ack(); + return IRQ_HANDLED; +} + +static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) +{ + printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); + memcpy(fujitsu.config.keymap, dmi->driver_data, + sizeof(fujitsu.config.keymap)); + return 1; +} + +static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) +{ + fujitsu_dmi_default(dmi); + fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; + fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; + return 1; +} + +static struct dmi_system_id dmi_ids[] __initconst = { + { + .callback = fujitsu_dmi_default, + .ident = "Fujitsu Siemens P/T Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK") + }, + .driver_data = keymap_Lifebook_Tseries + }, + { + .callback = fujitsu_dmi_default, + .ident = "Fujitsu Lifebook T Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T") + }, + .driver_data = keymap_Lifebook_Tseries + }, + { + .callback = fujitsu_dmi_stylistic, + .ident = "Fujitsu Siemens Stylistic T Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T") + }, + .driver_data = keymap_Stylistic_Tseries + }, + { + .callback = fujitsu_dmi_default, + .ident = "Fujitsu LifeBook U810", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810") + }, + .driver_data = keymap_Lifebook_U810 + }, + { + .callback = fujitsu_dmi_stylistic, + .ident = "Fujitsu Siemens Stylistic ST5xxx Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5") + }, + .driver_data = keymap_Stylistic_ST5xxx + }, + { + .callback = fujitsu_dmi_stylistic, + .ident = "Fujitsu Siemens Stylistic ST5xxx Series", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5") + }, + .driver_data = keymap_Stylistic_ST5xxx + }, + { + .callback = fujitsu_dmi_default, + .ident = "Unknown (using defaults)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, ""), + DMI_MATCH(DMI_PRODUCT_NAME, "") + }, + .driver_data = keymap_Lifebook_Tseries + }, + { NULL } +}; + +static acpi_status __devinit +fujitsu_walk_resources(struct acpi_resource *res, void *data) +{ + switch (res->type) { + case ACPI_RESOURCE_TYPE_IRQ: + fujitsu.irq = res->data.irq.interrupts[0]; + return AE_OK; + + case ACPI_RESOURCE_TYPE_IO: + fujitsu.io_base = res->data.io.minimum; + fujitsu.io_length = res->data.io.address_length; + return AE_OK; + + case ACPI_RESOURCE_TYPE_END_TAG: + if (fujitsu.irq && fujitsu.io_base) + return AE_OK; + else + return AE_NOT_FOUND; + + default: + return AE_ERROR; + } +} + +static int __devinit acpi_fujitsu_add(struct acpi_device *adev) +{ + acpi_status status; + int error; + + if (!adev) + return -EINVAL; + + status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, + fujitsu_walk_resources, NULL); + if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base) + return -ENODEV; + + sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev)); + sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS); + + snprintf(fujitsu.phys, sizeof(fujitsu.phys), + "%s/input0", acpi_device_hid(adev)); + + error = input_fujitsu_setup(&adev->dev, + acpi_device_name(adev), fujitsu.phys); + if (error) + return error; + + if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) { + input_fujitsu_remove(); + return -EBUSY; + } + + fujitsu_reset(); + + error = request_irq(fujitsu.irq, fujitsu_interrupt, + IRQF_SHARED, MODULENAME, fujitsu_interrupt); + if (error) { + release_region(fujitsu.io_base, fujitsu.io_length); + input_fujitsu_remove(); + return error; + } + + return 0; +} + +static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type) +{ + free_irq(fujitsu.irq, fujitsu_interrupt); + release_region(fujitsu.io_base, fujitsu.io_length); + input_fujitsu_remove(); + return 0; +} + +static int acpi_fujitsu_resume(struct acpi_device *adev) +{ + fujitsu_reset(); + return 0; +} + +static struct acpi_driver acpi_fujitsu_driver = { + .name = MODULENAME, + .class = "hotkey", + .ids = fujitsu_ids, + .ops = { + .add = acpi_fujitsu_add, + .remove = acpi_fujitsu_remove, + .resume = acpi_fujitsu_resume, + } +}; + +static int __init fujitsu_module_init(void) +{ + int error; + + dmi_check_system(dmi_ids); + + error = acpi_bus_register_driver(&acpi_fujitsu_driver); + if (error) + return error; + + return 0; +} + +static void __exit fujitsu_module_exit(void) +{ + acpi_bus_unregister_driver(&acpi_fujitsu_driver); +} + +module_init(fujitsu_module_init); +module_exit(fujitsu_module_exit); + +MODULE_AUTHOR("Robert Gerlach "); +MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("2.4"); + +MODULE_DEVICE_TABLE(acpi, fujitsu_ids); From 461e74377cfcfc2c0d6bbdfa8fc5fbc21b052c2a Mon Sep 17 00:00:00 2001 From: Ike Panhc Date: Fri, 3 Feb 2012 16:46:39 +0800 Subject: [PATCH 3/4] acer-wmi: No wifi rfkill on Lenovo machines We have several reports which says acer-wmi is loaded on ideapads and register rfkill for wifi which can not be unblocked. Since ideapad-laptop also register rfkill for wifi and it works reliably, it will be fine acer-wmi is not going to register rfkill for wifi once VPC2004 is found. Also put IBM0068/LEN0068 in the list. Though thinkpad_acpi has no wifi rfkill capability, there are reports which says acer-wmi also block wireless on Thinkpad E520/E420. Signed-off-by: Ike Panhc Signed-off-by: Matthew Garrett --- drivers/platform/x86/acer-wmi.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index b848277171a4..1e5290b5396d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -679,6 +679,32 @@ static acpi_status AMW0_find_mailled(void) return AE_OK; } +static int AMW0_set_cap_acpi_check_device_found; + +static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle, + u32 level, void *context, void **retval) +{ + AMW0_set_cap_acpi_check_device_found = 1; + return AE_OK; +} + +static const struct acpi_device_id norfkill_ids[] = { + { "VPC2004", 0}, + { "IBM0068", 0}, + { "LEN0068", 0}, + { "", 0}, +}; + +static int AMW0_set_cap_acpi_check_device(void) +{ + const struct acpi_device_id *id; + + for (id = norfkill_ids; id->id[0]; id++) + acpi_get_devices(id->id, AMW0_set_cap_acpi_check_device_cb, + NULL, NULL); + return AMW0_set_cap_acpi_check_device_found; +} + static acpi_status AMW0_set_capabilities(void) { struct wmab_args args; @@ -692,7 +718,9 @@ static acpi_status AMW0_set_capabilities(void) * work. */ if (wmi_has_guid(AMW0_GUID2)) { - interface->capability |= ACER_CAP_WIRELESS; + if ((quirks != &quirk_unknown) || + !AMW0_set_cap_acpi_check_device()) + interface->capability |= ACER_CAP_WIRELESS; return AE_OK; } From e424fb8cc4e6634c10f8159b1ff5618cf7bab9c6 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 28 Dec 2011 23:49:06 -0500 Subject: [PATCH 4/4] panasonic-laptop: avoid overflow in acpi_pcc_hotkey_add() num_sifr could go negative since acpi_pcc_get_sqty() returns -EINVAL on error. Then it could bypass the sanity check (num_sifr > 255). The subsequent call to kzalloc() would allocate a small buffer, leading to a memory corruption. Signed-off-by: Xi Wang Signed-off-by: Matthew Garrett --- drivers/platform/x86/panasonic-laptop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 05be30ee158b..ffff8b4b4949 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -562,8 +562,8 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) num_sifr = acpi_pcc_get_sqty(device); - if (num_sifr > 255) { - ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large")); + if (num_sifr < 0 || num_sifr > 255) { + ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr out of range")); return -ENODEV; }