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