summaryrefslogtreecommitdiff
path: root/drivers/net/fddi/skfp/smttimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/fddi/skfp/smttimer.c')
-rw-r--r--drivers/net/fddi/skfp/smttimer.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/drivers/net/fddi/skfp/smttimer.c b/drivers/net/fddi/skfp/smttimer.c
new file mode 100644
index 000000000..531795e98
--- /dev/null
+++ b/drivers/net/fddi/skfp/smttimer.c
@@ -0,0 +1,156 @@
+/******************************************************************************
+ *
+ * (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.
+ *
+ ******************************************************************************/
+
+/*
+ SMT timer
+*/
+
+#include "h/types.h"
+#include "h/fddi.h"
+#include "h/smc.h"
+
+#ifndef lint
+static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ;
+#endif
+
+static void timer_done(struct s_smc *smc, int restart);
+
+void smt_timer_init(struct s_smc *smc)
+{
+ smc->t.st_queue = NULL;
+ smc->t.st_fast.tm_active = FALSE ;
+ smc->t.st_fast.tm_next = NULL;
+ hwt_init(smc) ;
+}
+
+void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer)
+{
+ struct smt_timer **prev ;
+ struct smt_timer *tm ;
+
+ /*
+ * remove timer from queue
+ */
+ timer->tm_active = FALSE ;
+ if (smc->t.st_queue == timer && !timer->tm_next) {
+ hwt_stop(smc) ;
+ }
+ for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+ if (tm == timer) {
+ *prev = tm->tm_next ;
+ if (tm->tm_next) {
+ tm->tm_next->tm_delta += tm->tm_delta ;
+ }
+ return ;
+ }
+ }
+}
+
+void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time,
+ u_long token)
+{
+ struct smt_timer **prev ;
+ struct smt_timer *tm ;
+ u_long delta = 0 ;
+
+ time /= 16 ; /* input is uS, clock ticks are 16uS */
+ if (!time)
+ time = 1 ;
+ smt_timer_stop(smc,timer) ;
+ timer->tm_smc = smc ;
+ timer->tm_token = token ;
+ timer->tm_active = TRUE ;
+ if (!smc->t.st_queue) {
+ smc->t.st_queue = timer ;
+ timer->tm_next = NULL;
+ timer->tm_delta = time ;
+ hwt_start(smc,time) ;
+ return ;
+ }
+ /*
+ * timer correction
+ */
+ timer_done(smc,0) ;
+
+ /*
+ * find position in queue
+ */
+ delta = 0 ;
+ for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
+ if (delta + tm->tm_delta > time) {
+ break ;
+ }
+ delta += tm->tm_delta ;
+ }
+ /* insert in queue */
+ *prev = timer ;
+ timer->tm_next = tm ;
+ timer->tm_delta = time - delta ;
+ if (tm)
+ tm->tm_delta -= timer->tm_delta ;
+ /*
+ * start new with first
+ */
+ hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
+
+void smt_force_irq(struct s_smc *smc)
+{
+ smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST));
+}
+
+void smt_timer_done(struct s_smc *smc)
+{
+ timer_done(smc,1) ;
+}
+
+static void timer_done(struct s_smc *smc, int restart)
+{
+ u_long delta ;
+ struct smt_timer *tm ;
+ struct smt_timer *next ;
+ struct smt_timer **last ;
+ int done = 0 ;
+
+ delta = hwt_read(smc) ;
+ last = &smc->t.st_queue ;
+ tm = smc->t.st_queue ;
+ while (tm && !done) {
+ if (delta >= tm->tm_delta) {
+ tm->tm_active = FALSE ;
+ delta -= tm->tm_delta ;
+ last = &tm->tm_next ;
+ tm = tm->tm_next ;
+ }
+ else {
+ tm->tm_delta -= delta ;
+ delta = 0 ;
+ done = 1 ;
+ }
+ }
+ *last = NULL;
+ next = smc->t.st_queue ;
+ smc->t.st_queue = tm ;
+
+ for ( tm = next ; tm ; tm = next) {
+ next = tm->tm_next ;
+ timer_event(smc,tm->tm_token) ;
+ }
+
+ if (restart && smc->t.st_queue)
+ hwt_start(smc,smc->t.st_queue->tm_delta) ;
+}
+