fsm.c (4136B)
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);