1/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $
2 *
3 * Ansteuerung ARCOFI 2165
4 *
5 * Author       Karsten Keil
6 * Copyright    by Karsten Keil      <keil@isdn4linux.de>
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 */
12
13#include <linux/sched.h>
14#include "hisax.h"
15#include "isdnl1.h"
16#include "isac.h"
17#include "arcofi.h"
18
19#define ARCOFI_TIMER_VALUE	20
20
21static void
22add_arcofi_timer(struct IsdnCardState *cs) {
23	if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
24		del_timer(&cs->dc.isac.arcofitimer);
25	}
26	init_timer(&cs->dc.isac.arcofitimer);
27	cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000);
28	add_timer(&cs->dc.isac.arcofitimer);
29}
30
31static void
32send_arcofi(struct IsdnCardState *cs) {
33	add_arcofi_timer(cs);
34	cs->dc.isac.mon_txp = 0;
35	cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
36	memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc);
37	switch (cs->dc.isac.arcofi_bc) {
38	case 0: break;
39	case 1: cs->dc.isac.mon_tx[1] |= 0x40;
40		break;
41	default: break;
42	}
43	cs->dc.isac.mocr &= 0x0f;
44	cs->dc.isac.mocr |= 0xa0;
45	cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
46	(void) cs->readisac(cs, ISAC_MOSR);
47	cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
48	cs->dc.isac.mocr |= 0x10;
49	cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
50}
51
52int
53arcofi_fsm(struct IsdnCardState *cs, int event, void *data) {
54	if (cs->debug & L1_DEB_MONITOR) {
55		debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event);
56	}
57	if (event == ARCOFI_TIMEOUT) {
58		cs->dc.isac.arcofi_state = ARCOFI_NOP;
59		test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags);
60		wake_up(&cs->dc.isac.arcofi_wait);
61		return (1);
62	}
63	switch (cs->dc.isac.arcofi_state) {
64	case ARCOFI_NOP:
65		if (event == ARCOFI_START) {
66			cs->dc.isac.arcofi_list = data;
67			cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
68			send_arcofi(cs);
69		}
70		break;
71	case ARCOFI_TRANSMIT:
72		if (event == ARCOFI_TX_END) {
73			if (cs->dc.isac.arcofi_list->receive) {
74				add_arcofi_timer(cs);
75				cs->dc.isac.arcofi_state = ARCOFI_RECEIVE;
76			} else {
77				if (cs->dc.isac.arcofi_list->next) {
78					cs->dc.isac.arcofi_list =
79						cs->dc.isac.arcofi_list->next;
80					send_arcofi(cs);
81				} else {
82					if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
83						del_timer(&cs->dc.isac.arcofitimer);
84					}
85					cs->dc.isac.arcofi_state = ARCOFI_NOP;
86					wake_up(&cs->dc.isac.arcofi_wait);
87				}
88			}
89		}
90		break;
91	case ARCOFI_RECEIVE:
92		if (event == ARCOFI_RX_END) {
93			if (cs->dc.isac.arcofi_list->next) {
94				cs->dc.isac.arcofi_list =
95					cs->dc.isac.arcofi_list->next;
96				cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT;
97				send_arcofi(cs);
98			} else {
99				if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
100					del_timer(&cs->dc.isac.arcofitimer);
101				}
102				cs->dc.isac.arcofi_state = ARCOFI_NOP;
103				wake_up(&cs->dc.isac.arcofi_wait);
104			}
105		}
106		break;
107	default:
108		debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state);
109		return (2);
110	}
111	return (0);
112}
113
114static void
115arcofi_timer(struct IsdnCardState *cs) {
116	arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL);
117}
118
119void
120clear_arcofi(struct IsdnCardState *cs) {
121	if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) {
122		del_timer(&cs->dc.isac.arcofitimer);
123	}
124}
125
126void
127init_arcofi(struct IsdnCardState *cs) {
128	cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
129	cs->dc.isac.arcofitimer.data = (long) cs;
130	init_timer(&cs->dc.isac.arcofitimer);
131	init_waitqueue_head(&cs->dc.isac.arcofi_wait);
132	test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
133}
134