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