Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #ifndef _FSM_H_
0003 #define _FSM_H_
0004 
0005 #include <linux/kernel.h>
0006 #include <linux/types.h>
0007 #include <linux/timer.h>
0008 #include <linux/time.h>
0009 #include <linux/slab.h>
0010 #include <linux/sched.h>
0011 #include <linux/string.h>
0012 #include <linux/atomic.h>
0013 
0014 /**
0015  * Define this to get debugging messages.
0016  */
0017 #define FSM_DEBUG         0
0018 
0019 /**
0020  * Define this to get debugging massages for
0021  * timer handling.
0022  */
0023 #define FSM_TIMER_DEBUG   0
0024 
0025 /**
0026  * Define these to record a history of
0027  * Events/Statechanges and print it if a
0028  * action_function is not found.
0029  */
0030 #define FSM_DEBUG_HISTORY 0
0031 #define FSM_HISTORY_SIZE  40
0032 
0033 struct fsm_instance_t;
0034 
0035 /**
0036  * Definition of an action function, called by a FSM
0037  */
0038 typedef void (*fsm_function_t)(struct fsm_instance_t *, int, void *);
0039 
0040 /**
0041  * Internal jump table for a FSM
0042  */
0043 typedef struct {
0044     fsm_function_t *jumpmatrix;
0045     int nr_events;
0046     int nr_states;
0047     const char **event_names;
0048     const char **state_names;
0049 } fsm;
0050 
0051 #if FSM_DEBUG_HISTORY
0052 /**
0053  * Element of State/Event history used for debugging.
0054  */
0055 typedef struct {
0056     int state;
0057     int event;
0058 } fsm_history;
0059 #endif
0060 
0061 /**
0062  * Representation of a FSM
0063  */
0064 typedef struct fsm_instance_t {
0065     fsm *f;
0066     atomic_t state;
0067     char name[16];
0068     void *userdata;
0069     int userint;
0070     wait_queue_head_t wait_q;
0071 #if FSM_DEBUG_HISTORY
0072     int         history_index;
0073     int         history_size;
0074     fsm_history history[FSM_HISTORY_SIZE];
0075 #endif
0076 } fsm_instance;
0077 
0078 /**
0079  * Description of a state-event combination
0080  */
0081 typedef struct {
0082     int cond_state;
0083     int cond_event;
0084     fsm_function_t function;
0085 } fsm_node;
0086 
0087 /**
0088  * Description of a FSM Timer.
0089  */
0090 typedef struct {
0091     fsm_instance *fi;
0092     struct timer_list tl;
0093     int expire_event;
0094     void *event_arg;
0095 } fsm_timer;
0096 
0097 /**
0098  * Creates an FSM
0099  *
0100  * @param name        Name of this instance for logging purposes.
0101  * @param state_names An array of names for all states for logging purposes.
0102  * @param event_names An array of names for all events for logging purposes.
0103  * @param nr_states   Number of states for this instance.
0104  * @param nr_events   Number of events for this instance.
0105  * @param tmpl        An array of fsm_nodes, describing this FSM.
0106  * @param tmpl_len    Length of the describing array.
0107  * @param order       Parameter for allocation of the FSM data structs.
0108  */
0109 extern fsm_instance *
0110 init_fsm(char *name, const char **state_names,
0111      const char **event_names,
0112      int nr_states, int nr_events, const fsm_node *tmpl,
0113      int tmpl_len, gfp_t order);
0114 
0115 /**
0116  * Releases an FSM
0117  *
0118  * @param fi Pointer to an FSM, previously created with init_fsm.
0119  */
0120 extern void kfree_fsm(fsm_instance *fi);
0121 
0122 #if FSM_DEBUG_HISTORY
0123 extern void
0124 fsm_print_history(fsm_instance *fi);
0125 
0126 extern void
0127 fsm_record_history(fsm_instance *fi, int state, int event);
0128 #endif
0129 
0130 /**
0131  * Emits an event to a FSM.
0132  * If an action function is defined for the current state/event combination,
0133  * this function is called.
0134  *
0135  * @param fi    Pointer to FSM which should receive the event.
0136  * @param event The event do be delivered.
0137  * @param arg   A generic argument, handed to the action function.
0138  *
0139  * @return      0  on success,
0140  *              1  if current state or event is out of range
0141  *              !0 if state and event in range, but no action defined.
0142  */
0143 static inline int
0144 fsm_event(fsm_instance *fi, int event, void *arg)
0145 {
0146     fsm_function_t r;
0147     int state = atomic_read(&fi->state);
0148 
0149     if ((state >= fi->f->nr_states) ||
0150         (event >= fi->f->nr_events)       ) {
0151         printk(KERN_ERR "fsm(%s): Invalid state st(%ld/%ld) ev(%d/%ld)\n",
0152             fi->name, (long)state,(long)fi->f->nr_states, event,
0153             (long)fi->f->nr_events);
0154 #if FSM_DEBUG_HISTORY
0155         fsm_print_history(fi);
0156 #endif
0157         return 1;
0158     }
0159     r = fi->f->jumpmatrix[fi->f->nr_states * event + state];
0160     if (r) {
0161 #if FSM_DEBUG
0162         printk(KERN_DEBUG "fsm(%s): state %s event %s\n",
0163                fi->name, fi->f->state_names[state],
0164                fi->f->event_names[event]);
0165 #endif
0166 #if FSM_DEBUG_HISTORY
0167         fsm_record_history(fi, state, event);
0168 #endif
0169         r(fi, event, arg);
0170         return 0;
0171     } else {
0172 #if FSM_DEBUG || FSM_DEBUG_HISTORY
0173         printk(KERN_DEBUG "fsm(%s): no function for event %s in state %s\n",
0174                fi->name, fi->f->event_names[event],
0175                fi->f->state_names[state]);
0176 #endif
0177 #if FSM_DEBUG_HISTORY
0178         fsm_print_history(fi);
0179 #endif
0180         return !0;
0181     }
0182 }
0183 
0184 /**
0185  * Modifies the state of an FSM.
0186  * This does <em>not</em> trigger an event or calls an action function.
0187  *
0188  * @param fi    Pointer to FSM
0189  * @param state The new state for this FSM.
0190  */
0191 static inline void
0192 fsm_newstate(fsm_instance *fi, int newstate)
0193 {
0194     atomic_set(&fi->state,newstate);
0195 #if FSM_DEBUG_HISTORY
0196     fsm_record_history(fi, newstate, -1);
0197 #endif
0198 #if FSM_DEBUG
0199     printk(KERN_DEBUG "fsm(%s): New state %s\n", fi->name,
0200         fi->f->state_names[newstate]);
0201 #endif
0202     wake_up(&fi->wait_q);
0203 }
0204 
0205 /**
0206  * Retrieves the state of an FSM
0207  *
0208  * @param fi Pointer to FSM
0209  *
0210  * @return The current state of the FSM.
0211  */
0212 static inline int
0213 fsm_getstate(fsm_instance *fi)
0214 {
0215     return atomic_read(&fi->state);
0216 }
0217 
0218 /**
0219  * Retrieves the name of the state of an FSM
0220  *
0221  * @param fi Pointer to FSM
0222  *
0223  * @return The current state of the FSM in a human readable form.
0224  */
0225 extern const char *fsm_getstate_str(fsm_instance *fi);
0226 
0227 /**
0228  * Initializes a timer for an FSM.
0229  * This prepares an fsm_timer for usage with fsm_addtimer.
0230  *
0231  * @param fi    Pointer to FSM
0232  * @param timer The timer to be initialized.
0233  */
0234 extern void fsm_settimer(fsm_instance *fi, fsm_timer *);
0235 
0236 /**
0237  * Clears a pending timer of an FSM instance.
0238  *
0239  * @param timer The timer to clear.
0240  */
0241 extern void fsm_deltimer(fsm_timer *timer);
0242 
0243 /**
0244  * Adds and starts a timer to an FSM instance.
0245  *
0246  * @param timer    The timer to be added. The field fi of that timer
0247  *                 must have been set to point to the instance.
0248  * @param millisec Duration, after which the timer should expire.
0249  * @param event    Event, to trigger if timer expires.
0250  * @param arg      Generic argument, provided to expiry function.
0251  *
0252  * @return         0 on success, -1 if timer is already active.
0253  */
0254 extern int fsm_addtimer(fsm_timer *timer, int millisec, int event, void *arg);
0255 
0256 /**
0257  * Modifies a timer of an FSM.
0258  *
0259  * @param timer    The timer to modify.
0260  * @param millisec Duration, after which the timer should expire.
0261  * @param event    Event, to trigger if timer expires.
0262  * @param arg      Generic argument, provided to expiry function.
0263  */
0264 extern void fsm_modtimer(fsm_timer *timer, int millisec, int event, void *arg);
0265 
0266 #endif /* _FSM_H_ */