1 /** 2 * A generic FSM based on fsm used in isdn4linux 3 * 4 */ 5 6 #include "fsm.h" 7 #include <linux/module.h> 8 #include <linux/timer.h> 9 10 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); 11 MODULE_DESCRIPTION("Finite state machine helper functions"); 12 MODULE_LICENSE("GPL"); 13 14 fsm_instance * 15 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, 16 int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order) 17 { 18 int i; 19 fsm_instance *this; 20 fsm_function_t *m; 21 fsm *f; 22 23 this = kzalloc(sizeof(fsm_instance), order); 24 if (this == NULL) { 25 printk(KERN_WARNING 26 "fsm(%s): init_fsm: Couldn't alloc instance\n", name); 27 return NULL; 28 } 29 strlcpy(this->name, name, sizeof(this->name)); 30 31 f = kzalloc(sizeof(fsm), order); 32 if (f == NULL) { 33 printk(KERN_WARNING 34 "fsm(%s): init_fsm: Couldn't alloc fsm\n", name); 35 kfree_fsm(this); 36 return NULL; 37 } 38 f->nr_events = nr_events; 39 f->nr_states = nr_states; 40 f->event_names = event_names; 41 f->state_names = state_names; 42 this->f = f; 43 44 m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order); 45 if (m == NULL) { 46 printk(KERN_WARNING 47 "fsm(%s): init_fsm: Couldn't alloc jumptable\n", name); 48 kfree_fsm(this); 49 return NULL; 50 } 51 f->jumpmatrix = m; 52 53 for (i = 0; i < tmpl_len; i++) { 54 if ((tmpl[i].cond_state >= nr_states) || 55 (tmpl[i].cond_event >= nr_events) ) { 56 printk(KERN_ERR 57 "fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n", 58 name, i, (long)tmpl[i].cond_state, (long)f->nr_states, 59 (long)tmpl[i].cond_event, (long)f->nr_events); 60 kfree_fsm(this); 61 return NULL; 62 } else 63 m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] = 64 tmpl[i].function; 65 } 66 return this; 67 } 68 69 void 70 kfree_fsm(fsm_instance *this) 71 { 72 if (this) { 73 if (this->f) { 74 kfree(this->f->jumpmatrix); 75 kfree(this->f); 76 } 77 kfree(this); 78 } else 79 printk(KERN_WARNING 80 "fsm: kfree_fsm called with NULL argument\n"); 81 } 82 83 #if FSM_DEBUG_HISTORY 84 void 85 fsm_print_history(fsm_instance *fi) 86 { 87 int idx = 0; 88 int i; 89 90 if (fi->history_size >= FSM_HISTORY_SIZE) 91 idx = fi->history_index; 92 93 printk(KERN_DEBUG "fsm(%s): History:\n", fi->name); 94 for (i = 0; i < fi->history_size; i++) { 95 int e = fi->history[idx].event; 96 int s = fi->history[idx++].state; 97 idx %= FSM_HISTORY_SIZE; 98 if (e == -1) 99 printk(KERN_DEBUG " S=%s\n", 100 fi->f->state_names[s]); 101 else 102 printk(KERN_DEBUG " S=%s E=%s\n", 103 fi->f->state_names[s], 104 fi->f->event_names[e]); 105 } 106 fi->history_size = fi->history_index = 0; 107 } 108 109 void 110 fsm_record_history(fsm_instance *fi, int state, int event) 111 { 112 fi->history[fi->history_index].state = state; 113 fi->history[fi->history_index++].event = event; 114 fi->history_index %= FSM_HISTORY_SIZE; 115 if (fi->history_size < FSM_HISTORY_SIZE) 116 fi->history_size++; 117 } 118 #endif 119 120 const char * 121 fsm_getstate_str(fsm_instance *fi) 122 { 123 int st = atomic_read(&fi->state); 124 if (st >= fi->f->nr_states) 125 return "Invalid"; 126 return fi->f->state_names[st]; 127 } 128 129 static void 130 fsm_expire_timer(fsm_timer *this) 131 { 132 #if FSM_TIMER_DEBUG 133 printk(KERN_DEBUG "fsm(%s): Timer %p expired\n", 134 this->fi->name, this); 135 #endif 136 fsm_event(this->fi, this->expire_event, this->event_arg); 137 } 138 139 void 140 fsm_settimer(fsm_instance *fi, fsm_timer *this) 141 { 142 this->fi = fi; 143 this->tl.function = (void *)fsm_expire_timer; 144 this->tl.data = (long)this; 145 #if FSM_TIMER_DEBUG 146 printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name, 147 this); 148 #endif 149 init_timer(&this->tl); 150 } 151 152 void 153 fsm_deltimer(fsm_timer *this) 154 { 155 #if FSM_TIMER_DEBUG 156 printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name, 157 this); 158 #endif 159 del_timer(&this->tl); 160 } 161 162 int 163 fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg) 164 { 165 166 #if FSM_TIMER_DEBUG 167 printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n", 168 this->fi->name, this, millisec); 169 #endif 170 171 init_timer(&this->tl); 172 this->tl.function = (void *)fsm_expire_timer; 173 this->tl.data = (long)this; 174 this->expire_event = event; 175 this->event_arg = arg; 176 this->tl.expires = jiffies + (millisec * HZ) / 1000; 177 add_timer(&this->tl); 178 return 0; 179 } 180 181 /* FIXME: this function is never used, why */ 182 void 183 fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg) 184 { 185 186 #if FSM_TIMER_DEBUG 187 printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n", 188 this->fi->name, this, millisec); 189 #endif 190 191 del_timer(&this->tl); 192 init_timer(&this->tl); 193 this->tl.function = (void *)fsm_expire_timer; 194 this->tl.data = (long)this; 195 this->expire_event = event; 196 this->event_arg = arg; 197 this->tl.expires = jiffies + (millisec * HZ) / 1000; 198 add_timer(&this->tl); 199 } 200 201 EXPORT_SYMBOL(init_fsm); 202 EXPORT_SYMBOL(kfree_fsm); 203 EXPORT_SYMBOL(fsm_settimer); 204 EXPORT_SYMBOL(fsm_deltimer); 205 EXPORT_SYMBOL(fsm_addtimer); 206 EXPORT_SYMBOL(fsm_modtimer); 207 EXPORT_SYMBOL(fsm_getstate_str); 208 209 #if FSM_DEBUG_HISTORY 210 EXPORT_SYMBOL(fsm_print_history); 211 EXPORT_SYMBOL(fsm_record_history); 212 #endif 213