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
34 #include "linux_intern.h"
36 #include LC_LIBDEFS_FILE
39 #include <aros/debug.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
},
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
;
67 APTR callbackdata
= NULL
;
69 EnterFunc(bug("Kbd::New()\n"));
71 ObtainSemaphore(&LSD(cl
)->sema
);
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
)))
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"));
92 case aoHidd_Kbd_IrqHandler
:
93 callback
= (APTR
)tag
->ti_Data
;
94 D(bug("Got callback %p\n", (APTR
)tag
->ti_Data
));
97 case aoHidd_Kbd_IrqHandlerData
:
98 callbackdata
= (APTR
)tag
->ti_Data
;
99 D(bug("Got data %p\n", (APTR
)tag
->ti_Data
));
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
);
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
;
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");
163 /**************** scancode2hidd() ****************/
164 #define DEF_TAB_SIZE 128
166 const UBYTE deftable
[] =
297 static UWORD
scancode2hidd(UBYTE scancode
, struct linux_staticdata
*lsd
)
301 if ((scancode
& 0x80) == 0x80)
306 hiddcode
= scancode2rawkey
[scancode
];
310 if (scancode
>= DEF_TAB_SIZE
)
313 hiddcode
= deftable
[scancode
];
320 /**************** LoadScanCode2RawKeyTable() ***************************/
322 static void LoadScanCode2RawKeyTable(struct linux_staticdata
*lsd
)
324 char *filename
= "DEVS:Keymaps/X11/keycode2rawkey.table";
327 if ((fh
=Open(filename
, MODE_OLDFILE
)))
329 if ((256 == Read(fh
, scancode2rawkey
, 256)))
331 bug("LoadKeyCode2RawKeyTable: keycode2rawkey.table successfully loaded!\n");
336 bug("LoadKeyCode2RawKeyTable: Reading from \"%s\" failed!\n", filename
);
343 bug("\nLoadKeyCode2RawKeyTable: Loading \"%s\" failed!\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"
349 " mmake .default-linuxkeymaptable\n"
351 "or generating your own one:\n"
353 " mmake .change-linuxkeymaptable\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"
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"
362 " mmake .backup-linuxkeymaptable\n"
363 " mmake .restore-linuxkeymaptable\n"
365 "The keymap table will be backuped in your HOME directory.\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"
383 /******************** init_kbdclass() *********************************/
386 static int Init_KbdClass(LIBBASETYPEPTR LIBBASE
)
389 LoadScanCode2RawKeyTable(&LIBBASE
->lsd
);
392 if (!OOP_ObtainAttrBases(attrbases
))
395 if (!init_linuxkbd(&LIBBASE
->lsd
))
397 OOP_ReleaseAttrBases(attrbases
);
405 /*************** free_kbdclass() **********************************/
406 static int Expunge_KbdClass(LIBBASETYPEPTR LIBBASE
)
408 cleanup_linuxkbd(&LIBBASE
->lsd
);
409 OOP_ReleaseAttrBases(attrbases
);
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 */
422 if (-1 == ioctl(fd
, KDGKBMODE
, oldmode
))
424 fprintf(stderr
, "Unable to get old kbd mode: %s\n", strerror(errno
));
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
));
440 static int oldkbdmode
;
442 static struct termios oldtio
;
443 static struct linux_staticdata
*lsdata
;
445 BOOL mode_done
= FALSE
447 , termios_done
= FALSE
;
449 #define KBD_DEVNAME "/dev/console"
451 BOOL
init_linuxkbd(struct linux_staticdata
*lsd
)
456 kprintf("INIT_KBD\n");
458 lsd
->kbdfd
= kbdfd
= open(KBD_DEVNAME
, O_RDONLY
);
461 kprintf("!!! Could not open keyboard device: %s\n", strerror(errno
));
466 /* Try to read some data from the keyboard */
467 struct termios newtio
;
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
));
483 /* Set some new attrs */
484 newtio
.c_lflag
= ~(ICANON
| ECHO
| ISIG
);
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
));
497 kprintf("SET TERMIO ATTRS\n");
499 if (!set_kbd_mode(kbdfd
, K_MEDIUMRAW
, &oldkbdmode
))
501 kprintf("!!! Could not set kbdmode\n");
506 kprintf("KBD MODE SET\n");
510 ioctl(kbdfd
, KDSETMODE
, KD_GRAPHICS
); /* stegerg */
514 } /* if (termios attrs set) */
515 } /* if (got old termios attrs) */
520 cleanup_linuxkbd(lsd
);
527 VOID
cleanup_linuxkbd(struct linux_staticdata
*lsd
)
529 /* Reset the kbd mode */
532 ioctl(kbdfd
, KDSETMODE
, KD_TEXT
); /* stegerg */
534 set_kbd_mode(kbdfd
, oldkbdmode
, NULL
);
538 tcsetattr(kbdfd
, TCSAFLUSH
, &oldtio
);
543 cleanup_sighandling();
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
);
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)
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 */
589 kprintf("!!!!!!!! ERROR FORKING !!!!!!!!!!!!!!\n");
596 /* We are the child */
597 kprintf("----- CHILD GOING TO SLEEP ....\n");
599 kprintf("-------- CHILD EXITING ------------\n");
600 kill(getppid(), SIGTERM
);
605 /* We are the parent */
606 kprintf("------- PARENT: PID %d\n", getpid());
612 void cleanup_sighandling()
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
;
629 mid
= OOP_GetMethodID(IID_Hidd_LinuxKbd
, moHidd_LinuxKbd_HandleEvent
);
632 p
.scanCode
= scanCode
;
634 OOP_DoMethod(o
, (OOP_Msg
)&p
);