fsm.h 6.3 KB

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