fsm.h 6.3 KB

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