177 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * finite state machine implementation4 *5 * Author Karsten Keil <kkeil@novell.com>6 *7 * Thanks to Jan den Ouden8 * Fritz Elfert9 * 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 019 20int21mISDN_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_ERR37 "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 } else41 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 47void48mISDN_FsmFree(struct Fsm *fsm)49{50 kfree((void *) fsm->jumpmatrix);51}52EXPORT_SYMBOL(mISDN_FsmFree);53 54int55mISDN_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_ERR62 "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 85void86mISDN_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 void96FsmExpireTimer(struct timer_list *t)97{98 struct FsmTimer *ft = from_timer(ft, t, tl);99#if FSM_TIMER_DEBUG100 if (ft->fi->debug)101 ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft);102#endif103 mISDN_FsmEvent(ft->fi, ft->event, ft->arg);104}105 106void107mISDN_FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)108{109 ft->fi = fi;110#if FSM_TIMER_DEBUG111 if (ft->fi->debug)112 ft->fi->printdebug(ft->fi, "mISDN_FsmInitTimer %lx", (long) ft);113#endif114 timer_setup(&ft->tl, FsmExpireTimer, 0);115}116EXPORT_SYMBOL(mISDN_FsmInitTimer);117 118void119mISDN_FsmDelTimer(struct FsmTimer *ft, int where)120{121#if FSM_TIMER_DEBUG122 if (ft->fi->debug)123 ft->fi->printdebug(ft->fi, "mISDN_FsmDelTimer %lx %d",124 (long) ft, where);125#endif126 del_timer(&ft->tl);127}128EXPORT_SYMBOL(mISDN_FsmDelTimer);129 130int131mISDN_FsmAddTimer(struct FsmTimer *ft,132 int millisec, int event, void *arg, int where)133{134 135#if FSM_TIMER_DEBUG136 if (ft->fi->debug)137 ft->fi->printdebug(ft->fi, "mISDN_FsmAddTimer %lx %d %d",138 (long) ft, millisec, where);139#endif140 141 if (timer_pending(&ft->tl)) {142 if (ft->fi->debug) {143 printk(KERN_WARNING144 "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 158void159mISDN_FsmRestartTimer(struct FsmTimer *ft,160 int millisec, int event, void *arg, int where)161{162 163#if FSM_TIMER_DEBUG164 if (ft->fi->debug)165 ft->fi->printdebug(ft->fi, "mISDN_FsmRestartTimer %lx %d %d",166 (long) ft, millisec, where);167#endif168 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