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