added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / arch / all-linux / hidd / kbdclass.c
blob2eeb926060880b0ecfe452825f39d200368210cd
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Linux hidd handling keyboard
6 Lang: English.
7 */
9 #define __OOP_NOATTRBASES__
11 #include <dos/dos.h>
13 #include <proto/utility.h>
14 #include <proto/oop.h>
15 #include <proto/dos.h>
16 #include <oop/oop.h>
18 #include <hidd/hidd.h>
19 #include <hidd/keyboard.h>
20 #include <devices/inputevent.h>
21 #include <devices/rawkeycodes.h>
23 #include <aros/symbolsets.h>
25 /* hack: prevent linux include header <bits/time.h> to re-define timeval struct */
26 # define _STRUCT_TIMEVAL 1
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <string.h>
32 #include <errno.h>
34 #include "linux_intern.h"
36 #include LC_LIBDEFS_FILE
38 #define DEBUG 0
39 #include <aros/debug.h>
40 #include <stdio.h>
41 #include <stdlib.h>
43 static UBYTE scancode2rawkey[256];
44 static BOOL havetable;
45 void setup_sighandling(void);
46 void cleanup_sighandling();
48 static OOP_AttrBase HiddKbdAB = 0;
50 static struct OOP_ABDescr attrbases[] =
52 { IID_Hidd_Kbd, &HiddKbdAB },
53 { NULL , NULL }
56 static UBYTE scancode2rawkey[256];
57 static BOOL havetable = FALSE;
59 static UWORD scancode2hidd(UBYTE scancode, struct linux_staticdata *lsd);
61 /***** Kbd::New() ***************************************/
62 OOP_Object * LinuxKbd__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
64 BOOL has_kbd_hidd = FALSE;
65 struct TagItem *tag, *tstate;
66 APTR callback = NULL;
67 APTR callbackdata = NULL;
69 EnterFunc(bug("Kbd::New()\n"));
71 ObtainSemaphore(&LSD(cl)->sema);
72 if (LSD(cl)->kbdhidd)
73 has_kbd_hidd = TRUE;
74 ReleaseSemaphore(&LSD(cl)->sema);
76 if (has_kbd_hidd) /* Cannot open twice */
77 ReturnPtr("Kbd::New", OOP_Object *, NULL); /* Should have some error code here */
79 tstate = msg->attrList;
80 D(bug("tstate: %p, tag=%x\n", tstate, tstate->ti_Tag));
81 while ((tag = NextTagItem((const struct TagItem **)&tstate)))
83 ULONG idx;
85 D(bug("Got tag %d, data %x\n", tag->ti_Tag, tag->ti_Data));
87 if (IS_HIDDKBD_ATTR(tag->ti_Tag, idx))
89 D(bug("Kbd hidd tag\n"));
90 switch (idx)
92 case aoHidd_Kbd_IrqHandler:
93 callback = (APTR)tag->ti_Data;
94 D(bug("Got callback %p\n", (APTR)tag->ti_Data));
95 break;
97 case aoHidd_Kbd_IrqHandlerData:
98 callbackdata = (APTR)tag->ti_Data;
99 D(bug("Got data %p\n", (APTR)tag->ti_Data));
100 break;
104 } /* while (tags to process) */
105 if (NULL == callback)
106 ReturnPtr("Kbd::New", OOP_Object *, NULL); /* Should have some error code here */
108 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
109 if (o)
111 struct linuxkbd_data *data = OOP_INST_DATA(cl, o);
113 data->kbd_callback = (VOID (*)(APTR, UWORD))callback;
114 data->callbackdata = callbackdata;
116 ObtainSemaphore(&LSD(cl)->sema);
117 LSD(cl)->kbdhidd = o;
118 ReleaseSemaphore(&LSD(cl)->sema);
120 ReturnPtr("Kbd::New", OOP_Object *, o);
124 VOID LinuxKbd__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
126 ObtainSemaphore(&LSD(cl)->sema);
127 LSD(cl)->kbdhidd = NULL;
128 ReleaseSemaphore(&LSD(cl)->sema);
130 OOP_DoSuperMethod(cl, o, msg);
133 /***** LinuxKbd::HandleEvent() ***************************************/
135 VOID LinuxKbd__Hidd_LinuxKbd__HandleEvent(OOP_Class *cl, OOP_Object *o, struct pHidd_LinuxKbd_HandleEvent *msg)
137 struct linuxkbd_data *data;
138 UBYTE scancode;
139 UWORD hiddcode;
141 EnterFunc(bug("linuxkbd_handleevent()\n"));
143 data = OOP_INST_DATA(cl, o);
145 scancode = msg->scanCode;
146 hiddcode = scancode2hidd(scancode, LSD(cl));
148 if (hiddcode != 0xFF)
150 if (scancode >= 0x80)
151 hiddcode |= IECODE_UP_PREFIX;
153 data->kbd_callback(data->callbackdata, hiddcode);
156 ReturnVoid("Kbd::HandleEvent");
160 #undef LSD
161 #define LSD(cl) lsd
163 /**************** scancode2hidd() ****************/
164 #define DEF_TAB_SIZE 128
166 const UBYTE deftable[] =
168 0xff,
169 RAWKEY_ESCAPE,
170 RAWKEY_1,
171 RAWKEY_2,
172 RAWKEY_3,
173 RAWKEY_4,
174 RAWKEY_5,
175 RAWKEY_6,
176 RAWKEY_7,
177 RAWKEY_8,
178 RAWKEY_9,
179 RAWKEY_0,
180 RAWKEY_MINUS,
181 RAWKEY_EQUAL,
182 RAWKEY_BACKSPACE,
183 RAWKEY_TAB,
184 RAWKEY_Q,
185 RAWKEY_W,
186 RAWKEY_E,
187 RAWKEY_R,
188 RAWKEY_T,
189 RAWKEY_Y,
190 RAWKEY_U,
191 RAWKEY_I,
192 RAWKEY_O,
193 RAWKEY_P,
194 RAWKEY_LBRACKET,
195 RAWKEY_RBRACKET,
196 RAWKEY_RETURN,
197 RAWKEY_CONTROL,
198 RAWKEY_A,
199 RAWKEY_S,
200 RAWKEY_D,
201 RAWKEY_F,
202 RAWKEY_G,
203 RAWKEY_H,
204 RAWKEY_J,
205 RAWKEY_K,
206 RAWKEY_L,
207 RAWKEY_SEMICOLON,
208 RAWKEY_QUOTE,
209 RAWKEY_TILDE,
210 RAWKEY_LSHIFT,
211 RAWKEY_2B,
212 RAWKEY_Z,
213 RAWKEY_X,
214 RAWKEY_C,
215 RAWKEY_V,
216 RAWKEY_B,
217 RAWKEY_N,
218 RAWKEY_M,
219 RAWKEY_COMMA,
220 RAWKEY_PERIOD,
221 RAWKEY_SLASH,
222 RAWKEY_RSHIFT,
223 0x5C,
224 RAWKEY_LALT,
225 RAWKEY_SPACE,
226 RAWKEY_CAPSLOCK,
227 RAWKEY_F1,
228 RAWKEY_F2,
229 RAWKEY_F3,
230 RAWKEY_F4,
231 RAWKEY_F5,
232 RAWKEY_F6,
233 RAWKEY_F7,
234 RAWKEY_F8,
235 RAWKEY_F9,
236 RAWKEY_F10,
237 0x5A,
238 0xff,
239 RAWKEY_KP_7,
240 RAWKEY_KP_8,
241 RAWKEY_KP_9,
242 0x5D,
243 RAWKEY_KP_4,
244 RAWKEY_KP_5,
245 RAWKEY_KP_6,
246 RAWKEY_KP_PLUS,
247 RAWKEY_KP_1,
248 RAWKEY_KP_2,
249 RAWKEY_KP_3,
250 RAWKEY_KP_0,
251 RAWKEY_KP_DECIMAL,
252 0xff,
253 0xff,
254 RAWKEY_LESSGREATER,
255 RAWKEY_F11,
256 RAWKEY_F12,
257 0xff,
258 0xff,
259 0xff,
260 0xff,
261 0xff,
262 0xff,
263 0xff,
264 RAWKEY_KP_ENTER,
265 RAWKEY_CONTROL,
266 0x5B,
267 0xff,
268 RAWKEY_RALT,
269 RAWKEY_PAUSE,
270 RAWKEY_HOME,
271 RAWKEY_UP,
272 RAWKEY_PAGEUP,
273 RAWKEY_LEFT,
274 RAWKEY_RIGHT,
275 RAWKEY_END,
276 RAWKEY_DOWN,
277 RAWKEY_PAGEDOWN,
278 RAWKEY_INSERT,
279 RAWKEY_DELETE,
280 0xff,
281 0xff,
282 0xff,
283 0xff,
284 0xff,
285 0xff,
286 0xff,
287 RAWKEY_PAUSE,
288 0xff,
289 0xff,
290 0xff,
291 0xff,
292 0xff,
293 RAWKEY_LAMIGA,
294 RAWKEY_RAMIGA,
295 0xff
297 static UWORD scancode2hidd(UBYTE scancode, struct linux_staticdata *lsd)
299 UWORD hiddcode;
301 if ((scancode & 0x80) == 0x80)
302 scancode &= ~0x80;
304 if (havetable)
306 hiddcode = scancode2rawkey[scancode];
308 else
310 if (scancode >= DEF_TAB_SIZE)
311 hiddcode = 0xFF;
312 else
313 hiddcode = deftable[scancode];
316 return hiddcode;
319 #if 0
320 /**************** LoadScanCode2RawKeyTable() ***************************/
322 static void LoadScanCode2RawKeyTable(struct linux_staticdata *lsd)
324 char *filename = "DEVS:Keymaps/X11/keycode2rawkey.table";
325 BPTR fh;
327 if ((fh =Open(filename, MODE_OLDFILE)))
329 if ((256 == Read(fh, scancode2rawkey, 256)))
331 bug("LoadKeyCode2RawKeyTable: keycode2rawkey.table successfully loaded!\n");
332 havetable = TRUE;
334 else
336 bug("LoadKeyCode2RawKeyTable: Reading from \"%s\" failed!\n", filename);
338 Close(fh);
341 else
343 bug("\nLoadKeyCode2RawKeyTable: Loading \"%s\" failed!\n"
344 "\n"
345 "This means that many/most/all keys on your keyboard won't work as you\n"
346 "would expect in AROS. Therefore you should create this table by either\n"
347 "using the default table:\n"
348 "\n"
349 " mmake .default-linuxkeymaptable\n"
350 "\n"
351 "or generating your own one:\n"
352 "\n"
353 " mmake .change-linuxkeymaptable\n"
354 "\n"
355 "The default keymaptable probably works with most PCs having a 105 key\n"
356 "keyboard if you are using XFree86 as X Server (might also work with\n"
357 "others). So try that one first!\n"
358 "\n"
359 "Since the keymap table will be deleted when you do a \"make clean\" you\n"
360 "might want to make a backup of it. Then you will be able to restor it later:\n"
361 "\n"
362 " mmake .backup-linuxkeymaptable\n"
363 " mmake .restore-linuxkeymaptable\n"
364 "\n"
365 "The keymap table will be backuped in your HOME directory.\n"
366 "\n"
367 "Note that the keymaptable only makes sure that your keyboard looks as\n"
368 "much as possible like an Amiga keyboard to AROS. So with the keymaptable\n"
369 "alone the keyboard will behave like an Amiga keyboard with American layout\n."
370 "For other layouts you must activate the correct keymap file (which are in\n"
371 "\"DEVS:Keymaps\") just like in AmigaOS. Actually AROS has only German,\n"
372 "Italian and Swedish keymap files. You can activate them inside AROS by typing\n"
373 "this in a AROS Shell or adding it to the AROS Startup-Sequence:\n"
374 "\n"
375 " Setmap pc105_d\n"
376 " Setmap pc105_i\n"
377 " Setmap pc105_s\n"
378 "\n", filename);
381 #endif
383 /******************** init_kbdclass() *********************************/
386 static int Init_KbdClass(LIBBASETYPEPTR LIBBASE)
388 #if 0
389 LoadScanCode2RawKeyTable(&LIBBASE->lsd);
390 #endif
392 if (!OOP_ObtainAttrBases(attrbases))
393 return FALSE;
395 if (!init_linuxkbd(&LIBBASE->lsd))
397 OOP_ReleaseAttrBases(attrbases);
398 return FALSE;
401 return TRUE;
405 /*************** free_kbdclass() **********************************/
406 static int Expunge_KbdClass(LIBBASETYPEPTR LIBBASE)
408 cleanup_linuxkbd(&LIBBASE->lsd);
409 OOP_ReleaseAttrBases(attrbases);
410 return TRUE;
413 ADD2INITLIB(Init_KbdClass, 0)
414 ADD2EXPUNGELIB(Expunge_KbdClass, 0)
417 int set_kbd_mode(int fd, int mode, int *oldmode)
419 /* Get and preserve the old kbd mode */
420 if (NULL != oldmode)
422 if (-1 == ioctl(fd, KDGKBMODE, oldmode))
424 fprintf(stderr, "Unable to get old kbd mode: %s\n", strerror(errno));
425 return 0;
429 /* Set the new mode */
430 if (-1 == ioctl(fd, KDSKBMODE, mode))
432 fprintf(stderr, "Unable to set new kbd mode: %s\n", strerror(errno));
433 return 0;
436 return 1;
440 static int oldkbdmode;
441 static int kbdfd;
442 static struct termios oldtio;
443 static struct linux_staticdata *lsdata;
445 BOOL mode_done = FALSE
446 , fd_done = FALSE
447 , termios_done = FALSE;
449 #define KBD_DEVNAME "/dev/console"
451 BOOL init_linuxkbd(struct linux_staticdata *lsd)
453 BOOL ret = TRUE;
454 lsdata = lsd;
456 kprintf("INIT_KBD\n");
458 lsd->kbdfd = kbdfd = open(KBD_DEVNAME, O_RDONLY);
459 if (-1 == kbdfd)
461 kprintf("!!! Could not open keyboard device: %s\n", strerror(errno));
462 ret = FALSE;
464 else
466 /* Try to read some data from the keyboard */
467 struct termios newtio;
469 fd_done = TRUE;
472 setup_sighandling();
474 kprintf("SIGNALS SETUP\n");
476 if ( (-1 == tcgetattr(kbdfd, &oldtio)) || (-1 == tcgetattr(kbdfd, &newtio)))
478 kprintf("!!! Could not get old termios attrs: %s\n", strerror(errno));
479 ret = FALSE;
481 else
483 /* Set some new attrs */
484 newtio.c_lflag = ~(ICANON | ECHO | ISIG);
485 newtio.c_iflag = 0;
486 newtio.c_cc[VMIN] = 1;
487 newtio.c_cc[VTIME] = 0;
489 if (-1 == tcsetattr(kbdfd, TCSAFLUSH, &newtio))
491 kprintf("!!! Could not set new termio: %s\n", strerror(errno));
492 ret = FALSE;
494 else
496 termios_done = TRUE;
497 kprintf("SET TERMIO ATTRS\n");
499 if (!set_kbd_mode(kbdfd, K_MEDIUMRAW, &oldkbdmode))
501 kprintf("!!! Could not set kbdmode\n");
502 ret = FALSE;
504 else
506 kprintf("KBD MODE SET\n");
507 mode_done = TRUE;
508 ret = TRUE;
510 ioctl(kbdfd, KDSETMODE, KD_GRAPHICS); /* stegerg */
514 } /* if (termios attrs set) */
515 } /* if (got old termios attrs) */
518 if (!ret)
520 cleanup_linuxkbd(lsd);
523 return ret;
527 VOID cleanup_linuxkbd(struct linux_staticdata *lsd)
529 /* Reset the kbd mode */
530 if (mode_done)
532 ioctl(kbdfd, KDSETMODE, KD_TEXT); /* stegerg */
534 set_kbd_mode(kbdfd, oldkbdmode, NULL);
537 if (termios_done)
538 tcsetattr(kbdfd, TCSAFLUSH, &oldtio);
540 if (fd_done)
541 close(kbdfd);
543 cleanup_sighandling();
545 return;
548 const int signals[] =
550 SIGHUP, SIGINT, SIGQUIT, SIGILL,
551 SIGTRAP, SIGBUS, SIGFPE, SIGKILL,
552 /* SIGALRM, */ SIGSEGV , SIGTERM
556 void exit_sighandler(int sig)
558 printf("PARENT EXITING VIA SIGHANDLER\n");
559 cleanup_linuxkbd(lsdata);
560 exit(0);
563 void kbdsighandler(int sig)
565 cleanup_linuxkbd(lsdata);
568 /* Avoid that some signal kills us without resetting the keyboard */
569 void setup_sighandling(void)
571 ULONG i;
572 pid_t pid;
574 for (i = 0; i < sizeof (signals); i ++)
576 signal(signals[i], kbdsighandler);
579 signal(SIGTERM, exit_sighandler);
581 /* Sig alrm is is taken so we have to fork() to create a new process
582 that will kill us after a while */
584 pid = fork();
586 switch (pid)
588 case -1:
589 kprintf("!!!!!!!! ERROR FORKING !!!!!!!!!!!!!!\n");
590 exit(1);
593 case 0:
595 int *status = 0;
596 /* We are the child */
597 kprintf("----- CHILD GOING TO SLEEP ....\n");
598 sleep(120);
599 kprintf("-------- CHILD EXITING ------------\n");
600 kill(getppid(), SIGTERM);
601 exit(0);
604 default:
605 /* We are the parent */
606 kprintf("------- PARENT: PID %d\n", getpid());
607 break;
612 void cleanup_sighandling()
614 ULONG i;
616 for (i = 0; i < sizeof (signals); i ++)
618 signal(signals[i], SIG_DFL);
623 VOID HIDD_LinuxKbd_HandleEvent(OOP_Object *o, UBYTE scanCode)
625 static OOP_MethodID mid;
626 struct pHidd_LinuxKbd_HandleEvent p;
628 if (!mid)
629 mid = OOP_GetMethodID(IID_Hidd_LinuxKbd, moHidd_LinuxKbd_HandleEvent);
631 p.mID = mid;
632 p.scanCode = scanCode;
634 OOP_DoMethod(o, (OOP_Msg)&p);