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