don't update EClock here, the GetSysTime function does that already...
[AROS.git] / arch / i386-pc / timer / beginio.c
blob6586680a5096932ff52c335d46c8519745b18338
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 "ticks.h"
10 #include <devices/newstyle.h>
11 #include <exec/errors.h>
12 #include <exec/initializers.h>
13 #include <proto/exec.h>
14 #include <asm/io.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 BOOL timer_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/Abort(), exec/SendIO(), exec/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 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
87 EClockUpdate(TimerBase);
89 timereq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
90 timereq->tr_node.io_Error = 0;
92 unitNum = (ULONG)timereq->tr_node.io_Unit;
94 switch(timereq->tr_node.io_Command)
96 #if NEWSTYLE_DEVICE
97 case NSCMD_DEVICEQUERY:
98 #warning In timer.device this is maybe a bit problematic, as the timerequest structure does not have io_Data and io_Length members
100 if (timereq->tr_node.io_Message.mn_Length < sizeof(struct IOStdReq))
102 timereq->tr_node.io_Error = IOERR_BADLENGTH;
104 else if(ioStd(timereq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
106 timereq->tr_node.io_Error = IOERR_BADLENGTH;
108 else
110 struct NSDeviceQueryResult *d;
112 d = (struct NSDeviceQueryResult *)ioStd(timereq)->io_Data;
114 d->DevQueryFormat = 0;
115 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
116 d->DeviceType = NSDEVTYPE_TIMER;
117 d->DeviceSubType = 0;
118 d->SupportedCommands = (UWORD *)SupportedCommands;
120 ioStd(timereq)->io_Actual = sizeof(struct NSDeviceQueryResult);
122 break;
123 #endif
125 case TR_GETSYSTIME:
126 GetSysTime(&timereq->tr_time);
128 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
130 ReplyMsg((struct Message *)timereq);
132 replyit = FALSE; /* Because replyit will clear the timeval */
133 break;
135 case TR_SETSYSTIME:
136 Disable();
137 TimerBase->tb_CurrentTime.tv_secs = timereq->tr_time.tv_secs;
138 TimerBase->tb_CurrentTime.tv_micro = timereq->tr_time.tv_micro;
139 EClockSet(TimerBase);
140 Enable();
141 replyit = TRUE;
142 break;
144 case TR_ADDREQUEST:
145 switch(unitNum)
147 case UNIT_WAITUNTIL:
148 /* Firstly, check to see if request is for past */
149 Disable();
150 if(CmpTime(&TimerBase->tb_CurrentTime, &timereq->tr_time) <= 0)
152 Enable();
153 timereq->tr_time.tv_secs = timereq->tr_time.tv_micro = 0;
154 timereq->tr_node.io_Error = 0;
155 replyit = TRUE;
157 else
159 /* Ok, we add this to the list */
160 if (timer_addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_WAITVBL], timereq))
162 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
163 Timer0Setup(TimerBase);
165 Enable();
166 replyit = FALSE;
167 timereq->tr_node.io_Flags &= ~IOF_QUICK;
169 break;
171 case UNIT_MICROHZ:
172 case UNIT_VBLANK:
173 Disable();
174 AddTime(&timereq->tr_time, &TimerBase->tb_Elapsed);
175 /* Slot it into the list */
176 if (timer_addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_VBLANK], timereq))
178 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
179 Timer0Setup(TimerBase);
181 Enable();
182 timereq->tr_node.io_Flags &= ~IOF_QUICK;
183 replyit = FALSE;
184 break;
186 case UNIT_ECLOCK:
187 case UNIT_WAITECLOCK:
188 default:
189 replyit = FALSE;
190 timereq->tr_node.io_Error = IOERR_NOCMD;
191 break;
192 } /* switch(unitNum) */
193 break;
195 case CMD_CLEAR:
196 case CMD_FLUSH:
197 case CMD_INVALID:
198 case CMD_READ:
199 case CMD_RESET:
200 case CMD_START:
201 case CMD_STOP:
202 case CMD_UPDATE:
203 case CMD_WRITE:
204 default:
205 replyit = TRUE;
206 timereq->tr_node.io_Error = IOERR_NOCMD;
207 break;
208 } /* switch(command) */
210 if(replyit)
212 timereq->tr_time.tv_secs = 0;
213 timereq->tr_time.tv_micro = 0;
214 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
216 ReplyMsg((struct Message *)timereq);
220 AROS_LIBFUNC_EXIT
221 } /* BeginIO */
223 BOOL
224 timer_addToWaitList(struct TimerBase *TimerBase,
225 struct MinList *list,
226 struct timerequest *iotr)
228 /* We are disabled, so we should take as little time as possible. */
229 struct timerequest *tr;
230 BOOL added = FALSE;
232 ForeachNode(list, tr)
234 /* If the time in the new request is less than the next request */
235 if(CmpTime(&tr->tr_time, &iotr->tr_time) < 0)
237 /* Add the node before the next request */
238 Insert(
239 (struct List *)list,
240 (struct Node *)iotr,
241 tr->tr_node.io_Message.mn_Node.ln_Pred
243 added = TRUE;
244 break;
249 This will catch the case of either an empty list, or request is
250 for after all other requests
253 if(!added)
254 AddTail((struct List *)list, (struct Node *)iotr);
256 /* Return TRUE if it ended up on head of list */
258 return ((struct timerequest *)list->mlh_Head == iotr) ? TRUE : FALSE;