brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 8672d22 Raw
211 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * A generic FSM based on fsm used in isdn4linux4 *5 */6 7#include "fsm.h"8#include <linux/module.h>9#include <linux/slab.h>10#include <linux/timer.h>11 12MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert <felfert@millenux.com>");13MODULE_DESCRIPTION("Finite state machine helper functions");14MODULE_LICENSE("GPL");15 16fsm_instance *17init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,18		int nr_events, const fsm_node *tmpl, int tmpl_len, gfp_t order)19{20	int i;21	fsm_instance *this;22	fsm_function_t *m;23	fsm *f;24 25	this = kzalloc(sizeof(fsm_instance), order);26	if (this == NULL) {27		printk(KERN_WARNING28			"fsm(%s): init_fsm: Couldn't alloc instance\n", name);29		return NULL;30	}31	strscpy(this->name, name, sizeof(this->name));32	init_waitqueue_head(&this->wait_q);33 34	f = kzalloc(sizeof(fsm), order);35	if (f == NULL) {36		printk(KERN_WARNING37			"fsm(%s): init_fsm: Couldn't alloc fsm\n", name);38		kfree_fsm(this);39		return NULL;40	}41	f->nr_events = nr_events;42	f->nr_states = nr_states;43	f->event_names = event_names;44	f->state_names = state_names;45	this->f = f;46 47	m = kcalloc(nr_states*nr_events, sizeof(fsm_function_t), order);48	if (m == NULL) {49		printk(KERN_WARNING50			"fsm(%s): init_fsm: Couldn't alloc jumptable\n", name);51		kfree_fsm(this);52		return NULL;53	}54	f->jumpmatrix = m;55 56	for (i = 0; i < tmpl_len; i++) {57		if ((tmpl[i].cond_state >= nr_states) ||58		    (tmpl[i].cond_event >= nr_events)   ) {59			printk(KERN_ERR60				"fsm(%s): init_fsm: Bad template l=%d st(%ld/%ld) ev(%ld/%ld)\n",61				name, i, (long)tmpl[i].cond_state, (long)f->nr_states,62				(long)tmpl[i].cond_event, (long)f->nr_events);63			kfree_fsm(this);64			return NULL;65		} else66			m[nr_states * tmpl[i].cond_event + tmpl[i].cond_state] =67				tmpl[i].function;68	}69	return this;70}71 72void73kfree_fsm(fsm_instance *this)74{75	if (this) {76		if (this->f) {77			kfree(this->f->jumpmatrix);78			kfree(this->f);79		}80		kfree(this);81	} else82		printk(KERN_WARNING83			"fsm: kfree_fsm called with NULL argument\n");84}85 86#if FSM_DEBUG_HISTORY87void88fsm_print_history(fsm_instance *fi)89{90	int idx = 0;91	int i;92 93	if (fi->history_size >= FSM_HISTORY_SIZE)94		idx = fi->history_index;95 96	printk(KERN_DEBUG "fsm(%s): History:\n", fi->name);97	for (i = 0; i < fi->history_size; i++) {98		int e = fi->history[idx].event;99		int s = fi->history[idx++].state;100		idx %= FSM_HISTORY_SIZE;101		if (e == -1)102			printk(KERN_DEBUG "  S=%s\n",103			       fi->f->state_names[s]);104		else105			printk(KERN_DEBUG "  S=%s E=%s\n",106			       fi->f->state_names[s],107			       fi->f->event_names[e]);108	}109	fi->history_size = fi->history_index = 0;110}111 112void113fsm_record_history(fsm_instance *fi, int state, int event)114{115	fi->history[fi->history_index].state = state;116	fi->history[fi->history_index++].event = event;117	fi->history_index %= FSM_HISTORY_SIZE;118	if (fi->history_size < FSM_HISTORY_SIZE)119		fi->history_size++;120}121#endif122 123const char *124fsm_getstate_str(fsm_instance *fi)125{126	int st = atomic_read(&fi->state);127	if (st >= fi->f->nr_states)128		return "Invalid";129	return fi->f->state_names[st];130}131 132static void133fsm_expire_timer(struct timer_list *t)134{135	fsm_timer *this = from_timer(this, t, tl);136#if FSM_TIMER_DEBUG137	printk(KERN_DEBUG "fsm(%s): Timer %p expired\n",138	       this->fi->name, this);139#endif140	fsm_event(this->fi, this->expire_event, this->event_arg);141}142 143void144fsm_settimer(fsm_instance *fi, fsm_timer *this)145{146	this->fi = fi;147#if FSM_TIMER_DEBUG148	printk(KERN_DEBUG "fsm(%s): Create timer %p\n", fi->name,149	       this);150#endif151	timer_setup(&this->tl, fsm_expire_timer, 0);152}153 154void155fsm_deltimer(fsm_timer *this)156{157#if FSM_TIMER_DEBUG158	printk(KERN_DEBUG "fsm(%s): Delete timer %p\n", this->fi->name,159		this);160#endif161	del_timer(&this->tl);162}163 164int165fsm_addtimer(fsm_timer *this, int millisec, int event, void *arg)166{167 168#if FSM_TIMER_DEBUG169	printk(KERN_DEBUG "fsm(%s): Add timer %p %dms\n",170	       this->fi->name, this, millisec);171#endif172 173	timer_setup(&this->tl, fsm_expire_timer, 0);174	this->expire_event = event;175	this->event_arg = arg;176	this->tl.expires = jiffies + (millisec * HZ) / 1000;177	add_timer(&this->tl);178	return 0;179}180 181/* FIXME: this function is never used, why */182void183fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)184{185 186#if FSM_TIMER_DEBUG187	printk(KERN_DEBUG "fsm(%s): Restart timer %p %dms\n",188		this->fi->name, this, millisec);189#endif190 191	del_timer(&this->tl);192	timer_setup(&this->tl, fsm_expire_timer, 0);193	this->expire_event = event;194	this->event_arg = arg;195	this->tl.expires = jiffies + (millisec * HZ) / 1000;196	add_timer(&this->tl);197}198 199EXPORT_SYMBOL(init_fsm);200EXPORT_SYMBOL(kfree_fsm);201EXPORT_SYMBOL(fsm_settimer);202EXPORT_SYMBOL(fsm_deltimer);203EXPORT_SYMBOL(fsm_addtimer);204EXPORT_SYMBOL(fsm_modtimer);205EXPORT_SYMBOL(fsm_getstate_str);206 207#if FSM_DEBUG_HISTORY208EXPORT_SYMBOL(fsm_print_history);209EXPORT_SYMBOL(fsm_record_history);210#endif211