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