2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
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>
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"
37 #include "keyboard_gcc.h"
40 #include LC_LIBDEFS_FILE
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)
71 #define NUM_INPUTEVENTS(bytesize) ((bytesize) / sizeof(struct InputEvent))
72 #define NEXT_INPUTEVENT(event) (((struct InputEvent *)(event)) + 1)
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
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 /****************************************************************************************/
93 static const UWORD SupportedCommands
[] =
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 */
123 InitSemaphore(&KBBase
->kb_QueueLock
);
124 NEWLIST(&KBBase
->kb_ResetHandlerList
);
125 NEWLIST(&KBBase
->kb_PendingQueue
);
126 NEWLIST(&KBBase
->kb_kbunits
);
131 /****************************************************************************************/
133 static int GM_UNIQUENAME(Open
)
135 LIBBASETYPEPTR KBBase
,
136 struct IORequest
*ioreq
,
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
;
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
;
162 if((ioreq
->io_Unit
= AllocMem(sizeof(KBUnit
), MEMF_CLEAR
)) == NULL
)
164 ioreq
->io_Error
= IOERR_OPENFAIL
;
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
;
182 HiddKbdAB
= OOP_ObtainAttrBase(IID_Hidd_Kbd
);
185 ioreq
->io_Error
= IOERR_OPENFAIL
;
186 D(bug("keyboard.device: Could not get attrbase\n"));
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
},
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
));
214 CloseLibrary(KBBase
->kb_KbdHiddBase
);
215 KBBase
->kb_KbdHiddBase
= NULL
; /* Do cleanup below. */
221 if(!KBBase
->kb_KbdHiddBase
)
223 ioreq
->io_Error
= IOERR_OPENFAIL
;
225 /* TODO: Clean up. */
229 AddTail((struct List
*)&KBBase
->kb_kbunits
, (struct Node
*)&((struct KBUnit
*)(ioreq
->io_Unit
))->node
);
235 /****************************************************************************************/
237 static int GM_UNIQUENAME(Close
)
239 LIBBASETYPEPTR KBBase
,
240 struct IORequest
*ioreq
245 /* only free ioreq->io_Unit if it is ours */
247 ForeachNode(&KBBase
->kb_kbunits
, node
) {
248 if (node
== (struct Node
*)ioreq
->io_Unit
) {
250 FreeMem(node
, sizeof(KBUnit
));
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
)
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
;
282 switch (ioreq
->io_Command
)
285 case NSCMD_DEVICEQUERY
:
286 if(ioStd(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
288 ioreq
->io_Error
= IOERR_BADLENGTH
;
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
);
308 kbUn
->kbu_readPos
= KBBase
->kb_writePos
;
311 case KBD_ADDRESETHANDLER
:
313 Enqueue((struct List
*)(&KBBase
->kb_ResetHandlerList
),
314 (struct Node
*)(ioStd(ioreq
)->io_Data
));
315 KBBase
->kb_nHandlers
++;
319 case KBD_REMRESETHANDLER
:
321 Remove((struct Node
*)(ioStd(ioreq
)->io_Data
));
322 KBBase
->kb_nHandlers
--;
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 */
336 /* There is no good (defined) IOERR to return in this situation */
337 ioreq
->io_Error
= IOERR_NOCMD
;
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
);
350 /* Check for reset... via keybuffer or via HIDD? */
351 /* if(bufferkey == 0x78) ... */
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
;
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
);
374 D(bug("kbd: Events ready\n"));
376 writeEvents(ioreq
, KBBase
);
384 ioreq
->io_Error
= IOERR_NOCMD
;
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
);
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
417 nEvents
= NUM_INPUTEVENTS(ioStd(ioreq
)->io_Length
);
421 ioreq
->io_Error
= IOERR_BADLENGTH
;
422 D(bug("kbd: Bad length\n"));
426 D(bug("NEvents = %i", nEvents
));
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. */
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 ? ... */
451 /* stegerg: on PC keyboards caps lock also generates up events */
452 if (trueCode
!= AKC_CAPS_LOCK
)
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
;
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
)
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
));
531 ColdReboot(); /* Bye bye AROS */
538 /****************************************************************************************/
540 AROS_LH1(LONG
, abortio
,
541 AROS_LHA(struct IORequest
*, ioreq
, A1
),
542 struct KeyboardBase
*, KBBase
, 6, Keyboard
)
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
;
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 /****************************************************************************************/
580 /****************************************************************************************/
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
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
)
613 HIDDV_addServerItem(irqhidd_keyboard
, checkKBint
);
616 /****************************************************************************************/
620 /****************************************************************************************/
622 VOID
keyCallback(struct KeyboardBase
*KBBase
, UWORD keyCode
)
624 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
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
);
641 BVBITSET(CORRECT(keyCode
), KBBase
->kb_Matrix
);
642 D(bug("Wrote to matrix\n"));
646 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode
), KB_MAXKEYS
));
649 if(!IsListEmpty(&KBBase
->kb_PendingQueue
))
652 D(bug("doing software irq\n"));
653 Cause(&KBBase
->kb_Interrupt
);
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
));
665 /****************************************************************************************/
671 /****************************************************************************************/
673 /* Software interrupt to be called when keys are received */
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
))
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
)
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
;
710 /****************************************************************************************/
712 static const char end
= 0;
714 /****************************************************************************************/