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 <linux/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 wait_queue_head_t wait_q; 70 #if FSM_DEBUG_HISTORY 71 int history_index; 72 int history_size; 73 fsm_history history[FSM_HISTORY_SIZE]; 74 #endif 75 } fsm_instance; 76 77 /** 78 * Description of a state-event combination 79 */ 80 typedef struct { 81 int cond_state; 82 int cond_event; 83 fsm_function_t function; 84 } fsm_node; 85 86 /** 87 * Description of a FSM Timer. 88 */ 89 typedef struct { 90 fsm_instance *fi; 91 struct timer_list tl; 92 int expire_event; 93 void *event_arg; 94 } fsm_timer; 95 96 /** 97 * Creates an FSM 98 * 99 * @param name Name of this instance for logging purposes. 100 * @param state_names An array of names for all states for logging purposes. 101 * @param event_names An array of names for all events for logging purposes. 102 * @param nr_states Number of states for this instance. 103 * @param nr_events Number of events for this instance. 104 * @param tmpl An array of fsm_nodes, describing this FSM. 105 * @param tmpl_len Length of the describing array. 106 * @param order Parameter for allocation of the FSM data structs. 107 */ 108 extern fsm_instance * 109 init_fsm(char *name, const char **state_names, 110 const char **event_names, 111 int nr_states, int nr_events, const fsm_node *tmpl, 112 int tmpl_len, gfp_t order); 113 114 /** 115 * Releases an FSM 116 * 117 * @param fi Pointer to an FSM, previously created with init_fsm. 118 */ 119 extern void kfree_fsm(fsm_instance *fi); 120 121 #if FSM_DEBUG_HISTORY 122 extern void 123 fsm_print_history(fsm_instance *fi); 124 125 extern void 126 fsm_record_history(fsm_instance *fi, int state, int event); 127 #endif 128 129 /** 130 * Emits an event to a FSM. 131 * If an action function is defined for the current state/event combination, 132 * this function is called. 133 * 134 * @param fi Pointer to FSM which should receive the event. 135 * @param event The event do be delivered. 136 * @param arg A generic argument, handed to the action function. 137 * 138 * @return 0 on success, 139 * 1 if current state or event is out of range 140 * !0 if state and event in range, but no action defined. 141 */ 142 static inline int 143 fsm_event(fsm_instance *fi, int event, void *arg) 144 { 145 fsm_function_t r; 146 int state = atomic_read(&fi->state); 147 148 if ((state >= fi->f->nr_states) || 149 (event >= fi->f->nr_events) ) { 150 printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n", 151 fi->name, (long)state,(long)fi->f->nr_states, event, 152 (long)fi->f->nr_events); 153 #if FSM_DEBUG_HISTORY 154 fsm_print_history(fi); 155 #endif 156 return 1; 157 } 158 r = fi->f->jumpmatrix[fi->f->nr_states * event + state]; 159 if (r) { 160 #if FSM_DEBUG 161 printk(KERN_DEBUG "fsm(%s): state %s event %s\n", 162 fi->name, fi->f->state_names[state], 163 fi->f->event_names[event]); 164 #endif 165 #if FSM_DEBUG_HISTORY 166 fsm_record_history(fi, state, event); 167 #endif 168 r(fi, event, arg); 169 return 0; 170 } else { 171 #if FSM_DEBUG || FSM_DEBUG_HISTORY 172 printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n", 173 fi->name, fi->f->event_names[event], 174 fi->f->state_names[state]); 175 #endif 176 #if FSM_DEBUG_HISTORY 177 fsm_print_history(fi); 178 #endif 179 return !0; 180 } 181 } 182 183 /** 184 * Modifies the state of an FSM. 185 * This does <em>not</em> trigger an event or calls an action function. 186 * 187 * @param fi Pointer to FSM 188 * @param state The new state for this FSM. 189 */ 190 static inline void 191 fsm_newstate(fsm_instance *fi, int newstate) 192 { 193 atomic_set(&fi->state,newstate); 194 #if FSM_DEBUG_HISTORY 195 fsm_record_history(fi, newstate, -1); 196 #endif 197 #if FSM_DEBUG 198 printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name, 199 fi->f->state_names[newstate]); 200 #endif 201 wake_up(&fi->wait_q); 202 } 203 204 /** 205 * Retrieves the state of an FSM 206 * 207 * @param fi Pointer to FSM 208 * 209 * @return The current state of the FSM. 210 */ 211 static inline int 212 fsm_getstate(fsm_instance *fi) 213 { 214 return atomic_read(&fi->state); 215 } 216 217 /** 218 * Retrieves the name of the state of an FSM 219 * 220 * @param fi Pointer to FSM 221 * 222 * @return The current state of the FSM in a human readable form. 223 */ 224 extern const char *fsm_getstate_str(fsm_instance *fi); 225 226 /** 227 * Initializes a timer for an FSM. 228 * This prepares an fsm_timer for usage with fsm_addtimer. 229 * 230 * @param fi Pointer to FSM 231 * @param timer The timer to be initialized. 232 */ 233 extern void fsm_settimer(fsm_instance *fi, fsm_timer *); 234 235 /** 236 * Clears a pending timer of an FSM instance. 237 * 238 * @param timer The timer to clear. 239 */ 240 extern void fsm_deltimer(fsm_timer *timer); 241 242 /** 243 * Adds and starts a timer to an FSM instance. 244 * 245 * @param timer The timer to be added. The field fi of that timer 246 * must have been set to point to the instance. 247 * @param millisec Duration, after which the timer should expire. 248 * @param event Event, to trigger if timer expires. 249 * @param arg Generic argument, provided to expiry function. 250 * 251 * @return 0 on success, -1 if timer is already active. 252 */ 253 extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg); 254 255 /** 256 * Modifies a timer of an FSM. 257 * 258 * @param timer The timer to modify. 259 * @param millisec Duration, after which the timer should expire. 260 * @param event Event, to trigger if timer expires. 261 * @param arg Generic argument, provided to expiry function. 262 */ 263 extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg); 264 265 #endif /* _FSM_H_ */ 266