2 Copyright © 1995-2014, 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_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
)
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
);
511 ColdReboot(); /* Bye bye AROS */
518 /****************************************************************************************/
520 AROS_LH1(LONG
, abortio
,
521 AROS_LHA(struct IORequest
*, ioreq
, A1
),
522 struct KeyboardBase
*, KBBase
, 6, Keyboard
)
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
;
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 /****************************************************************************************/
560 /****************************************************************************************/
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
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
)
593 HIDDV_addServerItem(irqhidd_keyboard
, checkKBint
);
596 /****************************************************************************************/
600 /****************************************************************************************/
602 VOID
keyCallback(struct KeyboardBase
*KBBase
, UWORD keyCode
)
604 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
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
);
621 BVBITSET(CORRECT(keyCode
), KBBase
->kb_Matrix
);
622 D(bug("Wrote to matrix\n"));
626 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode
), KB_MAXKEYS
));
629 if(!IsListEmpty(&KBBase
->kb_PendingQueue
))
632 D(bug("doing software irq\n"));
633 Cause(&KBBase
->kb_Interrupt
);
635 AROS_INTC1(kbdSendQueuedEvents
, KBBase
);
642 /****************************************************************************************/
648 /****************************************************************************************/
650 /* Software interrupt to be called when keys are received */
654 AROS_INTH1(kbdSendQueuedEvents
, struct KeyboardBase
*, KBBase
)
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
)
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
;
687 /****************************************************************************************/
689 static const char end
= 0;
691 /****************************************************************************************/