~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/input/keyboard/sunkbd.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 
3
 */
 
4
 
 
5
/*
 
6
 * Sun keyboard driver for Linux
 
7
 */
 
8
 
 
9
/*
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation; either version 2 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
23
 *
 
24
 * Should you need to contact me, the author, you can do so either by
 
25
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 
26
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 
27
 */
 
28
 
 
29
#include <linux/delay.h>
 
30
#include <linux/sched.h>
 
31
#include <linux/slab.h>
 
32
#include <linux/module.h>
 
33
#include <linux/interrupt.h>
 
34
#include <linux/init.h>
 
35
#include <linux/input.h>
 
36
#include <linux/serio.h>
 
37
#include <linux/workqueue.h>
 
38
 
 
39
#define DRIVER_DESC     "Sun keyboard driver"
 
40
 
 
41
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 
42
MODULE_DESCRIPTION(DRIVER_DESC);
 
43
MODULE_LICENSE("GPL");
 
44
 
 
45
static unsigned char sunkbd_keycode[128] = {
 
46
          0,128,114,129,115, 59, 60, 68, 61, 87, 62, 88, 63,100, 64,112,
 
47
         65, 66, 67, 56,103,119, 99, 70,105,130,131,108,106,  1,  2,  3,
 
48
          4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 41, 14,110,113, 98, 55,
 
49
        116,132, 83,133,102, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
 
50
         26, 27,111,127, 71, 72, 73, 74,134,135,107,  0, 29, 30, 31, 32,
 
51
         33, 34, 35, 36, 37, 38, 39, 40, 43, 28, 96, 75, 76, 77, 82,136,
 
52
        104,137, 69, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,101,
 
53
         79, 80, 81,  0,  0,  0,138, 58,125, 57,126,109, 86, 78
 
54
};
 
55
 
 
56
#define SUNKBD_CMD_RESET        0x1
 
57
#define SUNKBD_CMD_BELLON       0x2
 
58
#define SUNKBD_CMD_BELLOFF      0x3
 
59
#define SUNKBD_CMD_CLICK        0xa
 
60
#define SUNKBD_CMD_NOCLICK      0xb
 
61
#define SUNKBD_CMD_SETLED       0xe
 
62
#define SUNKBD_CMD_LAYOUT       0xf
 
63
 
 
64
#define SUNKBD_RET_RESET        0xff
 
65
#define SUNKBD_RET_ALLUP        0x7f
 
66
#define SUNKBD_RET_LAYOUT       0xfe
 
67
 
 
68
#define SUNKBD_LAYOUT_5_MASK    0x20
 
69
#define SUNKBD_RELEASE          0x80
 
70
#define SUNKBD_KEY              0x7f
 
71
 
 
72
/*
 
73
 * Per-keyboard data.
 
74
 */
 
75
 
 
76
struct sunkbd {
 
77
        unsigned char keycode[ARRAY_SIZE(sunkbd_keycode)];
 
78
        struct input_dev *dev;
 
79
        struct serio *serio;
 
80
        struct work_struct tq;
 
81
        wait_queue_head_t wait;
 
82
        char name[64];
 
83
        char phys[32];
 
84
        char type;
 
85
        bool enabled;
 
86
        volatile s8 reset;
 
87
        volatile s8 layout;
 
88
};
 
89
 
 
90
/*
 
91
 * sunkbd_interrupt() is called by the low level driver when a character
 
92
 * is received.
 
93
 */
 
94
 
 
95
static irqreturn_t sunkbd_interrupt(struct serio *serio,
 
96
                unsigned char data, unsigned int flags)
 
