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 20 int 21 mISDN_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 } 45 EXPORT_SYMBOL(mISDN_FsmNew); 46 47 void 48 mISDN_FsmFree(struct Fsm *fsm) 49 { 50 kfree((void *) fsm->jumpmatrix); 51 } 52 EXPORT_SYMBOL(mISDN_FsmFree); 53 54 int 55 mISDN_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 } 83 EXPORT_SYMBOL(mISDN_FsmEvent); 84 85 void 86 mISDN_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 } 93 EXPORT_SYMBOL(mISDN_FsmChangeState); 94 95 static void 96 FsmExpireTimer(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 106 void 107 mISDN_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 } 116 EXPORT_SYMBOL(mISDN_FsmInitTimer); 117 118 void 119 mISDN_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 } 128 EXPORT_SYMBOL(mISDN_FsmDelTimer); 129 130 int 131 mISDN_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 } 156 EXPORT_SYMBOL(mISDN_FsmAddTimer); 157 158 void 159 mISDN_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 } 176 EXPORT_SYMBOL(mISDN_FsmRestartTimer); 177