2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
5 Desc: Linux hidd handling keyboard
9 #define __OOP_NOATTRBASES__
13 #include <proto/utility.h>
14 #include <proto/oop.h>
15 #include <proto/dos.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
37 #include "linux_intern.h"
39 #include LC_LIBDEFS_FILE
42 #include <aros/debug.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
},
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
;
70 APTR callbackdata
= NULL
;
72 EnterFunc(bug("Kbd::New()\n"));
74 ObtainSemaphore(&LSD(cl
)->sema
);
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
)))
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"));
95 case aoHidd_Kbd_IrqHandler
:
96 callback
= (APTR
)tag
->ti_Data
;
97 D(bug("Got callback %p\n", (APTR
)tag
->ti_Data
));
100 case aoHidd_Kbd_IrqHandlerData
:
101 callbackdata
= (APTR
)tag
->ti_Data
;
102 D(bug("Got data %p\n", (APTR
)tag
->ti_Data
));
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
);
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
;
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");
166 /**************** scancode2hidd() ****************/
167 #define DEF_TAB_SIZE 128
169 const UBYTE deftable
[] =
300 static UWORD
scancode2hidd(UBYTE scancode
, struct linux_staticdata
*lsd
)
304 if ((scancode
& 0x80) == 0x80)
309 hiddcode
= scancode2rawkey
[scancode
];
313 if (scancode
>= DEF_TAB_SIZE
)
316 hiddcode
= deftable
[scancode
];
323 /**************** LoadScanCode2RawKeyTable() ***************************/
325 static void LoadScanCode2RawKeyTable(struct linux_staticdata
*lsd
)
327 char *filename
= "DEVS:Keymaps/X11/keycode2rawkey.table";
330 if ((fh
=Open(filename
, MODE_OLDFILE
)))
332 if ((256 == Read(fh
, scancode2rawkey
, 256)))
334 bug("LoadKeyCode2RawKeyTable: keycode2rawkey.table successfully loaded!\n");
339 bug("LoadKeyCode2RawKeyTable: Reading from \"%s\" failed!\n", filename
);
346 bug("\nLoadKeyCode2RawKeyTable: Loading \"%s\" failed!\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"
352 " mmake .default-linuxkeymaptable\n"
354 "or generating your own one:\n"
356 " mmake .change-linuxkeymaptable\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"
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"
365 " mmake .backup-linuxkeymaptable\n"
366 " mmake .restore-linuxkeymaptable\n"
368 "The keymap table will be backuped in your HOME directory.\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"
386 /******************** init_kbdclass() *********************************/
389 static int Init_KbdClass(LIBBASETYPEPTR LIBBASE
)
392 LoadScanCode2RawKeyTable(&LIBBASE
->lsd
);
395 if (!OOP_ObtainAttrBases(attrbases
))
398 if (!init_linuxkbd(&LIBBASE
->lsd
))
400 OOP_ReleaseAttrBases(attrbases
);
408 /*************** free_kbdclass() **********************************/
409 static int Expunge_KbdClass(LIBBASETYPEPTR LIBBASE
)
411 cleanup_linuxkbd(&LIBBASE
->lsd
);
412 OOP_ReleaseAttrBases(attrbases
);
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 */
425 if (-1 == ioctl(fd
, KDGKBMODE
, oldmode
))
427 fprintf(stderr
, "Unable to get old kbd mode: %s\n", strerror(errno
));
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
));
443 static int oldkbdmode
;
445 static struct termios oldtio
;
446 static struct linux_staticdata
*lsdata
;
448 BOOL mode_done
= FALSE
450 , termios_done
= FALSE
;
452 #define KBD_DEVNAME "/dev/console"
454 BOOL
init_linuxkbd(struct linux_staticdata
*lsd
)
459 kprintf("INIT_KBD\n");
461 lsd
->kbdfd
= kbdfd
= open(KBD_DEVNAME
, O_RDONLY
);
464 kprintf("!!! Could not open keyboard device: %s\n", strerror(errno
));
469 /* Try to read some data from the keyboard */
470 struct termios newtio
;
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
));
486 /* Set some new attrs */
487 newtio
.c_lflag
= ~(ICANON
| ECHO
| ISIG
);
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
));
500 kprintf("SET TERMIO ATTRS\n");
502 if (!set_kbd_mode(kbdfd
, K_MEDIUMRAW
, &oldkbdmode
))
504 kprintf("!!! Could not set kbdmode\n");
509 kprintf("KBD MODE SET\n");
513 ioctl(kbdfd
, KDSETMODE
, KD_GRAPHICS
); /* stegerg */
517 } /* if (termios attrs set) */
518 } /* if (got old termios attrs) */
523 cleanup_linuxkbd(lsd
);
530 VOID
cleanup_linuxkbd(struct linux_staticdata
*lsd
)
532 /* Reset the kbd mode */
535 ioctl(kbdfd
, KDSETMODE
, KD_TEXT
); /* stegerg */
537 set_kbd_mode(kbdfd
, oldkbdmode
, NULL
);
541 tcsetattr(kbdfd
, TCSAFLUSH
, &oldtio
);
546 cleanup_sighandling();
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
);
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)
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 */
592 kprintf("!!!!!!!! ERROR FORKING !!!!!!!!!!!!!!\n");
599 /* We are the child */
600 kprintf("----- CHILD GOING TO SLEEP ....\n");
602 kprintf("-------- CHILD EXITING ------------\n");
603 kill(getppid(), SIGTERM
);
608 /* We are the parent */
609 kprintf("------- PARENT: PID %d\n", getpid());
615 void cleanup_sighandling()
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
;
632 mid
= OOP_GetMethodID(IID_Hidd_LinuxKbd
, moHidd_LinuxKbd_HandleEvent
);
635 p
.scanCode
= scanCode
;
637 OOP_DoMethod(o
, (OOP_Msg
)&p
);