revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / USB / classes / HID / kbdclass.c
blobc58f89f14142d028c836aca74b8fac5bf4ae6845
1 /*
2 Copyright (C) 2006 by Michal Schulz
3 $Id$
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.
21 #define DEBUG 0
23 #include <aros/debug.h>
24 #include <aros/libcall.h>
25 #include <aros/asmcall.h>
27 #include <dos/dos.h>
28 #include <dos/dosextens.h>
30 #include <devices/inputevent.h>
31 #include <devices/input.h>
32 #include <devices/rawkeycodes.h>
34 #include <usb/usb.h>
35 #include <usb/usb_core.h>
36 #include <usb/hid.h>
37 #include "hid.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
46 #define _(a) __(a)
48 static void update_leds(KbdData *kbd);
51 * Unusual convertions:
52 * PrintScreen -> Help
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)
96 #undef _
97 #undef __
99 void METHOD(USBKbd, Hidd_USBHID, ParseReport)
101 KbdData *kbd = OOP_INST_DATA(cl, o);
102 int i;
104 if (kbd->kbd_task)
106 CopyMem(kbd->code, kbd->prev_code, kbd->loc_keycnt + 1);
108 /* Clear the modifier code */
109 kbd->code[0] = 0;
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)
125 struct Task *t;
126 struct MemList *ml;
128 D(bug("[USBKbd] USBKeyboard::New()\n"));
130 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
131 if (o)
133 struct hid_data *d;
134 struct hid_item h;
136 KbdData *kbd = OOP_INST_DATA(cl, o);
137 kbd->sd = SD(cl);
138 kbd->o = 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);
155 kbd->loc_modcnt = 0;
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)
161 continue;
163 if (h.flags & HIO_VARIABLE)
165 kbd->loc_modcnt++;
167 if (kbd->loc_modcnt > 8)
169 bug("[USBKbd::New()] modifier code exceeds 8 bits size\n");
170 continue;
172 else
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);
179 else
181 kbd->loc_keycode = h.loc;
182 kbd->loc_keycnt = h.loc.count;
185 hid_end_parse(d);
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 },
203 { TAG_DONE, 0UL },
206 t = AllocMem(sizeof(struct Task), MEMF_PUBLIC|MEMF_CLEAR);
207 ml = AllocMem(sizeof(struct MemList) + sizeof(struct MemEntry), MEMF_PUBLIC|MEMF_CLEAR);
209 if (t && ml)
211 char *sp = AllocMem(10240, MEMF_PUBLIC|MEMF_CLEAR);
212 t->tc_SPLower = sp;
213 t->tc_SPUpper = sp + 10240;
214 #if AROS_STACK_GROWS_DOWNWARDS
215 t->tc_SPReg = (char *)t->tc_SPUpper - SP_OFFSET;
216 #else
217 t->tc_SPReg = (char *)t->tc_SPLower + SP_OFFSET;
218 #endif
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]);
234 kbd->kbd_task = t;
238 return o;
241 void METHOD(USBKbd, Root, Dispose)
243 KbdData *kbd = OOP_INST_DATA(cl, o);
245 if (kbd->kbd_task)
246 Signal(kbd->kbd_task, SIGBREAKF_CTRL_C);
248 if (kbd->report)
249 FreeVecPooled(SD(cl)->MemPool, kbd->report);
251 if (kbd->code)
252 FreeVecPooled(SD(cl)->MemPool, kbd->code);
254 if (kbd->prev_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 */
261 #define IEC_MAX 16
263 static inline void ie_send(struct IOStdReq *req, struct InputEvent *ie, int iec)
265 if (iec)
267 req->io_Data = ie;
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)
277 uint8_t reg = 0;
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, &reg, 1);
289 static uint16_t code2qual(uint16_t code)
291 uint16_t qual = 0;
292 switch(code)
294 case 0xE0:
295 case 0xE4:
296 qual = IEQUALIFIER_CONTROL;
297 break;
298 case 0xE1:
299 qual = IEQUALIFIER_LSHIFT;
300 break;
301 case 0xE2:
302 qual = IEQUALIFIER_LALT;
303 break;
304 case 0xE3:
305 qual = IEQUALIFIER_LCOMMAND;
306 break;
307 case 0xE5:
308 qual = IEQUALIFIER_RSHIFT;
309 break;
310 case 0xE6:
311 qual = IEQUALIFIER_RALT;
312 break;
313 case 0xE7:
314 qual = IEQUALIFIER_RCOMMAND;
315 break;
317 return qual;
320 #define IE_NEXT \
321 do { \
322 iec++; \
323 if (iec == IEC_MAX) { \
324 ie_send(req, ie, iec); \
325 iec = 0; \
327 } while(0);
329 static void kbd_process(OOP_Class *cl, OOP_Object *o)
331 KbdData *kbd = OOP_INST_DATA(cl, o);
332 uint32_t sigset;
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);
340 int iec;
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);
347 DeleteMsgPort(port);
348 kbd->kbd_task = NULL;
350 bug("[Kbd] Failed to open input.device\n");
352 return;
355 InputBase = req->io_Device;
357 for (;;)
359 sigset = Wait(SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
361 if (dos_not_ready)
363 struct Library *l = OpenLibrary("dos.library", 0);
364 if (l)
366 dos_not_ready = 0;
367 CloseLibrary(l);
370 else
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);
379 DeleteMsgPort(port);
380 FreeVec(ie);
381 return;
384 if (sigset & SIGBREAKF_CTRL_F)
386 int i;
388 iec = 0;
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");
399 else
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]));
427 D(bug("\n"));
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));
451 IE_NEXT
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;
481 IE_NEXT
485 /* Check all new keycode buffers */
486 for (i=0; i < kbd->loc_keycnt; i++)
488 int j;
490 /* Code == 0? Ignore */
491 if (!kbd->code[i+1])
492 continue;
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])
497 break;
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;
510 update_leds(kbd);
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]];
516 else
517 ie[iec].ie_Code = 0;
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;
536 IE_NEXT
540 /* check all old keycode buffers */
541 for (i=0; i < kbd->loc_keycnt; i++)
543 int j;
545 /* Code == 0? Ignore */
546 if (!kbd->prev_code[i+1])
547 continue;
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])
552 break;
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]];
561 else
562 ie[iec].ie_Code = 0;
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));
577 IE_NEXT
581 ie_send(req, ie, iec);