Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[linux-2.6] / drivers / net / skfp / hwt.c
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  * Timer Driver for FBI board (timer chip 82C54)
19  */
20
21 /*
22  * Modifications:
23  *
24  *      28-Jun-1994 sw  Edit v1.6.
25  *                      MCA: Added support for the SK-NET FDDI-FM2 adapter. The
26  *                       following functions have been added(+) or modified(*):
27  *                       hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*)
28  */
29
30 #include "h/types.h"
31 #include "h/fddi.h"
32 #include "h/smc.h"
33
34 #ifndef lint
35 static const char ID_sccs[] = "@(#)hwt.c        1.13 97/04/23 (C) SK " ;
36 #endif
37
38 /*
39  * Prototypes of local functions.
40  */
41 /* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */
42 /*static void hwt_restart() ; */
43
44 /************************
45  *
46  *      hwt_start
47  *
48  *      Start hardware timer (clock ticks are 16us).
49  *
50  *      void hwt_start(
51  *              struct s_smc *smc,
52  *              u_long time) ;
53  * In
54  *      smc - A pointer to the SMT Context structure.
55  *
56  *      time - The time in units of 16us to load the timer with.
57  * Out
58  *      Nothing.
59  *
60  ************************/
61 #define HWT_MAX (65000)
62
63 void hwt_start(struct s_smc *smc, u_long time)
64 {
65         u_short cnt ;
66
67         if (time > HWT_MAX)
68                 time = HWT_MAX ;
69
70         smc->hw.t_start = time ;
71         smc->hw.t_stop = 0L ;
72
73         cnt = (u_short)time ;
74         /*
75          * if time < 16 us
76          *      time = 16 us
77          */
78         if (!cnt)
79                 cnt++ ;
80
81         outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;    /* Load timer value. */
82         outpw(ADDR(B2_TI_CRTL), TIM_START) ;            /* Start timer. */
83
84         smc->hw.timer_activ = TRUE ;
85 }
86
87 /************************
88  *
89  *      hwt_stop
90  *
91  *      Stop hardware timer.
92  *
93  *      void hwt_stop(
94  *              struct s_smc *smc) ;
95  * In
96  *      smc - A pointer to the SMT Context structure.
97  * Out
98  *      Nothing.
99  *
100  ************************/
101 void hwt_stop(struct s_smc *smc)
102 {
103         outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
104         outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
105
106         smc->hw.timer_activ = FALSE ;
107 }
108
109 /************************
110  *
111  *      hwt_init
112  *
113  *      Initialize hardware timer.
114  *
115  *      void hwt_init(
116  *              struct s_smc *smc) ;
117  * In
118  *      smc - A pointer to the SMT Context structure.
119  * Out
120  *      Nothing.
121  *
122  ************************/
123 void hwt_init(struct s_smc *smc)
124 {
125         smc->hw.t_start = 0 ;
126         smc->hw.t_stop  = 0 ;
127         smc->hw.timer_activ = FALSE ;
128
129         hwt_restart(smc) ;
130 }
131
132 /************************
133  *
134  *      hwt_restart
135  *
136  *      Clear timer interrupt.
137  *
138  *      void hwt_restart(
139  *              struct s_smc *smc) ;
140  * In
141  *      smc - A pointer to the SMT Context structure.
142  * Out
143  *      Nothing.
144  *
145  ************************/
146 void hwt_restart(struct s_smc *smc)
147 {
148         hwt_stop(smc) ;
149 }
150
151 /************************
152  *
153  *      hwt_read
154  *
155  *      Stop hardware timer and read time elapsed since last start.
156  *
157  *      u_long hwt_read(smc) ;
158  * In
159  *      smc - A pointer to the SMT Context structure.
160  * Out
161  *      The elapsed time since last start in units of 16us.
162  *
163  ************************/
164 u_long hwt_read(struct s_smc *smc)
165 {
166         u_short tr ;
167         u_long  is ;
168
169         if (smc->hw.timer_activ) {
170                 hwt_stop(smc) ;
171                 tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
172
173                 is = GET_ISR() ;
174                 /* Check if timer expired (or wraparound). */
175                 if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
176                         hwt_restart(smc) ;
177                         smc->hw.t_stop = smc->hw.t_start ;
178                 }
179                 else
180                         smc->hw.t_stop = smc->hw.t_start - tr ;
181         }
182         return (smc->hw.t_stop) ;
183 }
184
185 #ifdef  PCI
186 /************************
187  *
188  *      hwt_quick_read
189  *
190  *      Stop hardware timer and read timer value and start the timer again.
191  *
192  *      u_long hwt_read(smc) ;
193  * In
194  *      smc - A pointer to the SMT Context structure.
195  * Out
196  *      current timer value in units of 80ns.
197  *
198  ************************/
199 u_long hwt_quick_read(struct s_smc *smc)
200 {
201         u_long interval ;
202         u_long time ;
203
204         interval = inpd(ADDR(B2_TI_INI)) ;
205         outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
206         time = inpd(ADDR(B2_TI_VAL)) ;
207         outpd(ADDR(B2_TI_INI),time) ;
208         outpw(ADDR(B2_TI_CRTL), TIM_START) ;
209         outpd(ADDR(B2_TI_INI),interval) ;
210
211         return(time) ;
212 }
213
214 /************************
215  *
216  *      hwt_wait_time(smc,start,duration)
217  *
218  *      This function returnes after the amount of time is elapsed
219  *      since the start time.
220  * 
221  * para start           start time
222  *      duration        time to wait
223  *
224  * NOTE: The fuction will return immediately, if the timer is not 
225  *       started
226  ************************/
227 void hwt_wait_time(struct s_smc *smc, u_long start, long int duration)
228 {
229         long    diff ;
230         long    interval ;
231         int     wrapped ;
232
233         /*
234          * check if timer is running
235          */
236         if (smc->hw.timer_activ == FALSE ||
237                 hwt_quick_read(smc) == hwt_quick_read(smc)) {
238                 return ;
239         }
240
241         interval = inpd(ADDR(B2_TI_INI)) ;
242         if (interval > duration) {
243                 do {
244                         diff = (long)(start - hwt_quick_read(smc)) ;
245                         if (diff < 0) {
246                                 diff += interval ;
247                         }
248                 } while (diff <= duration) ;
249         }
250         else {
251                 diff = interval ;
252                 wrapped = 0 ;
253                 do {
254                         if (!wrapped) {
255                                 if (hwt_quick_read(smc) >= start) {
256                                         diff += interval ;
257                                         wrapped = 1 ;
258                                 }
259                         }
260                         else {
261                                 if (hwt_quick_read(smc) < start) {
262                                         wrapped = 0 ;
263                                 }
264                         }
265                 } while (diff <= duration) ;
266         }
267 }
268 #endif
269