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