|  | /****************************************************************************** | 
|  | * | 
|  | *	(C)Copyright 1998,1999 SysKonnect, | 
|  | *	a business unit of Schneider & Koch & Co. Datensysteme GmbH. | 
|  | * | 
|  | *	See the file "skfddi.c" for further information. | 
|  | * | 
|  | *	This program is free software; you can redistribute it and/or modify | 
|  | *	it under the terms of the GNU General Public License as published by | 
|  | *	the Free Software Foundation; either version 2 of the License, or | 
|  | *	(at your option) any later version. | 
|  | * | 
|  | *	The information in this file is provided "AS IS" without warranty. | 
|  | * | 
|  | ******************************************************************************/ | 
|  |  | 
|  | /* | 
|  | * Timer Driver for FBI board (timer chip 82C54) | 
|  | */ | 
|  |  | 
|  | /* | 
|  | * Modifications: | 
|  | * | 
|  | *	28-Jun-1994 sw	Edit v1.6. | 
|  | *			MCA: Added support for the SK-NET FDDI-FM2 adapter. The | 
|  | *			 following functions have been added(+) or modified(*): | 
|  | *			 hwt_start(*), hwt_stop(*), hwt_restart(*), hwt_read(*) | 
|  | */ | 
|  |  | 
|  | #include "h/types.h" | 
|  | #include "h/fddi.h" | 
|  | #include "h/smc.h" | 
|  |  | 
|  | #ifndef	lint | 
|  | static const char ID_sccs[] = "@(#)hwt.c	1.13 97/04/23 (C) SK " ; | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Prototypes of local functions. | 
|  | */ | 
|  | /* 28-Jun-1994 sw - Note: hwt_restart() is also used in module 'drvfbi.c'. */ | 
|  | /*static void hwt_restart() ; */ | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_start | 
|  | * | 
|  | *	Start hardware timer (clock ticks are 16us). | 
|  | * | 
|  | *	void hwt_start( | 
|  | *		struct s_smc *smc, | 
|  | *		u_long time) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * | 
|  | *	time - The time in units of 16us to load the timer with. | 
|  | * Out | 
|  | *	Nothing. | 
|  | * | 
|  | ************************/ | 
|  | #define	HWT_MAX	(65000) | 
|  |  | 
|  | void hwt_start(struct s_smc *smc, u_long time) | 
|  | { | 
|  | u_short	cnt ; | 
|  |  | 
|  | if (time > HWT_MAX) | 
|  | time = HWT_MAX ; | 
|  |  | 
|  | smc->hw.t_start = time ; | 
|  | smc->hw.t_stop = 0L ; | 
|  |  | 
|  | cnt = (u_short)time ; | 
|  | /* | 
|  | * if time < 16 us | 
|  | *	time = 16 us | 
|  | */ | 
|  | if (!cnt) | 
|  | cnt++ ; | 
|  | #ifndef	PCI | 
|  | /* | 
|  | * 6.25MHz -> CLK0 : T0 (cnt0 = 16us)	-> OUT0 | 
|  | *    OUT0 -> CLK1 : T1 (cnt1)	OUT1	-> ISRA(IS_TIMINT) | 
|  | */ | 
|  | OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */ | 
|  | OUT_82c54_TIMER(1,cnt & 0xff) ;		/* LSB */ | 
|  | OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ;	/* MSB */ | 
|  | /* | 
|  | * start timer by switching counter 0 to mode 3 | 
|  | *	T0 resolution 16 us (CLK0=0.16us) | 
|  | */ | 
|  | OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ;	/* counter 0, mode 3 */ | 
|  | OUT_82c54_TIMER(0,100) ;		/* LSB */ | 
|  | OUT_82c54_TIMER(0,0) ;			/* MSB */ | 
|  | #else	/* PCI */ | 
|  | outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */ | 
|  | outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */ | 
|  | #endif	/* PCI */ | 
|  | smc->hw.timer_activ = TRUE ; | 
|  | } | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_stop | 
|  | * | 
|  | *	Stop hardware timer. | 
|  | * | 
|  | *	void hwt_stop( | 
|  | *		struct s_smc *smc) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * Out | 
|  | *	Nothing. | 
|  | * | 
|  | ************************/ | 
|  | void hwt_stop(struct s_smc *smc) | 
|  | { | 
|  | #ifndef PCI | 
|  | /* stop counter 0 by switching to mode 0 */ | 
|  | OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ;	/* counter 0, mode 0 */ | 
|  | OUT_82c54_TIMER(0,0) ;			/* LSB */ | 
|  | OUT_82c54_TIMER(0,0) ;			/* MSB */ | 
|  | #else	/* PCI */ | 
|  | outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; | 
|  | outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ; | 
|  | #endif	/* PCI */ | 
|  |  | 
|  | smc->hw.timer_activ = FALSE ; | 
|  | } | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_init | 
|  | * | 
|  | *	Initialize hardware timer. | 
|  | * | 
|  | *	void hwt_init( | 
|  | *		struct s_smc *smc) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * Out | 
|  | *	Nothing. | 
|  | * | 
|  | ************************/ | 
|  | void hwt_init(struct s_smc *smc) | 
|  | { | 
|  | smc->hw.t_start = 0 ; | 
|  | smc->hw.t_stop	= 0 ; | 
|  | smc->hw.timer_activ = FALSE ; | 
|  |  | 
|  | hwt_restart(smc) ; | 
|  | } | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_restart | 
|  | * | 
|  | *	Clear timer interrupt. | 
|  | * | 
|  | *	void hwt_restart( | 
|  | *		struct s_smc *smc) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * Out | 
|  | *	Nothing. | 
|  | * | 
|  | ************************/ | 
|  | void hwt_restart(struct s_smc *smc) | 
|  | { | 
|  | hwt_stop(smc) ; | 
|  | #ifndef	PCI | 
|  | OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */ | 
|  | OUT_82c54_TIMER(1,1 ) ;			/* LSB */ | 
|  | OUT_82c54_TIMER(1,0 ) ;			/* MSB */ | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_read | 
|  | * | 
|  | *	Stop hardware timer and read time elapsed since last start. | 
|  | * | 
|  | *	u_long hwt_read(smc) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * Out | 
|  | *	The elapsed time since last start in units of 16us. | 
|  | * | 
|  | ************************/ | 
|  | u_long hwt_read(struct s_smc *smc) | 
|  | { | 
|  | u_short	tr ; | 
|  | #ifndef	PCI | 
|  | u_short	is ; | 
|  | #else | 
|  | u_long	is ; | 
|  | #endif | 
|  |  | 
|  | if (smc->hw.timer_activ) { | 
|  | hwt_stop(smc) ; | 
|  | #ifndef	PCI | 
|  | OUT_82c54_TIMER(3,1<<6) ;	/* latch command */ | 
|  | tr = IN_82c54_TIMER(1) & 0xff ; | 
|  | tr += (IN_82c54_TIMER(1) & 0xff)<<8 ; | 
|  | #else	/* PCI */ | 
|  | tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ; | 
|  | #endif	/* PCI */ | 
|  | is = GET_ISR() ; | 
|  | /* Check if timer expired (or wraparound). */ | 
|  | if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) { | 
|  | hwt_restart(smc) ; | 
|  | smc->hw.t_stop = smc->hw.t_start ; | 
|  | } | 
|  | else | 
|  | smc->hw.t_stop = smc->hw.t_start - tr ; | 
|  | } | 
|  | return (smc->hw.t_stop) ; | 
|  | } | 
|  |  | 
|  | #ifdef	PCI | 
|  | /************************ | 
|  | * | 
|  | *	hwt_quick_read | 
|  | * | 
|  | *	Stop hardware timer and read timer value and start the timer again. | 
|  | * | 
|  | *	u_long hwt_read(smc) ; | 
|  | * In | 
|  | *	smc - A pointer to the SMT Context structure. | 
|  | * Out | 
|  | *	current timer value in units of 80ns. | 
|  | * | 
|  | ************************/ | 
|  | u_long hwt_quick_read(struct s_smc *smc) | 
|  | { | 
|  | u_long interval ; | 
|  | u_long time ; | 
|  |  | 
|  | interval = inpd(ADDR(B2_TI_INI)) ; | 
|  | outpw(ADDR(B2_TI_CRTL), TIM_STOP) ; | 
|  | time = inpd(ADDR(B2_TI_VAL)) ; | 
|  | outpd(ADDR(B2_TI_INI),time) ; | 
|  | outpw(ADDR(B2_TI_CRTL), TIM_START) ; | 
|  | outpd(ADDR(B2_TI_INI),interval) ; | 
|  |  | 
|  | return(time) ; | 
|  | } | 
|  |  | 
|  | /************************ | 
|  | * | 
|  | *	hwt_wait_time(smc,start,duration) | 
|  | * | 
|  | *	This function returnes after the amount of time is elapsed | 
|  | *	since the start time. | 
|  | * | 
|  | * para	start		start time | 
|  | *	duration	time to wait | 
|  | * | 
|  | * NOTE: The fuction will return immediately, if the timer is not | 
|  | *	 started | 
|  | ************************/ | 
|  | void hwt_wait_time(struct s_smc *smc, u_long start, long int duration) | 
|  | { | 
|  | long	diff ; | 
|  | long	interval ; | 
|  | int	wrapped ; | 
|  |  | 
|  | /* | 
|  | * check if timer is running | 
|  | */ | 
|  | if (smc->hw.timer_activ == FALSE || | 
|  | hwt_quick_read(smc) == hwt_quick_read(smc)) { | 
|  | return ; | 
|  | } | 
|  |  | 
|  | interval = inpd(ADDR(B2_TI_INI)) ; | 
|  | if (interval > duration) { | 
|  | do { | 
|  | diff = (long)(start - hwt_quick_read(smc)) ; | 
|  | if (diff < 0) { | 
|  | diff += interval ; | 
|  | } | 
|  | } while (diff <= duration) ; | 
|  | } | 
|  | else { | 
|  | diff = interval ; | 
|  | wrapped = 0 ; | 
|  | do { | 
|  | if (!wrapped) { | 
|  | if (hwt_quick_read(smc) >= start) { | 
|  | diff += interval ; | 
|  | wrapped = 1 ; | 
|  | } | 
|  | } | 
|  | else { | 
|  | if (hwt_quick_read(smc) < start) { | 
|  | wrapped = 0 ; | 
|  | } | 
|  | } | 
|  | } while (diff <= duration) ; | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  |