linux/drivers/isdn/mISDN/fsm.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * finite state machine implementation
   4 *
   5 * Author       Karsten Keil <kkeil@novell.com>
   6 *
   7 * Thanks to    Jan den Ouden
   8 *              Fritz Elfert
   9 * Copyright 2008  by Karsten Keil <kkeil@novell.com>
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/slab.h>
  14#include <linux/module.h>
  15#include <linux/string.h>
  16#include "fsm.h"
  17
  18#define FSM_TIMER_DEBUG 0
  19
  20int
  21mISDN_FsmNew(struct Fsm *fsm,
  22             struct FsmNode *fnlist, int fncount)
  23{
  24        int i;
  25
  26        fsm->jumpmatrix =
  27                kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count,
  28                                    fsm->event_count),
  29                        GFP_KERNEL);
  30        if (fsm->jumpmatrix == NULL)
  31                return -ENOMEM;
  32
  33        for (i = 0; i < fncount; i++)
  34                if ((fnlist[i].state >= fsm->state_count) ||
  35                    (fnlist[i].event >= fsm->event_count)) {
  36                        printk(KERN_ERR
  37                               "mISDN_FsmNew Error: %d st(%ld/%ld) ev(%ld/%ld)\n",
  38                               i, (long)fnlist[i].state, (long)fsm->state_count,
  39                               (long)fnlist[i].event, (long)fsm->event_count);
  40                } else
  41                        fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
  42                                        fnlist[i].state] = (FSMFNPTR) fnlist[i].routine;
  43        return 0;
  44}
  45EXPORT_SYMBOL(mISDN_FsmNew);
  46
  47void
  48mISDN_FsmFree(struct Fsm *fsm)
  49{
  50        kfree((void *) fsm->jumpmatrix);
  51}
  52EXPORT_SYMBOL(mISDN_FsmFree);
  53
  54int
  55mISDN_FsmEvent(struct FsmInst *fi, int event, void *arg)
  56{
  57        FSMFNPTR r;
  58
  59        if ((fi->state >= fi->fsm->state_count) ||
  60            (event >= fi->fsm->event_count)) {
  61                printk(KERN_ERR
  62                       "mISDN_FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n",
  63                       (long)fi->state, (long)fi->fsm->state_count, event,
  64                       (long)fi->fsm->event_count);
  65                return 1;
  66        }
  67        r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
  68        if (r) {
  69                if (fi->debug)
  70                        fi->printdebug(fi, "State %s Event %s",
  71                                       fi->fsm->strState[fi->state],
  72                                       fi->fsm->strEvent[event]);
  73                r(fi, event, arg);
  74                return 0;
  75        } else {
  76                if (fi->debug)
  77                        fi->printdebug(fi, "State %s Event %s no action",
  78                                       fi->fsm->strState[fi->state],
  79                                       fi->fsm->strEvent[event]);
  80                return 1;
  81        }
  82}
  83EXPORT_SYMBOL(mISDN_FsmEvent);
  84
  85void
  86mISDN_FsmChangeState(struct FsmInst *fi, int newstate)
  87{
  88        fi->state = newstate;
  89        if (fi->debug)
  90                fi->printdebug(fi, "ChangeState %s",
  91                               fi->fsm->strState[newstate]);
  92}
  93EXPORT_SYMBOL(mISDN_FsmChangeState);
  94
  95static void
  96FsmExpireTimer(struct timer_list *t)
  97{
  98        struct FsmTimer *ft = from_timer(ft, t, tl);
  99#if FSM_TIMER_DEBUG
 100        if (ft->fi->debug)
 101                ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);
 102#endif
 103        mISDN_FsmEvent(ft->fi, ft->event, ft->arg);
 104}
 105
 106void
 107mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
 108{
 109        ft->fi = fi;
 110#if FSM_TIMER_DEBUG
 111        if (ft->fi->debug)
 112                ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);
 113#endif
 114        timer_setup(&ft->tl, FsmExpireTimer, 0);
 115}
 116EXPORT_SYMBOL(mISDN_FsmInitTimer);
 117
 118void
 119mISDN_FsmDelTimer(struct FsmTimer *ft, int where)
 120{
 121#if FSM_TIMER_DEBUG
 122        if (ft->fi->debug)
 123                ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d",
 124                                   (long) ft, where);
 125#endif
 126        del_timer(&ft->tl);
 127}
 128EXPORT_SYMBOL(mISDN_FsmDelTimer);
 129
 130int
 131mISDN_FsmAddTimer(struct FsmTimer *ft,
 132                  int millisec, int event, void *arg, int where)
 133{
 134
 135#if FSM_TIMER_DEBUG
 136        if (ft->fi->debug)
 137                ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",
 138                                   (long) ft, millisec, where);
 139#endif
 140
 141        if (timer_pending(&ft->tl)) {
 142                if (ft->fi->debug) {
 143                        printk(KERN_WARNING
 144                               "mISDN_FsmAddTimer: timer already active!\n");
 145                        ft->fi->printdebug(ft->fi,
 146                                           "mISDN_FsmAddTimer already active!");
 147                }
 148                return -1;
 149        }
 150        ft->event = event;
 151        ft->arg = arg;
 152        ft->tl.expires = jiffies + (millisec * HZ) / 1000;
 153        add_timer(&ft->tl);
 154        return 0;
 155}
 156EXPORT_SYMBOL(mISDN_FsmAddTimer);
 157
 158void
 159mISDN_FsmRestartTimer(struct FsmTimer *ft,
 160                      int millisec, int event, void *arg, int where)
 161{
 162
 163#if FSM_TIMER_DEBUG
 164        if (ft->fi->debug)
 165                ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",
 166                                   (long) ft, millisec, where);
 167#endif
 168
 169        if (timer_pending(&ft->tl))
 170                del_timer(&ft->tl);
 171        ft->event = event;
 172        ft->arg = arg;
 173        ft->tl.expires = jiffies + (millisec * HZ) / 1000;
 174        add_timer(&ft->tl);
 175}
 176EXPORT_SYMBOL(mISDN_FsmRestartTimer);
 177