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 26 static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; 27 #endif 28 29 static void timer_done(struct s_smc *smc, int restart); 30 31 void 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 39 void 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 62 void 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 110 void 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 115 void smt_timer_done(struct s_smc *smc) 116 { 117 timer_done(smc,1) ; 118 } 119 120 static 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