| /* SPDX-License-Identifier: GPL-2.0 */ | |
| #ifndef __TRIGGER_H_ | |
| #define __TRIGGER_H_ 1 | |
| #include "util/debug.h" | |
| #include "asm/bug.h" | |
| /* | |
| * Use trigger to model operations which need to be executed when | |
| * an event (a signal, for example) is observed. | |
| * | |
| * States and transits: | |
| * | |
| * | |
| * OFF--> ON --> READY --(hit)--> HIT | |
| * ^ | | |
| * | (ready) | |
| * | | | |
| * \_____________/ | |
| * | |
| * is_hit and is_ready are two key functions to query the state of | |
| * a trigger. is_hit means the event already happen; is_ready means the | |
| * trigger is waiting for the event. | |
| */ | |
| struct trigger { | |
| volatile enum { | |
| TRIGGER_ERROR = -2, | |
| TRIGGER_OFF = -1, | |
| TRIGGER_ON = 0, | |
| TRIGGER_READY = 1, | |
| TRIGGER_HIT = 2, | |
| } state; | |
| const char *name; | |
| }; | |
| #define TRIGGER_WARN_ONCE(t, exp) \ | |
| WARN_ONCE(t->state != exp, "trigger '%s' state transist error: %d in %s()\n", \ | |
| t->name, t->state, __func__) | |
| static inline bool trigger_is_available(struct trigger *t) | |
| { | |
| return t->state >= 0; | |
| } | |
| static inline bool trigger_is_error(struct trigger *t) | |
| { | |
| return t->state <= TRIGGER_ERROR; | |
| } | |
| static inline void trigger_on(struct trigger *t) | |
| { | |
| TRIGGER_WARN_ONCE(t, TRIGGER_OFF); | |
| t->state = TRIGGER_ON; | |
| } | |
| static inline void trigger_ready(struct trigger *t) | |
| { | |
| if (!trigger_is_available(t)) | |
| return; | |
| t->state = TRIGGER_READY; | |
| } | |
| static inline void trigger_hit(struct trigger *t) | |
| { | |
| if (!trigger_is_available(t)) | |
| return; | |
| TRIGGER_WARN_ONCE(t, TRIGGER_READY); | |
| t->state = TRIGGER_HIT; | |
| } | |
| static inline void trigger_off(struct trigger *t) | |
| { | |
| if (!trigger_is_available(t)) | |
| return; | |
| t->state = TRIGGER_OFF; | |
| } | |
| static inline void trigger_error(struct trigger *t) | |
| { | |
| t->state = TRIGGER_ERROR; | |
| } | |
| static inline bool trigger_is_ready(struct trigger *t) | |
| { | |
| return t->state == TRIGGER_READY; | |
| } | |
| static inline bool trigger_is_hit(struct trigger *t) | |
| { | |
| return t->state == TRIGGER_HIT; | |
| } | |
| #define DEFINE_TRIGGER(n) \ | |
| struct trigger n = {.state = TRIGGER_OFF, .name = #n} | |
| #endif |