linux/drivers/s390/net/fsm.c
<<
>>
Prefs
   1/**
   2 * A generic FSM based on fsm used in isdn4linux
   3 *
   4 */
   5
   6#include "fsm.h"
   7#include <linux/module.h>
   8#include <linux/slab.h>
   9#include <linux/timer.h>
  10
  11MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
  12MODULE_DESCRIPTION("Finite state machine helper functions");
  13MODULE_LICENSE("GPL");
  14
  15fsm_instance *
  16init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
  17                int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)
  18{
  19        int i;
  20        fsm_instance *this;
  21        fsm_function_t *m;
  22        fsm *f;
  23
  24        this = kzalloc(sizeof(fsm_instance), order);
  25        if (this == NULL) {
  26                printk(KERN_WARNING
  27                        "fsm(%s): init_fsm: Couldn't alloc instance\n", name);
  28                return NULL;
  29        }
  30        strlcpy(this->name, name, sizeof(this->name));
  31        init_waitqueue_head(&this->wait_q);
  32
  33        f = kzalloc(sizeof(fsm), order);
  34        if (f == NULL) {
  35                printk(KERN_WARNING
  36                        "fsm(%s): init_fsm: Couldn't alloc fsm\n", name);
  37                kfree_fsm(this);
  38                return NULL;
  39        }
  40        f->nr_events = nr_events;
  41        f->nr_states = nr_states;
  42        f->event_names = event_names;
  43        f->state_names = state_names;
  44        this->f = f;
  45
  46        m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);
  47        if (m == NULL) {
  48                printk(KERN_WARNING
  49                        "fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);
  50                kfree_fsm(this);
  51                return NULL;
  52        }
  53        f->jumpmatrix = m;
  54
  55        for (i = 0; i < tmpl_len; i++) {
  56                if ((tmpl[i].cond_state >= nr_states) ||
  57                    (tmpl[i].cond_event >= nr_events)   ) {
  58                        printk(KERN_ERR
  59                                "fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
  60                                name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
  61                                (long)tmpl[i].cond_event, (long)f->nr_events);
  62                        kfree_fsm(this);
  63                        return NULL;
  64                } else
  65                        m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
  66                                tmpl[i].function;
  67        }
  68        return this;
  69}
  70
  71void
  72kfree_fsm(fsm_instance *this)
  73{
  74        if (this) {
  75                if (this->f) {
  76                        kfree(this->f->jumpmatrix);
  77                        kfree(this->f);
  78                }
  79                kfree(this);
  80        } else
  81                printk(KERN_WARNING
  82                        "fsm: kfree_fsm called with NULL argument\n");
  83}
  84
  85#if FSM_DEBUG_HISTORY
  86void
  87fsm_print_history(fsm_instance *fi)
  88{
  89        int idx = 0;
  90        int i;
  91
  92        if (fi->history_size >= FSM_HISTORY_SIZE)
  93                idx = fi->history_index;
  94
  95        printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
  96        for (i = 0; i < fi->history_size; i++) {
  97                int e = fi->history[idx].event;
  98                int s = fi->history[idx++].state;
  99                idx %= FSM_HISTORY_SIZE;
 100                if (e == -1)
 101                        printk(KERN_DEBUG "  S=%s\n",
 102                               fi->f->state_names[s]);
 103                else
 104                        printk(KERN_DEBUG "  S=%s E=%s\n",
 105                               fi->f->state_names[s],
 106                               fi->f->event_names[e]);
 107        }
 108        fi->history_size = fi->history_index = 0;
 109}
 110
 111void
 112fsm_record_history(fsm_instance *fi, int state, int event)
 113{
 114        fi->history[fi->history_index].state = state;
 115        fi->history[fi->history_index++].event = event;
 116        fi->history_index %= FSM_HISTORY_SIZE;
 117        if (fi->history_size < FSM_HISTORY_SIZE)
 118                fi->history_size++;
 119}
 120#endif
 121
 122const char *
 123fsm_getstate_str(fsm_instance *fi)
 124{
 125        int st = atomic_read(&fi->state);
 126        if (st >= fi->f->nr_states)
 127                return "Invalid";
 128        return fi->f->state_names[st];
 129}
 130
 131static void
 132fsm_expire_timer(fsm_timer *this)
 133{
 134#if FSM_TIMER_DEBUG
 135        printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
 136               this->fi->name, this);
 137#endif
 138        fsm_event(this->fi, this->expire_event, this->event_arg);
 139}
 140
 141void
 142fsm_settimer(fsm_instance *fi, fsm_timer *this)
 143{
 144        this->fi = fi;
 145        this->tl.function = (void *)fsm_expire_timer;
 146        this->tl.data = (long)this;
 147#if FSM_TIMER_DEBUG
 148        printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
 149               this);
 150#endif
 151        init_timer(&this->tl);
 152}
 153
 154void
 155fsm_deltimer(fsm_timer *this)
 156{
 157#if FSM_TIMER_DEBUG
 158        printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
 159                this);
 160#endif
 161        del_timer(&this->tl);
 162}
 163
 164int
 165fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
 166{
 167
 168#if FSM_TIMER_DEBUG
 169        printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
 170               this->fi->name, this, millisec);
 171#endif
 172
 173        init_timer(&this->tl);
 174        this->tl.function = (void *)fsm_expire_timer;
 175        this->tl.data = (long)this;
 176        this->expire_event = event;
 177        this->event_arg = arg;
 178        this->tl.expires = jiffies + (millisec * HZ) / 1000;
 179        add_timer(&this->tl);
 180        return 0;
 181}
 182
 183/* FIXME: this function is never used, why */
 184void
 185fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
 186{
 187
 188#if FSM_TIMER_DEBUG
 189        printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
 190                this->fi->name, this, millisec);
 191#endif
 192
 193        del_timer(&this->tl);
 194        init_timer(&this->tl);
 195        this->tl.function = (void *)fsm_expire_timer;
 196        this->tl.data = (long)this;
 197        this->expire_event = event;
 198        this->event_arg = arg;
 199        this->tl.expires = jiffies + (millisec * HZ) / 1000;
 200        add_timer(&this->tl);
 201}
 202
 203EXPORT_SYMBOL(init_fsm);
 204EXPORT_SYMBOL(kfree_fsm);
 205EXPORT_SYMBOL(fsm_settimer);
 206EXPORT_SYMBOL(fsm_deltimer);
 207EXPORT_SYMBOL(fsm_addtimer);
 208EXPORT_SYMBOL(fsm_modtimer);
 209EXPORT_SYMBOL(fsm_getstate_str);
 210
 211#if FSM_DEBUG_HISTORY
 212EXPORT_SYMBOL(fsm_print_history);
 213EXPORT_SYMBOL(fsm_record_history);
 214#endif
 215