linux/drivers/net/skfp/smttimer.c
<<
>>
Prefs
   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        SMT timer
  19*/
  20
  21#include "h/types.h"
  22#include "h/fddi.h"
  23#include "h/smc.h"
  24
  25#ifndef lint
  26static const char ID_sccs[] = "@(#)smttimer.c   2.4 97/08/04 (C) SK " ;
  27#endif
  28
  29static void timer_done(struct s_smc *smc, int restart);
  30
  31void smt_timer_init(struct s_smc *smc)
  32{
  33        smc->t.st_queue = NULL;
  34        smc->t.st_fast.tm_active = FALSE ;
  35        smc->t.st_fast.tm_next = NULL;
  36        hwt_init(smc) ;
  37}
  38
  39void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer)
  40{
  41        struct smt_timer        **prev ;
  42        struct smt_timer        *tm ;
  43
  44        /*
  45         * remove timer from queue
  46         */
  47        timer->tm_active = FALSE ;
  48        if (smc->t.st_queue == timer && !timer->tm_next) {
  49                hwt_stop(smc) ;
  50        }
  51        for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
  52                if (tm == timer) {
  53                        *prev = tm->tm_next ;
  54                        if (tm->tm_next) {
  55                                tm->tm_next->tm_delta += tm->tm_delta ;
  56                        }
  57                        return ;
  58                }
  59        }
  60}
  61
  62void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time,
  63                     u_long token)
  64{
  65        struct smt_timer        **prev ;
  66        struct smt_timer        *tm ;
  67        u_long                  delta = 0 ;
  68
  69        time /= 16 ;            /* input is uS, clock ticks are 16uS */
  70        if (!time)
  71                time = 1 ;
  72        smt_timer_stop(smc,timer) ;
  73        timer->tm_smc = smc ;
  74        timer->tm_token = token ;
  75        timer->tm_active = TRUE ;
  76        if (!smc->t.st_queue) {
  77                smc->t.st_queue = timer ;
  78                timer->tm_next = NULL;
  79                timer->tm_delta = time ;
  80                hwt_start(smc,time) ;
  81                return ;
  82        }
  83        /*
  84         * timer correction
  85         */
  86        timer_done(smc,0) ;
  87
  88        /*
  89         * find position in queue
  90         */
  91        delta = 0 ;
  92        for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
  93                if (delta + tm->tm_delta > time) {
  94                        break ;
  95                }
  96                delta += tm->tm_delta ;
  97        }
  98        /* insert in queue */
  99        *prev = timer ;
 100        timer->tm_next = tm ;
 101        timer->tm_delta = time - delta ;
 102        if (tm)
 103                tm->tm_delta -= timer->tm_delta ;
 104        /*
 105         * start new with first
 106         */
 107        hwt_start(smc,smc->t.st_queue->tm_delta) ;
 108}
 109
 110void smt_force_irq(struct s_smc *smc)
 111{
 112        smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 
 113}
 114
 115void smt_timer_done(struct s_smc *smc)
 116{
 117        timer_done(smc,1) ;
 118}
 119
 120static void timer_done(struct s_smc *smc, int restart)
 121{
 122        u_long                  delta ;
 123        struct smt_timer        *tm ;
 124        struct smt_timer        *next ;
 125        struct smt_timer        **last ;
 126        int                     done = 0 ;
 127
 128        delta = hwt_read(smc) ;
 129        last = &smc->t.st_queue ;
 130        tm = smc->t.st_queue ;
 131        while (tm && !done) {
 132                if (delta >= tm->tm_delta) {
 133                        tm->tm_active = FALSE ;
 134                        delta -= tm->tm_delta ;
 135                        last = &tm->tm_next ;
 136                        tm = tm->tm_next ;
 137                }
 138                else {
 139                        tm->tm_delta -= delta ;
 140                        delta = 0 ;
 141                        done = 1 ;
 142                }
 143        }
 144        *last = NULL;
 145        next = smc->t.st_queue ;
 146        smc->t.st_queue = tm ;
 147
 148        for ( tm = next ; tm ; tm = next) {
 149                next = tm->tm_next ;
 150                timer_event(smc,tm->tm_token) ;
 151        }
 152
 153        if (restart && smc->t.st_queue)
 154                hwt_start(smc,smc->t.st_queue->tm_delta) ;
 155}
 156
 157