1/* $Id: teleint.c,v 1.1.1.1 2007/08/03 18:52:36 Exp $
2 *
3 * low level stuff for TeleInt isdn cards
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/init.h>
14#include "hisax.h"
15#include "isac.h"
16#include "hfc_2bs0.h"
17#include "isdnl1.h"
18
19extern const char *CardType[];
20
21static const char *TeleInt_revision = "$Revision: 1.1.1.1 $";
22
23#define byteout(addr,val) outb(val,addr)
24#define bytein(addr) inb(addr)
25
26static inline u_char
27readreg(unsigned int ale, unsigned int adr, u_char off)
28{
29	register u_char ret;
30	int max_delay = 2000;
31
32	byteout(ale, off);
33	ret = HFC_BUSY & bytein(ale);
34	while (ret && --max_delay)
35		ret = HFC_BUSY & bytein(ale);
36	if (!max_delay) {
37		printk(KERN_WARNING "TeleInt Busy not inactive\n");
38		return (0);
39	}
40	ret = bytein(adr);
41	return (ret);
42}
43
44static inline void
45readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
46{
47	register u_char ret;
48	register int max_delay = 20000;
49	register int i;
50
51	byteout(ale, off);
52	for (i = 0; i<size; i++) {
53		ret = HFC_BUSY & bytein(ale);
54		while (ret && --max_delay)
55			ret = HFC_BUSY & bytein(ale);
56		if (!max_delay) {
57			printk(KERN_WARNING "TeleInt Busy not inactive\n");
58			return;
59		}
60		data[i] = bytein(adr);
61	}
62}
63
64
65static inline void
66writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
67{
68	register u_char ret;
69	int max_delay = 2000;
70
71	byteout(ale, off);
72	ret = HFC_BUSY & bytein(ale);
73	while (ret && --max_delay)
74		ret = HFC_BUSY & bytein(ale);
75	if (!max_delay) {
76		printk(KERN_WARNING "TeleInt Busy not inactive\n");
77		return;
78	}
79	byteout(adr, data);
80}
81
82static inline void
83writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
84{
85	register u_char ret;
86	register int max_delay = 20000;
87	register int i;
88
89	byteout(ale, off);
90	for (i = 0; i<size; i++) {
91		ret = HFC_BUSY & bytein(ale);
92		while (ret && --max_delay)
93			ret = HFC_BUSY & bytein(ale);
94		if (!max_delay) {
95			printk(KERN_WARNING "TeleInt Busy not inactive\n");
96			return;
97		}
98		byteout(adr, data[i]);
99	}
100}
101
102/* Interface functions */
103
104static u_char
105ReadISAC(struct IsdnCardState *cs, u_char offset)
106{
107	cs->hw.hfc.cip = offset;
108	return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset));
109}
110
111static void
112WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
113{
114	cs->hw.hfc.cip = offset;
115	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value);
116}
117
118static void
119ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
120{
121	cs->hw.hfc.cip = 0;
122	readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
123}
124
125static void
126WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
127{
128	cs->hw.hfc.cip = 0;
129	writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size);
130}
131
132static u_char
133ReadHFC(struct IsdnCardState *cs, int data, u_char reg)
134{
135	register u_char ret;
136
137	if (data) {
138		cs->hw.hfc.cip = reg;
139		byteout(cs->hw.hfc.addr | 1, reg);
140		ret = bytein(cs->hw.hfc.addr);
141		if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
142			debugl1(cs, "hfc RD %02x %02x", reg, ret);
143	} else
144		ret = bytein(cs->hw.hfc.addr | 1);
145	return (ret);
146}
147
148static void
149WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
150{
151	byteout(cs->hw.hfc.addr | 1, reg);
152	cs->hw.hfc.cip = reg;
153	if (data)
154		byteout(cs->hw.hfc.addr, value);
155	if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2))
156		debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value);
157}
158
159static irqreturn_t
160TeleInt_interrupt(int intno, void *dev_id)
161{
162	struct IsdnCardState *cs = dev_id;
163	u_char val;
164	u_long flags;
165
166	spin_lock_irqsave(&cs->lock, flags);
167	val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
168      Start_ISAC:
169	if (val)
170		isac_interrupt(cs, val);
171	val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA);
172	if (val) {
173		if (cs->debug & L1_DEB_ISAC)
174			debugl1(cs, "ISAC IntStat after IntRoutine");
175		goto Start_ISAC;
176	}
177	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF);
178	writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0);
179	spin_unlock_irqrestore(&cs->lock, flags);
180	return IRQ_HANDLED;
181}
182
183static void
184TeleInt_Timer(struct IsdnCardState *cs)
185{
186	int stat = 0;
187	u_long flags;
188
189	spin_lock_irqsave(&cs->lock, flags);
190	if (cs->bcs[0].mode) {
191		stat |= 1;
192		main_irq_hfc(&cs->bcs[0]);
193	}
194	if (cs->bcs[1].mode) {
195		stat |= 2;
196		main_irq_hfc(&cs->bcs[1]);
197	}
198	spin_unlock_irqrestore(&cs->lock, flags);
199	stat = HZ/100;
200	if (!stat)
201		stat = 1;
202	cs->hw.hfc.timer.expires = jiffies + stat;
203	add_timer(&cs->hw.hfc.timer);
204}
205
206static void
207release_io_TeleInt(struct IsdnCardState *cs)
208{
209	del_timer(&cs->hw.hfc.timer);
210	releasehfc(cs);
211	if (cs->hw.hfc.addr)
212		release_region(cs->hw.hfc.addr, 2);
213}
214
215static void
216reset_TeleInt(struct IsdnCardState *cs)
217{
218	printk(KERN_INFO "TeleInt: resetting card\n");
219	cs->hw.hfc.cirm |= HFC_RESET;
220	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset On */
221	mdelay(10);
222	cs->hw.hfc.cirm &= ~HFC_RESET;
223	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset Off */
224	mdelay(10);
225}
226
227static int
228TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
229{
230	u_long flags;
231	int delay;
232
233	switch (mt) {
234		case CARD_RESET:
235			spin_lock_irqsave(&cs->lock, flags);
236			reset_TeleInt(cs);
237			spin_unlock_irqrestore(&cs->lock, flags);
238			return(0);
239		case CARD_RELEASE:
240			release_io_TeleInt(cs);
241			return(0);
242		case CARD_INIT:
243			spin_lock_irqsave(&cs->lock, flags);
244			reset_TeleInt(cs);
245			inithfc(cs);
246			clear_pending_isac_ints(cs);
247			initisac(cs);
248			/* Reenable all IRQ */
249			cs->writeisac(cs, ISAC_MASK, 0);
250			cs->writeisac(cs, ISAC_CMDR, 0x41);
251			spin_unlock_irqrestore(&cs->lock, flags);
252			delay = HZ/100;
253			if (!delay)
254				delay = 1;
255			cs->hw.hfc.timer.expires = jiffies + delay;
256			add_timer(&cs->hw.hfc.timer);
257			return(0);
258		case CARD_TEST:
259			return(0);
260	}
261	return(0);
262}
263
264int __devinit
265setup_TeleInt(struct IsdnCard *card)
266{
267	struct IsdnCardState *cs = card->cs;
268	char tmp[64];
269
270	strcpy(tmp, TeleInt_revision);
271	printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp));
272	if (cs->typ != ISDN_CTYPE_TELEINT)
273		return (0);
274
275	cs->hw.hfc.addr = card->para[1] & 0x3fe;
276	cs->irq = card->para[0];
277	cs->hw.hfc.cirm = HFC_CIRM;
278	cs->hw.hfc.isac_spcr = 0x00;
279	cs->hw.hfc.cip = 0;
280	cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER;
281	cs->bcs[0].hw.hfc.send = NULL;
282	cs->bcs[1].hw.hfc.send = NULL;
283	cs->hw.hfc.fifosize = 7 * 1024 + 512;
284	cs->hw.hfc.timer.function = (void *) TeleInt_Timer;
285	cs->hw.hfc.timer.data = (long) cs;
286	init_timer(&cs->hw.hfc.timer);
287	if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) {
288		printk(KERN_WARNING
289		       "HiSax: %s config port %x-%x already in use\n",
290		       CardType[card->typ],
291		       cs->hw.hfc.addr,
292		       cs->hw.hfc.addr + 2);
293		return (0);
294	}
295	/* HW IO = IO */
296	byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff);
297	byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54);
298	switch (cs->irq) {
299		case 3:
300			cs->hw.hfc.cirm |= HFC_INTA;
301			break;
302		case 4:
303			cs->hw.hfc.cirm |= HFC_INTB;
304			break;
305		case 5:
306			cs->hw.hfc.cirm |= HFC_INTC;
307			break;
308		case 7:
309			cs->hw.hfc.cirm |= HFC_INTD;
310			break;
311		case 10:
312			cs->hw.hfc.cirm |= HFC_INTE;
313			break;
314		case 11:
315			cs->hw.hfc.cirm |= HFC_INTF;
316			break;
317		default:
318			printk(KERN_WARNING "TeleInt: wrong IRQ\n");
319			release_io_TeleInt(cs);
320			return (0);
321	}
322	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);
323	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt);
324
325	printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n",
326		cs->hw.hfc.addr, cs->irq);
327
328	setup_isac(cs);
329	cs->readisac = &ReadISAC;
330	cs->writeisac = &WriteISAC;
331	cs->readisacfifo = &ReadISACfifo;
332	cs->writeisacfifo = &WriteISACfifo;
333	cs->BC_Read_Reg = &ReadHFC;
334	cs->BC_Write_Reg = &WriteHFC;
335	cs->cardmsg = &TeleInt_card_msg;
336	cs->irq_func = &TeleInt_interrupt;
337	ISACVersion(cs, "TeleInt:");
338	return (1);
339}
340