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);