Fixed capitalisation typo.
[AROS.git] / rom / devs / keyboard / keyboard.c
blob385e0f0f68a1ed831a8b4dfdf284405ffa24fbbf
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Keyboard device
6 Lang: English
7 */
9 /* HISTORY: 12.04.98 SDuvan Began work
10 xx.06.98 SDuvan Fixes, added amigakeyboard.HIDD
11 04.06.10 Sonic Use keyboard.hidd
14 /****************************************************************************************/
16 #include <exec/resident.h>
17 #include <exec/interrupts.h>
18 #include <exec/initializers.h>
19 #include <devices/inputevent.h>
20 #include <devices/keyboard.h>
21 #include <devices/newstyle.h>
22 #include <proto/exec.h>
23 #include <proto/dos.h>
24 #include <proto/oop.h>
25 #include <exec/memory.h>
26 #include <exec/errors.h>
27 #include <exec/lists.h>
28 #include <oop/oop.h>
29 #include <utility/utility.h>
30 #include <hidd/keyboard.h>
31 #include <aros/libcall.h>
32 #include <aros/symbolsets.h>
33 #include "abstractkeycodes.h"
34 #include "keyboard_intern.h"
36 #ifdef __GNUC__
37 #include "keyboard_gcc.h"
38 #endif
40 #include LC_LIBDEFS_FILE
42 #define DEBUG 0
43 #include <aros/debug.h>
45 /****************************************************************************************/
47 #define NEWSTYLE_DEVICE 1
48 #define ALIGN_IS_EVIL 1
50 #define ioStd(x) ((struct IOStdReq *)x)
51 #define kbUn ((struct KBUnit *)(ioreq->io_Unit))
53 #define min(a,b) ((a) < (b)) ? (a) : (b)
54 #define ALIGN(x) ((((x) + (__AROS_STRUCTURE_ALIGNMENT - 1)) / __AROS_STRUCTURE_ALIGNMENT) * __AROS_STRUCTURE_ALIGNMENT)
56 #define isQualifier(x) ((((x) & ~KEYUPMASK) >= AKC_QUALIFIERS_FIRST) && (((x) & ~KEYUPMASK) <= AKC_QUALIFIERS_LAST))
58 /* Temporary - we should make a bit vector of this to check for numeric pad keys */
59 #define isNumericPad(x) ((x) == AKC_NUM_1 || (x) == AKC_NUM_2 || \
60 (x) == AKC_NUM_3 || (x) == AKC_NUM_4 || \
61 (x) == AKC_NUM_5 || (x) == AKC_NUM_6 || \
62 (x) == AKC_NUM_7 || (x) == AKC_NUM_8 || \
63 (x) == AKC_NUM_9 || (x) == AKC_NUM_0 || \
64 (x) == AKC_NUM_POINT || (x) == AKC_NUM_ENTER || \
65 (x) == AKC_NUM_DASH || (x) == AKC_NUM_LPAREN || \
66 (x) == AKC_NUM_RPAREN || (x) == AKC_NUM_SLASH || \
67 (x) == AKC_NUM_PLUS || (x) == AKC_NUM_TIMES)
69 #if ALIGN_IS_EVIL
71 #define NUM_INPUTEVENTS(bytesize) ((bytesize) / sizeof(struct InputEvent))
72 #define NEXT_INPUTEVENT(event) (((struct InputEvent *)(event)) + 1)
74 #else
76 /* Number of InputEvents we can store in io_Data */
77 /* be careful, the io_Length might be the size of the InputEvent structure,
78 but it can be that the ALIGN() returns a larger size and then nEvents would
79 be 0.
82 #define NUM_INPUTEVENTS(bytesize) (((bytesize) == sizeof(struct InputEvent)) ? \
83 1 : (bytesize) / ALIGN(sizeof(struct InputEvent)))
84 #define NEXT_INPUTEVENT(event) ((struct InputEvent *)((UBYTE*)(event) + \
85 ALIGN(sizeof(struct InputEvent))))
87 #endif /* ALIGN_IS_EVIL */
89 /****************************************************************************************/
91 #if NEWSTYLE_DEVICE
93 static const UWORD SupportedCommands[] =
95 CMD_CLEAR,
96 KBD_ADDRESETHANDLER,
97 KBD_REMRESETHANDLER,
98 KBD_RESETHANDLERDONE,
99 KBD_READMATRIX,
100 KBD_READEVENT,
101 NSCMD_DEVICEQUERY,
105 #endif
107 /****************************************************************************************/
109 VOID keyCallback(struct KeyboardBase *KBBase, UWORD keyCode);
110 AROS_UFP3(VOID, kbdSendQueuedEvents,
111 AROS_UFPA(struct KeyboardBase *, KBBase, A1),
112 AROS_UFPA(APTR, thisfunc, A5),
113 AROS_UFPA(struct ExecBase *, SysBase, A6));
114 static BOOL writeEvents(struct IORequest *ioreq, struct KeyboardBase *KBBase);
116 /****************************************************************************************/
118 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR KBBase)
120 /* reset static data */
121 HiddKbdAB = 0;
123 InitSemaphore(&KBBase->kb_QueueLock);
124 NEWLIST(&KBBase->kb_ResetHandlerList);
125 NEWLIST(&KBBase->kb_PendingQueue);
126 NEWLIST(&KBBase->kb_kbunits);
128 return TRUE;
131 /****************************************************************************************/
133 static int GM_UNIQUENAME(Open)
135 LIBBASETYPEPTR KBBase,
136 struct IORequest *ioreq,
137 ULONG unitnum,
138 ULONG flags
141 struct Library *OOPBase = GM_OOPBASE_FIELD(KBBase);
143 if (ioreq->io_Message.mn_Length < sizeof(struct IOStdReq))
145 D(bug("keyport.device/open: IORequest structure passed to OpenDevice is too small!\n"));
146 ioreq->io_Error = IOERR_OPENFAIL;
147 return FALSE;
150 if(KBBase->kb_keyBuffer == NULL)
152 KBBase->kb_keyBuffer = AllocMem(sizeof(UWORD)*KB_BUFFERSIZE, MEMF_ANY);
155 /* No memory for key buffer? */
156 if(KBBase->kb_keyBuffer == NULL)
158 ioreq->io_Error = IOERR_OPENFAIL;
159 return FALSE;
162 if((ioreq->io_Unit = AllocMem(sizeof(KBUnit), MEMF_CLEAR)) == NULL)
164 ioreq->io_Error = IOERR_OPENFAIL;
165 return FALSE;
168 /* nlorentz: Some extra stuff that must be inited */
169 if (NULL == KBBase->kb_Matrix)
171 KBBase->kb_Matrix = AllocMem(KB_MATRIXSIZE, MEMF_ANY|MEMF_CLEAR);
173 if (NULL == KBBase->kb_Matrix)
175 ioreq->io_Error = IOERR_OPENFAIL;
176 return FALSE;
180 if (!HiddKbdAB)
182 HiddKbdAB = OOP_ObtainAttrBase(IID_Hidd_Kbd);
183 if (!HiddKbdAB)
185 ioreq->io_Error = IOERR_OPENFAIL;
186 D(bug("keyboard.device: Could not get attrbase\n"));
187 return FALSE;
190 D(bug("keyboard.device: Attrbase: %x\n", HiddKbdAB));
192 KBBase->kb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
193 KBBase->kb_Interrupt.is_Node.ln_Pri = 0;
194 KBBase->kb_Interrupt.is_Data = (APTR)KBBase;
195 KBBase->kb_Interrupt.is_Code = kbdSendQueuedEvents;
197 if(!KBBase->kb_KbdHiddBase)
199 KBBase->kb_KbdHiddBase = OpenLibrary("keyboard.hidd", 0);
200 D(bug("keyboard.device: keyboard.hidd base 0x%p\n", KBBase->kb_KbdHiddBase));
202 /* Install our own keyboard handler if opened for the first time */
203 if(KBBase->kb_KbdHiddBase) {
204 struct TagItem tags[] = {
205 { aHidd_Kbd_IrqHandler , (IPTR)keyCallback },
206 { aHidd_Kbd_IrqHandlerData , (IPTR)KBBase },
207 { TAG_DONE }
210 KBBase->kb_Hidd = OOP_NewObject(NULL, CLID_Hidd_Kbd, tags);
211 D(bug("keyboard.device: keyboard HIDD object 0x%p\n", KBBase->kb_Hidd));
212 if(!KBBase->kb_Hidd)
214 CloseLibrary(KBBase->kb_KbdHiddBase);
215 KBBase->kb_KbdHiddBase = NULL; /* Do cleanup below. */
221 if(!KBBase->kb_KbdHiddBase)
223 ioreq->io_Error = IOERR_OPENFAIL;
224 return FALSE;
225 /* TODO: Clean up. */
228 Forbid();
229 AddTail((struct List*)&KBBase->kb_kbunits, (struct Node *)&((struct KBUnit*)(ioreq->io_Unit))->node);
230 Permit();
232 return TRUE;
235 /****************************************************************************************/
237 static int GM_UNIQUENAME(Close)
239 LIBBASETYPEPTR KBBase,
240 struct IORequest *ioreq
243 struct Node *node;
245 /* only free ioreq->io_Unit if it is ours */
246 Forbid();
247 ForeachNode(&KBBase->kb_kbunits, node) {
248 if (node == (struct Node*)ioreq->io_Unit) {
249 Remove(node);
250 FreeMem(node, sizeof(KBUnit));
251 break;
254 Permit();
256 return TRUE;
259 /****************************************************************************************/
261 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
262 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
263 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
265 /****************************************************************************************/
267 AROS_LH1(void, beginio,
268 AROS_LHA(struct IORequest *, ioreq, A1),
269 struct KeyboardBase *, KBBase, 5, Keyboard)
271 AROS_LIBFUNC_INIT
273 BOOL request_queued = FALSE;
276 D(bug("kbd: beginio(ioreq=%p, cmd=%d)\n", ioreq, ioreq->io_Command));
278 /* WaitIO will look into this */
279 ioreq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
280 ioreq->io_Error = 0;
282 switch (ioreq->io_Command)
284 #if NEWSTYLE_DEVICE
285 case NSCMD_DEVICEQUERY:
286 if(ioStd(ioreq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
288 ioreq->io_Error = IOERR_BADLENGTH;
290 else
292 struct NSDeviceQueryResult *d;
294 d = (struct NSDeviceQueryResult *)ioStd(ioreq)->io_Data;
296 d->DevQueryFormat = 0;
297 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
298 d->DeviceType = NSDEVTYPE_KEYBOARD;
299 d->DeviceSubType = 0;
300 d->SupportedCommands = (UWORD *)SupportedCommands;
302 ioStd(ioreq)->io_Actual = sizeof(struct NSDeviceQueryResult);
304 break;
305 #endif
307 case CMD_CLEAR:
308 kbUn->kbu_readPos = KBBase->kb_writePos;
309 break;
311 case KBD_ADDRESETHANDLER:
312 Disable();
313 Enqueue((struct List *)(&KBBase->kb_ResetHandlerList),
314 (struct Node *)(ioStd(ioreq)->io_Data));
315 KBBase->kb_nHandlers++;
316 Enable();
317 break;
319 case KBD_REMRESETHANDLER:
320 Disable();
321 Remove((struct Node *)(ioStd(ioreq)->io_Data));
322 KBBase->kb_nHandlers--;
323 Enable();
324 break;
326 case KBD_RESETHANDLERDONE:
327 /* We don't want any phony resets. */
329 if(KBBase->kb_ResetPhase == TRUE)
331 if(--(KBBase->kb_nHandlers) <= 0)
332 ColdReboot(); /* Shut down system */
334 else
336 /* There is no good (defined) IOERR to return in this situation */
337 ioreq->io_Error = IOERR_NOCMD;
339 break;
341 case KBD_READMATRIX:
342 ioStd(ioreq)->io_Actual = min(KB_MATRIXSIZE, ioStd(ioreq)->io_Length);
343 CopyMem(KBBase->kb_Matrix, ioStd(ioreq)->io_Data,
344 ioStd(ioreq)->io_Actual);
345 break;
347 case KBD_READEVENT:
349 /* TODO */
350 /* Check for reset... via keybuffer or via HIDD? */
351 /* if(bufferkey == 0x78) ... */
353 #if 0
354 if((((IPTR)ioStd(ioreq)->io_Data) & (__AROS_STRUCTURE_ALIGNMENT - 1)) != 0)
356 D(bug("kbd: Bad address\n"));
357 ioreq->io_Error = IOERR_BADADDRESS;
358 break;
360 #endif
362 Disable(); /* !! */
364 if(kbUn->kbu_readPos == KBBase->kb_writePos)
366 ioreq->io_Flags &= ~IOF_QUICK;
367 request_queued = TRUE;
368 D(bug("kbd: No keypresses, putting request in queue\n"));
370 kbUn->kbu_flags |= KBUF_PENDING;
371 AddTail((struct List *)&KBBase->kb_PendingQueue,
372 (struct Node *)ioreq);
373 } else {
374 D(bug("kbd: Events ready\n"));
376 writeEvents(ioreq, KBBase);
379 Enable();
381 break;
383 default:
384 ioreq->io_Error = IOERR_NOCMD;
385 break;
387 } /* switch (ioreq->io_Command) */
389 /* If the quick bit is not set, send the message to the port */
390 if(!(ioreq->io_Flags & IOF_QUICK) && !request_queued)
391 ReplyMsg(&ioreq->io_Message);
393 AROS_LIBFUNC_EXIT
396 /****************************************************************************************/
398 static BOOL writeEvents(struct IORequest *ioreq, struct KeyboardBase *KBBase)
400 int nEvents; /* Number of struct InputEvent:s that there is
401 room for in memory pointed to by io_Data */
402 UWORD code; /* Value of current keycode */
403 UWORD trueCode; /* Code without possible keypress addition */
404 int i; /* Loop variable */
405 struct InputEvent *event; /* Temporary variable */
406 BOOL moreevents = TRUE;
407 BOOL activate_resetphase = FALSE;
409 event = (struct InputEvent *)(ioStd(ioreq)->io_Data);
411 /* Number of InputEvents we can store in io_Data */
412 /* be careful, the io_Length might be the size of the InputEvent structure,
413 but it can be that the ALIGN() returns a larger size and then nEvents would
414 be 0.
417 nEvents = NUM_INPUTEVENTS(ioStd(ioreq)->io_Length);
419 if(nEvents == 0)
421 ioreq->io_Error = IOERR_BADLENGTH;
422 D(bug("kbd: Bad length\n"));
423 return TRUE;
426 D(bug("NEvents = %i", nEvents));
428 ioreq->io_Error = 0;
430 for(i = 0; i < nEvents; i++)
432 /* Update eventpointer -- this must be done here as I must set
433 ie_NextEvent to NULL if there are no more keys in the buffer. */
434 if(i != 0)
435 event = event->ie_NextEvent;
437 code = KBBase->kb_keyBuffer[kbUn->kbu_readPos++];
439 if(kbUn->kbu_readPos == KB_BUFFERSIZE)
440 kbUn->kbu_readPos = 0;
442 trueCode = code & AMIGAKEYMASK;
444 if(isQualifier(code) == TRUE)
447 /* Key released ? ... */
448 if(code & KEYUPMASK)
450 #if 1
451 /* stegerg: on PC keyboards caps lock also generates up events */
452 if (trueCode != AKC_CAPS_LOCK)
453 #endif
454 kbUn->kbu_Qualifiers &= ~(1 << (trueCode - AKC_QUALIFIERS_FIRST));
456 else /* ... or pressed? */
458 if (trueCode == AKC_CAPS_LOCK)
460 kbUn->kbu_Qualifiers ^= IEQUALIFIER_CAPSLOCK;
462 else
464 kbUn->kbu_Qualifiers |= 1 << (trueCode - AKC_QUALIFIERS_FIRST);
469 D(bug("kbd: Adding event of code %d\n", code));
471 event->ie_Class = IECLASS_RAWKEY;
472 event->ie_SubClass = 0;
473 event->ie_Code = code;
474 event->ie_Qualifier = kbUn->kbu_Qualifiers;
475 event->ie_Qualifier |= isNumericPad(trueCode) ? IEQUALIFIER_NUMERICPAD : 0;
476 event->ie_Prev1DownCode = (UBYTE)(kbUn->kbu_LastCode & 0xff);
477 event->ie_Prev1DownQual = kbUn->kbu_LastQuals;
478 event->ie_Prev2DownCode = (UBYTE)(kbUn->kbu_LastLastCode & 0xff);
479 event->ie_Prev2DownQual = kbUn->kbu_LastLastQuals;
480 event->ie_TimeStamp.tv_secs = 0;
481 event->ie_TimeStamp.tv_micro = 0;
483 /* Update list of previous states for dead key handling */
485 if (!(code & IECODE_UP_PREFIX) && !isQualifier(code))
487 kbUn->kbu_LastLastCode = kbUn->kbu_LastCode;
488 kbUn->kbu_LastLastQuals = kbUn->kbu_LastQuals;
489 kbUn->kbu_LastCode = code;
490 kbUn->kbu_LastQuals = (UBYTE)(kbUn->kbu_Qualifiers & 0xff);
493 if(code == 0x78) activate_resetphase = TRUE;
495 /* No more keys in buffer? */
496 if(kbUn->kbu_readPos == KBBase->kb_writePos)
498 moreevents = FALSE;
499 break;
502 event->ie_NextEvent = NEXT_INPUTEVENT(event);
506 D(bug("Done writing events!"));
507 event->ie_NextEvent = NULL;
509 if(activate_resetphase && !KBBase->kb_ResetPhase)
511 struct Interrupt *node;
513 KBBase->kb_ResetPhase = TRUE;
515 if(!IsListEmpty(&KBBase->kb_ResetHandlerList))
517 /* We may want to install a timer here so that ColdReboot()
518 will eventually be called even if a reset handler hang. */
519 ForeachNode(&KBBase->kb_ResetHandlerList, node)
521 /* We may be inside an interrupt when we come here. Maybe
522 we shall use some other technique? */
523 AROS_UFC3NR(VOID, node->is_Code,
524 AROS_UFCA(APTR, node->is_Data, A1),
525 AROS_UFCA(APTR, node->is_Code, A5),
526 AROS_UFCA(struct ExecBase *, SysBase, A6));
529 else
531 ColdReboot(); /* Bye bye AROS */
535 return moreevents;
538 /****************************************************************************************/
540 AROS_LH1(LONG, abortio,
541 AROS_LHA(struct IORequest *, ioreq, A1),
542 struct KeyboardBase *, KBBase, 6, Keyboard)
544 AROS_LIBFUNC_INIT
546 LONG ret = -1;
548 Disable();
549 if(kbUn->kbu_flags & KBUF_PENDING)
551 if (ioreq->io_Message.mn_Node.ln_Type == NT_MESSAGE)
553 Remove((struct Node *)ioreq);
554 ReplyMsg(&ioreq->io_Message);
556 ioreq->io_Error = IOERR_ABORTED;
558 if (IsListEmpty(&KBBase->kb_PendingQueue)) kbUn->kbu_flags &= ~KBUF_PENDING;
560 ret = 0;
563 Enable();
565 return ret;
567 AROS_LIBFUNC_EXIT
570 /****************************************************************************************/
572 #define CORRECT(x) (((x) & AMIGAKEYMASK) | (((x) & NOTAMIGAKEYMASK) >> 1))
573 #define BVBITCLEAR(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] &= ~(1 << ((x) & (sizeof(UBYTE)*8 - 1))))
574 #define BVBITSET(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] |= (1 << ((x) & (sizeof(UBYTE)*8 - 1))))
576 /****************************************************************************************/
578 #if 0
580 /****************************************************************************************/
583 78 Reset warning.
584 F9 Last key code bad, next key is same code retransmitted
585 FA Keyboard key buffer overflow
586 FC Keyboard self-test fail.
587 FD Initiate power-up key stream (for keys held or stuck at
588 power on)
589 FE Terminate power-up key stream.
592 #include <hardware/cia.h>
594 /****************************************************************************************/
596 BOOL HIDDM_initKeyboard(struct KeyboardHIDD *kh)
598 /* What should be done here? My guess is that we need the IRQ.hidd
599 before I can complete this function.
600 Presume that an IRQ.hidd exists, and that it has a method
601 HIDDV_addServerItem(ULONG level, BOOL (*)checkFunc) that adds an
602 interrupt server (sort of) to the real interrupt server at level
603 'level'. In the case of the keyboard.hidd, this would be level 6
604 (hardware wise) but probably something else in this context.
605 Then the code would look something like: */
608 kh->kh_irqhidd = FindHidd("IRQ.hidd");
610 if(kh->irqhidd == NULL)
611 return FALSE;
613 HIDDV_addServerItem(irqhidd_keyboard, checkKBint);
616 /****************************************************************************************/
618 #endif
620 /****************************************************************************************/
622 VOID keyCallback(struct KeyboardBase *KBBase, UWORD keyCode)
624 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
625 , KBBase, keyCode));
627 Disable();
629 KBBase->kb_keyBuffer[(KBBase->kb_writePos)++] = keyCode;
631 D(bug("Wrote to buffer\n"));
633 if(KBBase->kb_writePos == KB_BUFFERSIZE)
634 KBBase->kb_writePos = 0;
636 if (CORRECT(keyCode) < KB_MAXKEYS)
638 if(keyCode & KEYUPMASK)
639 BVBITCLEAR(CORRECT(keyCode), KBBase->kb_Matrix);
640 else
641 BVBITSET(CORRECT(keyCode), KBBase->kb_Matrix);
642 D(bug("Wrote to matrix\n"));
644 else
646 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode), KB_MAXKEYS));
649 if(!IsListEmpty(&KBBase->kb_PendingQueue))
651 #if 0
652 D(bug("doing software irq\n"));
653 Cause(&KBBase->kb_Interrupt);
654 #else
655 AROS_UFC3NR(VOID, kbdSendQueuedEvents,
656 AROS_UFCA(struct KeyboardBase *, KBBase , A1),
657 AROS_UFCA(APTR , NULL, A5),
658 AROS_UFCA(struct ExecBase * , SysBase , A6));
659 #endif
662 Enable();
665 /****************************************************************************************/
667 #undef BVBITSET
668 #undef BVBITCLEAR
669 #undef CORRECT
671 /****************************************************************************************/
673 /* Software interrupt to be called when keys are received */
675 #undef SysBase
677 AROS_UFH3(VOID, kbdSendQueuedEvents,
678 AROS_UFHA(struct KeyboardBase *, KBBase, A1),
679 AROS_UFHA(APTR, thisfunc, A5),
680 AROS_UFHA(struct ExecBase *, SysBase, A6))
682 AROS_USERFUNC_INIT
684 /* Broadcast keys */
685 struct IORequest *ioreq, *nextnode;
686 struct List *pendingList = (struct List *)&KBBase->kb_PendingQueue;
688 D(bug("Inside software irq\n"));
690 ForeachNodeSafe(pendingList, ioreq, nextnode)
692 BOOL moreevents;
694 D(bug("Replying msg: R: %i W: %i\n", kbUn->kbu_readPos,
695 KBBase->kb_writePos));
697 moreevents = writeEvents(ioreq, KBBase);
699 Remove((struct Node *)ioreq);
700 ReplyMsg((struct Message *)&ioreq->io_Message);
702 if (!moreevents) break;
705 if (IsListEmpty(pendingList)) kbUn->kbu_flags &= ~KBUF_PENDING;
707 AROS_USERFUNC_EXIT
710 /****************************************************************************************/
712 static const char end = 0;
714 /****************************************************************************************/