1 /******************************************************************************
2  *
3  *	(C)Copyright 1998,1999 SysKonnect,
4  *	a business unit of Schneider & Koch & Co. Datensysteme GmbH.
5  *
6  *	See the file "skfddi.c" for further information.
7  *
8  *	This program is free software; you can redistribute it and/or modify
9  *	it under the terms of the GNU General Public License as published by
10  *	the Free Software Foundation; either version 2 of the License, or
11  *	(at your option) any later version.
12  *
13  *	The information in this file is provided "AS IS" without warranty.
14  *
15  ******************************************************************************/
16 
17 /*
18 	SMT timer
19 */
20 
21 #include "h/types.h"
22 #include "h/fddi.h"
23 #include "h/smc.h"
24 
25 #ifndef	lint
26 static const char ID_sccs[] = "@(#)smttimer.c	2.4 97/08/04 (C) SK " ;
27 #endif
28 
29 /*
30  * external function declarations
31  */
32 extern u_long hwt_read() ;
33 extern void hwt_stop() ;
34 extern void hwt_start() ;
35 
36 static void timer_done() ;
37 
38 
smt_timer_init(smc)39 void smt_timer_init(smc)
40 struct s_smc *smc ;
41 {
42 	smc->t.st_queue = 0 ;
43 	smc->t.st_fast.tm_active = FALSE ;
44 	smc->t.st_fast.tm_next = 0 ;
45 	hwt_init(smc) ;
46 }
47 
smt_timer_stop(smc,timer)48 void smt_timer_stop(smc,timer)
49 struct s_smc *smc ;
50 struct smt_timer *timer ;
51 {
52 	struct smt_timer	**prev ;
53 	struct smt_timer	*tm ;
54 
55 	/*
56 	 * remove timer from queue
57 	 */
58 	timer->tm_active = FALSE ;
59 	if (smc->t.st_queue == timer && !timer->tm_next) {
60 		hwt_stop(smc) ;
61 	}
62 	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
63 		if (tm == timer) {
64 			*prev = tm->tm_next ;
65 			if (tm->tm_next) {
66 				tm->tm_next->tm_delta += tm->tm_delta ;
67 			}
68 			return ;
69 		}
70 	}
71 }
72 
smt_timer_start(smc,timer,time,token)73 void smt_timer_start(smc,timer,time,token)
74 struct s_smc *smc ;
75 struct smt_timer *timer ;
76 u_long		time ;
77 u_long		token ;
78 {
79 	struct smt_timer	**prev ;
80 	struct smt_timer	*tm ;
81 	u_long			delta = 0 ;
82 
83 	time /= 16 ;		/* input is uS, clock ticks are 16uS */
84 	if (!time)
85 		time = 1 ;
86 	smt_timer_stop(smc,timer) ;
87 	timer->tm_smc = smc ;
88 	timer->tm_token = token ;
89 	timer->tm_active = TRUE ;
90 	if (!smc->t.st_queue) {
91 		smc->t.st_queue = timer ;
92 		timer->tm_next = 0 ;
93 		timer->tm_delta = time ;
94 		hwt_start(smc,time) ;
95 		return ;
96 	}
97 	/*
98 	 * timer correction
99 	 */
100 	timer_done(smc,0) ;
101 
102 	/*
103 	 * find position in queue
104 	 */
105 	delta = 0 ;
106 	for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
107 		if (delta + tm->tm_delta > time) {
108 			break ;
109 		}
110 		delta += tm->tm_delta ;
111 	}
112 	/* insert in queue */
113 	*prev = timer ;
114 	timer->tm_next = tm ;
115 	timer->tm_delta = time - delta ;
116 	if (tm)
117 		tm->tm_delta -= timer->tm_delta ;
118 	/*
119 	 * start new with first
120 	 */
121 	hwt_start(smc,smc->t.st_queue->tm_delta) ;
122 }
123 
smt_force_irq(smc)124 void smt_force_irq(smc)
125 struct s_smc *smc ;
126 {
127 	smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST));
128 }
129 
smt_timer_done(smc)130 void smt_timer_done(smc)
131 struct s_smc *smc ;
132 {
133 	timer_done(smc,1) ;
134 }
135 
timer_done(smc,restart)136 static void timer_done(smc,restart)
137 struct s_smc *smc ;
138 int restart ;
139 {
140 	u_long			delta ;
141 	struct smt_timer	*tm ;
142 	struct smt_timer	*next ;
143 	struct smt_timer	**last ;
144 	int			done = 0 ;
145 
146 	delta = hwt_read(smc) ;
147 	last = &smc->t.st_queue ;
148 	tm = smc->t.st_queue ;
149 	while (tm && !done) {
150 		if (delta >= tm->tm_delta) {
151 			tm->tm_active = FALSE ;
152 			delta -= tm->tm_delta ;
153 			last = &tm->tm_next ;
154 			tm = tm->tm_next ;
155 		}
156 		else {
157 			tm->tm_delta -= delta ;
158 			delta = 0 ;
159 			done = 1 ;
160 		}
161 	}
162 	*last = 0 ;
163 	next = smc->t.st_queue ;
164 	smc->t.st_queue = tm ;
165 
166 	for ( tm = next ; tm ; tm = next) {
167 		next = tm->tm_next ;
168 		timer_event(smc,tm->tm_token) ;
169 	}
170 
171 	if (restart && smc->t.st_queue)
172 		hwt_start(smc,smc->t.st_queue->tm_delta) ;
173 }
174