Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | #ifndef _FSM_H_ #define _FSM_H_ #include <linux/kernel.h> #include <linux/types.h> #include <linux/timer.h> #include <linux/time.h> #include <linux/slab.h> #include <linux/sched.h> #include <linux/string.h> #include <linux/atomic.h> /** * Define this to get debugging messages. */ #define FSM_DEBUG 0 /** * Define this to get debugging massages for * timer handling. */ #define FSM_TIMER_DEBUG 0 /** * Define these to record a history of * Events/Statechanges and print it if a * action_function is not found. */ #define FSM_DEBUG_HISTORY 0 #define FSM_HISTORY_SIZE 40 struct fsm_instance_t; /** * Definition of an action function, called by a FSM */ typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *); /** * Internal jump table for a FSM */ typedef struct { fsm_function_t *jumpmatrix; int nr_events; int nr_states; const char **event_names; const char **state_names; } fsm; #if FSM_DEBUG_HISTORY /** * Element of State/Event history used for debugging. */ typedef struct { int state; int event; } fsm_history; #endif /** * Representation of a FSM */ typedef struct fsm_instance_t { fsm *f; atomic_t state; char name[16]; void *userdata; int userint; wait_queue_head_t wait_q; #if FSM_DEBUG_HISTORY int history_index; int history_size; fsm_history history[FSM_HISTORY_SIZE]; #endif } fsm_instance; /** * Description of a state-event combination */ typedef struct { int cond_state; int cond_event; fsm_function_t function; } fsm_node; /** * Description of a FSM Timer. */ typedef struct { fsm_instance *fi; struct timer_list tl; int expire_event; void *event_arg; } fsm_timer; /** * Creates an FSM * * @param name Name of this instance for logging purposes. * @param state_names An array of names for all states for logging purposes. * @param event_names An array of names for all events for logging purposes. * @param nr_states Number of states for this instance. * @param nr_events Number of events for this instance. * @param tmpl An array of fsm_nodes, describing this FSM. * @param tmpl_len Length of the describing array. * @param order Parameter for allocation of the FSM data structs. */ extern fsm_instance * init_fsm(char *name, const char **state_names, const char **event_names, int nr_states, int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order); /** * Releases an FSM * * @param fi Pointer to an FSM, previously created with init_fsm. */ extern void kfree_fsm(fsm_instance *fi); #if FSM_DEBUG_HISTORY extern void fsm_print_history(fsm_instance *fi); extern void fsm_record_history(fsm_instance *fi, int state, int event); #endif /** * Emits an event to a FSM. * If an action function is defined for the current state/event combination, * this function is called. * * @param fi Pointer to FSM which should receive the event. * @param event The event do be delivered. * @param arg A generic argument, handed to the action function. * * @return 0 on success, * 1 if current state or event is out of range * !0 if state and event in range, but no action defined. */ static inline int fsm_event(fsm_instance *fi, int event, void *arg) { fsm_function_t r; int state = atomic_read(&fi->state); if ((state >= fi->f->nr_states) || (event >= fi->f->nr_events) ) { printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n", fi->name, (long)state,(long)fi->f->nr_states, event, (long)fi->f->nr_events); #if FSM_DEBUG_HISTORY fsm_print_history(fi); #endif return 1; } r = fi->f->jumpmatrix[fi->f->nr_states * event + state]; if (r) { #if FSM_DEBUG printk(KERN_DEBUG "fsm(%s): state %s event %s\n", fi->name, fi->f->state_names[state], fi->f->event_names[event]); #endif #if FSM_DEBUG_HISTORY fsm_record_history(fi, state, event); #endif r(fi, event, arg); return 0; } else { #if FSM_DEBUG || FSM_DEBUG_HISTORY printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n", fi->name, fi->f->event_names[event], fi->f->state_names[state]); #endif #if FSM_DEBUG_HISTORY fsm_print_history(fi); #endif return !0; } } /** * Modifies the state of an FSM. * This does <em>not</em> trigger an event or calls an action function. * * @param fi Pointer to FSM * @param state The new state for this FSM. */ static inline void fsm_newstate(fsm_instance *fi, int newstate) { atomic_set(&fi->state,newstate); #if FSM_DEBUG_HISTORY fsm_record_history(fi, newstate, -1); #endif #if FSM_DEBUG printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name, fi->f->state_names[newstate]); #endif wake_up(&fi->wait_q); } /** * Retrieves the state of an FSM * * @param fi Pointer to FSM * * @return The current state of the FSM. */ static inline int fsm_getstate(fsm_instance *fi) { return atomic_read(&fi->state); } /** * Retrieves the name of the state of an FSM * * @param fi Pointer to FSM * * @return The current state of the FSM in a human readable form. */ extern const char *fsm_getstate_str(fsm_instance *fi); /** * Initializes a timer for an FSM. * This prepares an fsm_timer for usage with fsm_addtimer. * * @param fi Pointer to FSM * @param timer The timer to be initialized. */ extern void fsm_settimer(fsm_instance *fi, fsm_timer *); /** * Clears a pending timer of an FSM instance. * * @param timer The timer to clear. */ extern void fsm_deltimer(fsm_timer *timer); /** * Adds and starts a timer to an FSM instance. * * @param timer The timer to be added. The field fi of that timer * must have been set to point to the instance. * @param millisec Duration, after which the timer should expire. * @param event Event, to trigger if timer expires. * @param arg Generic argument, provided to expiry function. * * @return 0 on success, -1 if timer is already active. */ extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg); /** * Modifies a timer of an FSM. * * @param timer The timer to modify. * @param millisec Duration, after which the timer should expire. * @param event Event, to trigger if timer expires. * @param arg Generic argument, provided to expiry function. */ extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg); #endif /* _FSM_H_ */ |