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