~ubuntu-branches/debian/experimental/linux-2.6/experimental

« back to all changes in this revision

Viewing changes to drivers/platform/x86/fujitsu-tablet.c

  • Committer: Package Import Robot
  • Author(s): Ben Hutchings, Ben Hutchings
  • Date: 2012-03-21 03:08:36 UTC
  • mfrom: (1.2.34)
  • Revision ID: package-import@ubuntu.com-20120321030836-rvavg03lkz15wj2q
Tags: 3.3-1~experimental.1
* New upstream release: http://kernelnewbies.org/Linux_3.3

[ Ben Hutchings ]
* [x86] crypto: Enable CRYPTO_SERPENT_SSE2_586, CRYPTO_SERPENT_SSE2_X86_64
* aufs: Update to aufs3.x-rcN-20120312
* IB: Enable INFINIBAND_SRPT as module (Closes: #663041)

Show diffs side-by-side

added added

removed removed

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