97
{
 
98
        struct sunkbd *sunkbd = serio_get_drvdata(serio);
 
99
 
 
100
        if (sunkbd->reset <= -1) {
 
101
                /*
 
102
                 * If cp[i] is 0xff, sunkbd->reset will stay -1.
 
103
                 * The keyboard sends 0xff 0xff 0xID on powerup.
 
104
                 */
 
105
                sunkbd->reset = data;
 
106
                wake_up_interruptible(&sunkbd->wait);
 
107
                goto out;
 
108
        }
 
109
 
 
110
        if (sunkbd->layout == -1) {
 
111
                sunkbd->layout = data;
 
112
                wake_up_interruptible(&sunkbd->wait);
 
113
                goto out;
 
114
        }
 
115
 
 
116
        switch (data) {
 
117
 
 
118
        case SUNKBD_RET_RESET:
 
119
                schedule_work(&sunkbd->tq);
 
120
                sunkbd->reset = -1;
 
121
                break;
 
122
 
 
123
        case SUNKBD_RET_LAYOUT:
 
124
                sunkbd->layout = -1;
 
125
                break;
 
126
 
 
127
        case SUNKBD_RET_ALLUP: /* All keys released */
 
128
                break;
 
129
 
 
130
        default:
 
131
                if (!sunkbd->enabled)
 
132
                        break;
 
133
 
 
134
                if (sunkbd->keycode[data & SUNKBD_KEY]) {
 
135
                        input_report_key(sunkbd->dev,
 
136
                                         sunkbd->keycode[data & SUNKBD_KEY],
 
137
                                         !(data & SUNKBD_RELEASE));
 
138
                        input_sync(sunkbd->dev);
 
139
                } else {
 
140
                        printk(KERN_WARNING
 
141
                                "sunkbd.c: Unknown key (scancode %#x) %s.\n",
 
142
                                data & SUNKBD_KEY,
 
143
                                data & SUNKBD_RELEASE ? "released" : "pressed");
 
144
                }
 
145
        }
 
146
out:
 
147
        return IRQ_HANDLED;
 
148
}
 
149
 
 
150
/*
 
151
 * sunkbd_event() handles events from the input module.
 
152
 */
 
153
 
 
154
static int sunkbd_event(struct input_dev *dev,
 
155
                        unsigned int type, unsigned int code, int value)
 
156
{
 
157
        struct sunkbd *sunkbd = input_get_drvdata(dev);
 
158
 
 
159
        switch (type) {
 
160
 
 
161
        case EV_LED:
 
162
 
 
163
                serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
 
164
                serio_write(sunkbd->serio,
 
165
                        (!!test_bit(LED_CAPSL,   dev->led) << 3) |
 
166
                        (!!test_bit(LED_SCROLLL, dev->led) << 2) |
 
167
                        (!!test_bit(LED_COMPOSE, dev->led) << 1) |
 
168
                         !!test_bit(LED_NUML,    dev->led));
 
169
                return 0;
 
170
 
 
171
        case EV_SND:
 
172
 
 
173
                switch (code) {
 
174
 
 
175
                case SND_CLICK:
 
176
                        serio_write(sunkbd->serio, SUNKBD_CMD_NOCLICK - value);
 
177
                        return 0;
 
178
 
 
179
                case SND_BELL:
 
180
                        serio_write(sunkbd->serio, SUNKBD_CMD_BELLOFF - value);
 
181
                        return 0;
 
182
                }
 
183
 
 
184
                break;
 
185
        }
 
186
 
 
187
        return -1;
 
188
}
 
189
 
 
190
/*
 
191
 * sunkbd_initialize() checks for a Sun keyboard attached, and determines
 
192
 * its type.
 
193
 */
 
194
 
 
195
static int sunkbd_initialize(struct sunkbd *sunkbd)
 
196
{
 
197
        sunkbd->reset = -2;
 
198
        serio_write(sunkbd->serio, SUNKBD_CMD_RESET);
 
199
        wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
200
        if (sunkbd->reset < 0)
 
201
                return -1;
 
202
 
 
203
        sunkbd->type = sunkbd->reset;
 
204
 
 
205
        if (sunkbd->type == 4) {        /* Type 4 keyboard */
 
206
                sunkbd->layout = -2;
 
207
                serio_write(sunkbd->serio, SUNKBD_CMD_LAYOUT);
 
208
                wait_event_interruptible_timeout(sunkbd->wait,
 
209
                                                 sunkbd->layout >= 0, HZ / 4);
 
210
                if (sunkbd->layout < 0)
 
211
                        return -1;
 
212
                if (sunkbd->layout & SUNKBD_LAYOUT_5_MASK)
 
213
                        sunkbd->type = 5;
 
214
        }
 
215
 
 
216
        return 0;
 
217
}
 
