cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fujitsu-tablet.c (11482B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2006-2012 Robert Gerlach <khnz@gmx.de>
      4 * Copyright (C) 2005-2006 Jan Rychter <jan@rychter.com>
      5 */
      6
      7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      8
      9#include <linux/kernel.h>
     10#include <linux/module.h>
     11#include <linux/init.h>
     12#include <linux/bitops.h>
     13#include <linux/io.h>
     14#include <linux/ioport.h>
     15#include <linux/acpi.h>
     16#include <linux/device.h>
     17#include <linux/interrupt.h>
     18#include <linux/input.h>
     19#include <linux/delay.h>
     20#include <linux/dmi.h>
     21
     22#define MODULENAME "fujitsu-tablet"
     23
     24#define ACPI_FUJITSU_CLASS "fujitsu"
     25
     26#define INVERT_TABLET_MODE_BIT      0x01
     27#define INVERT_DOCK_STATE_BIT       0x02
     28#define FORCE_TABLET_MODE_IF_UNDOCK 0x04
     29
     30#define KEYMAP_LEN 16
     31
     32static const struct acpi_device_id fujitsu_ids[] = {
     33	{ .id = "FUJ02BD" },
     34	{ .id = "FUJ02BF" },
     35	{ .id = "" }
     36};
     37
     38struct fujitsu_config {
     39	unsigned short keymap[KEYMAP_LEN];
     40	unsigned int quirks;
     41};
     42
     43static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = {
     44	KEY_RESERVED,
     45	KEY_RESERVED,
     46	KEY_RESERVED,
     47	KEY_RESERVED,
     48	KEY_SCROLLDOWN,
     49	KEY_SCROLLUP,
     50	KEY_ROTATE_DISPLAY,
     51	KEY_LEFTCTRL,
     52	KEY_BRIGHTNESSUP,
     53	KEY_BRIGHTNESSDOWN,
     54	KEY_BRIGHTNESS_ZERO,
     55	KEY_RESERVED,
     56	KEY_RESERVED,
     57	KEY_RESERVED,
     58	KEY_RESERVED,
     59	KEY_LEFTALT
     60};
     61
     62static unsigned short keymap_Lifebook_T901[KEYMAP_LEN] __initdata = {
     63	KEY_RESERVED,
     64	KEY_RESERVED,
     65	KEY_RESERVED,
     66	KEY_RESERVED,
     67	KEY_SCROLLDOWN,
     68	KEY_SCROLLUP,
     69	KEY_CYCLEWINDOWS,
     70	KEY_LEFTCTRL,
     71	KEY_RESERVED,
     72	KEY_RESERVED,
     73	KEY_RESERVED,
     74	KEY_RESERVED,
     75	KEY_RESERVED,
     76	KEY_RESERVED,
     77	KEY_RESERVED,
     78	KEY_LEFTMETA
     79};
     80
     81static unsigned short keymap_Lifebook_T902[KEYMAP_LEN] __initdata = {
     82	KEY_RESERVED,
     83	KEY_VOLUMEDOWN,
     84	KEY_VOLUMEUP,
     85	KEY_CYCLEWINDOWS,
     86	KEY_PROG1,
     87	KEY_PROG2,
     88	KEY_LEFTMETA,
     89	KEY_RESERVED,
     90	KEY_RESERVED,
     91	KEY_RESERVED,
     92	KEY_RESERVED,
     93	KEY_RESERVED,
     94	KEY_RESERVED,
     95	KEY_RESERVED,
     96	KEY_RESERVED,
     97	KEY_RESERVED,
     98};
     99
    100static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = {
    101	KEY_RESERVED,
    102	KEY_RESERVED,
    103	KEY_RESERVED,
    104	KEY_RESERVED,
    105	KEY_PROG1,
    106	KEY_PROG2,
    107	KEY_ROTATE_DISPLAY,
    108	KEY_RESERVED,
    109	KEY_RESERVED,
    110	KEY_RESERVED,
    111	KEY_UP,
    112	KEY_DOWN,
    113	KEY_RESERVED,
    114	KEY_RESERVED,
    115	KEY_LEFTCTRL,
    116	KEY_LEFTALT
    117};
    118
    119static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initdata = {
    120	KEY_RESERVED,
    121	KEY_RESERVED,
    122	KEY_RESERVED,
    123	KEY_RESERVED,
    124	KEY_PRINT,
    125	KEY_BACKSPACE,
    126	KEY_SPACE,
    127	KEY_ENTER,
    128	KEY_BRIGHTNESSUP,
    129	KEY_BRIGHTNESSDOWN,
    130	KEY_DOWN,
    131	KEY_UP,
    132	KEY_SCROLLUP,
    133	KEY_SCROLLDOWN,
    134	KEY_LEFTCTRL,
    135	KEY_LEFTALT
    136};
    137
    138static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = {
    139	KEY_RESERVED,
    140	KEY_RESERVED,
    141	KEY_RESERVED,
    142	KEY_RESERVED,
    143	KEY_MAIL,
    144	KEY_ROTATE_DISPLAY,
    145	KEY_ESC,
    146	KEY_ENTER,
    147	KEY_BRIGHTNESSUP,
    148	KEY_BRIGHTNESSDOWN,
    149	KEY_DOWN,
    150	KEY_UP,
    151	KEY_SCROLLUP,
    152	KEY_SCROLLDOWN,
    153	KEY_LEFTCTRL,
    154	KEY_LEFTALT
    155};
    156
    157static struct {
    158	struct input_dev *idev;
    159	struct fujitsu_config config;
    160	unsigned long prev_keymask;
    161
    162	char phys[21];
    163
    164	int irq;
    165	int io_base;
    166	int io_length;
    167} fujitsu;
    168
    169static u8 fujitsu_ack(void)
    170{
    171	return inb(fujitsu.io_base + 2);
    172}
    173
    174static u8 fujitsu_status(void)
    175{
    176	return inb(fujitsu.io_base + 6);
    177}
    178
    179static u8 fujitsu_read_register(const u8 addr)
    180{
    181	outb(addr, fujitsu.io_base);
    182	return inb(fujitsu.io_base + 4);
    183}
    184
    185static void fujitsu_send_state(void)
    186{
    187	int state;
    188	int dock, tablet_mode;
    189
    190	state = fujitsu_read_register(0xdd);
    191
    192	dock = state & 0x02;
    193	if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT)
    194		dock = !dock;
    195
    196	if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) {
    197		tablet_mode = 1;
    198	} else{
    199		tablet_mode = state & 0x01;
    200		if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT)
    201			tablet_mode = !tablet_mode;
    202	}
    203
    204	input_report_switch(fujitsu.idev, SW_DOCK, dock);
    205	input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode);
    206	input_sync(fujitsu.idev);
    207}
    208
    209static void fujitsu_reset(void)
    210{
    211	int timeout = 50;
    212
    213	fujitsu_ack();
    214
    215	while ((fujitsu_status() & 0x02) && (--timeout))
    216		msleep(20);
    217
    218	fujitsu_send_state();
    219}
    220
    221static int input_fujitsu_setup(struct device *parent, const char *name,
    222			       const char *phys)
    223{
    224	struct input_dev *idev;
    225	int error;
    226	int i;
    227
    228	idev = input_allocate_device();
    229	if (!idev)
    230		return -ENOMEM;
    231
    232	idev->dev.parent = parent;
    233	idev->phys = phys;
    234	idev->name = name;
    235	idev->id.bustype = BUS_HOST;
    236	idev->id.vendor  = 0x1734;	/* Fujitsu Siemens Computer GmbH */
    237	idev->id.product = 0x0001;
    238	idev->id.version = 0x0101;
    239
    240	idev->keycode = fujitsu.config.keymap;
    241	idev->keycodesize = sizeof(fujitsu.config.keymap[0]);
    242	idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap);
    243
    244	__set_bit(EV_REP, idev->evbit);
    245
    246	for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++)
    247		if (fujitsu.config.keymap[i])
    248			input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]);
    249
    250	input_set_capability(idev, EV_MSC, MSC_SCAN);
    251
    252	input_set_capability(idev, EV_SW, SW_DOCK);
    253	input_set_capability(idev, EV_SW, SW_TABLET_MODE);
    254
    255	error = input_register_device(idev);
    256	if (error) {
    257		input_free_device(idev);
    258		return error;
    259	}
    260
    261	fujitsu.idev = idev;
    262	return 0;
    263}
    264
    265static void input_fujitsu_remove(void)
    266{
    267	input_unregister_device(fujitsu.idev);
    268}
    269
    270static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
    271{
    272	unsigned long keymask, changed;
    273	unsigned int keycode;
    274	int pressed;
    275	int i;
    276
    277	if (unlikely(!(fujitsu_status() & 0x01)))
    278		return IRQ_NONE;
    279
    280	fujitsu_send_state();
    281
    282	keymask  = fujitsu_read_register(0xde);
    283	keymask |= fujitsu_read_register(0xdf) << 8;
    284	keymask ^= 0xffff;
    285
    286	changed = keymask ^ fujitsu.prev_keymask;
    287	if (changed) {
    288		fujitsu.prev_keymask = keymask;
    289
    290		for_each_set_bit(i, &changed, KEYMAP_LEN) {
    291			keycode = fujitsu.config.keymap[i];
    292			pressed = keymask & changed & BIT(i);
    293
    294			if (pressed)
    295				input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i);
    296
    297			input_report_key(fujitsu.idev, keycode, pressed);
    298			input_sync(fujitsu.idev);
    299		}
    300	}
    301
    302	fujitsu_ack();
    303	return IRQ_HANDLED;
    304}
    305
    306static void __init fujitsu_dmi_common(const struct dmi_system_id *dmi)
    307{
    308	pr_info("%s\n", dmi->ident);
    309	memcpy(fujitsu.config.keymap, dmi->driver_data,
    310			sizeof(fujitsu.config.keymap));
    311}
    312
    313static int __init fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
    314{
    315	fujitsu_dmi_common(dmi);
    316	fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
    317	return 1;
    318}
    319
    320static int __init fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
    321{
    322	fujitsu_dmi_common(dmi);
    323	fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
    324	fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT;
    325	return 1;
    326}
    327
    328static const struct dmi_system_id dmi_ids[] __initconst = {
    329	{
    330		.callback = fujitsu_dmi_lifebook,
    331		.ident = "Fujitsu Lifebook T901",
    332		.matches = {
    333			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    334			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T901")
    335		},
    336		.driver_data = keymap_Lifebook_T901
    337	},
    338	{
    339		.callback = fujitsu_dmi_lifebook,
    340		.ident = "Fujitsu Lifebook T901",
    341		.matches = {
    342			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    343			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T901")
    344		},
    345		.driver_data = keymap_Lifebook_T901
    346	},
    347	{
    348		.callback = fujitsu_dmi_lifebook,
    349		.ident = "Fujitsu Lifebook T902",
    350		.matches = {
    351			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    352			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK T902")
    353		},
    354		.driver_data = keymap_Lifebook_T902
    355	},
    356	{
    357		.callback = fujitsu_dmi_lifebook,
    358		.ident = "Fujitsu Siemens P/T Series",
    359		.matches = {
    360			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    361			DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK")
    362		},
    363		.driver_data = keymap_Lifebook_Tseries
    364	},
    365	{
    366		.callback = fujitsu_dmi_lifebook,
    367		.ident = "Fujitsu Lifebook T Series",
    368		.matches = {
    369			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    370			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T")
    371		},
    372		.driver_data = keymap_Lifebook_Tseries
    373	},
    374	{
    375		.callback = fujitsu_dmi_stylistic,
    376		.ident = "Fujitsu Siemens Stylistic T Series",
    377		.matches = {
    378			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    379			DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T")
    380		},
    381		.driver_data = keymap_Stylistic_Tseries
    382	},
    383	{
    384		.callback = fujitsu_dmi_lifebook,
    385		.ident = "Fujitsu LifeBook U810",
    386		.matches = {
    387			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    388			DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810")
    389		},
    390		.driver_data = keymap_Lifebook_U810
    391	},
    392	{
    393		.callback = fujitsu_dmi_stylistic,
    394		.ident = "Fujitsu Siemens Stylistic ST5xxx Series",
    395		.matches = {
    396			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    397			DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5")
    398		},
    399		.driver_data = keymap_Stylistic_ST5xxx
    400	},
    401	{
    402		.callback = fujitsu_dmi_stylistic,
    403		.ident = "Fujitsu Siemens Stylistic ST5xxx Series",
    404		.matches = {
    405			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
    406			DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5")
    407		},
    408		.driver_data = keymap_Stylistic_ST5xxx
    409	},
    410	{
    411		.callback = fujitsu_dmi_lifebook,
    412		.ident = "Unknown (using defaults)",
    413		.matches = {
    414			DMI_MATCH(DMI_SYS_VENDOR, ""),
    415			DMI_MATCH(DMI_PRODUCT_NAME, "")
    416		},
    417		.driver_data = keymap_Lifebook_Tseries
    418	},
    419	{ NULL }
    420};
    421
    422static acpi_status fujitsu_walk_resources(struct acpi_resource *res, void *data)
    423{
    424	switch (res->type) {
    425	case ACPI_RESOURCE_TYPE_IRQ:
    426		fujitsu.irq = res->data.irq.interrupts[0];
    427		return AE_OK;
    428
    429	case ACPI_RESOURCE_TYPE_IO:
    430		fujitsu.io_base = res->data.io.minimum;
    431		fujitsu.io_length = res->data.io.address_length;
    432		return AE_OK;
    433
    434	case ACPI_RESOURCE_TYPE_END_TAG:
    435		if (fujitsu.irq && fujitsu.io_base)
    436			return AE_OK;
    437		else
    438			return AE_NOT_FOUND;
    439
    440	default:
    441		return AE_ERROR;
    442	}
    443}
    444
    445static int acpi_fujitsu_add(struct acpi_device *adev)
    446{
    447	acpi_status status;
    448	int error;
    449
    450	if (!adev)
    451		return -EINVAL;
    452
    453	status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
    454			fujitsu_walk_resources, NULL);
    455	if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
    456		return -ENODEV;
    457
    458	sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev));
    459	sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS);
    460
    461	snprintf(fujitsu.phys, sizeof(fujitsu.phys),
    462			"%s/input0", acpi_device_hid(adev));
    463
    464	error = input_fujitsu_setup(&adev->dev,
    465		acpi_device_name(adev), fujitsu.phys);
    466	if (error)
    467		return error;
    468
    469	if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) {
    470		input_fujitsu_remove();
    471		return -EBUSY;
    472	}
    473
    474	fujitsu_reset();
    475
    476	error = request_irq(fujitsu.irq, fujitsu_interrupt,
    477			IRQF_SHARED, MODULENAME, fujitsu_interrupt);
    478	if (error) {
    479		release_region(fujitsu.io_base, fujitsu.io_length);
    480		input_fujitsu_remove();
    481		return error;
    482	}
    483
    484	return 0;
    485}
    486
    487static int acpi_fujitsu_remove(struct acpi_device *adev)
    488{
    489	free_irq(fujitsu.irq, fujitsu_interrupt);
    490	release_region(fujitsu.io_base, fujitsu.io_length);
    491	input_fujitsu_remove();
    492	return 0;
    493}
    494
    495#ifdef CONFIG_PM_SLEEP
    496static int acpi_fujitsu_resume(struct device *dev)
    497{
    498	fujitsu_reset();
    499	return 0;
    500}
    501#endif
    502
    503static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
    504
    505static struct acpi_driver acpi_fujitsu_driver = {
    506	.name  = MODULENAME,
    507	.class = "hotkey",
    508	.ids   = fujitsu_ids,
    509	.ops   = {
    510		.add    = acpi_fujitsu_add,
    511		.remove	= acpi_fujitsu_remove,
    512	},
    513	.drv.pm = &acpi_fujitsu_pm,
    514};
    515
    516static int __init fujitsu_module_init(void)
    517{
    518	int error;
    519
    520	dmi_check_system(dmi_ids);
    521
    522	error = acpi_bus_register_driver(&acpi_fujitsu_driver);
    523	if (error)
    524		return error;
    525
    526	return 0;
    527}
    528
    529static void __exit fujitsu_module_exit(void)
    530{
    531	acpi_bus_unregister_driver(&acpi_fujitsu_driver);
    532}
    533
    534module_init(fujitsu_module_init);
    535module_exit(fujitsu_module_exit);
    536
    537MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>");
    538MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
    539MODULE_LICENSE("GPL");
    540MODULE_VERSION("2.5");
    541
    542MODULE_DEVICE_TABLE(acpi, fujitsu_ids);