revert between 56095 -> 55830 in arch
[AROS.git] / arch / m68k-amiga / timer / beginio.c
blobaeb775546fb0fc58f072d08a79722b2b4250ffb5
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: BeginIO - Start up a timer.device request.
6 Lang: english
7 */
9 #include <exec/errors.h>
10 #include <exec/initializers.h>
11 #include <devices/timer.h>
12 #include <proto/exec.h>
13 #include <proto/timer.h>
14 #include <devices/newstyle.h>
16 #include <timer_intern.h>
18 #define DEBUG 0
19 #include <aros/debug.h>
21 static void timer_addToWaitList(struct TimerBase *TimerBase, UWORD unit, struct timerequest *tr);
23 #define NEWSTYLE_DEVICE 1
25 #define ioStd(x) ((struct IOStdReq *)x)
27 #if NEWSTYLE_DEVICE
29 static const UWORD SupportedCommands[] =
31 TR_GETSYSTIME,
32 TR_SETSYSTIME,
33 TR_ADDREQUEST,
34 NSCMD_DEVICEQUERY,
38 #endif
41 AROS_LH1(void, BeginIO,
42 AROS_LHA(struct timerequest *, timereq, A1),
43 struct TimerBase *, TimerBase, 5, Timer)
46 AROS_LIBFUNC_INIT
48 ULONG unitNum;
49 BOOL replyit = FALSE;
51 timereq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
52 timereq->tr_node.io_Error = 0;
54 unitNum = (ULONG)timereq->tr_node.io_Unit;
56 D(bug("timer: %d %d %x %d/%d task: '%s'\n", unitNum, timereq->tr_node.io_Command,
57 timereq, timereq->tr_time.tv_secs, timereq->tr_time.tv_micro, FindTask(0)->tc_Node.ln_Name));
59 switch(timereq->tr_node.io_Command)
61 #if NEWSTYLE_DEVICE
62 case NSCMD_DEVICEQUERY:
63 if (timereq->tr_node.io_Message.mn_Length < sizeof(struct IOStdReq))
65 timereq->tr_node.io_Error = IOERR_BADLENGTH;
67 else if(ioStd(timereq)->io_Length < ((LONG)OFFSET(NSDeviceQueryResult, SupportedCommands)) + sizeof(UWORD *))
69 timereq->tr_node.io_Error = IOERR_BADLENGTH;
71 else
73 struct NSDeviceQueryResult *d;
75 d = (struct NSDeviceQueryResult *)ioStd(timereq)->io_Data;
77 d->DevQueryFormat = 0;
78 d->SizeAvailable = sizeof(struct NSDeviceQueryResult);
79 d->DeviceType = NSDEVTYPE_TIMER;
80 d->DeviceSubType = 0;
81 d->SupportedCommands = (UWORD *)SupportedCommands;
83 ioStd(timereq)->io_Actual = sizeof(struct NSDeviceQueryResult);
85 break;
86 #endif
88 case TR_GETSYSTIME:
89 GetSysTime(&timereq->tr_time);
90 if(!(timereq->tr_node.io_Flags & IOF_QUICK)) {
91 ReplyMsg((struct Message *)timereq);
93 replyit = FALSE; /* Because replyit will clear the timeval */
94 break;
96 case TR_SETSYSTIME:
97 Disable();
98 TimerBase->tb_CurrentTime.tv_secs = timereq->tr_time.tv_secs;
99 TimerBase->tb_CurrentTime.tv_micro = timereq->tr_time.tv_micro;
100 Enable();
101 replyit = TRUE;
102 break;
104 case TR_ADDREQUEST:
105 switch(unitNum)
107 case UNIT_WAITUNTIL:
109 convertunits(TimerBase, &timereq->tr_time, UNIT_VBLANK);
110 /* Firstly, check to see if request is for past */
111 Disable();
112 if(!cmp64(&TimerBase->tb_vb_count, &timereq->tr_time)) {
113 Enable();
114 timereq->tr_time.tv_secs = timereq->tr_time.tv_micro = 0;
115 timereq->tr_node.io_Error = 0;
116 replyit = TRUE;
117 } else {
118 timer_addToWaitList(TimerBase, UNIT_VBLANK, timereq);
119 Enable();
120 replyit = FALSE;
121 timereq->tr_node.io_Flags &= ~IOF_QUICK;
123 break;
125 case UNIT_MICROHZ:
126 convertunits(TimerBase, &timereq->tr_time, UNIT_MICROHZ);
127 Disable();
128 addmicro(TimerBase, &timereq->tr_time);
129 timer_addToWaitList(TimerBase, UNIT_MICROHZ, timereq);
130 Enable();
131 timereq->tr_node.io_Flags &= ~IOF_QUICK;
132 replyit = FALSE;
133 break;
134 case UNIT_VBLANK:
135 convertunits(TimerBase, &timereq->tr_time, UNIT_VBLANK);
136 add64(&timereq->tr_time, &TimerBase->tb_vb_count);
137 Disable();
138 timer_addToWaitList(TimerBase, UNIT_VBLANK, timereq);
139 Enable();
140 timereq->tr_node.io_Flags &= ~IOF_QUICK;
141 replyit = FALSE;
142 break;
143 case UNIT_ECLOCK:
144 Disable();
145 addmicro(TimerBase, &timereq->tr_time);
146 timer_addToWaitList(TimerBase, UNIT_MICROHZ, timereq);
147 Enable();
148 timereq->tr_node.io_Flags &= ~IOF_QUICK;
149 replyit = FALSE;
150 break;
151 case UNIT_WAITECLOCK:
152 Disable();
153 timer_addToWaitList(TimerBase, UNIT_MICROHZ, timereq);
154 Enable();
155 timereq->tr_node.io_Flags &= ~IOF_QUICK;
156 replyit = FALSE;
157 break;
158 default:
159 replyit = TRUE;
160 timereq->tr_node.io_Error = IOERR_NOCMD;
161 break;
162 } /* switch(unitNum) */
163 break;
165 case CMD_CLEAR:
166 case CMD_FLUSH:
167 case CMD_INVALID:
168 case CMD_READ:
169 case CMD_RESET:
170 case CMD_START:
171 case CMD_STOP:
172 case CMD_UPDATE:
173 case CMD_WRITE:
174 default:
175 replyit = TRUE;
176 timereq->tr_node.io_Error = IOERR_NOCMD;
177 break;
178 } /* switch(command) */
180 if(replyit)
182 timereq->tr_time.tv_secs = 0;
183 timereq->tr_time.tv_micro = 0;
184 if(!(timereq->tr_node.io_Flags & IOF_QUICK))
186 ReplyMsg((struct Message *)timereq);
190 AROS_LIBFUNC_EXIT
191 } /* BeginIO */
194 static void timer_addToWaitList(struct TimerBase *TimerBase, UWORD unit, struct timerequest *iotr)
196 /* We are disabled, so we should take as little time as possible. */
197 struct timerequest *tr;
198 BOOL added = FALSE, first = TRUE;
199 struct MinList *list = &TimerBase->tb_Lists[unit];
201 if (unit == UNIT_VBLANK) {
202 // always wait at least 1 full vblank
203 if (equ64(&iotr->tr_time, &TimerBase->tb_vb_count))
204 inc64(&iotr->tr_time);
205 inc64(&iotr->tr_time);
208 ForeachNode(list, tr) {
209 /* If the time in the new request is less than the next request */
210 if(CmpTime(&tr->tr_time, &iotr->tr_time) < 0) {
211 /* Add the node before the next request */
212 Insert((struct List *)list, (struct Node *)iotr, tr->tr_node.io_Message.mn_Node.ln_Pred);
213 added = TRUE;
214 break;
216 first = FALSE;
220 This will catch the case of either an empty list, or request is
221 for after all other requests
224 if(!added)
225 AddTail((struct List *)list, (struct Node *)iotr);
227 /* recalculate timers, list was empty or was added to head of list */
228 if (!added || first)
229 CheckTimer(TimerBase, unit);
231 D(bug("added %x: %d/%d->%d/%d\n", iotr,
232 (unit == UNIT_VBLANK ? TimerBase->tb_vb_count.tv_secs : TimerBase->tb_micro_count.tv_secs),
233 (unit == UNIT_VBLANK ? TimerBase->tb_vb_count.tv_usec : TimerBase->tb_micro_count.tv_usec),
234 iotr->tr_time.tv_secs, iotr->tr_time.tv_micro));