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