11da177e4SLinus Torvalds /** 21da177e4SLinus Torvalds * A generic FSM based on fsm used in isdn4linux 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 61da177e4SLinus Torvalds #include "fsm.h" 71da177e4SLinus Torvalds #include <linux/module.h> 81da177e4SLinus Torvalds #include <linux/timer.h> 91da177e4SLinus Torvalds 101da177e4SLinus Torvalds MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); 111da177e4SLinus Torvalds MODULE_DESCRIPTION("Finite state machine helper functions"); 121da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds fsm_instance * 151da177e4SLinus Torvalds init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, 16b4e3ca1aSAl Viro int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order) 171da177e4SLinus Torvalds { 181da177e4SLinus Torvalds int i; 191da177e4SLinus Torvalds fsm_instance *this; 201da177e4SLinus Torvalds fsm_function_t *m; 211da177e4SLinus Torvalds fsm *f; 221da177e4SLinus Torvalds 2388abaab4SEric Sesterhenn this = kzalloc(sizeof(fsm_instance), order); 241da177e4SLinus Torvalds if (this == NULL) { 251da177e4SLinus Torvalds printk(KERN_WARNING 261da177e4SLinus Torvalds "fsm(%s): init_fsm: Couldn't alloc instance\n", name); 271da177e4SLinus Torvalds return NULL; 281da177e4SLinus Torvalds } 291da177e4SLinus Torvalds strlcpy(this->name, name, sizeof(this->name)); 30*1e1815beSFrank Blaschka init_waitqueue_head(&this->wait_q); 311da177e4SLinus Torvalds 3288abaab4SEric Sesterhenn f = kzalloc(sizeof(fsm), order); 331da177e4SLinus Torvalds if (f == NULL) { 341da177e4SLinus Torvalds printk(KERN_WARNING 351da177e4SLinus Torvalds "fsm(%s): init_fsm: Couldn't alloc fsm\n", name); 361da177e4SLinus Torvalds kfree_fsm(this); 371da177e4SLinus Torvalds return NULL; 381da177e4SLinus Torvalds } 391da177e4SLinus Torvalds f->nr_events = nr_events; 401da177e4SLinus Torvalds f->nr_states = nr_states; 411da177e4SLinus Torvalds f->event_names = event_names; 421da177e4SLinus Torvalds f->state_names = state_names; 431da177e4SLinus Torvalds this->f = f; 441da177e4SLinus Torvalds 4588abaab4SEric Sesterhenn m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order); 461da177e4SLinus Torvalds if (m == NULL) { 471da177e4SLinus Torvalds printk(KERN_WARNING 481da177e4SLinus Torvalds "fsm(%s): init_fsm: Couldn't alloc jumptable\n", name); 491da177e4SLinus Torvalds kfree_fsm(this); 501da177e4SLinus Torvalds return NULL; 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds f->jumpmatrix = m; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds for (i = 0; i < tmpl_len; i++) { 551da177e4SLinus Torvalds if ((tmpl[i].cond_state >= nr_states) || 561da177e4SLinus Torvalds (tmpl[i].cond_event >= nr_events) ) { 571da177e4SLinus Torvalds printk(KERN_ERR 581da177e4SLinus Torvalds "fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n", 591da177e4SLinus Torvalds name, i, (long)tmpl[i].cond_state, (long)f->nr_states, 601da177e4SLinus Torvalds (long)tmpl[i].cond_event, (long)f->nr_events); 611da177e4SLinus Torvalds kfree_fsm(this); 621da177e4SLinus Torvalds return NULL; 631da177e4SLinus Torvalds } else 641da177e4SLinus Torvalds m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] = 651da177e4SLinus Torvalds tmpl[i].function; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds return this; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds void 711da177e4SLinus Torvalds kfree_fsm(fsm_instance *this) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds if (this) { 741da177e4SLinus Torvalds if (this->f) { 751da177e4SLinus Torvalds kfree(this->f->jumpmatrix); 761da177e4SLinus Torvalds kfree(this->f); 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds kfree(this); 791da177e4SLinus Torvalds } else 801da177e4SLinus Torvalds printk(KERN_WARNING 811da177e4SLinus Torvalds "fsm: kfree_fsm called with NULL argument\n"); 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY 851da177e4SLinus Torvalds void 861da177e4SLinus Torvalds fsm_print_history(fsm_instance *fi) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds int idx = 0; 891da177e4SLinus Torvalds int i; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds if (fi->history_size >= FSM_HISTORY_SIZE) 921da177e4SLinus Torvalds idx = fi->history_index; 931da177e4SLinus Torvalds 941da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): History:\n", fi->name); 951da177e4SLinus Torvalds for (i = 0; i < fi->history_size; i++) { 961da177e4SLinus Torvalds int e = fi->history[idx].event; 971da177e4SLinus Torvalds int s = fi->history[idx++].state; 981da177e4SLinus Torvalds idx %= FSM_HISTORY_SIZE; 991da177e4SLinus Torvalds if (e == -1) 1001da177e4SLinus Torvalds printk(KERN_DEBUG " S=%s\n", 1011da177e4SLinus Torvalds fi->f->state_names[s]); 1021da177e4SLinus Torvalds else 1031da177e4SLinus Torvalds printk(KERN_DEBUG " S=%s E=%s\n", 1041da177e4SLinus Torvalds fi->f->state_names[s], 1051da177e4SLinus Torvalds fi->f->event_names[e]); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds fi->history_size = fi->history_index = 0; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds void 1111da177e4SLinus Torvalds fsm_record_history(fsm_instance *fi, int state, int event) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds fi->history[fi->history_index].state = state; 1141da177e4SLinus Torvalds fi->history[fi->history_index++].event = event; 1151da177e4SLinus Torvalds fi->history_index %= FSM_HISTORY_SIZE; 1161da177e4SLinus Torvalds if (fi->history_size < FSM_HISTORY_SIZE) 1171da177e4SLinus Torvalds fi->history_size++; 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds #endif 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds const char * 1221da177e4SLinus Torvalds fsm_getstate_str(fsm_instance *fi) 1231da177e4SLinus Torvalds { 1241da177e4SLinus Torvalds int st = atomic_read(&fi->state); 1251da177e4SLinus Torvalds if (st >= fi->f->nr_states) 1261da177e4SLinus Torvalds return "Invalid"; 1271da177e4SLinus Torvalds return fi->f->state_names[st]; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds static void 1311da177e4SLinus Torvalds fsm_expire_timer(fsm_timer *this) 1321da177e4SLinus Torvalds { 1331da177e4SLinus Torvalds #if FSM_TIMER_DEBUG 1341da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): Timer %p expired\n", 1351da177e4SLinus Torvalds this->fi->name, this); 1361da177e4SLinus Torvalds #endif 1371da177e4SLinus Torvalds fsm_event(this->fi, this->expire_event, this->event_arg); 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds void 1411da177e4SLinus Torvalds fsm_settimer(fsm_instance *fi, fsm_timer *this) 1421da177e4SLinus Torvalds { 1431da177e4SLinus Torvalds this->fi = fi; 1441da177e4SLinus Torvalds this->tl.function = (void *)fsm_expire_timer; 1451da177e4SLinus Torvalds this->tl.data = (long)this; 1461da177e4SLinus Torvalds #if FSM_TIMER_DEBUG 1471da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name, 1481da177e4SLinus Torvalds this); 1491da177e4SLinus Torvalds #endif 1501da177e4SLinus Torvalds init_timer(&this->tl); 1511da177e4SLinus Torvalds } 1521da177e4SLinus Torvalds 1531da177e4SLinus Torvalds void 1541da177e4SLinus Torvalds fsm_deltimer(fsm_timer *this) 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds #if FSM_TIMER_DEBUG 1571da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name, 1581da177e4SLinus Torvalds this); 1591da177e4SLinus Torvalds #endif 1601da177e4SLinus Torvalds del_timer(&this->tl); 1611da177e4SLinus Torvalds } 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds int 1641da177e4SLinus Torvalds fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg) 1651da177e4SLinus Torvalds { 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds #if FSM_TIMER_DEBUG 1681da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n", 1691da177e4SLinus Torvalds this->fi->name, this, millisec); 1701da177e4SLinus Torvalds #endif 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds init_timer(&this->tl); 1731da177e4SLinus Torvalds this->tl.function = (void *)fsm_expire_timer; 1741da177e4SLinus Torvalds this->tl.data = (long)this; 1751da177e4SLinus Torvalds this->expire_event = event; 1761da177e4SLinus Torvalds this->event_arg = arg; 1771da177e4SLinus Torvalds this->tl.expires = jiffies + (millisec * HZ) / 1000; 1781da177e4SLinus Torvalds add_timer(&this->tl); 1791da177e4SLinus Torvalds return 0; 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds /* FIXME: this function is never used, why */ 1831da177e4SLinus Torvalds void 1841da177e4SLinus Torvalds fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg) 1851da177e4SLinus Torvalds { 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds #if FSM_TIMER_DEBUG 1881da177e4SLinus Torvalds printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n", 1891da177e4SLinus Torvalds this->fi->name, this, millisec); 1901da177e4SLinus Torvalds #endif 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds del_timer(&this->tl); 1931da177e4SLinus Torvalds init_timer(&this->tl); 1941da177e4SLinus Torvalds this->tl.function = (void *)fsm_expire_timer; 1951da177e4SLinus Torvalds this->tl.data = (long)this; 1961da177e4SLinus Torvalds this->expire_event = event; 1971da177e4SLinus Torvalds this->event_arg = arg; 1981da177e4SLinus Torvalds this->tl.expires = jiffies + (millisec * HZ) / 1000; 1991da177e4SLinus Torvalds add_timer(&this->tl); 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds EXPORT_SYMBOL(init_fsm); 2031da177e4SLinus Torvalds EXPORT_SYMBOL(kfree_fsm); 2041da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_settimer); 2051da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_deltimer); 2061da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_addtimer); 2071da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_modtimer); 2081da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_getstate_str); 2091da177e4SLinus Torvalds 2101da177e4SLinus Torvalds #if FSM_DEBUG_HISTORY 2111da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_print_history); 2121da177e4SLinus Torvalds EXPORT_SYMBOL(fsm_record_history); 2131da177e4SLinus Torvalds #endif 214