2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/synch.h>
28 #include <sys/syslog.h>
29 #include <sys/socket.h>
30 #include <sys/socketvar.h>
31 #include <sys/protosw.h> /* for protocol timeouts */
32 #include <net/if.h> /* for if timeout */
33 #include <netinet/in.h>
34 #include <net/sana2arp.h> /* for arp timeout */
36 #include <kern/amiga_includes.h>
37 #include <kern/amiga_time.h>
40 * include prototypes for timeout functions
42 #include <net/if_protos.h> /* if_slowtimo() */
43 #include <kern/uipc_domain_protos.h> /* pfslowtimo(), pffasttimo() */
46 * Global timer base pointer used throughout the code.
47 * Commodore says that same base should not be used by different task,
48 * so API users should have their own base pointer.
51 struct Library
*TimerBase
= NULL
;
53 struct Device
*TimerBase
= NULL
;
56 static struct MsgPort
*timerport
= NULL
; /* Timer message reply port */
57 static struct timerequest
*timerIORequest
= NULL
; /* template IORequest */
60 * timeoutrequest pointers for all the timeouts
62 static struct timeoutRequest
*ifTimer
= NULL
,
64 *protoSlowTimer
= NULL
,
65 *protoFastTimer
= NULL
;
67 static BOOL can_send_timeouts
= FALSE
;
70 * Initialize the timer. This MUST be called before any Timer functions are
71 * used (including get_time() and microtime() which use GetSysTime())
74 * timerIORequest is used as a template from which all needed timer
75 * IO messages are copied. The command field of the request is initialized to
76 * TR_ADDREQUEST. Requests node type is initialized to NT_UNKNOWN for us
77 * to be able to recognize if it has been used.
79 * Note that we need to check manually the version of the opened device. The
80 * version number must be at least 36 since we use the GetSysTime() function
81 * which is not defined in earlier versions.
83 * This initializes all the needed timeoutrequests too.
90 D(bug("[AROSTCP](amiga_timer.c) timer_init()\n"));
94 * Return success if already initialized
96 if (timerport
!= NULL
)
100 * allocate and initialize the timer message reply port
102 timerport
= CreateMsgPort();
103 if (timerport
!= NULL
) {
105 * allocate and initialize the template message structure
107 timerIORequest
= (struct timerequest
*)
108 CreateIORequest(timerport
, sizeof(struct timerequest
));
109 if (timerIORequest
!= NULL
) {
110 error
= OpenDevice(TIMERNAME
, UNIT_VBLANK
,
111 (struct IORequest
*)timerIORequest
, 0);
114 * Make sure that we got at least V36 timer, since we use some
115 * functions defined only in V36 and later.
117 if ((timerIORequest
->tr_node
.io_Device
)->dd_Library
.lib_Version
>= 36) {
119 * initialize TimerBase from timerIORequest
121 TimerBase
= timerIORequest
->tr_node
.io_Device
;
123 * Initialize some fields of the IO request to common values
125 timerIORequest
->tr_node
.io_Command
= TR_ADDREQUEST
;
127 * NT_UNKNOWN means unused, too (see note on exec/nodes.h)
129 timerIORequest
->tr_node
.io_Message
.mn_Node
.ln_Type
= NT_UNKNOWN
;
132 * create timeout requests for all timeouts;
134 ifTimer
= createTimeoutRequest(if_slowtimo
, 1 / IFNET_SLOWHZ
, 0);
135 arpTimer
= createTimeoutRequest(arptimer
, ARPT_AGE
, 0);
136 protoSlowTimer
= createTimeoutRequest(pfslowtimo
, 0, 1000000 / PR_SLOWHZ
);
137 protoFastTimer
= createTimeoutRequest(pffasttimo
, 0, 1000000 / PR_FASTHZ
);
138 if (protoFastTimer
&& protoSlowTimer
&& arpTimer
&& ifTimer
) {
139 can_send_timeouts
= TRUE
;
140 return (ULONG
)(1 << timerport
->mp_SigBit
);
147 * clean all in case of any error
155 * Deinitialize the timer.
156 * The requests are cancelled first.
161 #if defined(__AROS__)
162 D(bug("[AROSTCP](amiga_timer.c) timer_deinit()\n"));
164 can_send_timeouts
= FALSE
;
167 deleteTimeoutRequest(protoFastTimer
);
169 deleteTimeoutRequest(protoSlowTimer
);
171 deleteTimeoutRequest(arpTimer
);
173 deleteTimeoutRequest(ifTimer
);
175 if (timerIORequest
) {
177 if (timerIORequest
->tr_node
.io_Device
!= NULL
)
178 CloseDevice((struct IORequest
*)timerIORequest
);
179 DeleteIORequest((struct IORequest
*)timerIORequest
);
180 timerIORequest
= NULL
;
183 DeleteMsgPort(timerport
);
189 * Function to send all the timeout requests when everything is initialized
190 * DON'T even try to call this function otherwise!
195 #if defined(__AROS__)
196 D(bug("[AROSTCP](amiga_timer.c) timer_send()\n"));
198 if (can_send_timeouts
!= FALSE
) {
200 * Start timeout requests
202 sendTimeoutRequest(ifTimer
);
203 sendTimeoutRequest(arpTimer
);
204 sendTimeoutRequest(protoSlowTimer
);
205 sendTimeoutRequest(protoFastTimer
);
207 can_send_timeouts
= FALSE
;
212 * functions to create new timeoutRequest (after timer is initialized!)
214 struct timeoutRequest
*
215 createTimeoutRequest(TimerCallback_t fun
,
216 ULONG seconds
, ULONG micros
)
218 struct timeoutRequest
*tr
;
219 #if defined(__AROS__)
220 D(bug("[AROSTCP](amiga_timer.c) createTimeoutRequest()\n"));
225 * sanity check the micros value
227 if (micros
>= 1000000) {
228 log(LOG_ERR
, "More than 1000000 microseconds in initTimeoutRequest()\n");
234 * allocate IO request
236 tr
= (struct timeoutRequest
*)CreateIORequest(timerport
, sizeof(*tr
));
241 * copy initial values from the initialized timerrequest
245 tr
->timeout_request
.tr_node
.io_Message
.mn_Node
.ln_Type
=
246 timerIORequest
->tr_node
.io_Message
.mn_Node
.ln_Type
;
247 tr
->timeout_request
.tr_node
.io_Message
.mn_Node
.ln_Pri
=
248 timerIORequest
->tr_node
.io_Message
.mn_Node
.ln_Pri
;
249 tr
->timeout_request
.tr_node
.io_Message
.mn_Node
.ln_Name
=
250 timerIORequest
->tr_node
.io_Message
.mn_Node
.ln_Name
;
253 tr
->timeout_request
.tr_node
.io_Message
.mn_ReplyPort
=
254 timerIORequest
->tr_node
.io_Message
.mn_ReplyPort
;
257 tr
->timeout_request
.tr_node
.io_Device
= timerIORequest
->tr_node
.io_Device
;
258 tr
->timeout_request
.tr_node
.io_Unit
= timerIORequest
->tr_node
.io_Unit
;
259 tr
->timeout_request
.tr_node
.io_Command
= timerIORequest
->tr_node
.io_Command
;
260 tr
->timeout_request
.tr_node
.io_Flags
= timerIORequest
->tr_node
.io_Flags
;
265 tr
->timeout_timeval
.tv_secs
= seconds
;
266 tr
->timeout_timeval
.tv_micro
= micros
;
267 tr
->timeout_function
= fun
;
273 deleteTimeoutRequest(struct timeoutRequest
*tr
)
275 #if defined(__AROS__)
276 D(bug("[AROSTCP](amiga_timer.c) deleteTimeoutRequest()\n"));
279 * Abort the request if ever used
281 if (((struct Node
*)tr
)->ln_Type
!= NT_UNKNOWN
) {
282 AbortIO((struct IORequest
*)tr
);
283 WaitIO((struct IORequest
*)tr
);
285 * Make sure the signal gets cleared
287 SetSignal(0, 1 << timerport
->mp_SigBit
);
292 DeleteIORequest((struct IORequest
*)tr
);
295 BOOL
timer_poll(VOID
)
297 struct timeoutRequest
*timerReply
;
298 /* Uncomment the following lines to get debug - however please note: this func runs often */
299 //#if defined(__AROS__)
300 //D(bug("[AROSTCP](amiga_timer.c) timer_poll()\n"));
303 * Get all messages from the timer reply port.
305 if (timerReply
= (struct timeoutRequest
*)GetMsg(timerport
)) {
307 * enter softclock interrupt level
309 spl_t s
= splsoftclock();
313 handleTimeoutRequest(timerReply
);
315 * restart timeout request
317 sendTimeoutRequest(timerReply
);
319 * restore previous interrupt level