Added missing properties.
[AROS.git] / arch / all-linux / hidd / linuxkbd / kbdclass.c
blob3f13a9959eb1f80f11cc9c04217b630fb319b3ba
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 /* avoid conflicts between our __unused define and the ones that might come in
29 via fcntl.h */
30 #undef __unused
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <errno.h>
37 #include "linux_intern.h"
39 #include LC_LIBDEFS_FILE
41 #define DEBUG 0
42 #include <aros/debug.h>
43 #include <stdio.h>
44 #include <stdlib.h>
46 static UBYTE scancode2rawkey[256];
47 static BOOL havetable;
48 void setup_sighandling(void);
49 void cleanup_sighandling();
51 static OOP_AttrBase HiddKbdAB = 0;
53 static struct OOP_ABDescr attrbases[] =
55 { IID_Hidd_Kbd, &HiddKbdAB },
56 { NULL , NULL }
59 static UBYTE scancode2rawkey[256];
60 static BOOL havetable = FALSE;
62 static UWORD scancode2hidd(UBYTE scancode, struct linux_staticdata *lsd);
64 /***** Kbd::New() ***************************************/
65 OOP_Object * LinuxKbd__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
67 BOOL has_kbd_hidd = FALSE;
68 struct TagItem *tag, *tstate;
69 APTR callback = NULL;
70 APTR callbackdata = NULL;
72 EnterFunc(bug("Kbd::New()\n"));
74 ObtainSemaphore(&LSD(cl)->sema);
75 if (LSD(cl)->kbdhidd)
76 has_kbd_hidd = TRUE;
77 ReleaseSemaphore(&LSD(cl)->sema);
79 if (has_kbd_hidd) /* Cannot open twice */
80 ReturnPtr("Kbd::New", OOP_Object *, NULL); /* Should have some error code here */
82 tstate = msg->attrList;
83 D(bug("tstate: %p, tag=%x\n", tstate, tstate->ti_Tag));
84 while ((tag = NextTagItem(&tstate)))
86 ULONG idx;
88 D(bug("Got tag %d, data %x\n", tag->ti_Tag, tag->ti_Data));
90 if (IS_HIDDKBD_ATTR(tag->ti_Tag, idx))
92 D(bug("Kbd hidd tag\n"));
93 switch (idx)
95 case aoHidd_Kbd_IrqHandler:
96 callback = (APTR)tag->ti_Data;
97 D(bug("Got callback %p\n", (APTR)tag->ti_Data));
98 break;
100 case aoHidd_Kbd_IrqHandlerData:
101 callbackdata = (APTR)tag->ti_Data;
102 D(bug("Got data %p\n", (APTR)tag->ti_Data));
103 break;
107 } /* while (tags to process) */
108 if (NULL == callback)
109 ReturnPtr("Kbd::New", OOP_Object *, NULL); /* Should have some error code here */
111 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg)msg);
112 if (o)
114 struct linuxkbd_data *data = OOP_INST_DATA(cl, o);
116 data->kbd_callback = (VOID (*)(APTR, UWORD))callback;
117 data->callbackdata = callbackdata;
119 ObtainSemaphore(&LSD(cl)->sema);
120 LSD(cl)->kbdhidd = o;
121 ReleaseSemaphore(&LSD(cl)->sema);
123 ReturnPtr("Kbd::New", OOP_Object *, o);
127 VOID LinuxKbd__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
129 ObtainSemaphore(&LSD(cl)->sema);
130 LSD(cl)->kbdhidd = NULL;
131 ReleaseSemaphore(&LSD(cl)->sema);
133 OOP_DoSuperMethod(cl, o, msg);
136 /***** LinuxKbd::HandleEvent() ***************************************/
138 VOID LinuxKbd__Hidd_LinuxKbd__HandleEvent(OOP_Class *cl, OOP_Object *o, struct pHidd_LinuxKbd_HandleEvent *msg)
140 struct linuxkbd_data *data;
141 UBYTE scancode;
142 UWORD hiddcode;
144 EnterFunc(bug("linuxkbd_handleevent()\n"));
146 data = OOP_INST_DATA(cl, o);
148 scancode = msg->scanCode;
149 hiddcode = scancode2hidd(scancode, LSD(cl));
151 if (hiddcode != 0xFF)
153 if (scancode >= 0x80)
154 hiddcode |= IECODE_UP_PREFIX;
156 data->kbd_callback(data->callbackdata, hiddcode);
159 ReturnVoid("Kbd::HandleEvent");
163 #undef LSD
164 #define LSD(cl) lsd
166 /**************** scancode2hidd() ****************/
167 #define DEF_TAB_SIZE 128
169 const UBYTE deftable[] =
171 0xff,
172 RAWKEY_ESCAPE,
173 RAWKEY_1,
174 RAWKEY_2,
175 RAWKEY_3,
176 RAWKEY_4,
177 RAWKEY_5,
178 RAWKEY_6,
179 RAWKEY_7,
180 RAWKEY_8,
181 RAWKEY_9,
182 RAWKEY_0,
183 RAWKEY_MINUS,
184 RAWKEY_EQUAL,
185 RAWKEY_BACKSPACE,
186 RAWKEY_TAB,
187 RAWKEY_Q,
188 RAWKEY_W,
189 RAWKEY_E,
190 RAWKEY_R,
191 RAWKEY_T,
192 RAWKEY_Y,
193 RAWKEY_U,
194 RAWKEY_I,
195 RAWKEY_O,
196 RAWKEY_P,
197 RAWKEY_LBRACKET,
198 RAWKEY_RBRACKET,
199 RAWKEY_RETURN,
200 RAWKEY_CONTROL,
201 RAWKEY_A,
202 RAWKEY_S,
203 RAWKEY_D,
204 RAWKEY_F,
205 RAWKEY_G,
206 RAWKEY_H,
207 RAWKEY_J,
208 RAWKEY_K,
209 RAWKEY_L,
210 RAWKEY_SEMICOLON,
211 RAWKEY_QUOTE,
212 RAWKEY_TILDE,
213 RAWKEY_LSHIFT,
214 RAWKEY_2B,
215 RAWKEY_Z,
216 RAWKEY_X,
217 RAWKEY_C,
218 RAWKEY_V,
219 RAWKEY_B,
220 RAWKEY_N,
221 RAWKEY_M,
222 RAWKEY_COMMA,
223 RAWKEY_PERIOD,
224 RAWKEY_SLASH,
225 RAWKEY_RSHIFT,
226 0x5C,
227 RAWKEY_LALT,
228 RAWKEY_SPACE,
229 RAWKEY_CAPSLOCK,
230 RAWKEY_F1,
231 RAWKEY_F2,
232 RAWKEY_F3,
233 RAWKEY_F4,
234 RAWKEY_F5,
235 RAWKEY_F6,
236 RAWKEY_F7,
237 RAWKEY_F8,
238 RAWKEY_F9,
239 RAWKEY_F10,
240 0x5A,
241 0xff,
242 RAWKEY_KP_7,
243 RAWKEY_KP_8,
244 RAWKEY_KP_9,
245 0x5D,
246 RAWKEY_KP_4,
247 RAWKEY_KP_5,
248 RAWKEY_KP_6,
249 RAWKEY_KP_PLUS,
250 RAWKEY_KP_1,
251 RAWKEY_KP_2,
252 RAWKEY_KP_3,
253 RAWKEY_KP_0,
254 RAWKEY_KP_DECIMAL,
255 0xff,
256 0xff,
257 RAWKEY_LESSGREATER,
258 RAWKEY_F11,
259 RAWKEY_F12,
260 0xff,
261 0xff,
262 0xff,
263 0xff,
264 0xff,
265 0xff,
266 0xff,
267 RAWKEY_KP_ENTER,
268 RAWKEY_CONTROL,
269 0x5B,
270 0xff,
271 RAWKEY_RALT,
272 RAWKEY_PAUSE,
273 RAWKEY_HOME,
274 RAWKEY_UP,
275 RAWKEY_PAGEUP,
276 RAWKEY_LEFT,
277 RAWKEY_RIGHT,
278 RAWKEY_END,
279 RAWKEY_DOWN,
280 RAWKEY_PAGEDOWN,
281 RAWKEY_INSERT,
282 RAWKEY_DELETE,
283 0xff,
284 0xff,
285 0xff,
286 0xff,
287 0xff,
288 0xff,
289 0xff,
290 RAWKEY_PAUSE,
291 0xff,
292 0xff,
293 0xff,
294 0xff,
295 0xff,
296 RAWKEY_LAMIGA,
297 RAWKEY_RAMIGA,
298 0xff
300 static UWORD scancode2hidd(UBYTE scancode, struct linux_staticdata *lsd)
302 UWORD hiddcode;
304 if ((scancode & 0x80) == 0x80)
305 scancode &= ~0x80;
307 if (havetable)
309 hiddcode = scancode2rawkey[scancode];
311 else
313 if (scancode >= DEF_TAB_SIZE)
314 hiddcode = 0xFF;
315 else
316 hiddcode = deftable[scancode];
319 return hiddcode;
322 #if 0
323 /**************** LoadScanCode2RawKeyTable() ***************************/
325 static void LoadScanCode2RawKeyTable(struct linux_staticdata *lsd)
327 char *filename = "DEVS:Keymaps/X11/keycode2rawkey.table";
328 BPTR fh;
330 if ((fh =Open(filename, MODE_OLDFILE)))
332 if ((256 == Read(fh, scancode2rawkey, 256)))
334 bug("LoadKeyCode2RawKeyTable: keycode2rawkey.table successfully loaded!\n");
335 havetable = TRUE;
337 else
339 bug("LoadKeyCode2RawKeyTable: Reading from \"%s\" failed!\n", filename);
341 Close(fh);
344 else
346 bug("\nLoadKeyCode2RawKeyTable: Loading \"%s\" failed!\n"
347 "\n"
348 "This means that many/most/all keys on your keyboard won't work as you\n"
349 "would expect in AROS. Therefore you should create this table by either\n"
350 "using the default table:\n"
351 "\n"
352 " mmake .default-linuxkeymaptable\n"
353 "\n"
354 "or generating your own one:\n"
355 "\n"
356 " mmake .change-linuxkeymaptable\n"
357 "\n"
358 "The default keymaptable probably works with most PCs having a 105 key\n"
359 "keyboard if you are using XFree86 as X Server (might also work with\n"
360 "others). So try that one first!\n"
361 "\n"
362 "Since the keymap table will be deleted when you do a \"make clean\" you\n"
363 "might want to make a backup of it. Then you will be able to restor it later:\n"
364 "\n"
365 " mmake .backup-linuxkeymaptable\n"
366 " mmake .restore-linuxkeymaptable\n"
367 "\n"
368 "The keymap table will be backuped in your HOME directory.\n"
369 "\n"
370 "Note that the keymaptable only makes sure that your keyboard looks as\n"
371 "much as possible like an Amiga keyboard to AROS. So with the keymaptable\n"
372 "alone the keyboard will behave like an Amiga keyboard with American layout\n."
373 "For other layouts you must activate the correct keymap file (which are in\n"
374 "\"DEVS:Keymaps\") just like in AmigaOS. Actually AROS has only German,\n"
375 "Italian and Swedish keymap files. You can activate them inside AROS by typing\n"
376 "this in a AROS Shell or adding it to the AROS Startup-Sequence:\n"
377 "\n"
378 " Setmap pc105_d\n"
379 " Setmap pc105_i\n"
380 " Setmap pc105_s\n"
381 "\n", filename);
384 #endif
386 /******************** init_kbdclass() *********************************/
389 static int Init_KbdClass(LIBBASETYPEPTR LIBBASE)
391 #if 0
392 LoadScanCode2RawKeyTable(&LIBBASE->lsd);
393 #endif
395 if (!OOP_ObtainAttrBases(attrbases))
396 return FALSE;
398 if (!init_linuxkbd(&LIBBASE->lsd))
400 OOP_ReleaseAttrBases(attrbases);
401 return FALSE;
404 return TRUE;
408 /*************** free_kbdclass() **********************************/
409 static int Expunge_KbdClass(LIBBASETYPEPTR LIBBASE)
411 cleanup_linuxkbd(&LIBBASE->lsd);
412 OOP_ReleaseAttrBases(attrbases);
413 return TRUE;
416 ADD2INITLIB(Init_KbdClass, 0)
417 ADD2EXPUNGELIB(Expunge_KbdClass, 0)
420 int set_kbd_mode(int fd, int mode, int *oldmode)
422 /* Get and preserve the old kbd mode */
423 if (NULL != oldmode)
425 if (-1 == ioctl(fd, KDGKBMODE, oldmode))
427 fprintf(stderr, "Unable to get old kbd mode: %s\n", strerror(errno));
428 return 0;
432 /* Set the new mode */
433 if (-1 == ioctl(fd, KDSKBMODE, mode))
435 fprintf(stderr, "Unable to set new kbd mode: %s\n", strerror(errno));
436 return 0;
439 return 1;
443 static int oldkbdmode;
444 static int kbdfd;
445 static struct termios oldtio;
446 static struct linux_staticdata *lsdata;
448 BOOL mode_done = FALSE
449 , fd_done = FALSE
450 , termios_done = FALSE;
452 #define KBD_DEVNAME "/dev/console"
454 BOOL init_linuxkbd(struct linux_staticdata *lsd)
456 BOOL ret = TRUE;
457 lsdata = lsd;
459 kprintf("INIT_KBD\n");
461 lsd->kbdfd = kbdfd = open(KBD_DEVNAME, O_RDONLY);
462 if (-1 == kbdfd)
464 kprintf("!!! Could not open keyboard device: %s\n", strerror(errno));
465 ret = FALSE;
467 else
469 /* Try to read some data from the keyboard */
470 struct termios newtio;
472 fd_done = TRUE;
475 setup_sighandling();
477 kprintf("SIGNALS SETUP\n");
479 if ( (-1 == tcgetattr(kbdfd, &oldtio)) || (-1 == tcgetattr(kbdfd, &newtio)))
481 kprintf("!!! Could not get old termios attrs: %s\n", strerror(errno));
482 ret = FALSE;
484 else
486 /* Set some new attrs */
487 newtio.c_lflag = ~(ICANON | ECHO | ISIG);
488 newtio.c_iflag = 0;
489 newtio.c_cc[VMIN] = 1;
490 newtio.c_cc[VTIME] = 0;
492 if (-1 == tcsetattr(kbdfd, TCSAFLUSH, &newtio))
494 kprintf("!!! Could not set new termio: %s\n", strerror(errno));
495 ret = FALSE;
497 else
499 termios_done = TRUE;
500 kprintf("SET TERMIO ATTRS\n");
502 if (!set_kbd_mode(kbdfd, K_MEDIUMRAW, &oldkbdmode))
504 kprintf("!!! Could not set kbdmode\n");
505 ret = FALSE;
507 else
509 kprintf("KBD MODE SET\n");
510 mode_done = TRUE;
511 ret = TRUE;
513 ioctl(kbdfd, KDSETMODE, KD_GRAPHICS); /* stegerg */
517 } /* if (termios attrs set) */
518 } /* if (got old termios attrs) */
521 if (!ret)
523 cleanup_linuxkbd(lsd);
526 return ret;
530 VOID cleanup_linuxkbd(struct linux_staticdata *lsd)
532 /* Reset the kbd mode */
533 if (mode_done)
535 ioctl(kbdfd, KDSETMODE, KD_TEXT); /* stegerg */
537 set_kbd_mode(kbdfd, oldkbdmode, NULL);
540 if (termios_done)
541 tcsetattr(kbdfd, TCSAFLUSH, &oldtio);
543 if (fd_done)
544 close(kbdfd);
546 cleanup_sighandling();
548 return;
551 const int signals[] =
553 SIGHUP, SIGINT, SIGQUIT, SIGILL,
554 SIGTRAP, SIGBUS, SIGFPE, SIGKILL,
555 /* SIGALRM, */ SIGSEGV , SIGTERM
559 void exit_sighandler(int sig)
561 printf("PARENT EXITING VIA SIGHANDLER\n");
562 cleanup_linuxkbd(lsdata);
563 exit(0);
566 void kbdsighandler(int sig)
568 cleanup_linuxkbd(lsdata);
571 /* Avoid that some signal kills us without resetting the keyboard */
572 void setup_sighandling(void)
574 ULONG i;
575 pid_t pid;
577 for (i = 0; i < sizeof (signals); i ++)
579 signal(signals[i], kbdsighandler);
582 signal(SIGTERM, exit_sighandler);
584 /* Sig alrm is is taken so we have to fork() to create a new process
585 that will kill us after a while */
587 pid = fork();
589 switch (pid)
591 case -1:
592 kprintf("!!!!!!!! ERROR FORKING !!!!!!!!!!!!!!\n");
593 exit(1);
596 case 0:
598 int *status = 0;
599 /* We are the child */
600 kprintf("----- CHILD GOING TO SLEEP ....\n");
601 sleep(120);
602 kprintf("-------- CHILD EXITING ------------\n");
603 kill(getppid(), SIGTERM);
604 exit(0);
607 default:
608 /* We are the parent */
609 kprintf("------- PARENT: PID %d\n", getpid());
610 break;
615 void cleanup_sighandling()
617 ULONG i;
619 for (i = 0; i < sizeof (signals); i ++)
621 signal(signals[i], SIG_DFL);
626 VOID HIDD_LinuxKbd_HandleEvent(OOP_Object *o, UBYTE scanCode)
628 static OOP_MethodID mid;
629 struct pHidd_LinuxKbd_HandleEvent p;
631 if (!mid)
632 mid = OOP_GetMethodID(IID_Hidd_LinuxKbd, moHidd_LinuxKbd_HandleEvent);
634 p.mID = mid;
635 p.scanCode = scanCode;
637 OOP_DoMethod(o, (OOP_Msg)&p);