2 Copyright (C) 2006 by Michal Schulz
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 #include <aros/debug.h>
24 #include <aros/libcall.h>
25 #include <aros/asmcall.h>
28 #include <dos/dosextens.h>
30 #include <devices/inputevent.h>
31 #include <devices/input.h>
32 #include <devices/rawkeycodes.h>
35 #include <usb/usb_core.h>
39 #include <proto/oop.h>
40 #include <proto/dos.h>
41 #include <proto/input.h>
43 static void kbd_process();
45 #define __(a) RAWKEY_##a
48 static void update_leds(KbdData
*kbd
);
51 * Unusual convertions:
53 * NumLock -> 0 (driver state change)
55 static const uint8_t keyconv
[] = {
56 0xFF, 0xFF, 0xFF, 0xFF, /* 00 - 03 */
57 _(A
), _(B
), _(C
), _(D
), _(E
), _(F
), _(G
), _(H
), /* 04 - 0B */
58 _(I
), _(J
), _(K
), _(L
), _(M
), _(N
), _(O
), _(P
), /* 0C - 13 */
59 _(Q
), _(R
), _(S
), _(T
), _(U
), _(V
), _(W
), _(X
), /* 14 - 1B */
60 _(Y
), _(Z
), _(1), _(2), _(3), _(4), _(5), _(6), /* 1C - 23 */
61 _(7), _(8), _(9), _(0), /* 24 - 27 */
62 _(RETURN
), _(ESCAPE
), _(BACKSPACE
), _(TAB
), /* 28 - 2B */
63 _(SPACE
), _(MINUS
), _(EQUAL
), _(LBRACKET
), /* 2C - 2F */
64 _(RBRACKET
), _(BACKSLASH
), _(2B
), _(SEMICOLON
), /* 30 - 33 */
65 _(QUOTE
), _(TILDE
), _(COMMA
), _(PERIOD
), /* 34 - 37 */
66 _(SLASH
), _(CAPSLOCK
), _(F1
), _(F2
), /* 38 - 3B */
67 _(F3
), _(F4
), _(F5
), _(F6
), _(F7
), _(F8
), _(F9
), _(F10
), /* 3C - 43 */
68 _(F11
), _(F12
), _(HELP
), 0xFF, /* 44 - 47 */
69 0x6E, _(INSERT
), _(HOME
), _(PAGEUP
), /* 48 - 4B */
70 _(DELETE
), _(END
), _(PAGEDOWN
), _(RIGHT
), /* 4C - 4F */
71 _(LEFT
), _(DOWN
), _(UP
), 0x5A, /* 50 - 53 */
72 0x5B, 0x5C, 0x5D, _(KP_PLUS
), /* 54 - 57 */ // Keypad!!!!!!
73 _(KP_ENTER
), _(KP_1
), _(KP_2
), _(KP_3
), /* 58 - 5B */
74 _(KP_4
), _(KP_5
), _(KP_6
), _(KP_7
), /* 5C - 5F */
75 _(KP_8
), _(KP_9
), _(KP_0
), _(KP_DECIMAL
), /* 60 - 63 */
76 _(LESSGREATER
), 0xFF, 0xFF, 0xFF, /* 64 - 67 */
77 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 68 - 6F */
78 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 70 - 77 */
79 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 78 - 7F */
80 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 80 - 87 */
81 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 88 - 8F */
82 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 90 - 97 */
83 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* 98 - 9F */
84 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* A0 - A7 */
85 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* A8 - AF */
86 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* B0 - B7 */
87 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* B8 - BF */
88 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* C0 - C7 */
89 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* C8 - CF */
90 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* D0 - D7 */
91 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* D8 - DF */
92 _(CONTROL
), _(LSHIFT
), _(LALT
), _(LAMIGA
),
93 _(CONTROL
), _(RSHIFT
), _(RALT
), _(RAMIGA
)
99 void METHOD(USBKbd
, Hidd_USBHID
, ParseReport
)
101 KbdData
*kbd
= OOP_INST_DATA(cl
, o
);
106 CopyMem(kbd
->code
, kbd
->prev_code
, kbd
->loc_keycnt
+ 1);
108 /* Clear the modifier code */
111 for (i
=0; i
< kbd
->loc_modcnt
; i
++)
113 if (hid_get_data(msg
->report
, &kbd
->loc_mod
[i
].loc
))
114 kbd
->code
[0] |= 1 << i
;
117 CopyMem(msg
->report
+ kbd
->loc_keycode
.pos
/ 8, &kbd
->code
[1], kbd
->loc_keycode
.count
);
119 Signal(kbd
->kbd_task
, SIGBREAKF_CTRL_F
);
123 OOP_Object
*METHOD(USBKbd
, Root
, New
)
128 D(bug("[USBKbd] USBKeyboard::New()\n"));
130 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
136 KbdData
*kbd
= OOP_INST_DATA(cl
, o
);
139 kbd
->hd
= HIDD_USBHID_GetHidDescriptor(o
);
141 HIDD_USBHID_SetIdle(o
, 500 / 4, 0);
142 HIDD_USBHID_SetProtocol(o
, 1);
144 D(bug("[USBKbd::New()] Hid descriptor @ %p\n", kbd
->hd
));
145 D(bug("[USBKbd::New()] Number of Report descriptors: %d\n", kbd
->hd
->bNumDescriptors
));
147 kbd
->reportLength
= AROS_LE2WORD(kbd
->hd
->descrs
[0].wDescriptorLength
);
148 kbd
->report
= AllocVecPooled(SD(cl
)->MemPool
, kbd
->reportLength
);
150 D(bug("[USBKbd::New()] Getting report descriptor of size %d\n", kbd
->reportLength
));
152 HIDD_USBHID_GetReportDescriptor(o
, kbd
->reportLength
, kbd
->report
);
154 d
= hid_start_parse(kbd
->report
, kbd
->reportLength
, hid_input
);
157 while (hid_get_item(d
, &h
))
159 if (h
.kind
!= hid_input
|| (h
.flags
& HIO_CONST
) ||
160 HID_GET_USAGE_PAGE(h
.usage
) != HUP_KEYBOARD
)
163 if (h
.flags
& HIO_VARIABLE
)
167 if (kbd
->loc_modcnt
> 8)
169 bug("[USBKbd::New()] modifier code exceeds 8 bits size\n");
174 D(bug("[USBKbd::New()] modifier %d, code %02x\n", kbd
->loc_modcnt
, HID_GET_USAGE(h
.usage
)));
175 kbd
->loc_mod
[kbd
->loc_modcnt
-1].loc
= h
.loc
;
176 kbd
->loc_mod
[kbd
->loc_modcnt
-1].key
= HID_GET_USAGE(h
.usage
);
181 kbd
->loc_keycode
= h
.loc
;
182 kbd
->loc_keycnt
= h
.loc
.count
;
187 D(bug("[USBKbd::New()] %d key modifiers\n", kbd
->loc_modcnt
));
188 D(bug("[USBKbd::New()] This keyboard reports at most %d simultanously pressed keys\n", kbd
->loc_keycnt
));
190 kbd
->prev_code
= AllocVecPooled(SD(cl
)->MemPool
, kbd
->loc_keycnt
+ 1);
191 kbd
->code
= AllocVecPooled(SD(cl
)->MemPool
, kbd
->loc_keycnt
+ 1);
193 hid_locate(kbd
->report
, kbd
->reportLength
, HID_USAGE2(HUP_LEDS
, HUD_LED_NUM_LOCK
),
194 0, hid_output
, &kbd
->loc_numlock
, NULL
, NULL
);
195 hid_locate(kbd
->report
, kbd
->reportLength
, HID_USAGE2(HUP_LEDS
, HUD_LED_CAPS_LOCK
),
196 0, hid_output
, &kbd
->loc_capslock
, NULL
, NULL
);
197 hid_locate(kbd
->report
, kbd
->reportLength
, HID_USAGE2(HUP_LEDS
, HUD_LED_SCROLL_LOCK
),
198 0, hid_output
, &kbd
->loc_scrollock
, NULL
, NULL
);
200 struct TagItem tags
[] = {
201 { TASKTAG_ARG1
, (IPTR
)cl
},
202 { TASKTAG_ARG2
, (IPTR
)o
},
206 t
= AllocMem(sizeof(struct Task
), MEMF_PUBLIC
|MEMF_CLEAR
);
207 ml
= AllocMem(sizeof(struct MemList
) + sizeof(struct MemEntry
), MEMF_PUBLIC
|MEMF_CLEAR
);
211 char *sp
= AllocMem(10240, MEMF_PUBLIC
|MEMF_CLEAR
);
213 t
->tc_SPUpper
= sp
+ 10240;
214 #if AROS_STACK_GROWS_DOWNWARDS
215 t
->tc_SPReg
= (char *)t
->tc_SPUpper
- SP_OFFSET
;
217 t
->tc_SPReg
= (char *)t
->tc_SPLower
+ SP_OFFSET
;
220 ml
->ml_NumEntries
= 2;
221 ml
->ml_ME
[0].me_Addr
= t
;
222 ml
->ml_ME
[0].me_Length
= sizeof(struct Task
);
223 ml
->ml_ME
[1].me_Addr
= sp
;
224 ml
->ml_ME
[1].me_Length
= 10240;
226 NEWLIST(&t
->tc_MemEntry
);
227 ADDHEAD(&t
->tc_MemEntry
, &ml
->ml_Node
);
229 t
->tc_Node
.ln_Name
= "HID USB Keyboard";
230 t
->tc_Node
.ln_Type
= NT_TASK
;
231 t
->tc_Node
.ln_Pri
= 20; /* same priority as input.device */
233 NewAddTask(t
, kbd_process
, NULL
, &tags
[0]);
241 void METHOD(USBKbd
, Root
, Dispose
)
243 KbdData
*kbd
= OOP_INST_DATA(cl
, o
);
246 Signal(kbd
->kbd_task
, SIGBREAKF_CTRL_C
);
249 FreeVecPooled(SD(cl
)->MemPool
, kbd
->report
);
252 FreeVecPooled(SD(cl
)->MemPool
, kbd
->code
);
255 FreeVecPooled(SD(cl
)->MemPool
, kbd
->prev_code
);
257 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
260 /* Maximal number of input events before forced flush is issued */
263 static inline void ie_send(struct IOStdReq
*req
, struct InputEvent
*ie
, int iec
)
268 req
->io_Length
= iec
* sizeof(struct InputEvent
);
269 req
->io_Command
= IND_ADDEVENT
;
271 DoIO((struct IORequest
*)req
);
275 static void update_leds(KbdData
*kbd
)
279 if ((kbd
->leds
& LED_CAPSLOCK
) && kbd
->loc_capslock
.size
== 1)
280 reg
|= 1 << kbd
->loc_capslock
.pos
;
281 if ((kbd
->leds
& LED_NUMLOCK
) && kbd
->loc_numlock
.size
== 1)
282 reg
|= 1 << kbd
->loc_numlock
.pos
;
283 if ((kbd
->leds
& LED_SCROLLOCK
) && kbd
->loc_scrollock
.size
== 1)
284 reg
|= 1 << kbd
->loc_scrollock
.pos
;
286 HIDD_USBHID_SetReport(kbd
->o
, UHID_OUTPUT_REPORT
, 0, ®
, 1);
289 static uint16_t code2qual(uint16_t code
)
296 qual
= IEQUALIFIER_CONTROL
;
299 qual
= IEQUALIFIER_LSHIFT
;
302 qual
= IEQUALIFIER_LALT
;
305 qual
= IEQUALIFIER_LCOMMAND
;
308 qual
= IEQUALIFIER_RSHIFT
;
311 qual
= IEQUALIFIER_RALT
;
314 qual
= IEQUALIFIER_RCOMMAND
;
323 if (iec == IEC_MAX) { \
324 ie_send(req, ie, iec); \
329 static void kbd_process(OOP_Class
*cl
, OOP_Object
*o
)
331 KbdData
*kbd
= OOP_INST_DATA(cl
, o
);
333 uint8_t dos_not_ready
= 1;
335 struct MsgPort
*port
= CreateMsgPort();
336 struct IOStdReq
*req
= (struct IOStdReq
*)CreateIORequest(port
, sizeof(struct IOStdReq
));
337 struct Device
*InputBase
;
339 struct InputEvent
*ie
= AllocVec(IEC_MAX
* sizeof(struct InputEvent
), MEMF_PUBLIC
| MEMF_CLEAR
);
342 D(bug("[Kbd] Attempt to open input.device\n"));
344 if (OpenDevice("input.device", 0, (struct IORequest
*)req
, 0))
346 DeleteIORequest((struct IORequest
*)req
);
348 kbd
->kbd_task
= NULL
;
350 bug("[Kbd] Failed to open input.device\n");
355 InputBase
= req
->io_Device
;
359 sigset
= Wait(SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_F
);
363 struct Library
*l
= OpenLibrary("dos.library", 0);
373 if (sigset
& SIGBREAKF_CTRL_C
)
375 D(bug("[Kbd] USB keyboard detached. Cleaning up\n"));
377 CloseDevice((struct IORequest
*)req
);
378 DeleteIORequest((struct IORequest
*)req
);
384 if (sigset
& SIGBREAKF_CTRL_F
)
389 uint16_t qual
= PeekQualifier() & ~(0x1f);
390 uint8_t mod_up
, mod_down
;
392 /* In case of failure assume that the previous report is the current one too
393 * and do nothing else. */
394 if (kbd
->code
[1] == 1)
396 CopyMem(kbd
->prev_code
, kbd
->code
, kbd
->loc_keycnt
+ 1);
397 bug("[USBKbd] ERROR! Too many keys pressed at once?\n");
402 * Process qualifiers from previous event. They will be adapted
403 * to the new state later
405 for (i
=0; i
< kbd
->loc_modcnt
; i
++)
407 if (kbd
->prev_code
[0] & (1 << i
))
409 qual
|= code2qual(kbd
->loc_mod
[i
].key
);
413 if (kbd
->leds
& LED_CAPSLOCK
)
414 qual
|= IEQUALIFIER_CAPSLOCK
;
416 mod_up
= (kbd
->code
[0]^kbd
->prev_code
[0]) & ~kbd
->code
[0];
417 mod_down
= (kbd
->code
[0]^kbd
->prev_code
[0]) & kbd
->code
[0];
419 D(bug("[Kbd] down:%02x up:%02x buff:%02x", mod_down
, mod_up
, kbd
->code
[0]));
420 for (i
=0; i
< kbd
->loc_keycode
.count
; i
++)
421 D(bug(" %02x", kbd
->code
[i
+1]));
423 D(bug(" oldbuff:%02x", kbd
->prev_code
[0]));
424 for (i
=0; i
< kbd
->loc_keycode
.count
; i
++)
425 D(bug(" %02x", kbd
->prev_code
[i
+1]));
429 /* Process key up qualifiers */
430 for (i
=0; i
< kbd
->loc_modcnt
; i
++)
432 if (mod_up
& (1 << i
))
434 qual
&= ~code2qual(kbd
->loc_mod
[i
].key
);
436 ie
[iec
].ie_Class
= IECLASS_RAWKEY
;
437 ie
[iec
].ie_SubClass
= 0;
438 ie
[iec
].ie_Code
= keyconv
[kbd
->loc_mod
[i
].key
];
439 ie
[iec
].ie_Qualifier
= qual
;
441 ie
[iec
].ie_Code
|= IECODE_UP_PREFIX
;
443 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownCode
= kbd
->prev_key
;
444 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownQual
= kbd
->prev_qual
;
446 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownCode
= kbd
->prev_prev_key
;
447 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownQual
= kbd
->prev_prev_qual
;
449 D(bug("[Kbd] KeyUp event for key %02x->%02x\n", kbd
->loc_mod
[i
].key
, ie
[iec
].ie_Code
));
455 /* Process key down qualifiers */
456 for (i
=0; i
< kbd
->loc_modcnt
; i
++)
458 if (mod_down
& (1 << i
))
460 qual
|= code2qual(kbd
->loc_mod
[i
].key
);
462 ie
[iec
].ie_Class
= IECLASS_RAWKEY
;
463 ie
[iec
].ie_SubClass
= 0;
464 ie
[iec
].ie_Code
= keyconv
[kbd
->loc_mod
[i
].key
];
465 ie
[iec
].ie_Qualifier
= qual
;
467 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownCode
= kbd
->prev_key
;
468 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownQual
= kbd
->prev_qual
;
470 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownCode
= kbd
->prev_prev_key
;
471 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownQual
= kbd
->prev_prev_qual
;
473 D(bug("[Kbd] KeyDown event for key %02x->%02x\n", kbd
->loc_mod
[i
].key
, ie
[iec
].ie_Code
));
475 kbd
->prev_prev_key
= kbd
->prev_key
;
476 kbd
->prev_prev_qual
= kbd
->prev_qual
;
478 kbd
->prev_key
= ie
[iec
].ie_Code
;
479 kbd
->prev_qual
= ie
[iec
].ie_Qualifier
;
485 /* Check all new keycode buffers */
486 for (i
=0; i
< kbd
->loc_keycnt
; i
++)
490 /* Code == 0? Ignore */
494 /* Check whether this code exists in previous buffer */
495 for (j
=0; j
< kbd
->loc_keycnt
; j
++)
496 if (kbd
->code
[i
+1] == kbd
->prev_code
[j
+1])
499 /* Not in previous buffer. KeyDown event */
500 if (j
>= kbd
->loc_keycnt
&& keyconv
[kbd
->code
[i
+1]] != 0xff)
502 if (kbd
->code
[i
+1] == 0x39)
504 kbd
->leds
^= LED_CAPSLOCK
;
505 qual
^= IEQUALIFIER_CAPSLOCK
;
507 if (kbd
->code
[i
+1] == 0x53)
508 kbd
->leds
^= LED_NUMLOCK
;
512 ie
[iec
].ie_Class
= IECLASS_RAWKEY
;
513 ie
[iec
].ie_SubClass
= 0;
514 if (kbd
->code
[i
+1] < sizeof(keyconv
))
515 ie
[iec
].ie_Code
= keyconv
[kbd
->code
[i
+1]];
518 ie
[iec
].ie_Qualifier
= qual
;
519 if (kbd
->code
[i
+1] >= 0x54 && kbd
->code
[i
+1] <= 0x63)
520 ie
[iec
].ie_Qualifier
|= IEQUALIFIER_NUMERICPAD
;
522 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownCode
= kbd
->prev_key
;
523 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownQual
= kbd
->prev_qual
;
525 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownCode
= kbd
->prev_prev_key
;
526 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownQual
= kbd
->prev_prev_qual
;
528 D(bug("[Kbd] KeyDown event for key %02x->%02x\n", kbd
->code
[i
+1], ie
[iec
].ie_Code
));
530 kbd
->prev_prev_key
= kbd
->prev_key
;
531 kbd
->prev_prev_qual
= kbd
->prev_qual
;
533 kbd
->prev_key
= ie
[iec
].ie_Code
;
534 kbd
->prev_qual
= ie
[iec
].ie_Qualifier
;
540 /* check all old keycode buffers */
541 for (i
=0; i
< kbd
->loc_keycnt
; i
++)
545 /* Code == 0? Ignore */
546 if (!kbd
->prev_code
[i
+1])
549 /* Check whether this code exists in previous buffer */
550 for (j
=0; j
< kbd
->loc_keycnt
; j
++)
551 if (kbd
->prev_code
[i
+1] == kbd
->code
[j
+1])
554 /* Not in previous buffer. KeyUp event */
555 if (j
>= kbd
->loc_keycnt
&& keyconv
[kbd
->prev_code
[i
+1]] != 0xff)
557 ie
[iec
].ie_Class
= IECLASS_RAWKEY
;
558 ie
[iec
].ie_SubClass
= 0;
559 if (kbd
->prev_code
[i
+1] < sizeof(keyconv
))
560 ie
[iec
].ie_Code
= keyconv
[kbd
->prev_code
[i
+1]];
563 ie
[iec
].ie_Qualifier
= qual
;
564 if (kbd
->prev_code
[i
+1] >= 0x54 && kbd
->prev_code
[i
+1] <= 0x63)
565 ie
[iec
].ie_Qualifier
|= IEQUALIFIER_NUMERICPAD
;
567 ie
[iec
].ie_Code
|= IECODE_UP_PREFIX
;
569 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownCode
= kbd
->prev_key
;
570 ie
[iec
].ie_position
.ie_dead
.ie_prev1DownQual
= kbd
->prev_qual
;
572 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownCode
= kbd
->prev_prev_key
;
573 ie
[iec
].ie_position
.ie_dead
.ie_prev2DownQual
= kbd
->prev_prev_qual
;
575 D(bug("[Kbd] KeyUp event for key %02x->%02x\n", kbd
->prev_code
[i
+1], ie
[iec
].ie_Code
));
581 ie_send(req
, ie
, iec
);