File: /usr/src/linux/drivers/isdn/hisax/isurf.c

1     /* $Id: isurf.c,v 1.10.6.1 2001/02/16 16:43:27 kai Exp $
2      *
3      * isurf.c  low level stuff for Siemens I-Surf/I-Talk cards
4      *
5      * Author     Karsten Keil (keil@isdn4linux.de)
6      *
7      * This file is (c) under GNU General Public License
8      *
9      */
10     
11     #define __NO_VERSION__
12     #include <linux/init.h>
13     #include "hisax.h"
14     #include "isac.h"
15     #include "isar.h"
16     #include "isdnl1.h"
17     
18     extern const char *CardType[];
19     
20     static const char *ISurf_revision = "$Revision: 1.10.6.1 $";
21     
22     #define byteout(addr,val) outb(val,addr)
23     #define bytein(addr) inb(addr)
24     
25     #define ISURF_ISAR_RESET	1
26     #define ISURF_ISAC_RESET	2
27     #define ISURF_ISAR_EA		4
28     #define ISURF_ARCOFI_RESET	8
29     #define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
30     
31     #define ISURF_ISAR_OFFSET	0
32     #define ISURF_ISAC_OFFSET	0x100
33     #define ISURF_IOMEM_SIZE	0x400
34     /* Interface functions */
35     
36     static u_char
37     ReadISAC(struct IsdnCardState *cs, u_char offset)
38     {
39     	return (readb(cs->hw.isurf.isac + offset));
40     }
41     
42     static void
43     WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
44     {
45     	writeb(value, cs->hw.isurf.isac + offset); mb();
46     }
47     
48     static void
49     ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
50     {
51     	register int i;
52     	for (i = 0; i < size; i++)
53     		data[i] = readb(cs->hw.isurf.isac);
54     }
55     
56     static void
57     WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
58     {
59     	register int i;
60     	for (i = 0; i < size; i++){
61     		writeb(data[i], cs->hw.isurf.isac);mb();
62     	}
63     }
64     
65     /* ISAR access routines
66      * mode = 0 access with IRQ on
67      * mode = 1 access with IRQ off
68      * mode = 2 access with IRQ off and using last offset
69      */
70       
71     static u_char
72     ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
73     {	
74     	return(readb(cs->hw.isurf.isar + offset));
75     }
76     
77     static void
78     WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
79     {
80     	writeb(value, cs->hw.isurf.isar + offset);mb();
81     }
82     
83     static void
84     isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
85     {
86     	struct IsdnCardState *cs = dev_id;
87     	u_char val;
88     	int cnt = 5;
89     
90     	if (!cs) {
91     		printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
92     		return;
93     	}
94     
95     	val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
96           Start_ISAR:
97     	if (val & ISAR_IRQSTA)
98     		isar_int_main(cs);
99     	val = readb(cs->hw.isurf.isac + ISAC_ISTA);
100           Start_ISAC:
101     	if (val)
102     		isac_interrupt(cs, val);
103     	val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
104     	if ((val & ISAR_IRQSTA) && --cnt) {
105     		if (cs->debug & L1_DEB_HSCX)
106     			debugl1(cs, "ISAR IntStat after IntRoutine");
107     		goto Start_ISAR;
108     	}
109     	val = readb(cs->hw.isurf.isac + ISAC_ISTA);
110     	if (val && --cnt) {
111     		if (cs->debug & L1_DEB_ISAC)
112     			debugl1(cs, "ISAC IntStat after IntRoutine");
113     		goto Start_ISAC;
114     	}
115     	if (!cnt)
116     		printk(KERN_WARNING "ISurf IRQ LOOP\n");
117     
118     	writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
119     	writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
120     	writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
121     	writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
122     }
123     
124     void
125     release_io_isurf(struct IsdnCardState *cs)
126     {
127     	release_region(cs->hw.isurf.reset, 1);
128     	iounmap((unsigned char *)cs->hw.isurf.isar);
129     	release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
130     }
131     
132     static void
133     reset_isurf(struct IsdnCardState *cs, u_char chips)
134     {
135     	long flags;
136     
137     	printk(KERN_INFO "ISurf: resetting card\n");
138     
139     	byteout(cs->hw.isurf.reset, chips); /* Reset On */
140     	save_flags(flags);
141     	sti();
142     	set_current_state(TASK_UNINTERRUPTIBLE);
143     	schedule_timeout((10*HZ)/1000);
144     	byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
145     	set_current_state(TASK_UNINTERRUPTIBLE);
146     	schedule_timeout((10*HZ)/1000);
147     	restore_flags(flags);
148     }
149     
150     static int
151     ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
152     {
153     	switch (mt) {
154     		case CARD_RESET:
155     			reset_isurf(cs, ISURF_RESET);
156     			return(0);
157     		case CARD_RELEASE:
158     			release_io_isurf(cs);
159     			return(0);
160     		case CARD_INIT:
161     			clear_pending_isac_ints(cs);
162     			writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
163     			initisac(cs);
164     			initisar(cs);
165     			/* Reenable ISAC IRQ */
166     			cs->writeisac(cs, ISAC_MASK, 0);
167     			/* RESET Receiver and Transmitter */
168     			cs->writeisac(cs, ISAC_CMDR, 0x41);
169     			return(0);
170     		case CARD_TEST:
171     			return(0);
172     	}
173     	return(0);
174     }
175     
176     static int
177     isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
178     	int ret;
179     
180     	if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
181     		ret = isar_auxcmd(cs, ic);
182     		if (!ret) {
183     			reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
184     				ISURF_ARCOFI_RESET);
185     			initisac(cs);
186     			cs->writeisac(cs, ISAC_MASK, 0);
187     			cs->writeisac(cs, ISAC_CMDR, 0x41);
188     		}
189     		return(ret);
190     	}
191     	return(isar_auxcmd(cs, ic));
192     }
193     
194     int __init
195     setup_isurf(struct IsdnCard *card)
196     {
197     	int ver;
198     	struct IsdnCardState *cs = card->cs;
199     	char tmp[64];
200     
201     	strcpy(tmp, ISurf_revision);
202     	printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
203     	
204      	if (cs->typ != ISDN_CTYPE_ISURF)
205      		return(0);
206     	if (card->para[1] && card->para[2]) {
207     		cs->hw.isurf.reset = card->para[1];
208     		cs->hw.isurf.phymem = card->para[2];
209     		cs->irq = card->para[0];
210     	} else {
211     		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
212     			CardType[card->typ]);
213     		return (0);
214     	}
215     	if (check_region(cs->hw.isurf.reset, 1)) {
216     		printk(KERN_WARNING
217     			"HiSax: %s config port %x already in use\n",
218     			CardType[card->typ],
219     			cs->hw.isurf.reset);
220     			return (0);
221     	} else {
222     		request_region(cs->hw.isurf.reset, 1, "isurf isdn");
223     	}
224     	if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) {
225     		printk(KERN_WARNING
226     			"HiSax: %s memory region %lx-%lx already in use\n",
227     			CardType[card->typ],
228     			cs->hw.isurf.phymem,
229     			cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
230     		release_region(cs->hw.isurf.reset, 1);
231     		return (0);
232     	} else {
233     		request_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE,
234     			"isurf iomem");
235     	}
236     	cs->hw.isurf.isar =
237     		(unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
238     	cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
239     	printk(KERN_INFO
240     	       "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
241     	       cs->hw.isurf.reset,
242     	       cs->hw.isurf.phymem,
243     	       cs->irq);
244     
245     	cs->cardmsg = &ISurf_card_msg;
246     	cs->irq_func = &isurf_interrupt;
247     	cs->auxcmd = &isurf_auxcmd;
248     	cs->readisac = &ReadISAC;
249     	cs->writeisac = &WriteISAC;
250     	cs->readisacfifo = &ReadISACfifo;
251     	cs->writeisacfifo = &WriteISACfifo;
252     	cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
253     	cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
254     	reset_isurf(cs, ISURF_RESET);
255     	test_and_set_bit(HW_ISAR, &cs->HW_Flags);
256     	ISACVersion(cs, "ISurf:");
257     	cs->BC_Read_Reg = &ReadISAR;
258     	cs->BC_Write_Reg = &WriteISAR;
259     	cs->BC_Send_Data = &isar_fill_fifo;
260     	ver = ISARVersion(cs, "ISurf:");
261     	if (ver < 0) {
262     		printk(KERN_WARNING
263     			"ISurf: wrong ISAR version (ret = %d)\n", ver);
264     		release_io_isurf(cs);
265     		return (0);
266     	}
267     	return (1);
268     }
269