fsm.h 6.2 KB

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