| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++ ; | 
| Jeff Garzik | af09604 | 2007-07-24 01:30:36 -0400 | [diff] [blame] | 80 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 81 | 	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */ | 
 | 82 | 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */ | 
| Jeff Garzik | af09604 | 2007-07-24 01:30:36 -0400 | [diff] [blame] | 83 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 | 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; | 
 | 104 | 	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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) ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 167 | 	u_long	is ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 168 |  | 
 | 169 | 	if (smc->hw.timer_activ) { | 
 | 170 | 		hwt_stop(smc) ; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 171 | 		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; | 
| Jeff Garzik | af09604 | 2007-07-24 01:30:36 -0400 | [diff] [blame] | 172 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  |