Restored work-around for hangs when trying to use disk-based handlers
[tangerine.git] / arch / i386-pc / timer / beginio.c
blobff38fed19c8fa30d3fae89e5e56c8188fdecb8b6
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 EClockUpdate(TimerBase);
127 GetSysTime(&timereq->tr_time);
129 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
131 ReplyMsg((struct Message *)timereq);
133 replyit = FALSE; /* Because replyit will clear the timeval */
134 break;
136 case TR_SETSYSTIME:
137 Disable();
138 TimerBase->tb_CurrentTime.tv_secs = timereq->tr_time.tv_secs;
139 TimerBase->tb_CurrentTime.tv_micro = timereq->tr_time.tv_micro;
140 EClockSet(TimerBase);
141 Enable();
142 replyit = TRUE;
143 break;
145 case TR_ADDREQUEST:
146 switch(unitNum)
148 case UNIT_WAITUNTIL:
149 /* Firstly, check to see if request is for past */
150 Disable();
151 if(CmpTime(&TimerBase->tb_CurrentTime, &timereq->tr_time) <= 0)
153 Enable();
154 timereq->tr_time.tv_secs = timereq->tr_time.tv_micro = 0;
155 timereq->tr_node.io_Error = 0;
156 replyit = TRUE;
158 else
160 /* Ok, we add this to the list */
161 if (timer_addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_WAITVBL], timereq))
163 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
164 Timer0Setup(TimerBase);
166 Enable();
167 replyit = FALSE;
168 timereq->tr_node.io_Flags &= ~IOF_QUICK;
170 break;
172 case UNIT_MICROHZ:
173 case UNIT_VBLANK:
174 Disable();
175 AddTime(&timereq->tr_time, &TimerBase->tb_Elapsed);
176 /* Slot it into the list */
177 if (timer_addToWaitList(TimerBase, &TimerBase->tb_Lists[TL_VBLANK], timereq))
179 outb((inb(0x61) & 0xfd) | 1, 0x61); /* Enable the timer (set GATE on) */
180 Timer0Setup(TimerBase);
182 Enable();
183 timereq->tr_node.io_Flags &= ~IOF_QUICK;
184 replyit = FALSE;
185 break;
187 case UNIT_ECLOCK:
188 case UNIT_WAITECLOCK:
189 default:
190 replyit = FALSE;
191 timereq->tr_node.io_Error = IOERR_NOCMD;
192 break;
193 } /* switch(unitNum) */
194 break;
196 case CMD_CLEAR:
197 case CMD_FLUSH:
198 case CMD_INVALID:
199 case CMD_READ:
200 case CMD_RESET:
201 case CMD_START:
202 case CMD_STOP:
203 case CMD_UPDATE:
204 case CMD_WRITE:
205 default:
206 replyit = TRUE;
207 timereq->tr_node.io_Error = IOERR_NOCMD;
208 break;
209 } /* switch(command) */
211 if(replyit)
213 timereq->tr_time.tv_secs = 0;
214 timereq->tr_time.tv_micro = 0;
215 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
217 ReplyMsg((struct Message *)timereq);
221 AROS_LIBFUNC_EXIT
222 } /* BeginIO */
224 BOOL
225 timer_addToWaitList(struct TimerBase *TimerBase,
226 struct MinList *list,
227 struct timerequest *iotr)
229 /* We are disabled, so we should take as little time as possible. */
230 struct timerequest *tr;
231 BOOL added = FALSE;
233 ForeachNode(list, tr)
235 /* If the time in the new request is less than the next request */
236 if(CmpTime(&tr->tr_time, &iotr->tr_time) < 0)
238 /* Add the node before the next request */
239 Insert(
240 (struct List *)list,
241 (struct Node *)iotr,
242 tr->tr_node.io_Message.mn_Node.ln_Pred
244 added = TRUE;
245 break;
250 This will catch the case of either an empty list, or request is
251 for after all other requests
254 if(!added)
255 AddTail((struct List *)list, (struct Node *)iotr);
257 /* Return TRUE if it ended up on head of list */
259 return ((struct timerequest *)list->mlh_Head == iotr) ? TRUE : FALSE;