define __KERNEL_STRICT_NAMES to avoid inclusion of kernel types on systems that carry...
[cake.git] / rom / timer / beginio.c
blob559a4e24b99b8ab2d80fc6685089f85473d89d06
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: BeginIO - Start up a timer.device request.
6 Lang: english
7 */
9 #include "timer_intern.h"
10 #include <devices/newstyle.h>
11 #include <exec/errors.h>
12 #include <exec/initializers.h>
13 #include <proto/exec.h>
14 #include <aros/debug.h>
16 /****************************************************************************************/
18 #define NEWSTYLE_DEVICE 1
20 #define ioStd(x) ((struct IOStdReq *)x)
22 /****************************************************************************************/
24 #if NEWSTYLE_DEVICE
26 static const UWORD SupportedCommands[] =
28 TR_GETSYSTIME,
29 TR_SETSYSTIME,
30 TR_ADDREQUEST,
31 NSCMD_DEVICEQUERY,
35 #endif
37 /****************************************************************************************/
39 static void addToWaitList(struct TimerBase *, struct MinList *, struct timerequest *);
41 /*****i***********************************************************************
43 NAME */
44 #include <devices/timer.h>
45 #include <proto/timer.h>
46 AROS_LH1(void, BeginIO,
48 /* SYNOPSIS */
49 AROS_LHA(struct timerequest *, timereq, A1),
51 /* LOCATION */
52 struct TimerBase *, TimerBase, 5, Timer)
54 /* FUNCTION
55 BeginIO() will perform a timer.device command. It is normally
56 called from within DoIO() and SendIO().
58 INPUT
59 timereq - The request to process.
61 RESULT
62 The requested message will be processed.
64 NOTES
65 This function is safe to call from interrupts.
67 EXAMPLE
69 BUGS
71 SEE ALSO
72 exec.library/Abort(), exec.library/SendIO(), exec.library/DoIO()
74 INTERNALS
76 HISTORY
77 23-01-1998 iaint Implemented again.
79 ******************************************************************************/
81 AROS_LIBFUNC_INIT
83 ULONG unitNum;
84 BOOL replyit = FALSE;
86 timereq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
87 timereq->tr_node.io_Error = 0;
89 unitNum = (ULONG)timereq->tr_node.io_Unit;
91 switch(timereq->tr_node.io_Command)
93 #if NEWSTYLE_DEVICE
94 case NSCMD_DEVICEQUERY:
95 #warning In timer.device this is maybe a bit problematic, as the timerequest structure does not have io_Data and io_Length members
97 if (timereq->tr_node.io_Message.mn_Length < sizeof(struct IOStdReq))
99 timereq->tr_node.io_Error = IOERR_BADLENGTH;
101 else if(ioStd(timereq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
103 timereq->tr_node.io_Error = IOERR_BADLENGTH;
105 else
107 struct NSDeviceQueryResult *d;
109 d = (struct NSDeviceQueryResult *)ioStd(timereq)->io_Data;
111 d->DevQueryFormat = 0;
112 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
113 d->DeviceType = NSDEVTYPE_TIMER;
114 d->DeviceSubType = 0;
115 d->SupportedCommands = (UWORD *)SupportedCommands;
117 ioStd(timereq)->io_Actual = sizeof(struct NSDeviceQueryResult);
119 break;
120 #endif
122 case TR_GETSYSTIME:
123 GetSysTime(&timereq->tr_time);
125 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
127 ReplyMsg((struct Message *)timereq);
129 replyit = FALSE; /* Because replyit will clear the timeval */
130 break;
132 case TR_SETSYSTIME:
133 Disable();
134 TimerBase->tb_CurrentTime.tv_secs = timereq->tr_time.tv_secs;
135 TimerBase->tb_CurrentTime.tv_micro = timereq->tr_time.tv_micro;
136 Enable();
137 replyit = TRUE;
138 break;
140 case TR_ADDREQUEST:
141 switch(unitNum)
143 case UNIT_WAITUNTIL:
144 /* Firstly, check to see if request is for past */
145 Disable();
146 if(CmpTime(&TimerBase->tb_CurrentTime, &timereq->tr_time) <= 0)
148 Enable();
149 timereq->tr_time.tv_secs = timereq->tr_time.tv_micro = 0;
150 timereq->tr_node.io_Error = 0;
151 replyit = TRUE;
153 else
155 /* Ok, we add this to the list */
156 addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_WAITVBL], timereq);
157 Enable();
158 replyit = FALSE;
159 timereq->tr_node.io_Flags &= ~IOF_QUICK;
161 break;
163 case UNIT_VBLANK:
164 case UNIT_MICROHZ:
166 Adjust the time request to be relative to the
167 the elapsed time counter that we keep.
169 Disable();
170 AddTime(&timereq->tr_time, &TimerBase->tb_Elapsed);
172 /* Slot it into the list */
173 addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_VBLANK], timereq);
174 Enable();
175 timereq->tr_node.io_Flags &= ~IOF_QUICK;
176 replyit = FALSE;
177 break;
179 case UNIT_ECLOCK:
180 case UNIT_WAITECLOCK:
181 default:
182 replyit = FALSE;
183 timereq->tr_node.io_Error = IOERR_NOCMD;
184 break;
185 } /* switch(unitNum) */
186 break;
188 case CMD_CLEAR:
189 case CMD_FLUSH:
190 case CMD_INVALID:
191 case CMD_READ:
192 case CMD_RESET:
193 case CMD_START:
194 case CMD_STOP:
195 case CMD_UPDATE:
196 case CMD_WRITE:
197 default:
198 replyit = TRUE;
199 timereq->tr_node.io_Error = IOERR_NOCMD;
200 break;
202 } /* switch(command) */
204 if(replyit)
206 timereq->tr_time.tv_secs = 0;
207 timereq->tr_time.tv_micro = 0;
208 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
210 ReplyMsg((struct Message *)timereq);
214 AROS_LIBFUNC_EXIT
215 } /* BeginIO */
217 static void
218 addToWaitList( struct TimerBase *TimerBase,
219 struct MinList *list,
220 struct timerequest *iotr)
222 /* We are disabled, so we should take as little time as possible. */
223 struct timerequest *tr;
224 BOOL added = FALSE;
226 tr = (struct timerequest *)list->mlh_Head;
228 while(tr->tr_node.io_Message.mn_Node.ln_Succ != NULL)
230 /* If the time in the new request is less than the next request */
231 if(CmpTime(&tr->tr_time, &iotr->tr_time) < 0)
233 /* Add the node before the next request */
234 Insert(
235 (struct List *)list,
236 (struct Node *)iotr,
237 tr->tr_node.io_Message.mn_Node.ln_Pred
239 added = TRUE;
240 break;
242 tr = (struct timerequest *)tr->tr_node.io_Message.mn_Node.ln_Succ;
246 This will catch the case of either an empty list, or request is
247 for after all other requests
250 if(!added)
251 AddTail((struct List *)list, (struct Node *)iotr);
253 #if DEBUG
255 int i = 0;
256 bug("Current list contents:\n");
257 ForeachNode(list, tr)
259 bug("%ld: %ld.%ld\n", i,
260 tr->tr_time.tv_secs, tr->tr_time.tv_micro);
261 i++;
264 #endif /* DEBUG */