Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * A generic FSM based on fsm used in isdn4linux
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 /* FIXME: this function is never used, why */
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