0001
0002
0003
0004
0005
0006
0007 #include "fsm.h"
0008 #include <linux/module.h>
0009 #include <linux/slab.h>
0010 #include <linux/timer.h>
0011
0012 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
0013 MODULE_DESCRIPTION("Finite state machine helper functions");
0014 MODULE_LICENSE("GPL");
0015
0016 fsm_instance *
0017 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
0018 int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)
0019 {
0020 int i;
0021 fsm_instance *this;
0022 fsm_function_t *m;
0023 fsm *f;
0024
0025 this = kzalloc(sizeof(fsm_instance), order);
0026 if (this == NULL) {
0027 printk(KERN_WARNING
0028 "fsm(%s): init_fsm: Couldn't alloc instance\n", name);
0029 return NULL;
0030 }
0031 strlcpy(this->name, name, sizeof(this->name));
0032 init_waitqueue_head(&this->wait_q);
0033
0034 f = kzalloc(sizeof(fsm), order);
0035 if (f == NULL) {
0036 printk(KERN_WARNING
0037 "fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
0038 kfree_fsm(this);
0039 return NULL;
0040 }
0041 f->nr_events = nr_events;
0042 f->nr_states = nr_states;
0043 f->event_names = event_names;
0044 f->state_names = state_names;
0045 this->f = f;
0046
0047 m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);
0048 if (m == NULL) {
0049 printk(KERN_WARNING
0050 "fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
0051 kfree_fsm(this);
0052 return NULL;
0053 }
0054 f->jumpmatrix = m;
0055
0056 for (i = 0; i < tmpl_len; i++) {
0057 if ((tmpl[i].cond_state >= nr_states) ||
0058 (tmpl[i].cond_event >= nr_events) ) {
0059 printk(KERN_ERR
0060 "fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
0061 name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
0062 (long)tmpl[i].cond_event, (long)f->nr_events);
0063 kfree_fsm(this);
0064 return NULL;
0065 } else
0066 m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
0067 tmpl[i].function;
0068 }
0069 return this;
0070 }
0071
0072 void
0073 kfree_fsm(fsm_instance *this)
0074 {
0075 if (this) {
0076 if (this->f) {
0077 kfree(this->f->jumpmatrix);
0078 kfree(this->f);
0079 }
0080 kfree(this);
0081 } else
0082 printk(KERN_WARNING
0083 "fsm: kfree_fsm called with NULL argument\n");
0084 }
0085
0086 #if FSM_DEBUG_HISTORY
0087 void
0088 fsm_print_history(fsm_instance *fi)
0089 {
0090 int idx = 0;
0091 int i;
0092
0093 if (fi->history_size >= FSM_HISTORY_SIZE)
0094 idx = fi->history_index;
0095
0096 printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
0097 for (i = 0; i < fi->history_size; i++) {
0098 int e = fi->history[idx].event;
0099 int s = fi->history[idx++].state;
0100 idx %= FSM_HISTORY_SIZE;
0101 if (e == -1)
0102 printk(KERN_DEBUG " S=%s\n",
0103 fi->f->state_names[s]);
0104 else
0105 printk(KERN_DEBUG " S=%s E=%s\n",
0106 fi->f->state_names[s],
0107 fi->f->event_names[e]);
0108 }
0109 fi->history_size = fi->history_index = 0;
0110 }
0111
0112 void
0113 fsm_record_history(fsm_instance *fi, int state, int event)
0114 {
0115 fi->history[fi->history_index].state = state;
0116 fi->history[fi->history_index++].event = event;
0117 fi->history_index %= FSM_HISTORY_SIZE;
0118 if (fi->history_size < FSM_HISTORY_SIZE)
0119 fi->history_size++;
0120 }
0121 #endif
0122
0123 const char *
0124 fsm_getstate_str(fsm_instance *fi)
0125 {
0126 int st = atomic_read(&fi->state);
0127 if (st >= fi->f->nr_states)
0128 return "Invalid";
0129 return fi->f->state_names[st];
0130 }
0131
0132 static void
0133 fsm_expire_timer(struct timer_list *t)
0134 {
0135 fsm_timer *this = from_timer(this, t, tl);
0136 #if FSM_TIMER_DEBUG
0137 printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
0138 this->fi->name, this);
0139 #endif
0140 fsm_event(this->fi, this->expire_event, this->event_arg);
0141 }
0142
0143 void
0144 fsm_settimer(fsm_instance *fi, fsm_timer *this)
0145 {
0146 this->fi = fi;
0147 #if FSM_TIMER_DEBUG
0148 printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
0149 this);
0150 #endif
0151 timer_setup(&this->tl, fsm_expire_timer, 0);
0152 }
0153
0154 void
0155 fsm_deltimer(fsm_timer *this)
0156 {
0157 #if FSM_TIMER_DEBUG
0158 printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
0159 this);
0160 #endif
0161 del_timer(&this->tl);
0162 }
0163
0164 int
0165 fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
0166 {
0167
0168 #if FSM_TIMER_DEBUG
0169 printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
0170 this->fi->name, this, millisec);
0171 #endif
0172
0173 timer_setup(&this->tl, fsm_expire_timer, 0);
0174 this->expire_event = event;
0175 this->event_arg = arg;
0176 this->tl.expires = jiffies + (millisec * HZ) / 1000;
0177 add_timer(&this->tl);
0178 return 0;
0179 }
0180
0181
0182 void
0183 fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
0184 {
0185
0186 #if FSM_TIMER_DEBUG
0187 printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
0188 this->fi->name, this, millisec);
0189 #endif
0190
0191 del_timer(&this->tl);
0192 timer_setup(&this->tl, fsm_expire_timer, 0);
0193 this->expire_event = event;
0194 this->event_arg = arg;
0195 this->tl.expires = jiffies + (millisec * HZ) / 1000;
0196 add_timer(&this->tl);
0197 }
0198
0199 EXPORT_SYMBOL(init_fsm);
0200 EXPORT_SYMBOL(kfree_fsm);
0201 EXPORT_SYMBOL(fsm_settimer);
0202 EXPORT_SYMBOL(fsm_deltimer);
0203 EXPORT_SYMBOL(fsm_addtimer);
0204 EXPORT_SYMBOL(fsm_modtimer);
0205 EXPORT_SYMBOL(fsm_getstate_str);
0206
0207 #if FSM_DEBUG_HISTORY
0208 EXPORT_SYMBOL(fsm_print_history);
0209 EXPORT_SYMBOL(fsm_record_history);
0210 #endif