Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fujitsu-tablet.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2012 Robert Gerlach <[email protected]>
3  * Copyright (C) 2005-2006 Jan Rychter <[email protected]>
4  *
5  * You can redistribute and/or modify this program under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12  * Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20 
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/bitops.h>
25 #include <linux/io.h>
26 #include <linux/ioport.h>
27 #include <linux/acpi.h>
28 #include <linux/device.h>
29 #include <linux/interrupt.h>
30 #include <linux/input.h>
31 #include <linux/delay.h>
32 #include <linux/dmi.h>
33 
34 #define MODULENAME "fujitsu-tablet"
35 
36 #define ACPI_FUJITSU_CLASS "fujitsu"
37 
38 #define INVERT_TABLET_MODE_BIT 0x01
39 #define INVERT_DOCK_STATE_BIT 0x02
40 #define FORCE_TABLET_MODE_IF_UNDOCK 0x04
41 
42 #define KEYMAP_LEN 16
43 
44 static const struct acpi_device_id fujitsu_ids[] = {
45  { .id = "FUJ02BD" },
46  { .id = "FUJ02BF" },
47  { .id = "" }
48 };
49 
51  unsigned short keymap[KEYMAP_LEN];
52  unsigned int quirks;
53 };
54 
55 static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initdata = {
72 };
73 
74 static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initdata = {
79  KEY_PROG1,
80  KEY_PROG2,
85  KEY_UP,
86  KEY_DOWN,
91 };
92 
93 static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initdata = {
98  KEY_PRINT,
100  KEY_SPACE,
101  KEY_ENTER,
104  KEY_DOWN,
105  KEY_UP,
106  KEY_SCROLLUP,
108  KEY_LEFTCTRL,
110 };
111 
112 static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initdata = {
113  KEY_RESERVED,
114  KEY_RESERVED,
115  KEY_RESERVED,
116  KEY_RESERVED,
117  KEY_MAIL,
119  KEY_ESC,
120  KEY_ENTER,
123  KEY_DOWN,
124  KEY_UP,
125  KEY_SCROLLUP,
127  KEY_LEFTCTRL,
129 };
130 
131 static struct {
132  struct input_dev *idev;
134  unsigned long prev_keymask;
135 
136  char phys[21];
137 
138  int irq;
139  int io_base;
141 } fujitsu;
142 
143 static u8 fujitsu_ack(void)
144 {
145  return inb(fujitsu.io_base + 2);
146 }
147 
148 static u8 fujitsu_status(void)
149 {
150  return inb(fujitsu.io_base + 6);
151 }
152 
153 static u8 fujitsu_read_register(const u8 addr)
154 {
155  outb(addr, fujitsu.io_base);
156  return inb(fujitsu.io_base + 4);
157 }
158 
159 static void fujitsu_send_state(void)
160 {
161  int state;
162  int dock, tablet_mode;
163 
164  state = fujitsu_read_register(0xdd);
165 
166  dock = state & 0x02;
167  if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT)
168  dock = !dock;
169 
170  if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) {
171  tablet_mode = 1;
172  } else{
173  tablet_mode = state & 0x01;
174  if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT)
175  tablet_mode = !tablet_mode;
176  }
177 
178  input_report_switch(fujitsu.idev, SW_DOCK, dock);
179  input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode);
180  input_sync(fujitsu.idev);
181 }
182 
183 static void fujitsu_reset(void)
184 {
185  int timeout = 50;
186 
187  fujitsu_ack();
188 
189  while ((fujitsu_status() & 0x02) && (--timeout))
190  msleep(20);
191 
192  fujitsu_send_state();
193 }
194 
195 static int __devinit input_fujitsu_setup(struct device *parent,
196  const char *name, const char *phys)
197 {
198  struct input_dev *idev;
199  int error;
200  int i;
201 
202  idev = input_allocate_device();
203  if (!idev)
204  return -ENOMEM;
205 
206  idev->dev.parent = parent;
207  idev->phys = phys;
208  idev->name = name;
209  idev->id.bustype = BUS_HOST;
210  idev->id.vendor = 0x1734; /* Fujitsu Siemens Computer GmbH */
211  idev->id.product = 0x0001;
212  idev->id.version = 0x0101;
213 
214  idev->keycode = fujitsu.config.keymap;
215  idev->keycodesize = sizeof(fujitsu.config.keymap[0]);
216  idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap);
217 
218  __set_bit(EV_REP, idev->evbit);
219 
220  for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++)
221  if (fujitsu.config.keymap[i])
222  input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]);
223 
224  input_set_capability(idev, EV_MSC, MSC_SCAN);
225 
226  input_set_capability(idev, EV_SW, SW_DOCK);
227  input_set_capability(idev, EV_SW, SW_TABLET_MODE);
228 
229  error = input_register_device(idev);
230  if (error) {
231  input_free_device(idev);
232  return error;
233  }
234 
235  fujitsu.idev = idev;
236  return 0;
237 }
238 
239 static void input_fujitsu_remove(void)
240 {
241  input_unregister_device(fujitsu.idev);
242 }
243 
244 static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
245 {
246  unsigned long keymask, changed;
247  unsigned int keycode;
248  int pressed;
249  int i;
250 
251  if (unlikely(!(fujitsu_status() & 0x01)))
252  return IRQ_NONE;
253 
254  fujitsu_send_state();
255 
256  keymask = fujitsu_read_register(0xde);
257  keymask |= fujitsu_read_register(0xdf) << 8;
258  keymask ^= 0xffff;
259 
260  changed = keymask ^ fujitsu.prev_keymask;
261  if (changed) {
262  fujitsu.prev_keymask = keymask;
263 
264  for_each_set_bit(i, &changed, KEYMAP_LEN) {
265  keycode = fujitsu.config.keymap[i];
266  pressed = keymask & changed & BIT(i);
267 
268  if (pressed)
269  input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i);
270 
271  input_report_key(fujitsu.idev, keycode, pressed);
272  input_sync(fujitsu.idev);
273  }
274  }
275 
276  fujitsu_ack();
277  return IRQ_HANDLED;
278 }
279 
280 static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi)
281 {
282  pr_info("%s\n", dmi->ident);
283  memcpy(fujitsu.config.keymap, dmi->driver_data,
284  sizeof(fujitsu.config.keymap));
285 }
286 
287 static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
288 {
289  fujitsu_dmi_common(dmi);
290  fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
291  return 1;
292 }
293 
294 static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
295 {
296  fujitsu_dmi_common(dmi);
297  fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
298  fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT;
299  return 1;
300 }
301 
302 static const struct dmi_system_id dmi_ids[] __initconst = {
303  {
304  .callback = fujitsu_dmi_lifebook,
305  .ident = "Fujitsu Siemens P/T Series",
306  .matches = {
307  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
308  DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK")
309  },
310  .driver_data = keymap_Lifebook_Tseries
311  },
312  {
313  .callback = fujitsu_dmi_lifebook,
314  .ident = "Fujitsu Lifebook T Series",
315  .matches = {
316  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
317  DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T")
318  },
319  .driver_data = keymap_Lifebook_Tseries
320  },
321  {
322  .callback = fujitsu_dmi_stylistic,
323  .ident = "Fujitsu Siemens Stylistic T Series",
324  .matches = {
325  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
326  DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T")
327  },
328  .driver_data = keymap_Stylistic_Tseries
329  },
330  {
331  .callback = fujitsu_dmi_lifebook,
332  .ident = "Fujitsu LifeBook U810",
333  .matches = {
334  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
335  DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810")
336  },
337  .driver_data = keymap_Lifebook_U810
338  },
339  {
340  .callback = fujitsu_dmi_stylistic,
341  .ident = "Fujitsu Siemens Stylistic ST5xxx Series",
342  .matches = {
343  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
344  DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5")
345  },
346  .driver_data = keymap_Stylistic_ST5xxx
347  },
348  {
349  .callback = fujitsu_dmi_stylistic,
350  .ident = "Fujitsu Siemens Stylistic ST5xxx Series",
351  .matches = {
352  DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
353  DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5")
354  },
355  .driver_data = keymap_Stylistic_ST5xxx
356  },
357  {
358  .callback = fujitsu_dmi_lifebook,
359  .ident = "Unknown (using defaults)",
360  .matches = {
363  },
364  .driver_data = keymap_Lifebook_Tseries
365  },
366  { NULL }
367 };
368 
369 static acpi_status __devinit
370 fujitsu_walk_resources(struct acpi_resource *res, void *data)
371 {
372  switch (res->type) {
374  fujitsu.irq = res->data.irq.interrupts[0];
375  return AE_OK;
376 
378  fujitsu.io_base = res->data.io.minimum;
379  fujitsu.io_length = res->data.io.address_length;
380  return AE_OK;
381 
383  if (fujitsu.irq && fujitsu.io_base)
384  return AE_OK;
385  else
386  return AE_NOT_FOUND;
387 
388  default:
389  return AE_ERROR;
390  }
391 }
392 
393 static int __devinit acpi_fujitsu_add(struct acpi_device *adev)
394 {
396  int error;
397 
398  if (!adev)
399  return -EINVAL;
400 
401  status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS,
402  fujitsu_walk_resources, NULL);
403  if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base)
404  return -ENODEV;
405 
406  sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev));
407  sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS);
408 
409  snprintf(fujitsu.phys, sizeof(fujitsu.phys),
410  "%s/input0", acpi_device_hid(adev));
411 
412  error = input_fujitsu_setup(&adev->dev,
413  acpi_device_name(adev), fujitsu.phys);
414  if (error)
415  return error;
416 
417  if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) {
418  input_fujitsu_remove();
419  return -EBUSY;
420  }
421 
422  fujitsu_reset();
423 
424  error = request_irq(fujitsu.irq, fujitsu_interrupt,
425  IRQF_SHARED, MODULENAME, fujitsu_interrupt);
426  if (error) {
427  release_region(fujitsu.io_base, fujitsu.io_length);
428  input_fujitsu_remove();
429  return error;
430  }
431 
432  return 0;
433 }
434 
435 static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
436 {
437  free_irq(fujitsu.irq, fujitsu_interrupt);
438  release_region(fujitsu.io_base, fujitsu.io_length);
439  input_fujitsu_remove();
440  return 0;
441 }
442 
443 #ifdef CONFIG_PM_SLEEP
444 static int acpi_fujitsu_resume(struct device *dev)
445 {
446  fujitsu_reset();
447  return 0;
448 }
449 #endif
450 
451 static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
452 
453 static struct acpi_driver acpi_fujitsu_driver = {
454  .name = MODULENAME,
455  .class = "hotkey",
456  .ids = fujitsu_ids,
457  .ops = {
458  .add = acpi_fujitsu_add,
459  .remove = acpi_fujitsu_remove,
460  },
461  .drv.pm = &acpi_fujitsu_pm,
462 };
463 
464 static int __init fujitsu_module_init(void)
465 {
466  int error;
467 
468  dmi_check_system(dmi_ids);
469 
470  error = acpi_bus_register_driver(&acpi_fujitsu_driver);
471  if (error)
472  return error;
473 
474  return 0;
475 }
476 
477 static void __exit fujitsu_module_exit(void)
478 {
479  acpi_bus_unregister_driver(&acpi_fujitsu_driver);
480 }
481 
482 module_init(fujitsu_module_init);
483 module_exit(fujitsu_module_exit);
484 
485 MODULE_AUTHOR("Robert Gerlach <[email protected]>");
486 MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
487 MODULE_LICENSE("GPL");
488 MODULE_VERSION("2.5");
489 
490 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);