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 32 struct fsm_instance_t; 33 34 /** 35 * Definition of an action function, called by a FSM 36 */ 37 typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *); 38 39 /** 40 * Internal jump table for a FSM 41 */ 42 typedef 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 */ 54 typedef struct { 55 int state; 56 int event; 57 } fsm_history; 58 #endif 59 60 /** 61 * Representation of a FSM 62 */ 63 typedef 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 */ 79 typedef 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 */ 88 typedef 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 */ 107 extern fsm_instance * 108 init_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 */ 118 extern void kfree_fsm(fsm_instance *fi); 119 120 #if FSM_DEBUG_HISTORY 121 extern void 122 fsm_print_history(fsm_instance *fi); 123 124 extern void 125 fsm_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 */ 141 static inline int 142 fsm_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 */ 189 static inline void 190 fsm_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 */ 209 static inline int 210 fsm_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 */ 222 extern 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 */ 231 extern 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 */ 238 extern 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 */ 251 extern 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 */ 261 extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg); 262 263 #endif /* _FSM_H_ */ 264