File: /usr/src/linux/drivers/s390/net/fsm.c

1     /**
2      * $Id: fsm.c,v 1.3 2001/06/18 16:49:19 felfert Exp $
3      *
4      * A generic FSM based on fsm used in isdn4linux
5      *
6      */
7     
8     #include "fsm.h"
9     #include <linux/version.h>
10     #include <linux/config.h>
11     #include <linux/module.h>
12     
13     fsm_instance *
14     init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
15     		int nr_events, const fsm_node *tmpl, int tmpl_len, int order)
16     {
17     	int i;
18     	fsm_instance *this;
19     	fsm_function_t *m;
20     	fsm *f;
21     
22     	this = (fsm_instance *)kmalloc(sizeof(fsm_instance), order);
23     	if (this == NULL) {
24     		printk(KERN_WARNING
25     			"fsm(%s): init_fsm: Couldn't alloc instance\n", name);
26     		return NULL;
27     	}
28     	memset(this, 0, sizeof(fsm_instance));
29     	strncpy(this->name, name, sizeof(this->name));
30     
31     	f = (fsm *)kmalloc(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     	memset(f, 0, sizeof(fsm));
39     	f->nr_events = nr_events;
40     	f->nr_states = nr_states;
41     	f->event_names = event_names;
42     	f->state_names = state_names;
43     	this->f = f;
44     
45     	m = (fsm_function_t *)kmalloc(
46     			sizeof(fsm_function_t) * nr_states * nr_events, 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     	memset(m, 0, sizeof(fsm_function_t) * f->nr_states * f->nr_events);
54     	f->jumpmatrix = m;
55     
56     	for (i = 0; i < tmpl_len; i++) {
57     		if ((tmpl[i].cond_state >= nr_states) ||
58     		    (tmpl[i].cond_event >= nr_events)   ) {
59     			printk(KERN_ERR
60     				"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",
61     				name, i, (long)tmpl[i].cond_state, (long)f->nr_states,
62     				(long)tmpl[i].cond_event, (long)f->nr_events);
63     			kfree_fsm(this);
64     			return NULL;
65     		} else
66     			m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =
67     				tmpl[i].function;
68     	}
69     	return this;
70     }
71     
72     void
73     kfree_fsm(fsm_instance *this)
74     {
75     	if (this) {
76     		if (this->f) {
77     			if (this->f->jumpmatrix)
78     				kfree(this->f->jumpmatrix);
79     			kfree(this->f);
80     		}
81     		kfree(this);
82     	} else
83     		printk(KERN_WARNING
84     			"fsm: kfree_fsm called with NULL argument\n");
85     }
86     
87     #if FSM_DEBUG_HISTORY
88     void
89     fsm_print_history(fsm_instance *fi)
90     {
91     	int idx = 0;
92     	int i;
93     
94     	if (fi->history_size >= FSM_HISTORY_SIZE)
95     		idx = fi->history_index;
96     
97     	printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);
98     	for (i = 0; i < fi->history_size; i++) {
99     		int e = fi->history[idx].event;
100     		int s = fi->history[idx++].state;
101     		idx %= FSM_HISTORY_SIZE;
102     		if (e == -1)
103     			printk(KERN_DEBUG "  S=%s\n",
104     			       fi->f->state_names[s]);
105     		else
106     			printk(KERN_DEBUG "  S=%s E=%s\n",
107     			       fi->f->state_names[s],
108     			       fi->f->event_names[e]);
109     	}
110     	fi->history_size = fi->history_index = 0;
111     }
112     
113     void
114     fsm_record_history(fsm_instance *fi, int state, int event)
115     {
116     	fi->history[fi->history_index].state = state;
117     	fi->history[fi->history_index++].event = event;
118     	fi->history_index %= FSM_HISTORY_SIZE;
119     	if (fi->history_size < FSM_HISTORY_SIZE)
120     		fi->history_size++;
121     }
122     #endif
123     
124     const char *
125     fsm_getstate_str(fsm_instance *fi)
126     {
127     	int st = atomic_read(&fi->state);
128     	if (st >= fi->f->nr_states)
129     		return "Invalid";
130     	return fi->f->state_names[st];
131     }
132     
133     static void
134     fsm_expire_timer(fsm_timer *this)
135     {
136     #if FSM_TIMER_DEBUG
137     	printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",
138     	       this->fi->name, this);
139     #endif
140     	fsm_event(this->fi, this->expire_event, this->event_arg);
141     }
142     
143     void
144     fsm_settimer(fsm_instance *fi, fsm_timer *this)
145     {
146     	this->fi = fi;
147     	this->tl.function = (void *)fsm_expire_timer;
148     	this->tl.data = (long)this;
149     #if FSM_TIMER_DEBUG
150     	printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,
151     	       this);
152     #endif
153     	init_timer(&this->tl);
154     }
155     
156     void
157     fsm_deltimer(fsm_timer *this)
158     {
159     #if FSM_TIMER_DEBUG
160     	printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,
161     		this);
162     #endif
163     	del_timer(&this->tl);
164     }
165     
166     int
167     fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)
168     {
169     
170     #if FSM_TIMER_DEBUG
171     	printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",
172     	       this->fi->name, this, millisec);
173     #endif
174     
175     #if LINUX_VERSION_CODE >= 0x020300
176     	if (this->tl.list.next || this->tl.list.prev) {
177     		printk(KERN_WARNING "fsm(%s): timer already active!\n",
178     			this->fi->name);
179     		return -1;
180     	}
181     #else
182     	if (this->tl.next || this->tl.prev) {
183     		printk(KERN_WARNING "fsm(%s): timer already active!\n",
184     			this->fi->name);
185     		return -1;
186     	}
187     #endif
188     	init_timer(&this->tl);
189     	this->tl.function = (void *)fsm_expire_timer;
190     	this->tl.data = (long)this;
191     	this->expire_event = event;
192     	this->event_arg = arg;
193     	this->tl.expires = jiffies + (millisec * HZ) / 1000;
194     	add_timer(&this->tl);
195     	return 0;
196     }
197     
198     void
199     fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
200     {
201     
202     #if FSM_TIMER_DEBUG
203     	printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",
204     		this->fi->name, this, millisec);
205     #endif
206     
207     #if LINUX_VERSION_CODE >= 0x020300
208     	if (this->tl.list.next || this->tl.list.prev)
209     		del_timer(&this->tl);
210     #else
211     	if (this->tl.next || this->tl.prev)
212     		del_timer(&this->tl);
213     #endif
214     	init_timer(&this->tl);
215     	this->tl.function = (void *)fsm_expire_timer;
216     	this->tl.data = (long)this;
217     	this->expire_event = event;
218     	this->event_arg = arg;
219     	this->tl.expires = jiffies + (millisec * HZ) / 1000;
220     	add_timer(&this->tl);
221     }
222     
223     EXPORT_SYMBOL(init_fsm);
224     EXPORT_SYMBOL(kfree_fsm);
225     EXPORT_SYMBOL(fsm_settimer);
226     EXPORT_SYMBOL(fsm_deltimer);
227     EXPORT_SYMBOL(fsm_addtimer);
228     EXPORT_SYMBOL(fsm_modtimer);
229     EXPORT_SYMBOL(fsm_getstate_str);
230     
231     #if FSM_DEBUG_HISTORY
232     EXPORT_SYMBOL(fsm_print_history);
233     EXPORT_SYMBOL(fsm_record_history);
234     #endif
235