Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platfrm driver fixes from Matthew Garrett: "Some trivial patches that fix wifi on some Lenovos and avoid a potential memory corruption issue on some Panasonics, plus two straightforward new drivers that touch no existing code." * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: panasonic-laptop: avoid overflow in acpi_pcc_hotkey_add() acer-wmi: No wifi rfkill on Lenovo machines Fujitsu tablet extras driver x86: Add amilo-rfkill driver for some Fujitsu-Siemens Amilo laptops
This commit is contained in:
Коммит
2f1c2b8155
|
@ -2845,6 +2845,12 @@ S: Maintained
|
|||
F: drivers/media/video/m5mols/
|
||||
F: include/media/m5mols.h
|
||||
|
||||
FUJITSU TABLET EXTRAS
|
||||
M: Robert Gerlach <khnz@gmx.de>
|
||||
L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/fujitsu-tablet.c
|
||||
|
||||
FUSE: FILESYSTEM IN USERSPACE
|
||||
M: Miklos Szeredi <miklos@szeredi.hu>
|
||||
L: fuse-devel@lists.sourceforge.net
|
||||
|
|
|
@ -143,6 +143,30 @@ 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
|
||||
---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
|
||||
|
|
|
@ -17,12 +17,14 @@ 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
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <linux/module.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i8042.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill.h>
|
||||
|
||||
/*
|
||||
* 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 <ben@decadent.org.uk>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table);
|
||||
|
||||
module_init(amilo_rfkill_init);
|
||||
module_exit(amilo_rfkill_exit);
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2012 Robert Gerlach <khnz@gmx.de>
|
||||
* Copyright (C) 2005-2006 Jan Rychter <jan@rychter.com>
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
#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 <khnz@gmx.de>");
|
||||
MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("2.4");
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче