OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ec3104_keyb.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/drivers/char/ec3104_keyb.c
3
 *
4
 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
5
 *
6
 * based on linux/drivers/char/pc_keyb.c, which had the following comments:
7
 *
8
 * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
9
 * See keyboard.c for the whole history.
10
 *
11
 * Major cleanup by Martin Mares, May 1997
12
 *
13
 * Combined the keyboard and PS/2 mouse handling into one file,
14
 * because they share the same hardware.
15
 * Johan Myreen <jem@iki.fi> 1998-10-08.
16
 *
17
 * Code fixes to handle mouse ACKs properly.
18
 * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
19
 */
20
/* EC3104 note:
21
 * This code was written without any documentation about the EC3104 chip.  While
22
 * I hope I got most of the basic functionality right, the register names I use
23
 * are most likely completely different from those in the chip documentation.
24
 *
25
 * If you have any further information about the EC3104, please tell me
26
 * (prumpf@tux.org).
27
 */
28
 
29
#include <linux/config.h>
30
 
31
#include <linux/spinlock.h>
32
#include <linux/sched.h>
33
#include <linux/interrupt.h>
34
#include <linux/tty.h>
35
#include <linux/mm.h>
36
#include <linux/signal.h>
37
#include <linux/init.h>
38
#include <linux/kbd_ll.h>
39
#include <linux/delay.h>
40
#include <linux/random.h>
41
#include <linux/poll.h>
42
#include <linux/miscdevice.h>
43
#include <linux/slab.h>
44
#include <linux/kbd_kern.h>
45
#include <linux/smp_lock.h>
46
 
47
#include <asm/keyboard.h>
48
#include <asm/bitops.h>
49
#include <asm/uaccess.h>
50
#include <asm/irq.h>
51
#include <asm/system.h>
52
#include <asm/ec3104.h>
53
 
54
#include <asm/io.h>
55
 
56
/* Some configuration switches are present in the include file... */
57
 
58
#include <linux/pc_keyb.h>
59
 
60
#define MSR_CTS 0x10
61
#define MCR_RTS 0x02
62
#define LSR_DR 0x01
63
#define LSR_BOTH_EMPTY 0x60
64
 
65
static struct e5_struct {
66
        u8 packet[8];
67
        int pos;
68
        int length;
69
 
70
        u8 cached_mcr;
71
        u8 last_msr;
72
} ec3104_keyb;
73
 
74
/* Simple translation table for the SysRq keys */
75
 
76
 
77
#ifdef CONFIG_MAGIC_SYSRQ
78
unsigned char ec3104_kbd_sysrq_xlate[128] =
79
        "\000\0331234567890-=\177\t"                    /* 0x00 - 0x0f */
80
        "qwertyuiop[]\r\000as"                          /* 0x10 - 0x1f */
81
        "dfghjkl;'`\000\\zxcv"                          /* 0x20 - 0x2f */
82
        "bnm,./\000*\000 \000\201\202\203\204\205"      /* 0x30 - 0x3f */
83
        "\206\207\210\211\212\000\000789-456+1"         /* 0x40 - 0x4f */
84
        "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
85
        "\r\000/";                                      /* 0x60 - 0x6f */
86
#endif
87
 
88
static void kbd_write_command_w(int data);
89
static void kbd_write_output_w(int data);
90
#ifdef CONFIG_PSMOUSE
91
static void aux_write_ack(int val);
92
static void __aux_write_ack(int val);
93
#endif
94
 
95
static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
96
static unsigned char handle_kbd_event(void);
97
 
98
/* used only by send_data - set by keyboard_interrupt */
99
static volatile unsigned char reply_expected;
100
static volatile unsigned char acknowledge;
101
static volatile unsigned char resend;
102
 
103
 
104
int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
105
{
106
        return 0;
107
}
108
 
109
int ec3104_kbd_getkeycode(unsigned int scancode)
110
{
111
        return 0;
112
}
113
 
114
 
115
/* yes, it probably would be faster to use an array.  I don't care. */
116
 
117
static inline unsigned char ec3104_scan2key(unsigned char scancode)
118
{
119
        switch (scancode) {
120
        case  1: /* '`' */
121
                return 41;
122
 
123
        case  2 ... 27:
124
                return scancode;
125
 
126
        case 28: /* '\\' */
127
                return 43;
128
 
129
        case 29 ... 39:
130
                return scancode + 1;
131
 
132
        case 40: /* '\r' */
133
                return 28;
134
 
135
        case 41 ... 50:
136
                return scancode + 3;
137
 
138
        case 51: /* ' ' */
139
                return 57;
140
 
141
        case 52: /* escape */
142
                return 1;
143
 
144
        case 54: /* insert/delete (labelled delete) */
145
                /* this should arguably be 110, but I'd like to have ctrl-alt-del
146
                 * working with a standard keymap */
147
                return 111;
148
 
149
        case 55: /* left */
150
                return 105;
151
        case 56: /* home */
152
                return 102;
153
        case 57: /* end */
154
                return 107;
155
        case 58: /* up */
156
                return 103;
157
        case 59: /* down */
158
                return 108;
159
        case 60: /* pgup */
160
                return 104;
161
        case 61: /* pgdown */
162
                return 109;
163
        case 62: /* right */
164
                return 106;
165
 
166
        case 79 ... 88: /* f1 - f10 */
167
                return scancode - 20;
168
 
169
        case 89 ... 90: /* f11 - f12 */
170
                return scancode - 2;
171
 
172
        case 91: /* left shift */
173
                return 42;
174
 
175
        case 92: /* right shift */
176
                return 54;
177
 
178
        case 93: /* left alt */
179
                return 56;
180
        case 94: /* right alt */
181
                return 100;
182
        case 95: /* left ctrl */
183
                return 29;
184
        case 96: /* right ctrl */
185
                return 97;
186
 
187
        case 97: /* caps lock */
188
                return 58;
189
        case 102: /* left windows */
190
                return 125;
191
        case 103: /* right windows */
192
                return 126;
193
 
194
        case 106: /* Fn */
195
                /* this is wrong. */
196
                return 84;
197
 
198
        default:
199
                return 0;
200
        }
201
}
202
 
203
int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode,
204
                    char raw_mode)
205
{
206
        scancode &= 0x7f;
207
 
208
        *keycode = ec3104_scan2key(scancode);
209
 
210
        return 1;
211
}
212
 
213
char ec3104_kbd_unexpected_up(unsigned char keycode)
214
{
215
        return 0200;
216
}
217
 
218
static inline void handle_keyboard_event(unsigned char scancode)
219
{
220
#ifdef CONFIG_VT
221
        handle_scancode(scancode, !(scancode & 0x80));
222
#endif                          
223
        tasklet_schedule(&keyboard_tasklet);
224
}
225
 
226
void ec3104_kbd_leds(unsigned char leds)
227
{
228
}
229
 
230
static u8 e5_checksum(u8 *packet, int count)
231
{
232
        int i;
233
        u8 sum = 0;
234
 
235
        for (i=0; i<count; i++)
236
                sum ^= packet[i];
237
 
238
        if (sum & 0x80)
239
                sum ^= 0xc0;
240
 
241
        return sum;
242
}
243
 
244
static void e5_wait_for_cts(struct e5_struct *k)
245
{
246
        u8 msr;
247
 
248
        do {
249
                msr = ctrl_inb(EC3104_SER4_MSR);
250
        } while (!(msr & MSR_CTS));
251
}
252
 
253
 
254
static void e5_send_byte(u8 byte, struct e5_struct *k)
255
{
256
        u8 status;
257
 
258
        do {
259
                status = ctrl_inb(EC3104_SER4_LSR);
260
        } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
261
 
262
        printk("<%02x>", byte);
263
 
264
        ctrl_outb(byte, EC3104_SER4_DATA);
265
 
266
        do {
267
                status = ctrl_inb(EC3104_SER4_LSR);
268
        } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY);
269
 
270
}
271
 
272
static int e5_send_packet(u8 *packet, int count, struct e5_struct *k)
273
{
274
        int i;
275
 
276
        disable_irq(EC3104_IRQ_SER4);
277
 
278
        if (k->cached_mcr & MCR_RTS) {
279
                printk("e5_send_packet: too slow\n");
280
                enable_irq(EC3104_IRQ_SER4);
281
                return -EAGAIN;
282
        }
283
 
284
        k->cached_mcr |= MCR_RTS;
285
        ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
286
 
287
        e5_wait_for_cts(k);
288
 
289
        printk("p: ");
290
 
291
        for(i=0; i<count; i++)
292
                e5_send_byte(packet[i], k);
293
 
294
        e5_send_byte(e5_checksum(packet, count), k);
295
 
296
        printk("\n");
297
 
298
        udelay(1500);
299
 
300
        k->cached_mcr &= ~MCR_RTS;
301
        ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
302
 
303
        set_current_state(TASK_UNINTERRUPTIBLE);
304
 
305
 
306
 
307
        enable_irq(EC3104_IRQ_SER4);
308
 
309
 
310
 
311
        return 0;
312
}
313
 
