| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:34 +02:00
										 |  |  | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | #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
 | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | #define INVERT_DOCK_STATE_BIT       0x02
 | 
					
						
							|  |  |  | #define FORCE_TABLET_MODE_IF_UNDOCK 0x04
 | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 17:12:01 -07:00
										 |  |  | static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = { | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	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 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-04 14:13:04 -04:00
										 |  |  | static unsigned short keymap_Lifebook_T901[KEYMAP_LEN] __initdata = { | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_SCROLLDOWN, | 
					
						
							|  |  |  | 	KEY_SCROLLUP, | 
					
						
							|  |  |  | 	KEY_CYCLEWINDOWS, | 
					
						
							|  |  |  | 	KEY_LEFTCTRL, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_LEFTMETA | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned short keymap_Lifebook_T902[KEYMAP_LEN] __initdata = { | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_VOLUMEDOWN, | 
					
						
							|  |  |  | 	KEY_VOLUMEUP, | 
					
						
							|  |  |  | 	KEY_CYCLEWINDOWS, | 
					
						
							|  |  |  | 	KEY_PROG1, | 
					
						
							|  |  |  | 	KEY_PROG2, | 
					
						
							|  |  |  | 	KEY_LEFTMETA, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | 	KEY_RESERVED, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 17:12:01 -07:00
										 |  |  | static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = { | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	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 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 17:12:01 -07:00
										 |  |  | static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initdata = { | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	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 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 17:12:01 -07:00
										 |  |  | static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = { | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 	if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT) | 
					
						
							|  |  |  | 		dock = !dock; | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 13:18:33 -08:00
										 |  |  | static int input_fujitsu_setup(struct device *parent, const char *name, | 
					
						
							|  |  |  | 			       const char *phys) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 19:43:12 +02:00
										 |  |  | static void __init fujitsu_dmi_common(const struct dmi_system_id *dmi) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:34 +02:00
										 |  |  | 	pr_info("%s\n", dmi->ident); | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	memcpy(fujitsu.config.keymap, dmi->driver_data, | 
					
						
							|  |  |  | 			sizeof(fujitsu.config.keymap)); | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 19:43:12 +02:00
										 |  |  | static int __init fujitsu_dmi_lifebook(const struct dmi_system_id *dmi) | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | { | 
					
						
							|  |  |  | 	fujitsu_dmi_common(dmi); | 
					
						
							|  |  |  | 	fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-16 19:43:12 +02:00
										 |  |  | static int __init fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 	fujitsu_dmi_common(dmi); | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 	fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT; | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-04 17:12:01 -07:00
										 |  |  | static const struct dmi_system_id dmi_ids[] __initconst = { | 
					
						
							| 
									
										
										
										
											2014-04-04 14:13:04 -04:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							|  |  |  | 		.ident = "Fujitsu Lifebook T901", | 
					
						
							|  |  |  | 		.matches = { | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T901") | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.driver_data = keymap_Lifebook_T901 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							|  |  |  | 		.ident = "Fujitsu Lifebook T901", | 
					
						
							|  |  |  | 		.matches = { | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T901") | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.driver_data = keymap_Lifebook_T901 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							|  |  |  | 		.ident = "Fujitsu Lifebook T902", | 
					
						
							|  |  |  | 		.matches = { | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T902") | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.driver_data = keymap_Lifebook_T902 | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 		.ident = "Fujitsu Siemens P/T Series", | 
					
						
							|  |  |  | 		.matches = { | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK") | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.driver_data = keymap_Lifebook_Tseries | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 		.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 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 		.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 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | 		.callback = fujitsu_dmi_lifebook, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 		.ident = "Unknown (using defaults)", | 
					
						
							|  |  |  | 		.matches = { | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_SYS_VENDOR, ""), | 
					
						
							|  |  |  | 			DMI_MATCH(DMI_PRODUCT_NAME, "") | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		.driver_data = keymap_Lifebook_Tseries | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	{ NULL } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 13:18:33 -08:00
										 |  |  | static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 13:18:33 -08:00
										 |  |  | static int acpi_fujitsu_add(struct acpi_device *adev) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-24 00:24:48 +01:00
										 |  |  | static int acpi_fujitsu_remove(struct acpi_device *adev) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	free_irq(fujitsu.irq, fujitsu_interrupt); | 
					
						
							|  |  |  | 	release_region(fujitsu.io_base, fujitsu.io_length); | 
					
						
							|  |  |  | 	input_fujitsu_remove(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-09 23:00:13 +02:00
										 |  |  | #ifdef CONFIG_PM_SLEEP
 | 
					
						
							| 
									
										
										
										
											2012-06-29 23:39:57 +02:00
										 |  |  | static int acpi_fujitsu_resume(struct device *dev) | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	fujitsu_reset(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-08-09 23:00:13 +02:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 23:39:57 +02:00
										 |  |  | static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | static struct acpi_driver acpi_fujitsu_driver = { | 
					
						
							|  |  |  | 	.name  = MODULENAME, | 
					
						
							|  |  |  | 	.class = "hotkey", | 
					
						
							|  |  |  | 	.ids   = fujitsu_ids, | 
					
						
							|  |  |  | 	.ops   = { | 
					
						
							|  |  |  | 		.add    = acpi_fujitsu_add, | 
					
						
							|  |  |  | 		.remove	= acpi_fujitsu_remove, | 
					
						
							| 
									
										
										
										
											2012-06-29 23:39:57 +02:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	.drv.pm = &acpi_fujitsu_pm, | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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"); | 
					
						
							| 
									
										
										
										
											2012-04-03 22:34:35 +02:00
										 |  |  | MODULE_VERSION("2.5"); | 
					
						
							| 
									
										
										
										
											2012-01-18 14:26:22 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | MODULE_DEVICE_TABLE(acpi, fujitsu_ids); |