2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Commodities input handler
11 * Currently, there is no protection against stupid users. If you, for
12 instance, install a broker and attach a custom object to it, and this
13 custom object's function is to Route the messages to the broker, there
14 will be a deadlock, as the message list will never get empty.
15 I have no GOOD solution for this, and therefore nothing to prevent
16 this type of deadlock is implemented. One way could be to have a counter
17 (in every message) that says how many times a message has been routed
18 and if this counter reaches MAGICAL_VALUE the message is Disposed of.
19 The above should then perhaps be accompanied by a new COMMAND,
20 CXCMD_CYCLE that tells (at least Exchange) that something isn't quite
23 * CX_TYPEFILTER isn't documented anywhere (and it's obsolete) meaning
24 that the action done in case of a typefilter is not known to be the
30 ??.08.97 SDuvan Implemented
31 16.08.99 Working version
34 /***************************************************************************/
37 #include <proto/exec.h>
38 #include <proto/commodities.h>
39 #include <exec/lists.h>
40 #include <exec/memory.h>
41 #include <aros/asmcall.h>
45 #define DEBUG_CXTREE(x) ;//if ((msg->cxm_Data->ie_Class == IECLASS_RAWMOUSE) && (msg->cxm_Data->ie_Code != 255)) { x; }
46 #define DEBUG_TRANSFUNC(x) ;
47 #define DEBUG_SENDFUNC(x) ;
48 #define DEBUG_COPYIEVENT(x) x;
52 #include <aros/debug.h>
54 static void ProduceEvent(CxMsg
*, struct CommoditiesBase
*CxBase
);
55 static void DebugFunc(CxMsg
*, CxObj
*, struct CommoditiesBase
*CxBase
);
56 static void TransFunc(CxMsg
*, CxObj
*, struct CommoditiesBase
*CxBase
);
57 static void SendFunc(CxMsg
*, CxObj
*, struct CommoditiesBase
*CxBase
);
58 BOOL
CopyInputEvent(struct InputEvent
*from
, struct InputEvent
*to
, struct CommoditiesBase
*CxBase
);
61 extern void cx_Thunk(void);
65 "movem.l %a0-%a1,%sp@-\n"
72 AROS_UFH2(struct InputEvent
*, CxTree
,
73 AROS_UFHA(struct InputEvent
* , events
, A0
),
74 AROS_UFHA(struct CommoditiesBase
*, CxBase
, A6
))
80 struct Node
*node
, *succ
;
87 ObtainSemaphore(&CxBase
->cx_SignalSemaphore
);
89 if (IsListEmpty(&CxBase
->cx_BrokerList
))
91 ReleaseSemaphore(&CxBase
->cx_SignalSemaphore
);
96 /* Take care of the processed input events */
97 ForeachNodeSafe(&CxBase
->cx_GeneratedInputEvents
, node
, succ
)
99 struct GeneratedInputEvent
*tempEvent
;
101 tempEvent
= (struct GeneratedInputEvent
*)(((UBYTE
*)node
) - offsetof(struct GeneratedInputEvent
, node
));
102 FreeCxStructure(tempEvent
, CX_INPUTEVENT
, (struct Library
*)CxBase
);
105 CxBase
->cx_IEvents
= NULL
;
106 CxBase
->cx_EventExtra
= &CxBase
->cx_IEvents
;
107 NEWLIST(&CxBase
->cx_GeneratedInputEvents
);
109 /* Free all the replied messages */
110 while ((tempMsg
= (CxMsg
*)GetMsg(&CxBase
->cx_MsgPort
)) != NULL
)
112 FreeCxStructure(tempMsg
, CX_MESSAGE
, (struct Library
*)CxBase
);
119 kprintf("List of brokers:\n");
121 ForeachNode(&CxBase
->cx_BrokerList
, node
)
123 if (CXOBJType(node
) == CX_BROKER
)
125 kprintf("B: %s\n", node
->co_Ext
.co_BExt
->bext_Name
);
129 kprintf("Something else\n");
135 /* Route all messages to the first broker */
137 co
= (CxObj
*)GetHead(&CxBase
->cx_BrokerList
);
140 kprintf("Initial broker: %s\n", co
->co_Ext
.co_BExt
->bext_Name
);
143 ForeachNode(&CxBase
->cx_MessageList
, tempMsg
)
145 ROUTECxMsg(tempMsg
, co
);
148 AddIEvents(events
); /* Add the new events (incapsulated in commodtity
149 messages) to the message list. */
151 /***************************************************************************/
153 /* Process the new events */
155 while ((msg
= (CxMsg
*)GetHead(&CxBase
->cx_MessageList
)) != NULL
)
157 co
= msg
->cxm_Routing
;
159 DEBUG_CXTREE(dprintf("CxTree: Msg %p Object %p\n", msg
, co
));
161 while (co
== NULL
&& msg
->cxm_Level
!= 0)
163 // kprintf("Next level %i\n", msg->cxm_Level - 1);
166 co
= msg
->cxm_retObj
[msg
->cxm_Level
];
167 co
= (CxObj
*)GetSucc(&co
->co_Node
);
169 // kprintf("Found return object %p\n", co);
171 // if (CXOBJType(co) == CX_BROKER)
173 // kprintf("Returnobj (broker) = %s\n",
174 // co->co_Ext.co_BExt->bext_Name);
178 /* If there are no more objects that shall process the event, we
179 link it in to the list of ready input events */
183 ProduceEvent(msg
, CxBase
);
190 if(CXOBJType(co
) == CX_BROKER
)
191 kprintf("Broker: %s\n", co
->co_Ext
.co_BExt
->bext_Name
);
193 if(co
->co_Node
.ln_Succ
!= NULL
&&
194 co
->co_Node
.ln_Succ
->ln_Type
== CX_BROKER
)
195 kprintf("Routing to next broker %s (this broker=%s) %p\n",
196 ((CxObj
*)(co
->co_Node
.ln_Succ
))->co_Ext
.co_BExt
->bext_Name
,
197 co
->co_Ext
.co_BExt
->bext_Name
,
202 /* Route the message to the next object */
204 ROUTECxMsg(msg
, (CxObj
*)GetSucc(&co
->co_Node
));
206 if (!(co
->co_Flags
& COF_ACTIVE
))
211 DEBUG_CXTREE(dprintf("CxTree: Object %p Type %d\n", co
, CXOBJType(co
)));
213 switch (CXOBJType(co
))
216 DEBUG_CXTREE(dprintf("CxTree: CX_INVALID\n"));
220 DEBUG_CXTREE(dprintf("CxTree: CX_FILTER\n"));
222 DEBUG_CXTREE(dprintf("CxTree: Filter 0x%lx\n",
225 if ((co
->co_Error
& COERR_BADFILTER
))
227 DEBUG_CXTREE(dprintf("CxTree: bad filter!\n"));
231 if (msg
->cxm_Type
== CXM_IEVENT
)
233 DEBUG_CXTREE(dprintf("CxTree: Data 0x%lx FilterIX 0x%lx\n",
235 co
->co_Ext
.co_FilterIX
));
236 if (MatchIX(msg
->cxm_Data
, co
->co_Ext
.co_FilterIX
) != 0)
238 DEBUG_CXTREE(dprintf("CxTree: filter matched\n"));
239 DivertCxMsg(msg
, co
, co
);
243 DEBUG_CXTREE(dprintf("CxTree: filter not matched\n"));
248 DEBUG_CXTREE(dprintf("CxTree: no CXM_EVENT\n"));
253 DEBUG_CXTREE(dprintf("CxTree: CX_TYPEFILTER\n"));
254 if ((msg
->cxm_Type
& co
->co_Ext
.co_TypeFilter
) != 0)
256 DEBUG_CXTREE(dprintf("CxTree: hit\n"));
257 DivertCxMsg(msg
, co
, co
);
262 DEBUG_CXTREE(dprintf("CxTree: CX_SEND\n"));
263 SendFunc(msg
, co
, CxBase
);
267 DEBUG_CXTREE(dprintf("CxTree: CX_SIGNAL Task 0x%lx <%s>\n",
268 co
->co_Ext
.co_SignalExt
->sixt_Task
,
269 co
->co_Ext
.co_SignalExt
->sixt_Task
->tc_Node
.ln_Name
));
270 Signal(co
->co_Ext
.co_SignalExt
->sixt_Task
,
271 1 << co
->co_Ext
.co_SignalExt
->sixt_SigBit
);
275 DEBUG_CXTREE(dprintf("CxTree: CX_TRANSLATE\n"));
276 TransFunc(msg
, co
, CxBase
);
280 DEBUG_CXTREE(dprintf("CxTree: CX_BROKER\n"));
281 DivertCxMsg(msg
, co
, co
);
285 DEBUG_CXTREE(dprintf("CxTree: CX_DEBUG\n"));
286 DebugFunc(msg
, co
, CxBase
);
290 DEBUG_CXTREE(dprintf("CxTree: CX_CUSTOM\n"));
291 msg
->cxm_ID
= co
->co_Ext
.co_CustomExt
->cext_ID
;
293 DEBUG_CXTREE(dprintf("CxTree: Action 0x%lx\n",
294 co
->co_Ext
.co_CustomExt
->cext_Action
));
295 /* Action shouldn't be NULL, but well, sometimes it is...
297 if (co
->co_Ext
.co_CustomExt
->cext_Action
)
300 /* The autodocs suggest the arguments should be passed on the stack.
301 * But they were also in a0/a1 and some things seem to rely on that.
302 * Let's also pass CxBase in a6 just in case.
304 * All other architectures (should) be using the stack.
306 AROS_UFC4NR(void, cx_Thunk
,
307 AROS_UFCA(CxMsg
*, msg
, A0
),
308 AROS_UFCA(CxObj
*, co
, A1
),
309 AROS_UFCA(APTR
, co
->co_Ext
.co_CustomExt
->cext_Action
, A2
),
310 AROS_UFCA(struct CommoditiesBase
*, CxBase
, A6
));
314 *(CxMsg
**)REG_A7
= msg
;
315 *(CxObj
**)(REG_A7
+ 4) = co
;
317 AROS_UFC3(void, co
->co_Ext
.co_CustomExt
->cext_Action
,
318 AROS_UFCA(CxMsg
*, msg
, A0
),
319 AROS_UFCA(CxObj
*, co
, A1
),
320 AROS_UFCA(struct CommoditiesBase
*, CxBase
, A6
));
329 DEBUG_CXTREE(dprintf("CxTree: CX_ZERO\n"));
330 ProduceEvent(msg
, CxBase
);
334 DEBUG_CXTREE(dprintf("CxTree: done\n"));
337 ReleaseSemaphore(&CxBase
->cx_SignalSemaphore
);
339 return CxBase
->cx_IEvents
;
345 static void ProduceEvent(CxMsg
*msg
, struct CommoditiesBase
*CxBase
)
347 struct GeneratedInputEvent
*temp
;
349 if ((temp
= (struct GeneratedInputEvent
*)AllocCxStructure(CX_INPUTEVENT
, 0,
350 (struct Library
*)CxBase
)) != NULL
)
352 if (!CopyInputEvent(msg
->cxm_Data
, &temp
->ie
, CxBase
))
354 DEBUG_COPYIEVENT(dprintf("ProduceEvent: CopyInputEvent() failed!\n"));
357 /* Put the input event last in the ready list and update bookkeeping */
358 temp
->ie
.ie_NextEvent
= NULL
;
360 *(CxBase
->cx_EventExtra
) = &temp
->ie
;
361 CxBase
->cx_EventExtra
= &temp
->ie
.ie_NextEvent
;
363 AddTail((struct List
*)&CxBase
->cx_GeneratedInputEvents
,
364 (struct Node
*)&temp
->node
);
371 static void SendFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
374 struct InputEvent
*saveIE
; /* To save the InputEvent pointer
375 from being destroyed by CopyMem() */
377 DEBUG_SENDFUNC(dprintf("SendFunc: msg %p co %p MsgPort %p ID 0x%lx\n",
378 msg
, co
, co
->co_Ext
.co_SendExt
->sext_MsgPort
, co
->co_Ext
.co_SendExt
->sext_ID
));
380 if (co
->co_Ext
.co_SendExt
->sext_MsgPort
== NULL
)
385 tempMsg
= (CxMsg
*)AllocCxStructure(CX_MESSAGE
, CXM_DOUBLE
,
386 (struct Library
*)CxBase
);
390 DEBUG_SENDFUNC(dprintf("SendFunc: failed!\n"));
394 saveIE
= tempMsg
->cxm_Data
;
395 CopyMem(msg
, tempMsg
, sizeof(CxMsg
));
396 tempMsg
->cxm_Data
= saveIE
;
398 if (!CopyInputEvent(msg
->cxm_Data
, tempMsg
->cxm_Data
, CxBase
))
400 DEBUG_COPYIEVENT(dprintf("SendFunc: CopyInputEvent() failed!\n"));
403 tempMsg
->cxm_ID
= co
->co_Ext
.co_SendExt
->sext_ID
;
405 PutMsg(co
->co_Ext
.co_SendExt
->sext_MsgPort
, (struct Message
*)tempMsg
);
409 static void TransFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
411 struct InputEvent
*event
;
414 DEBUG_TRANSFUNC(dprintf("TransFunc: msg %p co %p ie %p\n",
415 msg
, co
, co
->co_Ext
.co_IE
));
417 if (co
->co_Ext
.co_IE
!= NULL
)
419 event
= co
->co_Ext
.co_IE
;
423 struct InputEvent
*saveIE
; /* To save the InputEvent pointer
424 from being destroyed by CopyMem() */
426 DEBUG_TRANSFUNC(dprintf("TransFunc: Generate class %d code 0x%x\n",
427 event
->ie_Class
, event
->ie_Code
));
429 if ((msg2
= (CxMsg
*)AllocCxStructure(CX_MESSAGE
, CXM_DOUBLE
,
430 (struct Library
*)CxBase
)) == NULL
)
432 DEBUG_TRANSFUNC(dprintf("TransFunc: failed!\n"));
436 saveIE
= msg2
->cxm_Data
;
437 CopyMem(msg
, msg2
, sizeof(CxMsg
));
438 msg2
->cxm_Data
= saveIE
;
440 /* Don't care about errors for now */
441 if (!CopyInputEvent(event
, msg2
->cxm_Data
, CxBase
))
443 DEBUG_COPYIEVENT(dprintf("TransFunc: CopyInputEvent() failed!\n"));
446 AddHead(&CxBase
->cx_MessageList
, (struct Node
*)msg2
);
448 } while ((event
= event
->ie_NextEvent
) != NULL
);
455 static void DebugFunc(CxMsg
*msg
, CxObj
*co
, struct CommoditiesBase
*CxBase
)
457 kprintf("\n----\nDEBUG NODE: %lx, ID: %lx\n"
458 "\tCxMsg: %lx, type: %x, data %lx destination %lx\n",
459 co
, co
->co_Ext
.co_DebugID
, msg
->cxm_Routing
, msg
->cxm_Data
,
462 if (msg
->cxm_Type
!= CXM_IEVENT
)
467 kprintf("dump IE: %lx\n"
471 "\nEventAddress %lx",
472 msg
->cxm_Data
, msg
->cxm_Data
->ie_Class
, msg
->cxm_Data
->ie_Code
,
473 msg
->cxm_Data
->ie_Qualifier
, msg
->cxm_Data
->ie_EventAddress
);
477 BOOL
CopyInputEvent(struct InputEvent
*from
, struct InputEvent
*to
,
478 struct CommoditiesBase
*CxBase
)
480 memmove(to
, from
, sizeof(struct InputEvent
));
482 if (from
->ie_Class
== IECLASS_NEWPOINTERPOS
)
484 switch (from
->ie_SubClass
)
486 case IESUBCLASS_PIXEL
:
487 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IEPointerPixel
),
493 memmove(to
->ie_EventAddress
, from
->ie_EventAddress
, sizeof(struct IEPointerPixel
));
496 case IESUBCLASS_TABLET
:
497 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IEPointerTablet
),
503 memmove(to
->ie_EventAddress
, from
->ie_EventAddress
, sizeof(struct IEPointerTablet
));
506 case IESUBCLASS_NEWTABLET
:
507 if ((to
->ie_EventAddress
= AllocVec(sizeof(struct IENewTablet
),
513 memmove(to
->ie_EventAddress
, from
->ie_EventAddress
, sizeof(struct IENewTablet
));
525 AROS_UFH2(struct InputEvent
*, cxIHandler
,
526 AROS_UFHA(struct InputEvent
* , events
, A0
),
527 AROS_UFHA(struct CommoditiesBase
*, CxBase
, A1
))
531 return AROS_UFC2(struct InputEvent
*, AROS_ASMSYMNAME(CxTree
),
532 AROS_UFCA(struct InputEvent
* , events
, A0
),
533 AROS_UFCA(struct CommoditiesBase
*, CxBase
, A6
));