brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 7b31c25 Raw
416 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Author	Karsten Keil <kkeil@novell.com>5 *6 * Copyright 2008  by Karsten Keil <kkeil@novell.com>7 */8 9 10#include <linux/slab.h>11#include <linux/module.h>12#include <linux/mISDNhw.h>13#include "core.h"14#include "layer1.h"15#include "fsm.h"16 17static u_int *debug;18 19struct layer1 {20	u_long Flags;21	struct FsmInst l1m;22	struct FsmTimer timer3;23	struct FsmTimer timerX;24	int delay;25	int t3_value;26	struct dchannel *dch;27	dchannel_l1callback *dcb;28};29 30#define TIMER3_DEFAULT_VALUE	700031 32static33struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL};34 35enum {36	ST_L1_F2,37	ST_L1_F3,38	ST_L1_F4,39	ST_L1_F5,40	ST_L1_F6,41	ST_L1_F7,42	ST_L1_F8,43};44 45#define L1S_STATE_COUNT (ST_L1_F8 + 1)46 47static char *strL1SState[] =48{49	"ST_L1_F2",50	"ST_L1_F3",51	"ST_L1_F4",52	"ST_L1_F5",53	"ST_L1_F6",54	"ST_L1_F7",55	"ST_L1_F8",56};57 58enum {59	EV_PH_ACTIVATE,60	EV_PH_DEACTIVATE,61	EV_RESET_IND,62	EV_DEACT_CNF,63	EV_DEACT_IND,64	EV_POWER_UP,65	EV_ANYSIG_IND,66	EV_INFO2_IND,67	EV_INFO4_IND,68	EV_TIMER_DEACT,69	EV_TIMER_ACT,70	EV_TIMER3,71};72 73#define L1_EVENT_COUNT (EV_TIMER3 + 1)74 75static char *strL1Event[] =76{77	"EV_PH_ACTIVATE",78	"EV_PH_DEACTIVATE",79	"EV_RESET_IND",80	"EV_DEACT_CNF",81	"EV_DEACT_IND",82	"EV_POWER_UP",83	"EV_ANYSIG_IND",84	"EV_INFO2_IND",85	"EV_INFO4_IND",86	"EV_TIMER_DEACT",87	"EV_TIMER_ACT",88	"EV_TIMER3",89};90 91static void92l1m_debug(struct FsmInst *fi, char *fmt, ...)93{94	struct layer1 *l1 = fi->userdata;95	struct va_format vaf;96	va_list va;97 98	va_start(va, fmt);99 100	vaf.fmt = fmt;101	vaf.va = &va;102 103	printk(KERN_DEBUG "%s: %pV\n", dev_name(&l1->dch->dev.dev), &vaf);104 105	va_end(va);106}107 108static void109l1_reset(struct FsmInst *fi, int event, void *arg)110{111	mISDN_FsmChangeState(fi, ST_L1_F3);112}113 114static void115l1_deact_cnf(struct FsmInst *fi, int event, void *arg)116{117	struct layer1 *l1 = fi->userdata;118 119	mISDN_FsmChangeState(fi, ST_L1_F3);120	if (test_bit(FLG_L1_ACTIVATING, &l1->Flags))121		l1->dcb(l1->dch, HW_POWERUP_REQ);122}123 124static void125l1_deact_req_s(struct FsmInst *fi, int event, void *arg)126{127	struct layer1 *l1 = fi->userdata;128 129	mISDN_FsmChangeState(fi, ST_L1_F3);130	mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2);131	test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags);132}133 134static void135l1_power_up_s(struct FsmInst *fi, int event, void *arg)136{137	struct layer1 *l1 = fi->userdata;138 139	if (test_bit(FLG_L1_ACTIVATING, &l1->Flags)) {140		mISDN_FsmChangeState(fi, ST_L1_F4);141		l1->dcb(l1->dch, INFO3_P8);142	} else143		mISDN_FsmChangeState(fi, ST_L1_F3);144}145 146static void147l1_go_F5(struct FsmInst *fi, int event, void *arg)148{149	mISDN_FsmChangeState(fi, ST_L1_F5);150}151 152static void153l1_go_F8(struct FsmInst *fi, int event, void *arg)154{155	mISDN_FsmChangeState(fi, ST_L1_F8);156}157 158static void159l1_info2_ind(struct FsmInst *fi, int event, void *arg)160{161	struct layer1 *l1 = fi->userdata;162 163	mISDN_FsmChangeState(fi, ST_L1_F6);164	l1->dcb(l1->dch, INFO3_P8);165}166 167static void168l1_info4_ind(struct FsmInst *fi, int event, void *arg)169{170	struct layer1 *l1 = fi->userdata;171 172	mISDN_FsmChangeState(fi, ST_L1_F7);173	l1->dcb(l1->dch, INFO3_P8);174	if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags))175		mISDN_FsmDelTimer(&l1->timerX, 4);176	if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) {177		if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags))178			mISDN_FsmDelTimer(&l1->timer3, 3);179		mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2);180		test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags);181	}182}183 184static void185l1_timer3(struct FsmInst *fi, int event, void *arg)186{187	struct layer1 *l1 = fi->userdata;188 189	test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags);190	if (test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags)) {191		if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))192			l1->dcb(l1->dch, HW_D_NOBLOCKED);193		l1->dcb(l1->dch, PH_DEACTIVATE_IND);194	}195	if (l1->l1m.state != ST_L1_F6) {196		mISDN_FsmChangeState(fi, ST_L1_F3);197		/* do not force anything here, we need send INFO 0 */198	}199}200 201static void202l1_timer_act(struct FsmInst *fi, int event, void *arg)203{204	struct layer1 *l1 = fi->userdata;205 206	test_and_clear_bit(FLG_L1_ACTTIMER, &l1->Flags);207	test_and_set_bit(FLG_L1_ACTIVATED, &l1->Flags);208	l1->dcb(l1->dch, PH_ACTIVATE_IND);209}210 211static void212l1_timer_deact(struct FsmInst *fi, int event, void *arg)213{214	struct layer1 *l1 = fi->userdata;215 216	test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags);217	test_and_clear_bit(FLG_L1_ACTIVATED, &l1->Flags);218	if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))219		l1->dcb(l1->dch, HW_D_NOBLOCKED);220	l1->dcb(l1->dch, PH_DEACTIVATE_IND);221	l1->dcb(l1->dch, HW_DEACT_REQ);222}223 224static void225l1_activate_s(struct FsmInst *fi, int event, void *arg)226{227	struct layer1 *l1 = fi->userdata;228 229	mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2);230	test_and_set_bit(FLG_L1_T3RUN, &l1->Flags);231	/* Tell HW to send INFO 1 */232	l1->dcb(l1->dch, HW_RESET_REQ);233}234 235static void236l1_activate_no(struct FsmInst *fi, int event, void *arg)237{238	struct layer1 *l1 = fi->userdata;239 240	if ((!test_bit(FLG_L1_DEACTTIMER, &l1->Flags)) &&241	    (!test_bit(FLG_L1_T3RUN, &l1->Flags))) {242		test_and_clear_bit(FLG_L1_ACTIVATING, &l1->Flags);243		if (test_and_clear_bit(FLG_L1_DBLOCKED, &l1->Flags))244			l1->dcb(l1->dch, HW_D_NOBLOCKED);245		l1->dcb(l1->dch, PH_DEACTIVATE_IND);246	}247}248 249static struct FsmNode L1SFnList[] =250{251	{ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},252	{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},253	{ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},254	{ST_L1_F3, EV_RESET_IND, l1_reset},255	{ST_L1_F4, EV_RESET_IND, l1_reset},256	{ST_L1_F5, EV_RESET_IND, l1_reset},257	{ST_L1_F6, EV_RESET_IND, l1_reset},258	{ST_L1_F7, EV_RESET_IND, l1_reset},259	{ST_L1_F8, EV_RESET_IND, l1_reset},260	{ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf},261	{ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf},262	{ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf},263	{ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},264	{ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},265	{ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},266	{ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},267	{ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},268	{ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},269	{ST_L1_F3, EV_POWER_UP,  l1_power_up_s},270	{ST_L1_F4, EV_ANYSIG_IND, l1_go_F5},271	{ST_L1_F6, EV_ANYSIG_IND, l1_go_F8},272	{ST_L1_F7, EV_ANYSIG_IND, l1_go_F8},273	{ST_L1_F3, EV_INFO2_IND, l1_info2_ind},274	{ST_L1_F4, EV_INFO2_IND, l1_info2_ind},275	{ST_L1_F5, EV_INFO2_IND, l1_info2_ind},276	{ST_L1_F7, EV_INFO2_IND, l1_info2_ind},277	{ST_L1_F8, EV_INFO2_IND, l1_info2_ind},278	{ST_L1_F3, EV_INFO4_IND, l1_info4_ind},279	{ST_L1_F4, EV_INFO4_IND, l1_info4_ind},280	{ST_L1_F5, EV_INFO4_IND, l1_info4_ind},281	{ST_L1_F6, EV_INFO4_IND, l1_info4_ind},282	{ST_L1_F8, EV_INFO4_IND, l1_info4_ind},283	{ST_L1_F3, EV_TIMER3, l1_timer3},284	{ST_L1_F4, EV_TIMER3, l1_timer3},285	{ST_L1_F5, EV_TIMER3, l1_timer3},286	{ST_L1_F6, EV_TIMER3, l1_timer3},287	{ST_L1_F8, EV_TIMER3, l1_timer3},288	{ST_L1_F7, EV_TIMER_ACT, l1_timer_act},289	{ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact},290	{ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact},291	{ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact},292	{ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact},293	{ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact},294	{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},295};296 297static void298release_l1(struct layer1 *l1) {299	mISDN_FsmDelTimer(&l1->timerX, 0);300	mISDN_FsmDelTimer(&l1->timer3, 0);301	if (l1->dch)302		l1->dch->l1 = NULL;303	module_put(THIS_MODULE);304	kfree(l1);305}306 307int308l1_event(struct layer1 *l1, u_int event)309{310	int		err = 0;311 312	if (!l1)313		return -EINVAL;314	switch (event) {315	case HW_RESET_IND:316		mISDN_FsmEvent(&l1->l1m, EV_RESET_IND, NULL);317		break;318	case HW_DEACT_IND:319		mISDN_FsmEvent(&l1->l1m, EV_DEACT_IND, NULL);320		break;321	case HW_POWERUP_IND:322		mISDN_FsmEvent(&l1->l1m, EV_POWER_UP, NULL);323		break;324	case HW_DEACT_CNF:325		mISDN_FsmEvent(&l1->l1m, EV_DEACT_CNF, NULL);326		break;327	case ANYSIGNAL:328		mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);329		break;330	case LOSTFRAMING:331		mISDN_FsmEvent(&l1->l1m, EV_ANYSIG_IND, NULL);332		break;333	case INFO2:334		mISDN_FsmEvent(&l1->l1m, EV_INFO2_IND, NULL);335		break;336	case INFO4_P8:337		mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);338		break;339	case INFO4_P10:340		mISDN_FsmEvent(&l1->l1m, EV_INFO4_IND, NULL);341		break;342	case PH_ACTIVATE_REQ:343		if (test_bit(FLG_L1_ACTIVATED, &l1->Flags))344			l1->dcb(l1->dch, PH_ACTIVATE_IND);345		else {346			test_and_set_bit(FLG_L1_ACTIVATING, &l1->Flags);347			mISDN_FsmEvent(&l1->l1m, EV_PH_ACTIVATE, NULL);348		}349		break;350	case CLOSE_CHANNEL:351		release_l1(l1);352		break;353	default:354		if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) {355			int val = event & HW_TIMER3_VMASK;356 357			if (val < 5)358				val = 5;359			if (val > 30)360				val = 30;361			l1->t3_value = val;362			break;363		}364		if (*debug & DEBUG_L1)365			printk(KERN_DEBUG "%s %x unhandled\n",366			       __func__, event);367		err = -EINVAL;368	}369	return err;370}371EXPORT_SYMBOL(l1_event);372 373int374create_l1(struct dchannel *dch, dchannel_l1callback *dcb) {375	struct layer1	*nl1;376 377	nl1 = kzalloc(sizeof(struct layer1), GFP_ATOMIC);378	if (!nl1) {379		printk(KERN_ERR "kmalloc struct layer1 failed\n");380		return -ENOMEM;381	}382	nl1->l1m.fsm = &l1fsm_s;383	nl1->l1m.state = ST_L1_F3;384	nl1->Flags = 0;385	nl1->t3_value = TIMER3_DEFAULT_VALUE;386	nl1->l1m.debug = *debug & DEBUG_L1_FSM;387	nl1->l1m.userdata = nl1;388	nl1->l1m.userint = 0;389	nl1->l1m.printdebug = l1m_debug;390	nl1->dch = dch;391	nl1->dcb = dcb;392	mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3);393	mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX);394	__module_get(THIS_MODULE);395	dch->l1 = nl1;396	return 0;397}398EXPORT_SYMBOL(create_l1);399 400int401Isdnl1_Init(u_int *deb)402{403	debug = deb;404	l1fsm_s.state_count = L1S_STATE_COUNT;405	l1fsm_s.event_count = L1_EVENT_COUNT;406	l1fsm_s.strEvent = strL1Event;407	l1fsm_s.strState = strL1SState;408	return mISDN_FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList));409}410 411void412Isdnl1_cleanup(void)413{414	mISDN_FsmFree(&l1fsm_s);415}416