]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/services/gfx/mw/v2_0/src/drivers/kbd_ttyscan.c
Cleanup CVS ipmorted branch
[karo-tx-redboot.git] / packages / services / gfx / mw / v2_0 / src / drivers / kbd_ttyscan.c
1 /*
2  * Copyright (c) 2000 Greg Haerr <greg@censoft.com>
3  *
4  * Microwindows /dev/tty console scancode keyboard driver for Linux
5  */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <termios.h>
14 #include <sys/ioctl.h>
15 #include <linux/keyboard.h>
16 #include <linux/kd.h>
17 #include <linux/vt.h>
18 #include "device.h"
19 #include "fb.h"
20
21 #define KEYBOARD        "/dev/tty"      /* console kbd to open*/
22
23 static int  TTY_Open(KBDDEVICE *pkd);
24 static void TTY_Close(void);
25 static void TTY_GetModifierInfo(MWKEYMOD *modifiers, MWKEYMOD *curmodifiers);
26 static int  TTY_Read(MWKEY *kbuf, MWKEYMOD *modifiers, MWSCANCODE *scancode);
27
28 KBDDEVICE kbddev = {
29         TTY_Open,
30         TTY_Close,
31         TTY_GetModifierInfo,
32         TTY_Read,
33         NULL
34 };
35
36 #define RELEASED        0
37 #define PRESSED         1
38
39 static  int             fd;             /* file descriptor for keyboard */
40 static  struct termios  old;            /* original terminal modes */
41 static  int             old_kbd_mode;
42 static unsigned char    key_state[MWKEY_LAST];  /* FIXME - make sparse array */
43 static MWKEYMOD         key_modstate;
44
45 /* kernel unicode tables per shiftstate and scancode*/
46 #define NUM_VGAKEYMAPS  (1<<KG_CAPSSHIFT)       /* kernel key maps*/
47 static unsigned short   os_keymap[NUM_VGAKEYMAPS][NR_KEYS];
48
49 /* PC scancode -> Microwindows key value mapping for non-Linux kernel values*/
50 static MWKEY            keymap[128] = {
51 MWKEY_UNKNOWN, MWKEY_ESCAPE, '1', '2', '3',                             /* 0*/
52 '4', '5', '6', '7', '8',                                                /* 5*/
53 '9', '0', '-', '=', MWKEY_BACKSPACE,                                    /* 10*/
54 MWKEY_TAB, 'q', 'w', 'e', 'r',                                          /* 15*/
55 't', 'y', 'u', 'i', 'o',                                                /* 20*/
56 'o', '[', ']', MWKEY_ENTER, MWKEY_LCTRL,                                /* 25*/
57 'a', 's', 'd', 'f', 'g',                                                /* 30*/
58 'h', 'j', 'k', 'l', ';',                                                /* 35*/
59 '\'', '`', MWKEY_LSHIFT, '\\', 'z',                                     /* 40*/
60 'x', 'c', 'v', 'b', 'n',                                                /* 45*/
61 'm', ',', '.', '/', MWKEY_RSHIFT,                                       /* 50*/
62 MWKEY_KP_MULTIPLY, MWKEY_LALT, ' ', MWKEY_CAPSLOCK, MWKEY_F1,           /* 55*/
63 MWKEY_F2, MWKEY_F3, MWKEY_F4, MWKEY_F5, MWKEY_F6,                       /* 60*/
64 MWKEY_F7, MWKEY_F8, MWKEY_F9, MWKEY_F10, MWKEY_NUMLOCK,                 /* 65*/
65 MWKEY_SCROLLOCK, MWKEY_KP7, MWKEY_KP8, MWKEY_KP9, MWKEY_KP_MINUS,       /* 70*/
66 MWKEY_KP4, MWKEY_KP5, MWKEY_KP6, MWKEY_KP_PLUS, MWKEY_KP1,              /* 75*/
67 MWKEY_KP2, MWKEY_KP3, MWKEY_KP0, MWKEY_KP_PERIOD, MWKEY_UNKNOWN,        /* 80*/
68 MWKEY_UNKNOWN, MWKEY_UNKNOWN, MWKEY_F11, MWKEY_F12, MWKEY_UNKNOWN,      /* 85*/
69 MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,  /* 90*/
70 MWKEY_UNKNOWN, MWKEY_KP_ENTER, MWKEY_RCTRL, MWKEY_KP_DIVIDE,MWKEY_PRINT,/* 95*/
71 MWKEY_RALT, MWKEY_BREAK, MWKEY_HOME, MWKEY_UP, MWKEY_PAGEUP,            /* 100*/
72 MWKEY_LEFT, MWKEY_RIGHT, MWKEY_END, MWKEY_DOWN, MWKEY_PAGEDOWN,         /* 105*/
73 MWKEY_INSERT, MWKEY_DELETE, MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,  /* 110*/
74 MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_PAUSE,    /* 115*/
75 MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,MWKEY_UNKNOWN,  /* 120*/
76 MWKEY_LMETA, MWKEY_RMETA, MWKEY_MENU                                    /* 125*/
77 };
78
79 static MWBOOL   UpdateKeyState(int pressed, MWKEY mwkey);
80 static void     UpdateLEDState(MWKEYMOD modstate);
81 static MWKEY    TranslateScancode(int scancode, MWKEYMOD modstate);
82 static void     LoadKernelKeymaps(int fd);
83 static MWBOOL   switch_vt(unsigned short which);
84
85 /*
86  * Open the keyboard.
87  * This is real simple, we just use a special file handle
88  * that allows non-blocking I/O, and put the terminal into
89  * character mode.
90  */
91 static int
92 TTY_Open(KBDDEVICE *pkd)
93 {
94   char *env;
95
96         int             i;
97         int             ledstate = 0;
98         struct termios  new;
99
100         /* Open "CONSOLE" or /dev/tty device*/
101         if(!(env = getenv("CONSOLE")))
102                 fd = open(KEYBOARD, O_NONBLOCK);
103         else
104                 fd = open(env, O_NONBLOCK);
105         if (fd < 0)
106                 return -1;
107
108         /* Save previous settings*/
109         if (ioctl(fd, KDGKBMODE, &old_kbd_mode) < 0) {
110                 perror("KDGKMODE");
111                 goto err;
112         }
113         if (tcgetattr(fd, &old) < 0)
114                 goto err;
115
116         /* Set medium-raw keyboard mode */
117         new = old;
118         /* ISIG and BRKINT must be set otherwise '2' is ^C (scancode 3)!!*/
119         new.c_lflag &= ~(ICANON | ECHO | ISIG);
120         new.c_iflag &= ~(ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON 
121                         | BRKINT);
122         new.c_cc[VMIN] = 0;
123         new.c_cc[VTIME] = 0;
124
125         if (tcsetattr(fd, TCSAFLUSH, &new) < 0) {
126                 TTY_Close();
127                 return -1;
128         }
129         if (ioctl(fd, KDSKBMODE, K_MEDIUMRAW) < 0) {
130                 TTY_Close();
131                 return -1;
132         }
133
134         /* Load OS keymappings*/
135         LoadKernelKeymaps(fd);
136
137         /* Initialize keyboard state*/
138         key_modstate = MWKMOD_NONE;
139         for (i=0; i<MWKEY_LAST; ++i)
140                 key_state[i] = RELEASED;
141         
142         /* preset CAPSLOCK and NUMLOCK from startup LED state*/
143         if (ioctl(fd, KDGETLED, &ledstate) == 0) {
144                 if (ledstate & LED_CAP) {
145                         key_modstate |= MWKMOD_CAPS;
146                         key_state[MWKEY_CAPSLOCK] = PRESSED;
147                 }
148                 if (ledstate & LED_NUM) {
149                         key_modstate |= MWKMOD_NUM;
150                         key_state[MWKEY_NUMLOCK] = PRESSED;
151                 }
152         }
153         UpdateLEDState(key_modstate);
154
155         return fd;
156
157 err:
158         close(fd);
159         fd = -1;
160         return -1;
161 }
162
163 /*
164  * Close the keyboard.
165  * This resets the terminal modes.
166  */
167 static void
168 TTY_Close(void)
169 {
170         int     ledstate = 0x80000000L;
171
172         if (fd >= 0) {
173                 /* revert LEDs to follow key modifiers*/
174                 if (ioctl(fd, KDSETLED, ledstate) < 0)
175                         perror("KDSETLED");
176
177                 /* reset terminal mode*/
178                 if (ioctl(fd, KDSKBMODE, old_kbd_mode) < 0)
179                         perror("KDSKBMODE");
180                 tcsetattr(fd, TCSAFLUSH, &old);
181
182                 close(fd);
183         }
184         fd = -1;
185 }
186
187 /*
188  * Return the possible modifiers and current modifiers for the keyboard.
189  */
190 static  void
191 TTY_GetModifierInfo(MWKEYMOD *modifiers, MWKEYMOD *curmodifiers)
192 {
193         if (modifiers)
194                 *modifiers = MWKMOD_CTRL | MWKMOD_SHIFT | MWKMOD_ALT |
195                         MWKMOD_META | MWKMOD_ALTGR | MWKMOD_CAPS | MWKMOD_NUM;
196         if (curmodifiers)
197                 *curmodifiers = key_modstate;
198 }
199
200 /*
201  * This reads one keystroke from the keyboard, and the current state of
202  * the modifier keys (ALT, SHIFT, etc).  Returns -1 on error, 0 if no data
203  * is ready, 1 on a keypress, and 2 on keyrelease.
204  * This is a non-blocking call.
205  */
206 static int
207 TTY_Read(MWKEY *kbuf, MWKEYMOD *modifiers, MWSCANCODE *pscancode)
208 {
209         int     cc;                     /* characters read */
210         int     pressed;
211         int     scancode;
212         MWKEY   mwkey;
213         unsigned char buf[128];
214
215         cc = read(fd, buf, 1);
216         if (cc > 0) {
217                 pressed = (*buf & 0x80) ? RELEASED: PRESSED;
218                 scancode = *buf & 0x7f;
219                 mwkey = keymap[scancode];
220
221                 /**if(pressed) {
222                         printf("scan %02x really: %08x\n", *buf&0x7F, *buf);
223                         printf("mwkey: %02x (%c)\n", mwkey, mwkey);
224                 }**/
225
226                 /* Handle Alt-FN for vt switch */
227                 switch (mwkey) {
228                 case MWKEY_F1:
229                 case MWKEY_F2:
230                 case MWKEY_F3:
231                 case MWKEY_F4:
232                 case MWKEY_F5:
233                 case MWKEY_F6:
234                 case MWKEY_F7:
235                 case MWKEY_F8:
236                 case MWKEY_F9:
237                 case MWKEY_F10:
238                 case MWKEY_F11:
239                 case MWKEY_F12:
240                         if (key_modstate & MWKMOD_ALT) {
241                                 if (switch_vt(mwkey-MWKEY_F1+1)) {
242                                         mwkey = MWKEY_REDRAW;
243                                 }
244                         }
245                         break;
246                         /* Fall through to normal processing */
247                 default:
248                         /* update internal key states*/
249                         if (!UpdateKeyState(pressed, mwkey))
250                                 return 0;
251
252                         /* mwkey is 0 if only a modifier is hit */
253                         if(mwkey != MWKEY_LCTRL && 
254                            mwkey != MWKEY_RCTRL &&
255                            mwkey != MWKEY_LALT &&
256                            mwkey != MWKEY_RALT &&
257                            mwkey != MWKEY_RSHIFT &&
258                            mwkey != MWKEY_LSHIFT) {
259                                 /* translate scancode to key value*/
260                                 mwkey = TranslateScancode(scancode, key_modstate);
261                         } else {
262                                 //printf("Modifier only\n");
263                                 //mwkey = 0;
264                         }
265                         
266                         /* XXX Hack to get scancodes to come out the same as 
267                            everything else */
268                         switch(scancode) {
269                                 case 0x1:           /* esc              */
270
271                                 case 0x29:          /* `                */
272                                 case 0x2  ... 0xe:  /* 1 - BackSpace    */
273
274                                 case 0xf  ... 0x1b: /* TAB - ]          */
275                                 case 0x2b:          /* \                */
276
277                                 case 0x3a:          /* Caps-Lock        */
278                                 case 0x1e ... 0x28: /* a - '            */
279                                 case 0x1c:          /* Enter            */
280
281                                 case 0x2a:          /* LShift           */
282                                 case 0x2c ... 0x35: /* z - /            */
283                                 case 0x36:          /* RShift           */
284
285                                 case 0x1d:          /* LCtrl            */
286                                 //case 0x7d:          /* LWin           */
287                                 case 0x38:          /* LAlt             */
288                                 case 0x39:          /* Space            */
289                                 //case 0x64:          /* RAlt           */
290                                 //case 0x7e:          /* RWin           */
291                                 //case 0x7f:          /* Win-PopupMenu  */
292                                 //case 0x61:          /* RCtrl          */
293
294                                 //case 0x63:          /* SysReq         */
295                                 //case 0x46:          /* Scroll Lock    */
296                                 //case 0x77:          /* Pause/Break    */
297                                         scancode += 8;
298                                         break;
299
300                                 case 0x6e:            /* Insert         */
301                                         scancode -= 0x4;
302                                         break;
303                                 case 0x66:            /* Home           */
304                                 case 0x68:            /* Page-Up        */
305                                         scancode -= 0x5;
306                                         break;
307
308                                 case 0x6f:            /* Delete         */
309                                 case 0x6b:            /* End            */
310                                 case 0x6d:            /* Page-Down      */
311                                         scancode -= 0x4;
312                                         break;
313                                 
314                                 case 0x67:            /* Up arrow       */
315                                 case 0x69:            /* Left arrow     */
316                                         scancode -= 0x5;
317                                         break;
318                                 
319                                 case 0x6a:            /* Right arrow    */
320                                 case 0x6c:            /* Down arrow     */
321                                         scancode -= 0x4;
322                                         break;
323
324                                 default: 
325                                         break;
326                         }
327                         break;
328                 }       
329                 *kbuf = mwkey;
330                 *modifiers = key_modstate;
331                 *pscancode = scancode;
332
333                 /**if(pressed) {
334                         printf("Returning: mwkey: 0x%04x, mods: 0x%x,
335                                 sc:0x%04x\n\n", *kbuf, *modifiers, *pscancode);
336                 }**/
337                 return pressed ? 1 : 2;
338         }
339
340         if ((cc < 0) && (errno != EINTR) && (errno != EAGAIN))
341                 return -1;
342         return 0;
343 }
344
345 /* Update the internal keyboard state, return TRUE if changed*/
346 static MWBOOL
347 UpdateKeyState(int pressed, MWKEY mwkey)
348 {
349         MWKEYMOD modstate = key_modstate;
350
351         //printf("UpdateKeyState %02x %02x\n", pressed, mwkey);
352         if (pressed == PRESSED) {
353                 switch (mwkey) {
354                 case MWKEY_NUMLOCK:
355                 case MWKEY_CAPSLOCK:
356                         /* change state on release because of auto-repeat*/
357                         return FALSE;
358                 case MWKEY_LCTRL:
359                         modstate |= MWKMOD_LCTRL;
360                         break;
361                 case MWKEY_RCTRL:
362                         modstate |= MWKMOD_RCTRL;
363                         break;
364                 case MWKEY_LSHIFT:
365                         modstate |= MWKMOD_LSHIFT;
366                         break;
367                 case MWKEY_RSHIFT:
368                         modstate |= MWKMOD_RSHIFT;
369                         break;
370                 case MWKEY_LALT:
371                         modstate |= MWKMOD_LALT;
372                         break;
373                 case MWKEY_RALT:
374                         modstate |= MWKMOD_RALT;
375                         break;
376                 case MWKEY_LMETA:
377                         modstate |= MWKMOD_LMETA;
378                         break;
379                 case MWKEY_RMETA:
380                         modstate |= MWKMOD_RMETA;
381                         break;
382                 case MWKEY_ALTGR:
383                         modstate |= MWKMOD_ALTGR;
384                         break;
385                 default:
386                         break;
387                 }
388         } else {
389                 switch (mwkey) {
390                 case MWKEY_NUMLOCK:
391                         key_modstate ^= MWKMOD_NUM;
392                         key_state[MWKEY_NUMLOCK] ^= PRESSED;
393                         UpdateLEDState(key_modstate);
394                         return TRUE;
395                 case MWKEY_CAPSLOCK:
396                         key_modstate ^= MWKMOD_CAPS;
397                         key_state[MWKEY_CAPSLOCK] ^= PRESSED;
398                         UpdateLEDState(key_modstate);
399                         return TRUE;
400                 case MWKEY_LCTRL:
401                         modstate &= ~MWKMOD_LCTRL;
402                         break;
403                 case MWKEY_RCTRL:
404                         modstate &= ~MWKMOD_RCTRL;
405                         break;
406                 case MWKEY_LSHIFT:
407                         modstate &= ~MWKMOD_LSHIFT;
408                         break;
409                 case MWKEY_RSHIFT:
410                         modstate &= ~MWKMOD_RSHIFT;
411                         break;
412                 case MWKEY_LALT:
413                         modstate &= ~MWKMOD_LALT;
414                         break;
415                 case MWKEY_RALT:
416                         modstate &= ~MWKMOD_RALT;
417                         break;
418                 case MWKEY_LMETA:
419                         modstate &= ~MWKMOD_LMETA;
420                         break;
421                 case MWKEY_RMETA:
422                         modstate &= ~MWKMOD_RMETA;
423                         break;
424                 case MWKEY_ALTGR:
425                         modstate &= ~MWKMOD_ALTGR;
426                         break;
427                 default:
428                         break;
429                 }
430         }
431
432 #if 0
433         /* Drop events that don't change state */
434         if (key_state[mwkey] == pressed)
435                 return FALSE;
436 #endif
437         /* Update internal keyboard state */
438         key_state[mwkey] = (unsigned char)pressed;
439         key_modstate = modstate;
440         return TRUE;
441 }
442
443 static void
444 UpdateLEDState(MWKEYMOD modstate)
445 {
446         int     ledstate = 0;
447
448         if (modstate & MWKMOD_CAPS)
449                 ledstate |= LED_CAP;
450         if (modstate & MWKMOD_NUM)
451                 ledstate |= LED_NUM;
452         ioctl(fd, KDSETLED, ledstate);
453 }
454
455 /* translate a scancode and modifier state to an MWKEY*/
456 static MWKEY
457 TranslateScancode(int scancode, MWKEYMOD modstate)
458 {
459         unsigned short  mwkey = 0;
460         int             map = 0;
461
462         //printf("Translate: 0x%04x\n", scancode);
463
464         /* determine appropriate kernel table*/
465         if (modstate & MWKMOD_SHIFT)
466                 map |= (1<<KG_SHIFT);
467         if (modstate & MWKMOD_CTRL)
468                 map |= (1<<KG_CTRL);
469         if (modstate & MWKMOD_ALT)
470                 map |= (1<<KG_ALT);
471         if (modstate & MWKMOD_ALTGR)
472                 map |= (1<<KG_ALTGR);
473         if (KTYP(os_keymap[map][scancode]) == KT_LETTER) {
474                 if (modstate & MWKMOD_CAPS)
475                         map |= (1<<KG_SHIFT);
476         }
477         if (KTYP(os_keymap[map][scancode]) == KT_PAD) {
478                 if (modstate & MWKMOD_NUM) {
479                         switch (keymap[scancode]) {
480                         case MWKEY_KP0:
481                         case MWKEY_KP1:
482                         case MWKEY_KP2:
483                         case MWKEY_KP3:
484                         case MWKEY_KP4:
485                         case MWKEY_KP5:
486                         case MWKEY_KP6:
487                         case MWKEY_KP7:
488                         case MWKEY_KP8:
489                         case MWKEY_KP9:
490                                 mwkey = keymap[scancode] - MWKEY_KP0 + '0';
491                                 break;
492                         case MWKEY_KP_PERIOD:
493                                 mwkey = '.';
494                                 break;
495                         case MWKEY_KP_DIVIDE:
496                                 mwkey = '/';
497                                 break;
498                         case MWKEY_KP_MULTIPLY:
499                                 mwkey = '*';
500                                 break;
501                         case MWKEY_KP_MINUS:
502                                 mwkey = '-';
503                                 break;
504                         case MWKEY_KP_PLUS:
505                                 mwkey = '+';
506                                 break;
507                         case MWKEY_KP_ENTER:
508                                 mwkey = MWKEY_ENTER;
509                                 break;
510                         case MWKEY_KP_EQUALS:
511                                 mwkey = '-';
512                                 break;
513                         }
514                 }
515         } else
516                 mwkey = KVAL(os_keymap[map][scancode]);
517         
518         if (!mwkey)
519                 mwkey = keymap[scancode];
520
521         /* perform additional translations*/
522         switch (mwkey) {
523         case 127:
524                 mwkey = MWKEY_BACKSPACE;
525                 break;
526         case MWKEY_BREAK:
527         case MWKEY_PAUSE:
528                 mwkey = MWKEY_QUIT;
529                 break;
530         case 0x1c:      /* kernel maps print key to ctrl-\ */
531         case MWKEY_SYSREQ:
532                 mwkey = MWKEY_PRINT;
533                 break;
534         }
535
536         /* printf("TranslateScancode %02x to mwkey %d\n", scancode, mwkey); */
537         return mwkey;
538 }
539
540 /* load Linux keyboard mappings, used as first try for scancode conversion*/
541 static void
542 LoadKernelKeymaps(int fd)
543 {
544         int             map, i;
545         struct kbentry  entry;
546
547         /* Load all the keysym mappings */
548         for (map=0; map<NUM_VGAKEYMAPS; ++map) {
549                 memset(os_keymap[map], 0, NR_KEYS*sizeof(unsigned short));
550                 for (i=0; i<NR_KEYS; ++i) {
551                         entry.kb_table = map;
552                         entry.kb_index = i;
553                         if (ioctl(fd, KDGKBENT, &entry) == 0) {
554                                 /* change K_ENTER to \r*/
555                                 if (entry.kb_value == K_ENTER)
556                                         entry.kb_value = K(KT_ASCII,13);
557
558                                 if ((KTYP(entry.kb_value) == KT_LATIN) ||
559                                     (KTYP(entry.kb_value) == KT_ASCII) ||
560                                     (KTYP(entry.kb_value) == KT_PAD) ||
561                                     (KTYP(entry.kb_value) == KT_LETTER)
562                                     )
563                                         os_keymap[map][i] = entry.kb_value;
564                         }
565                 }
566         }
567
568 }
569 /* Handle switching to another VC, returns when our VC is back */
570 static MWBOOL
571 switch_vt(unsigned short which)
572 {
573         struct vt_stat vtstate;
574         unsigned short current;
575         static unsigned short r[16], g[16], b[16];
576
577         /* Figure out whether or not we're switching to a new console */
578         if ((ioctl(fd, VT_GETSTATE, &vtstate) < 0) ||
579             (which == vtstate.v_active)) {
580                 return FALSE;
581         }
582         current = vtstate.v_active;
583
584         /* save palette, goto text mode*/
585         ioctl_getpalette(0, 16, r, g, b);
586         ioctl(fd, KDSETMODE, KD_TEXT);
587
588         /* New console, switch to it */
589         if (ioctl(fd, VT_ACTIVATE, which) == 0) {
590                 /* Wait for our console to be activated again */
591                 ioctl(fd, VT_WAITACTIVE, which);
592                 while (ioctl(fd, VT_WAITACTIVE, current) < 0) {
593                         if ((errno != EINTR) && (errno != EAGAIN)) {
594                                 /* Unknown VT error, cancel*/
595                                 break;
596                         }
597                         usleep(100000);
598                 }
599         }
600
601         /* Restore graphics mode and the contents of the screen */
602         ioctl(fd, KDSETMODE, KD_GRAPHICS);
603         ioctl_setpalette(0, 16, r, g, b);
604         return TRUE;
605 }