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