218
 
 
219
/*
 
220
 * sunkbd_reinit() sets leds and beeps to a state the computer remembers they
 
221
 * were in.
 
222
 */
 
223
 
 
224
static void sunkbd_reinit(struct work_struct *work)
 
225
{
 
226
        struct sunkbd *sunkbd = container_of(work, struct sunkbd, tq);
 
227
 
 
228
        wait_event_interruptible_timeout(sunkbd->wait, sunkbd->reset >= 0, HZ);
 
229
 
 
230
        serio_write(sunkbd->serio, SUNKBD_CMD_SETLED);
 
231
        serio_write(sunkbd->serio,
 
232
                (!!test_bit(LED_CAPSL,   sunkbd->dev->led) << 3) |
 
233
                (!!test_bit(LED_SCROLLL, sunkbd->dev->led) << 2) |
 
234
                (!!test_bit(LED_COMPOSE, sunkbd->dev->led) << 1) |
 
235
                 !!test_bit(LED_NUML,    sunkbd->dev->led));
 
236
        serio_write(sunkbd->serio,
 
237
                SUNKBD_CMD_NOCLICK - !!test_bit(SND_CLICK, sunkbd->dev->snd));
 
238
        serio_write(sunkbd->serio,
 
239
                SUNKBD_CMD_BELLOFF - !!test_bit(SND_BELL, sunkbd->dev->snd));
 
240
}
 
241
 
 
242
static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
 
243
{
 
244
        serio_pause_rx(sunkbd->serio);
 
245
        sunkbd->enabled = enable;
 
246
        serio_continue_rx(sunkbd->serio);
 
247
}
 
248
 
 
249
/*
 
250
 * sunkbd_connect() probes for a Sun keyboard and fills the necessary
 
251
 * structures.
 
252
 */
 
253
 
 
254
static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
 
255
{
 
256
        struct sunkbd *sunkbd;
 
257
        struct input_dev *input_dev;
 
258
        int err = -ENOMEM;
 
259
        int i;
 
260
 
 
261
        sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
 
262
        input_dev = input_allocate_device();
 
263
        if (!sunkbd || !input_dev)
 
264
                goto fail1;
 
265
 
 
266
        sunkbd->serio = serio;
 
267
        sunkbd->dev = input_dev;
 
268
        init_waitqueue_head(&sunkbd->wait);
 
269
        INIT_WORK(&sunkbd->tq, sunkbd_reinit);
 
270
        snprintf(sunkbd->phys, sizeof(sunkbd->phys), "%s/input0", serio->phys);
 
271
 
 
272
        serio_set_drvdata(serio, sunkbd);
 
273
 
 
274
        err = serio_open(serio, drv);
 
275
        if (err)
 
276
                goto fail2;
 
277
 
 
278
        if (sunkbd_initialize(sunkbd) < 0) {
 
279
                err = -ENODEV;
 
280
                goto fail3;
 
281
        }
 
282
 
 
283
        snprintf(sunkbd->name, sizeof(sunkbd->name),
 
284
                 "Sun Type %d keyboard", sunkbd->type);
 
285
        memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
 
286
 
 
287
        input_dev->name = sunkbd->name;
 
288
        input_dev->phys = sunkbd->phys;
 
289
        input_dev->id.bustype = BUS_RS232;
 
290
        input_dev->id.vendor  = SERIO_SUNKBD;
 
291
        input_dev->id.product = sunkbd->type;
 
292
        input_dev->id.version = 0x0100;
 
293
        input_dev->dev.parent = &serio->dev;
 
294
 
 
295
        input_set_drvdata(input_dev, sunkbd);
 
296
 
 
297
        input_dev->event = sunkbd_event;
 
298
 
 
299
        input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) |
 
