1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /****************************************************************************** 3 * 4 * (C)Copyright 1998,1999 SysKonnect, 5 * a business unit of Schneider & Koch & Co. Datensysteme GmbH. 6 * 7 * See the file "skfddi.c" for further information. 8 * 9 * The information in this file is provided "AS IS" without warranty. 10 * 11 ******************************************************************************/ 12 13 /* 14 SMT timer 15 */ 16 17 #include "h/types.h" 18 #include "h/fddi.h" 19 #include "h/smc.h" 20 21 #ifndef lint 22 static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; 23 #endif 24 25 static void timer_done(struct s_smc *smc, int restart); 26 27 void smt_timer_init(struct s_smc *smc) 28 { 29 smc->t.st_queue = NULL; 30 smc->t.st_fast.tm_active = FALSE ; 31 smc->t.st_fast.tm_next = NULL; 32 hwt_init(smc) ; 33 } 34 35 void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer) 36 { 37 struct smt_timer **prev ; 38 struct smt_timer *tm ; 39 40 /* 41 * remove timer from queue 42 */ 43 timer->tm_active = FALSE ; 44 if (smc->t.st_queue == timer && !timer->tm_next) { 45 hwt_stop(smc) ; 46 } 47 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 48 if (tm == timer) { 49 *prev = tm->tm_next ; 50 if (tm->tm_next) { 51 tm->tm_next->tm_delta += tm->tm_delta ; 52 } 53 return ; 54 } 55 } 56 } 57 58 void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, 59 u_long token) 60 { 61 struct smt_timer **prev ; 62 struct smt_timer *tm ; 63 u_long delta = 0 ; 64 65 time /= 16 ; /* input is uS, clock ticks are 16uS */ 66 if (!time) 67 time = 1 ; 68 smt_timer_stop(smc,timer) ; 69 timer->tm_smc = smc ; 70 timer->tm_token = token ; 71 timer->tm_active = TRUE ; 72 if (!smc->t.st_queue) { 73 smc->t.st_queue = timer ; 74 timer->tm_next = NULL; 75 timer->tm_delta = time ; 76 hwt_start(smc,time) ; 77 return ; 78 } 79 /* 80 * timer correction 81 */ 82 timer_done(smc,0) ; 83 84 /* 85 * find position in queue 86 */ 87 delta = 0 ; 88 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 89 if (delta + tm->tm_delta > time) { 90 break ; 91 } 92 delta += tm->tm_delta ; 93 } 94 /* insert in queue */ 95 *prev = timer ; 96 timer->tm_next = tm ; 97 timer->tm_delta = time - delta ; 98 if (tm) 99 tm->tm_delta -= timer->tm_delta ; 100 /* 101 * start new with first 102 */ 103 hwt_start(smc,smc->t.st_queue->tm_delta) ; 104 } 105 106 void smt_force_irq(struct s_smc *smc) 107 { 108 smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 109 } 110 111 void smt_timer_done(struct s_smc *smc) 112 { 113 timer_done(smc,1) ; 114 } 115 116 static void timer_done(struct s_smc *smc, int restart) 117 { 118 u_long delta ; 119 struct smt_timer *tm ; 120 struct smt_timer *next ; 121 struct smt_timer **last ; 122 int done = 0 ; 123 124 delta = hwt_read(smc) ; 125 last = &smc->t.st_queue ; 126 tm = smc->t.st_queue ; 127 while (tm && !done) { 128 if (delta >= tm->tm_delta) { 129 tm->tm_active = FALSE ; 130 delta -= tm->tm_delta ; 131 last = &tm->tm_next ; 132 tm = tm->tm_next ; 133 } 134 else { 135 tm->tm_delta -= delta ; 136 delta = 0 ; 137 done = 1 ; 138 } 139 } 140 *last = NULL; 141 next = smc->t.st_queue ; 142 smc->t.st_queue = tm ; 143 144 for ( tm = next ; tm ; tm = next) { 145 next = tm->tm_next ; 146 timer_event(smc,tm->tm_token) ; 147 } 148 149 if (restart && smc->t.st_queue) 150 hwt_start(smc,smc->t.st_queue->tm_delta) ; 151 } 152 153