314
/*
315
 * E5 packets we know about:
316
 * E5->host 0x80 0x05 <checksum> - resend packet
317
 * host->E5 0x83 0x43 <contrast> - set LCD contrast
318
 * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight
319
 * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2
320
 * E5->host 0x88 <scancode> <checksum> - key press
321
 */
322
 
323
static void e5_receive(struct e5_struct *k)
324
{
325
        k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA);
326
 
327
        if (k->pos == 1) {
328
                switch(k->packet[0]) {
329
                case 0x80:
330
                        k->length = 3;
331
                        break;
332
 
333
                case 0x87: /* PS2 ext */
334
                        k->length = 6;
335
                        break;
336
 
337
                case 0x88: /* keyboard */
338
                        k->length = 3;
339
                        break;
340
 
341
                default:
342
                        k->length = 1;
343
                        printk(KERN_WARNING "unknown E5 packet %02x\n",
344
                               k->packet[0]);
345
                }
346
        }
347
 
348
        if (k->pos == k->length) {
349
                int i;
350
 
351
                if (e5_checksum(k->packet, k->length) != 0)
352
                        printk(KERN_WARNING "E5: wrong checksum\n");
353
 
354
#if 0
355
                printk("E5 packet [");
356
                for(i=0; i<k->length; i++) {
357
                        printk("%02x ", k->packet[i]);
358
                }
359
 
360
                printk("(%02x)]\n", e5_checksum(k->packet, k->length-1));
361
#endif
362
 
363
                switch(k->packet[0]) {
364
                case 0x80:
365
                case 0x88:
366
                        handle_keyboard_event(k->packet[1]);
367
                        break;
368
                }
369
 
370
                k->pos = k->length = 0;
371
        }
372
}
373
 
374
static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs)
375
{
376
        struct e5_struct *k = &ec3104_keyb;
377
        u8 msr, lsr;
378
 
379
        kbd_pt_regs = regs;
380
 
381
        msr = ctrl_inb(EC3104_SER4_MSR);
382
 
383
        if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
384
                if (k->cached_mcr & MCR_RTS)
385
                        printk("confused: RTS already high\n");
386
                /* CTS went high.  Send RTS. */
387
                k->cached_mcr |= MCR_RTS;
388
 
389
                ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
390
        } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
391
                /* CTS went low. */
392
                if (!(k->cached_mcr & MCR_RTS))
393
                        printk("confused: RTS already low\n");
394
 
395
                k->cached_mcr &= ~MCR_RTS;
396
 
397
                ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
398
        }
399
 
400
        k->last_msr = msr;
401
 
402
        lsr = ctrl_inb(EC3104_SER4_LSR);
403
 
404
        if (lsr & LSR_DR)
405
                e5_receive(k);
406
}
407
 
408
static void ec3104_keyb_clear_state(void)
409
{
410
        struct e5_struct *k = &ec3104_keyb;
411
        u8 msr, lsr;
412
 
413
        /* we want CTS to be low */
414
        k->last_msr = 0;
415
 
416
        for (;;) {
417
                schedule_timeout(HZ/10);
418
 
419
                msr = ctrl_inb(EC3104_SER4_MSR);
420
 
421
                lsr = ctrl_inb(EC3104_SER4_LSR);
422
 
423
                if (lsr & LSR_DR) {
424
                        e5_receive(k);
425
                        continue;
426
                }
427
 
428
                if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) {
429
                        if (k->cached_mcr & MCR_RTS)
430
                                printk("confused: RTS already high\n");
431
                        /* CTS went high.  Send RTS. */
432
                        k->cached_mcr |= MCR_RTS;
433
 
434
                        ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
435
                } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) {
436
                        /* CTS went low. */
437
                        if (!(k->cached_mcr & MCR_RTS))
438
                                printk("confused: RTS already low\n");
439
 
440
                        k->cached_mcr &= ~MCR_RTS;
441
 
442
                        ctrl_outb(k->cached_mcr, EC3104_SER4_MCR);
443
                } else
444
                        break;
445
 
446
                k->last_msr = msr;
447
 
448
                continue;
449
        }
450
}
451
 
452
void __init ec3104_kbd_init_hw(void)
453
{
454
        ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR);
455
        ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR);
456
 
457
        ec3104_keyb_clear_state();
458
 
459
        /* Ok, finally allocate the IRQ, and off we go.. */
460
        request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL);
461
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.