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 35static 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 63void 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#ifndef PCI 81 /* 82 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us) -> OUT0 83 * OUT0 -> CLK1 : T1 (cnt1) OUT1 -> ISRA(IS_TIMINT) 84 */ 85 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ 86 OUT_82c54_TIMER(1,cnt & 0xff) ; /* LSB */ 87 OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ; /* MSB */ 88 /* 89 * start timer by switching counter 0 to mode 3 90 * T0 resolution 16 us (CLK0=0.16us) 91 */ 92 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ; /* counter 0, mode 3 */ 93 OUT_82c54_TIMER(0,100) ; /* LSB */ 94 OUT_82c54_TIMER(0,0) ; /* MSB */ 95#else /* PCI */ 96 outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ; /* Load timer value. */ 97 outpw(ADDR(B2_TI_CRTL), TIM_START) ; /* Start timer. */ 98#endif /* PCI */ 99 smc->hw.timer_activ = TRUE ; 100} 101 102/************************ 103 * 104 * hwt_stop 105 * 106 * Stop hardware timer. 107 * 108 * void hwt_stop( 109 * struct s_smc *smc) ; 110 * In 111 * smc - A pointer to the SMT Context structure. 112 * Out 113 * Nothing. 114 * 115 ************************/ 116void hwt_stop(struct s_smc *smc) 117{ 118#ifndef PCI 119 /* stop counter 0 by switching to mode 0 */ 120 OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ; /* counter 0, mode 0 */ 121 OUT_82c54_TIMER(0,0) ; /* LSB */ 122 OUT_82c54_TIMER(0,0) ; /* MSB */ 123#else /* PCI */ 124 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; 125 outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; 126#endif /* PCI */ 127 128 smc->hw.timer_activ = FALSE ; 129} 130 131/************************ 132 * 133 * hwt_init 134 * 135 * Initialize hardware timer. 136 * 137 * void hwt_init( 138 * struct s_smc *smc) ; 139 * In 140 * smc - A pointer to the SMT Context structure. 141 * Out 142 * Nothing. 143 * 144 ************************/ 145void hwt_init(struct s_smc *smc) 146{ 147 smc->hw.t_start = 0 ; 148 smc->hw.t_stop = 0 ; 149 smc->hw.timer_activ = FALSE ; 150 151 hwt_restart(smc) ; 152} 153 154/************************ 155 * 156 * hwt_restart 157 * 158 * Clear timer interrupt. 159 * 160 * void hwt_restart( 161 * struct s_smc *smc) ; 162 * In 163 * smc - A pointer to the SMT Context structure. 164 * Out 165 * Nothing. 166 * 167 ************************/ 168void hwt_restart(struct s_smc *smc) 169{ 170 hwt_stop(smc) ; 171#ifndef PCI 172 OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ; /* counter 1, mode 0 */ 173 OUT_82c54_TIMER(1,1 ) ; /* LSB */ 174 OUT_82c54_TIMER(1,0 ) ; /* MSB */ 175#endif 176} 177 178/************************ 179 * 180 * hwt_read 181 * 182 * Stop hardware timer and read time elapsed since last start. 183 * 184 * u_long hwt_read(smc) ; 185 * In 186 * smc - A pointer to the SMT Context structure. 187 * Out 188 * The elapsed time since last start in units of 16us. 189 * 190 ************************/ 191u_long hwt_read(struct s_smc *smc) 192{ 193 u_short tr ; 194#ifndef PCI 195 u_short is ; 196#else 197 u_long is ; 198#endif 199 200 if (smc->hw.timer_activ) { 201 hwt_stop(smc) ; 202#ifndef PCI 203 OUT_82c54_TIMER(3,1<<6) ; /* latch command */ 204 tr = IN_82c54_TIMER(1) & 0xff ; 205 tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; 206#else /* PCI */ 207 tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; 208#endif /* PCI */ 209 is = GET_ISR() ; 210 /* Check if timer expired (or wraparound). */ 211 if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { 212 hwt_restart(smc) ; 213 smc->hw.t_stop = smc->hw.t_start ; 214 } 215 else 216 smc->hw.t_stop = smc->hw.t_start - tr ; 217 } 218 return (smc->hw.t_stop) ; 219} 220 221#ifdef PCI 222/************************ 223 * 224 * hwt_quick_read 225 * 226 * Stop hardware timer and read timer value and start the timer again. 227 * 228 * u_long hwt_read(smc) ; 229 * In 230 * smc - A pointer to the SMT Context structure. 231 * Out 232 * current timer value in units of 80ns. 233 * 234 ************************/ 235u_long hwt_quick_read(struct s_smc *smc) 236{ 237 u_long interval ; 238 u_long time ; 239 240 interval = inpd(ADDR(B2_TI_INI)) ; 241 outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; 242 time = inpd(ADDR(B2_TI_VAL)) ; 243 outpd(ADDR(B2_TI_INI),time) ; 244 outpw(ADDR(B2_TI_CRTL), TIM_START) ; 245 outpd(ADDR(B2_TI_INI),interval) ; 246 247 return(time) ; 248} 249 250/************************ 251 * 252 * hwt_wait_time(smc,start,duration) 253 * 254 * This function returnes after the amount of time is elapsed 255 * since the start time. 256 * 257 * para start start time 258 * duration time to wait 259 * 260 * NOTE: The fuction will return immediately, if the timer is not 261 * started 262 ************************/ 263void hwt_wait_time(struct s_smc *smc, u_long start, long int duration) 264{ 265 long diff ; 266 long interval ; 267 int wrapped ; 268 269 /* 270 * check if timer is running 271 */ 272 if (smc->hw.timer_activ == FALSE || 273 hwt_quick_read(smc) == hwt_quick_read(smc)) { 274 return ; 275 } 276 277 interval = inpd(ADDR(B2_TI_INI)) ; 278 if (interval > duration) { 279 do { 280 diff = (long)(start - hwt_quick_read(smc)) ; 281 if (diff < 0) { 282 diff += interval ; 283 } 284 } while (diff <= duration) ; 285 } 286 else { 287 diff = interval ; 288 wrapped = 0 ; 289 do { 290 if (!wrapped) { 291 if (hwt_quick_read(smc) >= start) { 292 diff += interval ; 293 wrapped = 1 ; 294 } 295 } 296 else { 297 if (hwt_quick_read(smc) < start) { 298 wrapped = 0 ; 299 } 300 } 301 } while (diff <= duration) ; 302 } 303} 304#endif 305