revert between 56095 -> 55830 in arch
[AROS.git] / rom / devs / keyboard / keyboard.c
blob7fecfa86cb5ee9ab9eab443290bce7d349964fd8
1 /*
2 Copyright © 1995-2014, 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_INTP(kbdSendQueuedEvents);
111 static BOOL writeEvents(struct IORequest *ioreq, struct KeyboardBase *KBBase);
113 /****************************************************************************************/
115 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR KBBase)
117 /* reset static data */
118 HiddKbdAB = 0;
120 InitSemaphore(&KBBase->kb_QueueLock);
121 NEWLIST(&KBBase->kb_ResetHandlerList);
122 NEWLIST(&KBBase->kb_PendingQueue);
123 NEWLIST(&KBBase->kb_kbunits);
125 return TRUE;
128 /****************************************************************************************/
130 static int GM_UNIQUENAME(Open)
132 LIBBASETYPEPTR KBBase,
133 struct IORequest *ioreq,
134 ULONG unitnum,
135 ULONG flags
138 struct Library *OOPBase = GM_OOPBASE_FIELD(KBBase);
140 if (ioreq->io_Message.mn_Length < sizeof(struct IOStdReq))
142 D(bug("keyport.device/open: IORequest structure passed to OpenDevice is too small!\n"));
143 ioreq->io_Error = IOERR_OPENFAIL;
144 return FALSE;
147 if(KBBase->kb_keyBuffer == NULL)
149 KBBase->kb_keyBuffer = AllocMem(sizeof(UWORD)*KB_BUFFERSIZE, MEMF_ANY);
152 /* No memory for key buffer? */
153 if(KBBase->kb_keyBuffer == NULL)
155 ioreq->io_Error = IOERR_OPENFAIL;
156 return FALSE;
159 if((ioreq->io_Unit = AllocMem(sizeof(KBUnit), MEMF_CLEAR)) == NULL)
161 ioreq->io_Error = IOERR_OPENFAIL;
162 return FALSE;
165 /* nlorentz: Some extra stuff that must be inited */
166 if (NULL == KBBase->kb_Matrix)
168 KBBase->kb_Matrix = AllocMem(KB_MATRIXSIZE, MEMF_ANY|MEMF_CLEAR);
170 if (NULL == KBBase->kb_Matrix)
172 ioreq->io_Error = IOERR_OPENFAIL;
173 return FALSE;
177 if (!HiddKbdAB)
179 HiddKbdAB = OOP_ObtainAttrBase(IID_Hidd_Kbd);
180 if (!HiddKbdAB)
182 ioreq->io_Error = IOERR_OPENFAIL;
183 D(bug("keyboard.device: Could not get attrbase\n"));
184 return FALSE;
187 D(bug("keyboard.device: Attrbase: %x\n", HiddKbdAB));
189 KBBase->kb_Interrupt.is_Node.ln_Type = NT_INTERRUPT;
190 KBBase->kb_Interrupt.is_Node.ln_Pri = 0;
191 KBBase->kb_Interrupt.is_Data = (APTR)KBBase;
192 KBBase->kb_Interrupt.is_Code = (VOID_FUNC)kbdSendQueuedEvents;
194 if(!KBBase->kb_KbdHiddBase)
196 KBBase->kb_KbdHiddBase = OpenLibrary("keyboard.hidd", 0);
197 D(bug("keyboard.device: keyboard.hidd base 0x%p\n", KBBase->kb_KbdHiddBase));
199 /* Install our own keyboard handler if opened for the first time */
200 if(KBBase->kb_KbdHiddBase) {
201 struct TagItem tags[] = {
202 { aHidd_Kbd_IrqHandler , (IPTR)keyCallback },
203 { aHidd_Kbd_IrqHandlerData , (IPTR)KBBase },
204 { TAG_DONE }
207 KBBase->kb_Hidd = OOP_NewObject(NULL, CLID_Hidd_Kbd, tags);
208 D(bug("keyboard.device: keyboard HIDD object 0x%p\n", KBBase->kb_Hidd));
209 if(!KBBase->kb_Hidd)
211 CloseLibrary(KBBase->kb_KbdHiddBase);
212 KBBase->kb_KbdHiddBase = NULL; /* Do cleanup below. */
218 if(!KBBase->kb_KbdHiddBase)
220 ioreq->io_Error = IOERR_OPENFAIL;
221 return FALSE;
222 /* TODO: Clean up. */
225 Forbid();
226 AddTail((struct List*)&KBBase->kb_kbunits, (struct Node *)&((struct KBUnit*)(ioreq->io_Unit))->node);
227 Permit();
229 return TRUE;
232 /****************************************************************************************/
234 static int GM_UNIQUENAME(Close)
236 LIBBASETYPEPTR KBBase,
237 struct IORequest *ioreq
240 struct Node *node;
242 /* only free ioreq->io_Unit if it is ours */
243 Forbid();
244 ForeachNode(&KBBase->kb_kbunits, node) {
245 if (node == (struct Node*)ioreq->io_Unit) {
246 Remove(node);
247 FreeMem(node, sizeof(KBUnit));
248 break;
251 Permit();
253 return TRUE;
256 /****************************************************************************************/
258 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
259 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
260 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
262 /****************************************************************************************/
264 AROS_LH1(void, beginio,
265 AROS_LHA(struct IORequest *, ioreq, A1),
266 struct KeyboardBase *, KBBase, 5, Keyboard)
268 AROS_LIBFUNC_INIT
270 BOOL request_queued = FALSE;
273 D(bug("kbd: beginio(ioreq=%p, cmd=%d)\n", ioreq, ioreq->io_Command));
275 /* WaitIO will look into this */
276 ioreq->io_Message.mn_Node.ln_Type = NT_MESSAGE;
277 ioreq->io_Error = 0;
279 switch (ioreq->io_Command)
281 #if NEWSTYLE_DEVICE
282 case NSCMD_DEVICEQUERY:
283 if(ioStd(ioreq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
285 ioreq->io_Error = IOERR_BADLENGTH;
287 else
289 struct NSDeviceQueryResult *d;
291 d = (struct NSDeviceQueryResult *)ioStd(ioreq)->io_Data;
293 d->DevQueryFormat = 0;
294 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
295 d->DeviceType = NSDEVTYPE_KEYBOARD;
296 d->DeviceSubType = 0;
297 d->SupportedCommands = (UWORD *)SupportedCommands;
299 ioStd(ioreq)->io_Actual = sizeof(struct NSDeviceQueryResult);
301 break;
302 #endif
304 case CMD_CLEAR:
305 kbUn->kbu_readPos = KBBase->kb_writePos;
306 break;
308 case KBD_ADDRESETHANDLER:
309 Disable();
310 Enqueue((struct List *)(&KBBase->kb_ResetHandlerList),
311 (struct Node *)(ioStd(ioreq)->io_Data));
312 KBBase->kb_nHandlers++;
313 Enable();
314 break;
316 case KBD_REMRESETHANDLER:
317 Disable();
318 Remove((struct Node *)(ioStd(ioreq)->io_Data));
319 KBBase->kb_nHandlers--;
320 Enable();
321 break;
323 case KBD_RESETHANDLERDONE:
324 /* We don't want any phony resets. */
326 if(KBBase->kb_ResetPhase == TRUE)
328 if(--(KBBase->kb_nHandlers) <= 0)
329 ColdReboot(); /* Shut down system */
331 else
333 /* There is no good (defined) IOERR to return in this situation */
334 ioreq->io_Error = IOERR_NOCMD;
336 break;
338 case KBD_READMATRIX:
339 ioStd(ioreq)->io_Actual = min(KB_MATRIXSIZE, ioStd(ioreq)->io_Length);
340 CopyMem(KBBase->kb_Matrix, ioStd(ioreq)->io_Data,
341 ioStd(ioreq)->io_Actual);
342 break;
344 case KBD_READEVENT:
346 /* TODO */
347 /* Check for reset... via keybuffer or via HIDD? */
348 /* if(bufferkey == 0x78) ... */
350 #if 0
351 if((((IPTR)ioStd(ioreq)->io_Data) & (__AROS_STRUCTURE_ALIGNMENT - 1)) != 0)
353 D(bug("kbd: Bad address\n"));
354 ioreq->io_Error = IOERR_BADADDRESS;
355 break;
357 #endif
359 Disable(); /* !! */
361 if(kbUn->kbu_readPos == KBBase->kb_writePos)
363 ioreq->io_Flags &= ~IOF_QUICK;
364 request_queued = TRUE;
365 D(bug("kbd: No keypresses, putting request in queue\n"));
367 kbUn->kbu_flags |= KBUF_PENDING;
368 AddTail((struct List *)&KBBase->kb_PendingQueue,
369 (struct Node *)ioreq);
370 } else {
371 D(bug("kbd: Events ready\n"));
373 writeEvents(ioreq, KBBase);
376 Enable();
378 break;
380 default:
381 ioreq->io_Error = IOERR_NOCMD;
382 break;
384 } /* switch (ioreq->io_Command) */
386 /* If the quick bit is not set, send the message to the port */
387 if(!(ioreq->io_Flags & IOF_QUICK) && !request_queued)
388 ReplyMsg(&ioreq->io_Message);
390 AROS_LIBFUNC_EXIT
393 /****************************************************************************************/
395 static BOOL writeEvents(struct IORequest *ioreq, struct KeyboardBase *KBBase)
397 int nEvents; /* Number of struct InputEvent:s that there is
398 room for in memory pointed to by io_Data */
399 UWORD code; /* Value of current keycode */
400 UWORD trueCode; /* Code without possible keypress addition */
401 int i; /* Loop variable */
402 struct InputEvent *event; /* Temporary variable */
403 BOOL moreevents = TRUE;
404 BOOL activate_resetphase = FALSE;
406 event = (struct InputEvent *)(ioStd(ioreq)->io_Data);
408 /* Number of InputEvents we can store in io_Data */
409 /* be careful, the io_Length might be the size of the InputEvent structure,
410 but it can be that the ALIGN() returns a larger size and then nEvents would
411 be 0.
414 nEvents = NUM_INPUTEVENTS(ioStd(ioreq)->io_Length);
416 if(nEvents == 0)
418 ioreq->io_Error = IOERR_BADLENGTH;
419 D(bug("kbd: Bad length\n"));
420 return TRUE;
423 D(bug("NEvents = %i", nEvents));
425 ioreq->io_Error = 0;
427 for(i = 0; i < nEvents; i++)
429 /* Update eventpointer -- this must be done here as I must set
430 ie_NextEvent to NULL if there are no more keys in the buffer. */
431 if(i != 0)
432 event = event->ie_NextEvent;
434 code = KBBase->kb_keyBuffer[kbUn->kbu_readPos++];
436 if(kbUn->kbu_readPos == KB_BUFFERSIZE)
437 kbUn->kbu_readPos = 0;
439 trueCode = code & AMIGAKEYMASK;
441 if(isQualifier(code) == TRUE)
444 /* Key released ? ... */
445 if(code & KEYUPMASK)
447 #if 1
448 /* stegerg: on PC keyboards caps lock also generates up events */
449 if (trueCode != AKC_CAPS_LOCK)
450 #endif
451 kbUn->kbu_Qualifiers &= ~(1 << (trueCode - AKC_QUALIFIERS_FIRST));
453 else /* ... or pressed? */
455 if (trueCode == AKC_CAPS_LOCK)
457 kbUn->kbu_Qualifiers ^= IEQUALIFIER_CAPSLOCK;
459 else
461 kbUn->kbu_Qualifiers |= 1 << (trueCode - AKC_QUALIFIERS_FIRST);
466 D(bug("kbd: Adding event of code %d\n", code));
468 event->ie_Class = IECLASS_RAWKEY;
469 event->ie_SubClass = 0;
470 event->ie_Code = code;
471 event->ie_Qualifier = kbUn->kbu_Qualifiers;
472 event->ie_Qualifier |= isNumericPad(trueCode) ? IEQUALIFIER_NUMERICPAD : 0;
473 event->ie_TimeStamp.tv_secs = 0;
474 event->ie_TimeStamp.tv_micro = 0;
476 if(code == 0x78) activate_resetphase = TRUE;
478 /* No more keys in buffer? */
479 if(kbUn->kbu_readPos == KBBase->kb_writePos)
481 moreevents = FALSE;
482 break;
485 event->ie_NextEvent = NEXT_INPUTEVENT(event);
489 D(bug("Done writing events!"));
490 event->ie_NextEvent = NULL;
492 if(activate_resetphase && !KBBase->kb_ResetPhase)
494 struct Interrupt *node;
496 KBBase->kb_ResetPhase = TRUE;
498 if(!IsListEmpty(&KBBase->kb_ResetHandlerList))
500 /* We may want to install a timer here so that ColdReboot()
501 will eventually be called even if a reset handler hangs */
502 ForeachNode(&KBBase->kb_ResetHandlerList, node)
504 /* We may be inside an interrupt when we come here. Maybe
505 we shall use some other technique? */
506 AROS_INTC1(node->is_Code, node->is_Data);
509 else
511 ColdReboot(); /* Bye bye AROS */
515 return moreevents;
518 /****************************************************************************************/
520 AROS_LH1(LONG, abortio,
521 AROS_LHA(struct IORequest *, ioreq, A1),
522 struct KeyboardBase *, KBBase, 6, Keyboard)
524 AROS_LIBFUNC_INIT
526 LONG ret = -1;
528 Disable();
529 if(kbUn->kbu_flags & KBUF_PENDING)
531 if (ioreq->io_Message.mn_Node.ln_Type == NT_MESSAGE)
533 Remove((struct Node *)ioreq);
534 ReplyMsg(&ioreq->io_Message);
536 ioreq->io_Error = IOERR_ABORTED;
538 if (IsListEmpty(&KBBase->kb_PendingQueue)) kbUn->kbu_flags &= ~KBUF_PENDING;
540 ret = 0;
543 Enable();
545 return ret;
547 AROS_LIBFUNC_EXIT
550 /****************************************************************************************/
552 #define CORRECT(x) (((x) & AMIGAKEYMASK) | (((x) & NOTAMIGAKEYMASK) >> 1))
553 #define BVBITCLEAR(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] &= ~(1 << ((x) & (sizeof(UBYTE)*8 - 1))))
554 #define BVBITSET(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] |= (1 << ((x) & (sizeof(UBYTE)*8 - 1))))
556 /****************************************************************************************/
558 #if 0
560 /****************************************************************************************/
563 78 Reset warning.
564 F9 Last key code bad, next key is same code retransmitted
565 FA Keyboard key buffer overflow
566 FC Keyboard self-test fail.
567 FD Initiate power-up key stream (for keys held or stuck at
568 power on)
569 FE Terminate power-up key stream.
572 #include <hardware/cia.h>
574 /****************************************************************************************/
576 BOOL HIDDM_initKeyboard(struct KeyboardHIDD *kh)
578 /* What should be done here? My guess is that we need the IRQ.hidd
579 before I can complete this function.
580 Presume that an IRQ.hidd exists, and that it has a method
581 HIDDV_addServerItem(ULONG level, BOOL (*)checkFunc) that adds an
582 interrupt server (sort of) to the real interrupt server at level
583 'level'. In the case of the keyboard.hidd, this would be level 6
584 (hardware wise) but probably something else in this context.
585 Then the code would look something like: */
588 kh->kh_irqhidd = FindHidd("IRQ.hidd");
590 if(kh->irqhidd == NULL)
591 return FALSE;
593 HIDDV_addServerItem(irqhidd_keyboard, checkKBint);
596 /****************************************************************************************/
598 #endif
600 /****************************************************************************************/
602 VOID keyCallback(struct KeyboardBase *KBBase, UWORD keyCode)
604 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
605 , KBBase, keyCode));
607 Disable();
609 KBBase->kb_keyBuffer[(KBBase->kb_writePos)++] = keyCode;
611 D(bug("Wrote to buffer\n"));
613 if(KBBase->kb_writePos == KB_BUFFERSIZE)
614 KBBase->kb_writePos = 0;
616 if (CORRECT(keyCode) < KB_MAXKEYS)
618 if(keyCode & KEYUPMASK)
619 BVBITCLEAR(CORRECT(keyCode), KBBase->kb_Matrix);
620 else
621 BVBITSET(CORRECT(keyCode), KBBase->kb_Matrix);
622 D(bug("Wrote to matrix\n"));
624 else
626 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode), KB_MAXKEYS));
629 if(!IsListEmpty(&KBBase->kb_PendingQueue))
631 #if 0
632 D(bug("doing software irq\n"));
633 Cause(&KBBase->kb_Interrupt);
634 #else
635 AROS_INTC1(kbdSendQueuedEvents, KBBase);
636 #endif
639 Enable();
642 /****************************************************************************************/
644 #undef BVBITSET
645 #undef BVBITCLEAR
646 #undef CORRECT
648 /****************************************************************************************/
650 /* Software interrupt to be called when keys are received */
652 #undef SysBase
654 AROS_INTH1(kbdSendQueuedEvents, struct KeyboardBase *, KBBase)
656 AROS_INTFUNC_INIT
658 /* Broadcast keys */
659 struct IORequest *ioreq, *nextnode;
660 struct List *pendingList = (struct List *)&KBBase->kb_PendingQueue;
662 D(bug("Inside software irq\n"));
664 ForeachNodeSafe(pendingList, ioreq, nextnode)
666 BOOL moreevents;
668 D(bug("Replying msg: R: %i W: %i\n", kbUn->kbu_readPos,
669 KBBase->kb_writePos));
671 moreevents = writeEvents(ioreq, KBBase);
673 Remove((struct Node *)ioreq);
674 ReplyMsg((struct Message *)&ioreq->io_Message);
676 if (!moreevents) break;
679 if (IsListEmpty(pendingList)) kbUn->kbu_flags &= ~KBUF_PENDING;
681 return FALSE;
683 AROS_INTFUNC_EXIT
686 #if (0)
687 /****************************************************************************************/
689 static const char end = 0;
691 /****************************************************************************************/
692 #endif