300
                BIT_MASK(EV_SND) | BIT_MASK(EV_REP);
 
301
        input_dev->ledbit[0] = BIT_MASK(LED_CAPSL) | BIT_MASK(LED_COMPOSE) |
 
302
                BIT_MASK(LED_SCROLLL) | BIT_MASK(LED_NUML);
 
303
        input_dev->sndbit[0] = BIT_MASK(SND_CLICK) | BIT_MASK(SND_BELL);
 
304
 
 
305
        input_dev->keycode = sunkbd->keycode;
 
306
        input_dev->keycodesize = sizeof(unsigned char);
 
307
        input_dev->keycodemax = ARRAY_SIZE(sunkbd_keycode);
 
308
        for (i = 0; i < ARRAY_SIZE(sunkbd_keycode); i++)
 
309
                __set_bit(sunkbd->keycode[i], input_dev->keybit);
 
310
        __clear_bit(KEY_RESERVED, input_dev->keybit);
 
311
 
 
312
        sunkbd_enable(sunkbd, true);
 
313
 
 
314
        err = input_register_device(sunkbd->dev);
 
315
        if (err)
 
316
                goto fail4;
 
317
 
 
318
        return 0;
 
319
 
 
320
 fail4: sunkbd_enable(sunkbd, false);
 
321
 fail3: serio_close(serio);
 
322
 fail2: serio_set_drvdata(serio, NULL);
 
323
 fail1: input_free_device(input_dev);
 
324
        kfree(sunkbd);
 
325
        return err;
 
326
}
 
327
 
 
328
/*
 
329
 * sunkbd_disconnect() unregisters and closes behind us.
 
330
 */
 
331
 
 
332
static void sunkbd_disconnect(struct serio *serio)
 
333
{
 
334
        struct sunkbd *sunkbd = serio_get_drvdata(serio);
 
335
 
 
336
        sunkbd_enable(sunkbd, false);
 
337
        input_unregister_device(sunkbd->dev);
 
338
        serio_close(serio);
 
339
        serio_set_drvdata(serio, NULL);
 
340
        kfree(sunkbd);
 
341
}
 
342
 
 
343
static struct serio_device_id sunkbd_serio_ids[] = {
 
344
        {
 
345
                .type   = SERIO_RS232,
 
346
                .proto  = SERIO_SUNKBD,
 
347
                .id     = SERIO_ANY,
 
348
                .extra  = SERIO_ANY,
 
349
        },
 
350
        {
 
351
                .type   = SERIO_RS232,
 
352
                .proto  = SERIO_UNKNOWN, /* sunkbd does probe */
 
353
                .id     = SERIO_ANY,
 
354
                .extra  = SERIO_ANY,
 
355
        },
 
356
        { 0 }
 
357
};
 
358
 
 
359
MODULE_DEVICE_TABLE(serio, sunkbd_serio_ids);
 
360
 
 
361
static struct serio_driver sunkbd_drv = {
 
362
        .driver         = {
 
363
                .name   = "sunkbd",
 
364
        },
 
365
        .description    = DRIVER_DESC,
 
366
        .id_table       = sunkbd_serio_ids,
 
367
        .interrupt      = sunkbd_interrupt,
 
368
        .connect        = sunkbd_connect,
 
369
        .disconnect     = sunkbd_disconnect,
 
370
};
 
371
 
 
372
/*
 
373
 * The functions for insering/removing us as a module.
 
374
 */
 
375
 
 
376
static int __init sunkbd_init(void)
 
377
{
 
378
        return serio_register_driver(&sunkbd_drv);
 
379
}
 
380
 
 
381
static void __exit sunkbd_exit(void)
 
382
{
 
383
        serio_unregister_driver(&sunkbd_drv);
 
384
}
 
385
 
 
386
module_init(sunkbd_init);
 
387
module_exit(sunkbd_exit);