2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
9 /* NOTE: Currently, only mice are supported */
11 /****************************************************************************************/
13 #include <exec/interrupts.h>
14 #include <exec/initializers.h>
15 #include <hardware/intbits.h>
16 #include <devices/inputevent.h>
17 #include <devices/gameport.h>
18 #include <devices/newstyle.h>
19 #include <devices/rawkeycodes.h>
20 #include <proto/exec.h>
21 #include <proto/dos.h>
22 #include <proto/oop.h>
23 #include <exec/memory.h>
24 #include <exec/errors.h>
25 #include <exec/lists.h>
27 #include <utility/utility.h>
28 #include <hidd/mouse.h>
29 #include <aros/libcall.h>
30 #include <aros/asmcall.h>
31 #include <aros/symbolsets.h>
32 #include "gameport_intern.h"
35 #include "gameport_gcc.h"
39 #include <aros/debug.h>
41 #include LC_LIBDEFS_FILE
43 /****************************************************************************************/
45 #define NEWSTYLE_DEVICE 1
46 #define ALIGN_IS_EVIL 1
48 #define ioStd(x) ((struct IOStdReq *)x)
49 #define gpUn ((struct GPUnit *)(ioreq->io_Unit))
51 #define min(a,b) ((a) < (b)) ? (a) : (b)
52 #define ABS(a) ((a) >= 0) ? (a) : (-(a))
53 #define ALIGN(x) ((((x) + (__AROS_STRUCTURE_ALIGNMENT - 1)) / \
54 __AROS_STRUCTURE_ALIGNMENT) * __AROS_STRUCTURE_ALIGNMENT)
58 #define NUM_INPUTEVENTS(bytesize) ((bytesize) / sizeof(struct InputEvent))
59 #define NEXT_INPUTEVENT(event) (((struct InputEvent *)(event)) + 1)
63 /* Number of InputEvents we can store in io_Data */
64 /* be careful, the io_Length might be the size of the InputEvent structure,
65 but it can be that the ALIGN() returns a larger size and then nEvents would
69 #define NUM_INPUTEVENTS(bytesize) (((bytesize) == sizeof(struct InputEvent)) ? \
70 1 : (bytesize) / ALIGN(sizeof(struct InputEvent)))
71 #define NEXT_INPUTEVENT(event) ((struct InputEvent *)((UBYTE*)(event) + \
72 ALIGN(sizeof(struct InputEvent))))
74 #endif /* ALIGN_IS_EVIL */
76 #define IECODE_DUMMY_WHEEL 0xFE
78 /****************************************************************************************/
82 static const UWORD SupportedCommands
[] =
96 /****************************************************************************************/
98 static BOOL
fillrequest(struct IORequest
*ioreq
, BOOL
*trigged
, struct GameportBase
*GPBase
);
99 static VOID
mouseCallback(struct GameportBase
*GPBase
,
100 struct pHidd_Mouse_ExtEvent
*ev
);
101 static AROS_INTP(gpSendQueuedEvents
);
104 /****************************************************************************************/
106 /* 'data' is a pointer to GPBase->gp_nTicks. */
108 AROS_INTH1(gpVBlank
, LIBBASETYPEPTR
, GPBase
)
112 if (GPBase
->gp_nTicks
< ~0)
122 static int GM_UNIQUENAME(init
)(LIBBASETYPEPTR GPBase
)
126 /* reset static data */
129 for(i
= 0; i
< GP_NUNITS
; i
++)
131 GPBase
->gp_cTypes
[i
] = GPCT_NOCONTROLLER
;
134 InitSemaphore(&GPBase
->gp_QueueLock
);
135 InitSemaphore(&GPBase
->gp_Lock
);
136 NEWLIST(&GPBase
->gp_PendingQueue
);
138 GPBase
->gp_Interrupt
.is_Node
.ln_Type
= NT_INTERRUPT
;
139 GPBase
->gp_Interrupt
.is_Node
.ln_Pri
= 0;
140 GPBase
->gp_Interrupt
.is_Data
= (APTR
)GPBase
;
141 GPBase
->gp_Interrupt
.is_Code
= (VOID_FUNC
)gpSendQueuedEvents
;
143 GPBase
->gp_VBlank
.is_Code
= (VOID_FUNC
)gpVBlank
;
144 GPBase
->gp_VBlank
.is_Data
= GPBase
;
145 GPBase
->gp_VBlank
.is_Node
.ln_Name
= "Gameport VBlank server";
146 GPBase
->gp_VBlank
.is_Node
.ln_Pri
= 0;
147 GPBase
->gp_VBlank
.is_Node
.ln_Type
= NT_INTERRUPT
;
149 /* Add a VBLANK server to take care of event timing. */
150 AddIntServer(INTB_VERTB
, &GPBase
->gp_VBlank
);
155 /****************************************************************************************/
157 static int GM_UNIQUENAME(open
)
159 LIBBASETYPEPTR GPBase
,
160 struct IORequest
*ioreq
,
165 struct Library
*OOPBase
;
167 /* Erroneous unit? */
168 if (unitnum
> GP_MAXUNIT
)
170 ioreq
->io_Error
= IOERR_OPENFAIL
;
175 if (ioreq
->io_Message
.mn_Length
< sizeof(struct IOStdReq
))
177 D(bug("gameport.device/open: IORequest structure passed to OpenDevice "
179 ioreq
->io_Error
= IOERR_OPENFAIL
;
184 if (GPBase
->gp_eventBuffer
== NULL
)
186 GPBase
->gp_eventBuffer
= AllocMem(sizeof(UWORD
) * GP_BUFFERSIZE
,
190 /* No memory for key buffer? */
191 if (GPBase
->gp_eventBuffer
== NULL
)
193 ioreq
->io_Error
= IOERR_OPENFAIL
;
198 if ((ioreq
->io_Unit
= AllocMem(sizeof(GPUnit
), MEMF_CLEAR
)) == NULL
)
200 ioreq
->io_Error
= IOERR_OPENFAIL
;
205 gpUn
->gpu_unitNum
= unitnum
;
207 OOPBase
= OpenLibrary("oop.library", 0);
209 ioreq
->io_Error
= IOERR_OPENFAIL
;
215 HiddMouseAB
= OOP_ObtainAttrBase(IID_Hidd_Mouse
);
219 ioreq
->io_Error
= IOERR_OPENFAIL
;
220 CloseLibrary(OOPBase
);
221 D(bug("gameport.device: Could not get attrbase\n"));
227 D(bug("gameport.device: Attrbase: %x\n", HiddMouseAB
));
229 /******* nlorentz: End of stuff added by me ********/
231 if(!GPBase
->gp_MouseHiddBase
)
233 GPBase
->gp_MouseHiddBase
= OpenLibrary("mouse.hidd", 0);
235 /* Install our own keyboard handler if opened for the first time */
236 if(GPBase
->gp_MouseHiddBase
) {
237 struct TagItem tags
[] = {
238 { aHidd_Mouse_IrqHandler
, (IPTR
)mouseCallback
},
239 { aHidd_Mouse_IrqHandlerData
, (IPTR
)GPBase
},
243 GPBase
->gp_Hidd
= OOP_NewObject(NULL
, CLID_Hidd_Mouse
, tags
);
244 D(bug("keyboard.device: keyboard HIDD object 0x%p\n", GPBase
->gp_Hidd
));
247 CloseLibrary(GPBase
->gp_MouseHiddBase
);
248 GPBase
->gp_MouseHiddBase
= NULL
; /* Do cleanup below. */
253 CloseLibrary(OOPBase
);
255 if(!GPBase
->gp_MouseHiddBase
)
257 ioreq
->io_Error
= IOERR_OPENFAIL
;
259 /* TODO: Clean up. */
265 /****************************************************************************************/
267 static int GM_UNIQUENAME(close
)
269 LIBBASETYPEPTR GPBase
,
270 struct IORequest
*ioreq
273 FreeMem(ioreq
->io_Unit
, sizeof(GPUnit
));
278 /****************************************************************************************/
280 ADD2INITLIB(GM_UNIQUENAME(init
),0)
281 ADD2OPENDEV(GM_UNIQUENAME(open
),0)
282 ADD2CLOSEDEV(GM_UNIQUENAME(close
),0)
284 /****************************************************************************************/
286 AROS_LH1(void, beginio
,
287 AROS_LHA(struct IORequest
*, ioreq
, A1
),
288 struct GameportBase
*, GPBase
, 5, Gameport
)
292 BOOL request_queued
= FALSE
;
294 D(bug("gpd: beginio(ioreq=%p, cmd=%d)\n", ioreq
, ioreq
->io_Command
));
296 /* WaitIO will look into this */
297 ioreq
->io_Message
.mn_Node
.ln_Type
= NT_MESSAGE
;
300 switch (ioreq
->io_Command
)
303 case NSCMD_DEVICEQUERY
:
304 if(ioStd(ioreq
)->io_Length
< ((LONG
)OFFSET(NSDeviceQueryResult
, SupportedCommands
)) + sizeof(UWORD
*))
306 ioreq
->io_Error
= IOERR_BADLENGTH
;
310 struct NSDeviceQueryResult
*d
;
312 d
= (struct NSDeviceQueryResult
*)ioStd(ioreq
)->io_Data
;
314 d
->DevQueryFormat
= 0;
315 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
316 d
->DeviceType
= NSDEVTYPE_GAMEPORT
;
317 d
->DeviceSubType
= 0;
318 d
->SupportedCommands
= (UWORD
*)SupportedCommands
;
320 ioStd(ioreq
)->io_Actual
= sizeof(struct NSDeviceQueryResult
);
326 gpUn
->gpu_readPos
= GPBase
->gp_writePos
;
330 if (ioStd(ioreq
)->io_Length
< sizeof(UBYTE
))
332 ioreq
->io_Error
= IOERR_BADLENGTH
;
336 ObtainSemaphoreShared(&GPBase
->gp_Lock
);
337 *((UBYTE
*)(ioStd(ioreq
)->io_Data
)) = (GPBase
->gp_cTypes
)[gpUn
->gpu_unitNum
];
338 ReleaseSemaphore(&GPBase
->gp_Lock
);
342 if (ioStd(ioreq
)->io_Length
!= sizeof(UBYTE
))
344 ioreq
->io_Error
= IOERR_BADLENGTH
;
348 ObtainSemaphore(&GPBase
->gp_Lock
);
349 (GPBase
->gp_cTypes
)[gpUn
->gpu_unitNum
] = *((UBYTE
*)(ioStd(ioreq
)->io_Data
));
350 ReleaseSemaphore(&GPBase
->gp_Lock
);
354 if (ioStd(ioreq
)->io_Length
!= sizeof(struct GamePortTrigger
))
356 ioreq
->io_Error
= IOERR_BADLENGTH
;
360 *((struct GamePortTrigger
*)(ioStd(ioreq
)->io_Data
)) = gpUn
->gpu_trigger
;
364 if (ioStd(ioreq
)->io_Length
!= sizeof(struct GamePortTrigger
))
366 ioreq
->io_Error
= IOERR_BADLENGTH
;
370 gpUn
->gpu_trigger
= *((struct GamePortTrigger
*)(ioStd(ioreq
)->io_Data
));
375 if(((IPTR
)(&(ioStd(ioreq
)->io_Data
)) & (__AROS_STRUCTURE_ALIGNMENT
- 1)) != 0)
377 D(bug("gpd: Bad address\n"));
378 ioreq
->io_Error
= IOERR_BADADDRESS
;
383 D(bug("gpd: Readpos: %d, Writepos: %d\n", gpUn
->gpu_readPos
,
384 GPBase
->gp_writePos
));
386 /* We queue the request if there are no events in the queue or if
387 the unit didn't trig on the events thate were in the queue. */
391 if (gpUn
->gpu_readPos
== GPBase
->gp_writePos
)
393 request_queued
= TRUE
;
399 fillrequest(ioreq
, &trigged
, GPBase
);
403 request_queued
= TRUE
;
409 ioreq
->io_Flags
&= ~IOF_QUICK
;
411 D(bug("gpd: No mouse events, putting request in queue\n"));
413 gpUn
->gpu_flags
|= GBUF_PENDING
;
414 AddTail((struct List
*)&GPBase
->gp_PendingQueue
,
415 (struct Node
*)ioreq
);
423 ioreq
->io_Error
= IOERR_NOCMD
;
426 } /* switch (ioreq->io_Command) */
428 /* If the quick bit is not set, send the message to the port */
429 if (!(ioreq
->io_Flags
& IOF_QUICK
) && !request_queued
)
431 ReplyMsg(&ioreq
->io_Message
);
437 /******************************************************************************/
440 AROS_LH1(LONG
, abortio
,
441 AROS_LHA(struct IORequest
*, ioreq
, A1
),
442 struct GameportBase
*, GPBase
, 6, Gameport
)
450 if (gpUn
->gpu_flags
& GBUF_PENDING
)
452 if (ioreq
->io_Message
.mn_Node
.ln_Type
== NT_MESSAGE
)
454 Remove((struct Node
*)ioreq
);
455 ReplyMsg(&ioreq
->io_Message
);
457 ioreq
->io_Error
= IOERR_ABORTED
;
459 if (IsListEmpty(&GPBase
->gp_PendingQueue
))
461 gpUn
->gpu_flags
&= ~GBUF_PENDING
;
475 /****************************************************************************************/
477 static VOID
mouseCallback(struct GameportBase
*GPBase
,
478 struct pHidd_Mouse_ExtEvent
*ev
)
482 D(bug("mouseCallBack(GPBase=%p, button=%d, x=%d, y=%d, type=%d, flags=0x%04X)\n",
483 GPBase
, ev
->button
, ev
->x
, ev
->y
, ev
->type
, ev
->flags
));
485 /* Convert the event */
488 case vHidd_Mouse_Button1
:
489 amigacode
= IECODE_LBUTTON
;
492 case vHidd_Mouse_Button2
:
493 amigacode
= IECODE_RBUTTON
;
496 case vHidd_Mouse_Button3
:
497 amigacode
= IECODE_MBUTTON
;
503 case vHidd_Mouse_Release
:
504 amigacode
|= IECODE_UP_PREFIX
;
507 case vHidd_Mouse_Motion
:
508 amigacode
= IECODE_NOBUTTON
;
511 case vHidd_Mouse_WheelMotion
:
512 amigacode
= IECODE_DUMMY_WHEEL
;
518 GPBase
->gp_eventBuffer
[GPBase
->gp_writePos
++] = amigacode
;
519 GPBase
->gp_eventBuffer
[GPBase
->gp_writePos
++] = ev
->x
;
520 GPBase
->gp_eventBuffer
[GPBase
->gp_writePos
++] = ev
->y
;
521 GPBase
->gp_eventBuffer
[GPBase
->gp_writePos
++] = ev
->flags
;
523 D(bug("Wrote to buffer\n"));
525 if (GPBase
->gp_writePos
== GP_NUMELEMENTS
)
527 GPBase
->gp_writePos
= 0;
531 if (!IsListEmpty(&GPBase
->gp_PendingQueue
))
534 D(bug("doing software irq, node type=%d\n", GPBase
->gp_Interrupt
.is_Node
.ln_Type
));
535 Cause(&GPBase
->gp_Interrupt
);
537 AROS_INTC1(gpSendQueuedEvents
, GPBase
);
544 /****************************************************************************************/
546 /* nlorentz: Software interrupt to be called when keys are received
547 Copied and pasted from the function above */
551 static AROS_INTH1(gpSendQueuedEvents
, struct GameportBase
*, GPBase
)
556 struct IORequest
*ioreq
, *nextnode
;
557 struct List
*pendingList
;
559 pendingList
= (struct List
*)&GPBase
->gp_PendingQueue
;
561 D(bug("Inside software irq\n"));
563 ForeachNodeSafe(pendingList
, ioreq
, nextnode
)
565 BOOL moreevents
, trigged
;
567 D(bug("Replying msg\n"));
568 moreevents
= fillrequest(ioreq
, &trigged
, GPBase
);
572 Remove((struct Node
*)ioreq
);
573 ReplyMsg((struct Message
*)&ioreq
->io_Message
);
582 if (IsListEmpty(pendingList
))
584 gpUn
->gpu_flags
&= ~GBUF_PENDING
;
592 /****************************************************************************************/
594 /* When this function is called, there *must* be at least one event ready for
595 processing. It returns TRUE as long as there are more events to preocess */
597 static BOOL
fillrequest(struct IORequest
*ioreq
, BOOL
*trigged
,
598 struct GameportBase
*GPBase
)
600 BOOL moreevents
= TRUE
;
601 BOOL down
, up
, wheel
;
602 int i
; /* Loop variable */
603 int nEvents
; /* Number of struct InputEvent that there
604 is room for in memory pointed to by
606 struct InputEvent
*event
; /* Temporary variable */
610 nEvents
= NUM_INPUTEVENTS(ioStd(ioreq
)->io_Length
);
614 ioreq
->io_Error
= IOERR_BADLENGTH
;
615 D(bug("gpd: Bad length\n"));
620 event
= (struct InputEvent
*)(ioStd(ioreq
)->io_Data
);
624 for (i
= 0; i
< nEvents
; ) /* no i++ here, this is done if event is to report */
631 code
= GPBase
->gp_eventBuffer
[gpUn
->gpu_readPos
++];
632 x
= GPBase
->gp_eventBuffer
[gpUn
->gpu_readPos
++];
633 y
= GPBase
->gp_eventBuffer
[gpUn
->gpu_readPos
++];
634 flags
= GPBase
->gp_eventBuffer
[gpUn
->gpu_readPos
++];
636 down
= up
= wheel
= FALSE
; /* Reset states */
638 /* Take care of the qualifiers */
642 gpUn
->gpu_Qualifiers
|= IEQUALIFIER_LEFTBUTTON
;
646 case IECODE_LBUTTON
| IECODE_UP_PREFIX
:
647 gpUn
->gpu_Qualifiers
&= ~IEQUALIFIER_LEFTBUTTON
;
652 gpUn
->gpu_Qualifiers
|= IEQUALIFIER_MIDBUTTON
;
656 case IECODE_MBUTTON
| IECODE_UP_PREFIX
:
657 gpUn
->gpu_Qualifiers
&= ~IEQUALIFIER_MIDBUTTON
;
662 gpUn
->gpu_Qualifiers
|= IEQUALIFIER_RBUTTON
;
666 case IECODE_RBUTTON
| IECODE_UP_PREFIX
:
667 gpUn
->gpu_Qualifiers
&= ~IEQUALIFIER_RBUTTON
;
671 case IECODE_DUMMY_WHEEL
:
675 code
= RAWKEY_NM_WHEEL_UP
;
679 code
= RAWKEY_NM_WHEEL_DOWN
;
683 code
= RAWKEY_NM_WHEEL_LEFT
;
687 code
= RAWKEY_NM_WHEEL_RIGHT
;
697 if (gpUn
->gpu_readPos
== GP_NUMELEMENTS
)
699 gpUn
->gpu_readPos
= 0;
702 D(bug("gpd: Adding event of code %d\n", code
));
706 #warning This needs to be fixed. And needs different handling, depending on whether coords are relative (x86-native) or not (x86-linux)!!!!
709 /* Should we report this event? */
710 if((down
&& (gpUn
->gpu_trigger
.gpt_Keys
& GPTF_DOWNKEYS
)) ||
711 (up
&& (gpUn
->gpu_trigger
.gpt_Keys
& GPTF_UPKEYS
)) ||
712 (ABS(gpUn
->gpu_lastX
- x
) > gpUn
->gpu_trigger
.gpt_XDelta
) ||
713 (ABS(gpUn
->gpu_lastY
- y
) > gpUn
->gpu_trigger
.gpt_YDelta
) ||
714 (GPBase
->gp_nTicks
> gpUn
->gpu_trigger
.gpt_Timeout
) ||
717 (void)(wheel
); /* This is unused */
718 (void)(down
); /* This is unused */
724 if (*trigged
== TRUE
)
726 event
= event
->ie_NextEvent
;
733 event
->ie_Class
= (wheel
? IECLASS_NEWMOUSE
: IECLASS_RAWMOUSE
);
734 event
->ie_SubClass
= 0; /* Only port 0 for now */
735 event
->ie_Code
= code
;
736 event
->ie_Qualifier
= gpUn
->gpu_Qualifiers
;
737 if (flags
& vHidd_Mouse_Relative
) event
->ie_Qualifier
|= IEQUALIFIER_RELATIVEMOUSE
;
745 event
->ie_TimeStamp
.tv_secs
= GPBase
->gp_nTicks
;
746 event
->ie_TimeStamp
.tv_micro
= 0;
748 /* Reset frame delta counter */
749 GPBase
->gp_nTicks
= 0;
752 event
->ie_NextEvent
= NEXT_INPUTEVENT(event
);
755 /* No more keys in buffer? */
756 if (gpUn
->gpu_readPos
== GPBase
->gp_writePos
)
763 event
->ie_NextEvent
= NULL
;
768 /****************************************************************************************/
770 static const char end
= 0;
772 /****************************************************************************************/