blob: e01f8a0f35c6341679b9a1ded6370cadb5808837 [file] [log] [blame]
/******************************************************************************
*
* (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