2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
9 /* HISTORY: 12.04.98 SDuvan Began work
10 xx.06.98 SDuvan Fixes, added amigakeyboard.HIDD
13 /****************************************************************************************/
15 #include <exec/resident.h>
16 #include <exec/interrupts.h>
17 #include <exec/initializers.h>
18 #include <devices/inputevent.h>
19 #include <devices/keyboard.h>
20 #include <devices/newstyle.h>
21 #include <proto/exec.h>
22 #include <proto/dos.h>
23 #include <proto/oop.h>
24 #include <exec/memory.h>
25 #include <exec/errors.h>
26 #include <exec/lists.h>
28 #include <utility/utility.h>
29 #include <hidd/keyboard.h>
30 #include <aros/libcall.h>
31 #include <aros/symbolsets.h>
32 #include "abstractkeycodes.h"
33 #include "keyboard_intern.h"
34 #include "devs_private.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
[] =
108 /****************************************************************************************/
110 VOID
keyCallback(struct KeyboardBase
*KBBase
, UWORD keyCode
);
111 AROS_UFP3(VOID
, kbdSendQueuedEvents
,
112 AROS_UFPA(struct KeyboardBase
*, KBBase
, A1
),
113 AROS_UFPA(APTR
, thisfunc
, A5
),
114 AROS_UFPA(struct ExecBase
*, SysBase
, A6
));
115 static BOOL
writeEvents(struct IORequest
*ioreq
, struct KeyboardBase
*KBBase
);
117 /****************************************************************************************/
119 static int GM_UNIQUENAME(Init
)(LIBBASETYPEPTR KBBase
)
121 /* reset static data */
124 InitSemaphore(&KBBase
->kb_QueueLock
);
125 NEWLIST(&KBBase
->kb_ResetHandlerList
);
126 NEWLIST(&KBBase
->kb_PendingQueue
);
131 /****************************************************************************************/
133 static int GM_UNIQUENAME(Open
)
135 LIBBASETYPEPTR KBBase
,
136 struct IORequest
*ioreq
,
141 if (ioreq
->io_Message
.mn_Length
< sizeof(struct IOStdReq
))
143 D(bug("keyport.device/open: IORequest structure passed to OpenDevice is too small!\n"));
144 ioreq
->io_Error
= IOERR_OPENFAIL
;
148 if(KBBase
->kb_keyBuffer
== NULL
)
150 KBBase
->kb_keyBuffer
= AllocMem(sizeof(UWORD
)*KB_BUFFERSIZE
, MEMF_ANY
);
153 /* No memory for key buffer? */
154 if(KBBase
->kb_keyBuffer
== NULL
)
156 ioreq
->io_Error
= IOERR_OPENFAIL
;
160 if((ioreq
->io_Unit
= AllocMem(sizeof(KBUnit
), MEMF_CLEAR
)) == NULL
)
162 ioreq
->io_Error
= IOERR_OPENFAIL
;
166 /* nlorentz: Some extra stuff that must be inited */
167 if (NULL
== KBBase
->kb_Matrix
)
169 KBBase
->kb_Matrix
= AllocMem(KB_MATRIXSIZE
, MEMF_ANY
|MEMF_CLEAR
);
171 if (NULL
== KBBase
->kb_Matrix
)
173 ioreq
->io_Error
= IOERR_OPENFAIL
;
180 HiddKbdAB
= OOP_ObtainAttrBase(IID_Hidd_Kbd
);
183 ioreq
->io_Error
= IOERR_OPENFAIL
;
184 D(bug("keyboard.device: Could not get attrbase\n"));
188 D(bug("keyboard.device: Attrbase: %x\n", HiddKbdAB
));
190 KBBase
->kb_Interrupt
.is_Node
.ln_Type
= NT_INTERRUPT
;
191 KBBase
->kb_Interrupt
.is_Node
.ln_Pri
= 0;
192 KBBase
->kb_Interrupt
.is_Data
= (APTR
)KBBase
;
193 KBBase
->kb_Interrupt
.is_Code
= kbdSendQueuedEvents
;
195 /******* nlorentz: End of stuff added by me ********/
198 /* nlorentz: No lowlevel library yet */
200 if(!KBBase
->kb_LowLevelBase
)
202 KBBase
->kb_LowLevelBase
= OpenLibrary("lowlevel.library", 41);
204 /* Install our own keyboard handler if opened for the first time */
205 if(KBBase
->kb_LowLevelBase
)
206 if((KBBase
->kb_kbIrqHandle
= AddKBInt(keyCallback
, KBBase
)) == NULL
)
208 CloseLibrary(KBBase
->kb_LowLevelBase
);
209 KBBase
->kb_LowLevelBase
= NULL
; /* Do cleanup below. */
214 if(!KBBase
->kb_LowLevelBase
)
216 ioreq
->io_Error
= IOERR_OPENFAIL
;
218 /* TODO: Clean up. */
225 /****************************************************************************************/
227 static int GM_UNIQUENAME(Close
)
229 LIBBASETYPEPTR KBBase
,
230 struct IORequest
*ioreq
233 FreeMem(ioreq
->io_Unit
, sizeof(KBUnit
));
238 /****************************************************************************************/
240 ADD2INITLIB(GM_UNIQUENAME(Init
), 0)
241 ADD2OPENDEV(GM_UNIQUENAME(Open
), 0)
242 ADD2CLOSEDEV(GM_UNIQUENAME(Close
), 0)
244 /****************************************************************************************/
246 AROS_LH1(void, beginio
,
247 AROS_LHA(struct IORequest
*, ioreq
, A1
),
248 struct KeyboardBase
*, KBBase
, 5, Keyboard
)
252 BOOL request_queued
= FALSE
;
255 D(bug("kbd: beginio(ioreq=%p, cmd=%d)\n", ioreq
, ioreq
->io_Command
));
257 /* WaitIO will look into this */
258 ioreq
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
261 switch (ioreq
->io_Command
)
264 case NSCMD_DEVICEQUERY
:
265 if(ioStd(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
267 ioreq
->io_Error
= IOERR_BADLENGTH
;
271 struct NSDeviceQueryResult
*d
;
273 d
= (struct NSDeviceQueryResult
*)ioStd(ioreq
)->io_Data
;
275 d
->DevQueryFormat
= 0;
276 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
277 d
->DeviceType
= NSDEVTYPE_KEYBOARD
;
278 d
->DeviceSubType
= 0;
279 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
281 ioStd(ioreq
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
287 kbUn
->kbu_readPos
= KBBase
->kb_writePos
;
290 case KBD_ADDRESETHANDLER
:
292 Enqueue((struct List
*)(&KBBase
->kb_ResetHandlerList
),
293 (struct Node
*)(ioStd(ioreq
)->io_Data
));
294 KBBase
->kb_nHandlers
++;
298 case KBD_REMRESETHANDLER
:
300 Remove((struct Node
*)(ioStd(ioreq
)->io_Data
));
301 KBBase
->kb_nHandlers
--;
305 case KBD_RESETHANDLERDONE
:
306 /* We don't want any phony resets. */
308 if(KBBase
->kb_ResetPhase
== TRUE
)
310 if(--(KBBase
->kb_nHandlers
) <= 0)
311 ColdReboot(); /* Shut down system */
315 /* There is no good (defined) IOERR to return in this situation */
316 ioreq
->io_Error
= IOERR_NOCMD
;
321 ioStd(ioreq
)->io_Actual
= min(KB_MATRIXSIZE
, ioStd(ioreq
)->io_Length
);
322 CopyMem(KBBase
->kb_Matrix
, ioStd(ioreq
)->io_Data
,
323 ioStd(ioreq
)->io_Actual
);
329 /* Check for reset... via keybuffer or via HIDD? */
330 /* if(bufferkey == 0x78) ... */
333 if((((IPTR
)ioStd(ioreq
)->io_Data
) & (__AROS_STRUCTURE_ALIGNMENT
- 1)) != 0)
335 D(bug("kbd: Bad address\n"));
336 ioreq
->io_Error
= IOERR_BADADDRESS
;
343 if(kbUn
->kbu_readPos
== KBBase
->kb_writePos
)
345 ioreq
->io_Flags
&= ~IOF_QUICK
;
346 request_queued
= TRUE
;
347 D(bug("kbd: No keypresses, putting request in queue\n"));
349 kbUn
->kbu_flags
|= KBUF_PENDING
;
350 AddTail((struct List
*)&KBBase
->kb_PendingQueue
,
351 (struct Node
*)ioreq
);
353 D(bug("kbd: Events ready\n"));
355 writeEvents(ioreq
, KBBase
);
362 /* nlorentz: This command lets the keyboard.device initialize
363 the HIDD to use. It must be done this way, because
364 HIDDs might be loaded from disk, and keyboard.device is
365 inited before DOS is up and running.
366 The name of the HIDD class is in
367 ioStd(rew)->io_Data. Note that maybe we should
368 receive a pointer to an already created HIDD object instead.
369 Also note that the below is just a temporary hack, should
370 probably use IRQ HIDD instead to set the IRQ handler.
374 struct TagItem tags
[] =
376 { aHidd_Kbd_IrqHandler
, (IPTR
)keyCallback
},
377 { aHidd_Kbd_IrqHandlerData
, (IPTR
)KBBase
},
381 D(bug("keyboard.device: Received CMD_HIDDINIT, hiddname=\"%s\"\n"
382 , (STRPTR
)ioStd(ioreq
)->io_Data
));
384 if (KBBase
->kb_Hidd
!= NULL
)
385 OOP_DisposeObject(KBBase
->kb_Hidd
);
386 KBBase
->kb_Hidd
= OOP_NewObject(NULL
, (STRPTR
)ioStd(ioreq
)->io_Data
, tags
);
387 if (!KBBase
->kb_Hidd
)
389 D(bug("keyboard.device: Failed to open hidd.\n"));
390 ioreq
->io_Error
= IOERR_OPENFAIL
;
395 ioreq
->io_Error
= IOERR_NOCMD
;
398 } /* switch (ioreq->io_Command) */
400 /* If the quick bit is not set, send the message to the port */
401 if(!(ioreq
->io_Flags
& IOF_QUICK
) && !request_queued
)
402 ReplyMsg(&ioreq
->io_Message
);
407 /****************************************************************************************/
409 static BOOL
writeEvents(struct IORequest
*ioreq
, struct KeyboardBase
*KBBase
)
411 int nEvents
; /* Number of struct InputEvent:s that there is
412 room for in memory pointed to by io_Data */
413 UWORD code
; /* Value of current keycode */
414 UWORD trueCode
; /* Code without possible keypress addition */
415 int i
; /* Loop variable */
416 struct InputEvent
*event
; /* Temporary variable */
417 BOOL moreevents
= TRUE
;
418 BOOL activate_resetphase
= FALSE
;
420 event
= (struct InputEvent
*)(ioStd(ioreq
)->io_Data
);
422 /* Number of InputEvents we can store in io_Data */
423 /* be careful, the io_Length might be the size of the InputEvent structure,
424 but it can be that the ALIGN() returns a larger size and then nEvents would
428 nEvents
= NUM_INPUTEVENTS(ioStd(ioreq
)->io_Length
);
432 ioreq
->io_Error
= IOERR_BADLENGTH
;
433 D(bug("kbd: Bad length\n"));
437 D(bug("NEvents = %i", nEvents
));
441 for(i
= 0; i
< nEvents
; i
++)
443 /* Update eventpointer -- this must be done here as I must set
444 ie_NextEvent to NULL if there are no more keys in the buffer. */
446 event
= event
->ie_NextEvent
;
448 code
= KBBase
->kb_keyBuffer
[kbUn
->kbu_readPos
++];
450 if(kbUn
->kbu_readPos
== KB_BUFFERSIZE
)
451 kbUn
->kbu_readPos
= 0;
453 trueCode
= code
& AMIGAKEYMASK
;
455 if(isQualifier(code
) == TRUE
)
458 /* Key released ? ... */
462 /* stegerg: on PC keyboards caps lock also generates up events */
463 if (trueCode
!= AKC_CAPS_LOCK
)
465 kbUn
->kbu_Qualifiers
&= ~(1 << (trueCode
- AKC_QUALIFIERS_FIRST
));
467 else /* ... or pressed? */
469 if (trueCode
== AKC_CAPS_LOCK
)
471 kbUn
->kbu_Qualifiers
^= IEQUALIFIER_CAPSLOCK
;
475 kbUn
->kbu_Qualifiers
|= 1 << (trueCode
- AKC_QUALIFIERS_FIRST
);
480 D(bug("kbd: Adding event of code %d\n", code
));
482 event
->ie_Class
= IECLASS_RAWKEY
;
483 event
->ie_SubClass
= 0;
484 event
->ie_Code
= code
;
485 event
->ie_Qualifier
= kbUn
->kbu_Qualifiers
;
486 event
->ie_Qualifier
|= isNumericPad(trueCode
) ? IEQUALIFIER_NUMERICPAD
: 0;
487 event
->ie_Prev1DownCode
= (UBYTE
)(kbUn
->kbu_LastCode
& 0xff);
488 event
->ie_Prev1DownQual
= kbUn
->kbu_LastQuals
;
489 event
->ie_Prev2DownCode
= (UBYTE
)(kbUn
->kbu_LastLastCode
& 0xff);
490 event
->ie_Prev2DownQual
= kbUn
->kbu_LastLastQuals
;
491 event
->ie_TimeStamp
.tv_secs
= 0;
492 event
->ie_TimeStamp
.tv_micro
= 0;
494 /* Update list of previous states for dead key handling */
496 if (!(code
& IECODE_UP_PREFIX
) && !isQualifier(code
))
498 kbUn
->kbu_LastLastCode
= kbUn
->kbu_LastCode
;
499 kbUn
->kbu_LastLastQuals
= kbUn
->kbu_LastQuals
;
500 kbUn
->kbu_LastCode
= code
;
501 kbUn
->kbu_LastQuals
= (UBYTE
)(kbUn
->kbu_Qualifiers
& 0xff);
504 if(code
== 0x78) activate_resetphase
= TRUE
;
506 /* No more keys in buffer? */
507 if(kbUn
->kbu_readPos
== KBBase
->kb_writePos
)
513 event
->ie_NextEvent
= NEXT_INPUTEVENT(event
);
517 D(bug("Done writing events!"));
518 event
->ie_NextEvent
= NULL
;
520 if(activate_resetphase
&& !KBBase
->kb_ResetPhase
)
522 struct Interrupt
*node
;
524 KBBase
->kb_ResetPhase
= TRUE
;
526 if(!IsListEmpty(&KBBase
->kb_ResetHandlerList
))
528 /* We may want to install a timer here so that ColdReboot()
529 will eventually be called even if a reset handler hang. */
530 ForeachNode(&KBBase
->kb_ResetHandlerList
, node
)
532 /* We may be inside an interrupt when we come here. Maybe
533 we shall use some other technique? */
534 AROS_UFC3(VOID
, node
->is_Code
,
535 AROS_UFCA(APTR
, node
->is_Data
, A1
),
536 AROS_UFCA(APTR
, node
->is_Code
, A5
),
537 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
542 ColdReboot(); /* Bye bye AROS */
549 /****************************************************************************************/
551 AROS_LH1(LONG
, abortio
,
552 AROS_LHA(struct IORequest
*, ioreq
, A1
),
553 struct KeyboardBase
*, KBBase
, 6, Keyboard
)
560 if(kbUn
->kbu_flags
& KBUF_PENDING
)
562 if (ioreq
->io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
564 Remove((struct Node
*)ioreq
);
565 ReplyMsg(&ioreq
->io_Message
);
567 ioreq
->io_Error
= IOERR_ABORTED
;
569 if (IsListEmpty(&KBBase
->kb_PendingQueue
)) kbUn
->kbu_flags
&= ~KBUF_PENDING
;
581 /****************************************************************************************/
583 #define CORRECT(x) (((x) & AMIGAKEYMASK) | (((x) & NOTAMIGAKEYMASK) >> 1))
584 #define BVBITCLEAR(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] &= ~(1 << ((x) & (sizeof(UBYTE)*8 - 1))))
585 #define BVBITSET(x, y) ((y)[(x) / (sizeof(UBYTE)*8)] |= (1 << ((x) & (sizeof(UBYTE)*8 - 1))))
587 /****************************************************************************************/
591 /****************************************************************************************/
595 F9 Last key code bad, next key is same code retransmitted
596 FA Keyboard key buffer overflow
597 FC Keyboard self-test fail.
598 FD Initiate power-up key stream (for keys held or stuck at
600 FE Terminate power-up key stream.
603 #include <hardware/cia.h>
605 /****************************************************************************************/
607 BOOL
HIDDM_initKeyboard(struct KeyboardHIDD
*kh
)
609 /* What should be done here? My guess is that we need the IRQ.hidd
610 before I can complete this function.
611 Presume that an IRQ.hidd exists, and that it has a method
612 HIDDV_addServerItem(ULONG level, BOOL (*)checkFunc) that adds an
613 interrupt server (sort of) to the real interrupt server at level
614 'level'. In the case of the keyboard.hidd, this would be level 6
615 (hardware wise) but probably something else in this context.
616 Then the code would look something like: */
619 kh
->kh_irqhidd
= FindHidd("IRQ.hidd");
621 if(kh
->irqhidd
== NULL
)
624 HIDDV_addServerItem(irqhidd_keyboard
, checkKBint
);
627 /****************************************************************************************/
631 /****************************************************************************************/
633 VOID
keyCallback(struct KeyboardBase
*KBBase
, UWORD keyCode
)
635 D(bug("keyCallBack(KBBase=%p, keyCode=%d)\n"
640 KBBase
->kb_keyBuffer
[(KBBase
->kb_writePos
)++] = keyCode
;
642 D(bug("Wrote to buffer\n"));
644 if(KBBase
->kb_writePos
== KB_BUFFERSIZE
)
645 KBBase
->kb_writePos
= 0;
647 if (CORRECT(keyCode
) < KB_MAXKEYS
)
649 if(keyCode
& KEYUPMASK
)
650 BVBITCLEAR(CORRECT(keyCode
), KBBase
->kb_Matrix
);
652 BVBITSET(CORRECT(keyCode
), KBBase
->kb_Matrix
);
653 D(bug("Wrote to matrix\n"));
657 D(bug("Keycode value too high. Is %d. Should be < %d\n", CORRECT(keyCode
), KB_MAXKEYS
));
660 if(!IsListEmpty(&KBBase
->kb_PendingQueue
))
663 D(bug("doing software irq\n"));
664 Cause(&KBBase
->kb_Interrupt
);
666 AROS_UFC3(VOID
, kbdSendQueuedEvents
,
667 AROS_UFCA(struct KeyboardBase
*, KBBase
, A1
),
668 AROS_UFCA(APTR
, NULL
, A5
),
669 AROS_UFCA(struct ExecBase
* , SysBase
, A6
));
676 /****************************************************************************************/
682 /****************************************************************************************/
684 /* Software interrupt to be called when keys are received */
688 AROS_UFH3(VOID
, kbdSendQueuedEvents
,
689 AROS_UFHA(struct KeyboardBase
*, KBBase
, A1
),
690 AROS_UFHA(APTR
, thisfunc
, A5
),
691 AROS_UFHA(struct ExecBase
*, SysBase
, A6
))
696 struct IORequest
*ioreq
, *nextnode
;
697 struct List
*pendingList
= (struct List
*)&KBBase
->kb_PendingQueue
;
699 D(bug("Inside software irq\n"));
701 ForeachNodeSafe(pendingList
, ioreq
, nextnode
)
705 D(bug("Replying msg: R: %i W: %i\n", kbUn
->kbu_readPos
,
706 KBBase
->kb_writePos
));
708 moreevents
= writeEvents(ioreq
, KBBase
);
710 Remove((struct Node
*)ioreq
);
711 ReplyMsg((struct Message
*)&ioreq
->io_Message
);
713 if (!moreevents
) break;
716 if (IsListEmpty(pendingList
)) kbUn
->kbu_flags
&= ~KBUF_PENDING
;
721 /****************************************************************************************/
723 static const char end
= 0;
725 /****************************************************************************************/