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_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 */
120 InitSemaphore(&KBBase
->kb_QueueLock
);
121 NEWLIST(&KBBase
->kb_ResetHandlerList
);
122 NEWLIST(&KBBase
->kb_PendingQueue
);
123 NEWLIST(&KBBase
->kb_kbunits
);
128 /****************************************************************************************/
130 static int GM_UNIQUENAME(Open
)
132 LIBBASETYPEPTR KBBase
,
133 struct IORequest
*ioreq
,
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
;
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
;
159 if((ioreq
->io_Unit
= AllocMem(sizeof(KBUnit
), MEMF_CLEAR
)) == NULL
)
161 ioreq
->io_Error
= IOERR_OPENFAIL
;
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
;
179 HiddKbdAB
= OOP_ObtainAttrBase(IID_Hidd_Kbd
);
182 ioreq
->io_Error
= IOERR_OPENFAIL
;
183 D(bug("keyboard.device: Could not get attrbase\n"));
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
},
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
));
211 CloseLibrary(KBBase
->kb_KbdHiddBase
);
212 KBBase
->kb_KbdHiddBase
= NULL
; /* Do cleanup below. */
218 if(!KBBase
->kb_KbdHiddBase
)
220 ioreq
->io_Error
= IOERR_OPENFAIL
;
222 /* TODO: Clean up. */
226 AddTail((struct List
*)&KBBase
->kb_kbunits
, (struct Node
*)&((struct KBUnit
*)(ioreq
->io_Unit
))->node
);
232 /****************************************************************************************/
234 static int GM_UNIQUENAME(Close
)
236 LIBBASETYPEPTR KBBase
,
237 struct IORequest
*ioreq
242 /* only free ioreq->io_Unit if it is ours */
244 ForeachNode(&KBBase
->kb_kbunits
, node
) {
245 if (node
== (struct Node
*)ioreq
->io_Unit
) {
247 FreeMem(node
, sizeof(KBUnit
));
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
)
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
;
279 switch (ioreq
->io_Command
)
282 case NSCMD_DEVICEQUERY
:
283 if(ioStd(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
285 ioreq
->io_Error
= IOERR_BADLENGTH
;
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
);
305 kbUn
->kbu_readPos
= KBBase
->kb_writePos
;
308 case KBD_ADDRESETHANDLER
:
310 Enqueue((struct List
*)(&KBBase
->kb_ResetHandlerList
),
311 (struct Node
*)(ioStd(ioreq
)->io_Data
));
312 KBBase
->kb_nHandlers
++;
316 case KBD_REMRESETHANDLER
:
318 Remove((struct Node
*)(ioStd(ioreq
)->io_Data
));
319 KBBase
->kb_nHandlers
--;
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 */
333 /* There is no good (defined) IOERR to return in this situation */
334 ioreq
->io_Error
= IOERR_NOCMD
;
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
);
347 /* Check for reset... via keybuffer or via HIDD? */
348 /* if(bufferkey == 0x78) ... */
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
;
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
);
371 D(bug("kbd: Events ready\n"));
373 writeEvents(ioreq
, KBBase
);
381 ioreq
->io_Error
= IOERR_NOCMD
;
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
);
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
414 nEvents
= NUM_INPUTEVENTS(ioStd(ioreq
)->io_Length
);
418 ioreq
->io_Error
= IOERR_BADLENGTH
;
419 D(bug("kbd: Bad length\n"));
423 D(bug("NEvents = %i", nEvents
));
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. */
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 ? ... */
448 /* stegerg: on PC keyboards caps lock also generates up events */
449 if (trueCode
!= AKC_CAPS_LOCK
)
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
;
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_Prev1DownCode
= (UBYTE
)(kbUn
->kbu_LastCode
& 0xff);
474 event
->ie_Prev1DownQual
= kbUn
->kbu_LastQuals
;
475 event
->ie_Prev2DownCode
= (UBYTE
)(kbUn
->kbu_LastLastCode
& 0xff);
476 event
->ie_Prev2DownQual
= kbUn
->kbu_LastLastQuals
;
477 event
->ie_TimeStamp
.tv_secs
= 0;
478 event
->ie_TimeStamp
.tv_micro
= 0;
480 /* Update list of previous states for dead key handling */
482 if (!(code
& IECODE_UP_PREFIX
) && !isQualifier(code
))
484 kbUn
->kbu_LastLastCode
= kbUn
->kbu_LastCode
;
485 kbUn
->kbu_LastLastQuals
= kbUn
->kbu_LastQuals
;
486 kbUn
->kbu_LastCode
= code
;
487 kbUn
->kbu_LastQuals
= (UBYTE
)(kbUn
->kbu_Qualifiers
& 0xff);
490 if(code
== 0x78) activate_resetphase
= TRUE
;
492 /* No more keys in buffer? */
493 if(kbUn
->kbu_readPos
== KBBase
->kb_writePos
)
499 event
->ie_NextEvent
= NEXT_INPUTEVENT(event
);
503 D(bug("Done writing events!"));
504 event
->ie_NextEvent
= NULL
;
506 if(activate_resetphase
&& !KBBase
->kb_ResetPhase
)
508 struct Interrupt
*node
;
510 KBBase
->kb_ResetPhase
= TRUE
;
512 if(!IsListEmpty(&KBBase
->kb_ResetHandlerList
))
514 /* We may want to install a timer here so that ColdReboot()
515 will eventually be called even if a reset handler hangs */
516 ForeachNode(&KBBase
->kb_ResetHandlerList
, node
)
518 /* We may be inside an interrupt when we come here. Maybe
519 we shall use some other technique? */
520 AROS_INTC1(node
->is_Code
, node
->is_Data
);
525 ColdReboot(); /* Bye bye AROS */
532 /****************************************************************************************/
534 AROS_LH1(LONG
, abortio
,
535 AROS_LHA(struct IORequest
*, ioreq
, A1
),
536 struct KeyboardBase
*, KBBase
, 6, Keyboard
)
543 if(kbUn
->kbu_flags
& KBUF_PENDING
)
545 if (ioreq
->io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
547 Remove((struct Node
*)ioreq
);
548 ReplyMsg(&ioreq
->io_Message
);
550 ioreq
->io_Error
= IOERR_ABORTED
;
552 if (IsListEmpty(&KBBase
->kb_PendingQueue
)) kbUn
->kbu_flags
&= ~KBUF_PENDING
;
564 /****************************************************************************************/
566 #define CORRECT(x) (((x) & AMIGAKEYMASK) | (((x) & NOTAMIGAKEYMASK) >> 1))
567 #define BVBITCLEAR(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] &= ~(1 << ((x) & (sizeof(UBYTE)*8 - 1))))
568 #define BVBITSET(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] |= (1 << ((x) & (sizeof(UBYTE)*8 - 1))))
570 /****************************************************************************************/
574 /****************************************************************************************/
578 F9 Last key code bad, next key is same code retransmitted
579 FA Keyboard key buffer overflow
580 FC Keyboard self-test fail.
581 FD Initiate power-up key stream (for keys held or stuck at
583 FE Terminate power-up key stream.
586 #include <hardware/cia.h>
588 /****************************************************************************************/
590 BOOL
HIDDM_initKeyboard(struct KeyboardHIDD
*kh
)
592 /* What should be done here? My guess is that we need the IRQ.hidd
593 before I can complete this function.
594 Presume that an IRQ.hidd exists, and that it has a method
595 HIDDV_addServerItem(ULONG level, BOOL (*)checkFunc) that adds an
596 interrupt server (sort of) to the real interrupt server at level
597 'level'. In the case of the keyboard.hidd, this would be level 6
598 (hardware wise) but probably something else in this context.
599 Then the code would look something like: */
602 kh
->kh_irqhidd
= FindHidd("IRQ.hidd");
604 if(kh
->irqhidd
== NULL
)
607 HIDDV_addServerItem(irqhidd_keyboard
, checkKBint
);
610 /****************************************************************************************/
614 /****************************************************************************************/
616 VOID
keyCallback(struct KeyboardBase
*KBBase
, UWORD keyCode
)
618 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
623 KBBase
->kb_keyBuffer
[(KBBase
->kb_writePos
)++] = keyCode
;
625 D(bug("Wrote to buffer\n"));
627 if(KBBase
->kb_writePos
== KB_BUFFERSIZE
)
628 KBBase
->kb_writePos
= 0;
630 if (CORRECT(keyCode
) < KB_MAXKEYS
)
632 if(keyCode
& KEYUPMASK
)
633 BVBITCLEAR(CORRECT(keyCode
), KBBase
->kb_Matrix
);
635 BVBITSET(CORRECT(keyCode
), KBBase
->kb_Matrix
);
636 D(bug("Wrote to matrix\n"));
640 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode
), KB_MAXKEYS
));
643 if(!IsListEmpty(&KBBase
->kb_PendingQueue
))
646 D(bug("doing software irq\n"));
647 Cause(&KBBase
->kb_Interrupt
);
649 AROS_INTC1(kbdSendQueuedEvents
, KBBase
);
656 /****************************************************************************************/
662 /****************************************************************************************/
664 /* Software interrupt to be called when keys are received */
668 AROS_INTH1(kbdSendQueuedEvents
, struct KeyboardBase
*, KBBase
)
673 struct IORequest
*ioreq
, *nextnode
;
674 struct List
*pendingList
= (struct List
*)&KBBase
->kb_PendingQueue
;
676 D(bug("Inside software irq\n"));
678 ForeachNodeSafe(pendingList
, ioreq
, nextnode
)
682 D(bug("Replying msg: R: %i W: %i\n", kbUn
->kbu_readPos
,
683 KBBase
->kb_writePos
));
685 moreevents
= writeEvents(ioreq
, KBBase
);
687 Remove((struct Node
*)ioreq
);
688 ReplyMsg((struct Message
*)&ioreq
->io_Message
);
690 if (!moreevents
) break;
693 if (IsListEmpty(pendingList
)) kbUn
->kbu_flags
&= ~KBUF_PENDING
;
700 /****************************************************************************************/
702 static const char end
= 0;
704 /****************************************************************************************/