1 /* $Id: isurf.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2  *
3  * low level stuff for Siemens I-Surf/I-Talk 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 #define __NO_VERSION__
14 #include <linux/init.h>
15 #include "hisax.h"
16 #include "isac.h"
17 #include "isar.h"
18 #include "isdnl1.h"
19 #include <linux/isapnp.h>
20 
21 extern const char *CardType[];
22 
23 static const char *ISurf_revision = "$Revision: 1.1.4.1 $";
24 
25 #define byteout(addr,val) outb(val,addr)
26 #define bytein(addr) inb(addr)
27 
28 #define ISURF_ISAR_RESET	1
29 #define ISURF_ISAC_RESET	2
30 #define ISURF_ISAR_EA		4
31 #define ISURF_ARCOFI_RESET	8
32 #define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
33 
34 #define ISURF_ISAR_OFFSET	0
35 #define ISURF_ISAC_OFFSET	0x100
36 #define ISURF_IOMEM_SIZE	0x400
37 /* Interface functions */
38 
39 static u_char
ReadISAC(struct IsdnCardState * cs,u_char offset)40 ReadISAC(struct IsdnCardState *cs, u_char offset)
41 {
42 	return (readb(cs->hw.isurf.isac + offset));
43 }
44 
45 static void
WriteISAC(struct IsdnCardState * cs,u_char offset,u_char value)46 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
47 {
48 	writeb(value, cs->hw.isurf.isac + offset); mb();
49 }
50 
51 static void
ReadISACfifo(struct IsdnCardState * cs,u_char * data,int size)52 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
53 {
54 	register int i;
55 	for (i = 0; i < size; i++)
56 		data[i] = readb(cs->hw.isurf.isac);
57 }
58 
59 static void
WriteISACfifo(struct IsdnCardState * cs,u_char * data,int size)60 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
61 {
62 	register int i;
63 	for (i = 0; i < size; i++){
64 		writeb(data[i], cs->hw.isurf.isac);mb();
65 	}
66 }
67 
68 /* ISAR access routines
69  * mode = 0 access with IRQ on
70  * mode = 1 access with IRQ off
71  * mode = 2 access with IRQ off and using last offset
72  */
73 
74 static u_char
ReadISAR(struct IsdnCardState * cs,int mode,u_char offset)75 ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
76 {
77 	return(readb(cs->hw.isurf.isar + offset));
78 }
79 
80 static void
WriteISAR(struct IsdnCardState * cs,int mode,u_char offset,u_char value)81 WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
82 {
83 	writeb(value, cs->hw.isurf.isar + offset);mb();
84 }
85 
86 static void
isurf_interrupt(int intno,void * dev_id,struct pt_regs * regs)87 isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
88 {
89 	struct IsdnCardState *cs = dev_id;
90 	u_char val;
91 	int cnt = 5;
92 
93 	if (!cs) {
94 		printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
95 		return;
96 	}
97 
98 	val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
99       Start_ISAR:
100 	if (val & ISAR_IRQSTA)
101 		isar_int_main(cs);
102 	val = readb(cs->hw.isurf.isac + ISAC_ISTA);
103       Start_ISAC:
104 	if (val)
105 		isac_interrupt(cs, val);
106 	val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
107 	if ((val & ISAR_IRQSTA) && --cnt) {
108 		if (cs->debug & L1_DEB_HSCX)
109 			debugl1(cs, "ISAR IntStat after IntRoutine");
110 		goto Start_ISAR;
111 	}
112 	val = readb(cs->hw.isurf.isac + ISAC_ISTA);
113 	if (val && --cnt) {
114 		if (cs->debug & L1_DEB_ISAC)
115 			debugl1(cs, "ISAC IntStat after IntRoutine");
116 		goto Start_ISAC;
117 	}
118 	if (!cnt)
119 		printk(KERN_WARNING "ISurf IRQ LOOP\n");
120 
121 	writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
122 	writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
123 	writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
124 	writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
125 }
126 
127 void
release_io_isurf(struct IsdnCardState * cs)128 release_io_isurf(struct IsdnCardState *cs)
129 {
130 	release_region(cs->hw.isurf.reset, 1);
131 	iounmap((unsigned char *)cs->hw.isurf.isar);
132 	release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
133 }
134 
135 static void
reset_isurf(struct IsdnCardState * cs,u_char chips)136 reset_isurf(struct IsdnCardState *cs, u_char chips)
137 {
138 	long flags;
139 
140 	printk(KERN_INFO "ISurf: resetting card\n");
141 
142 	byteout(cs->hw.isurf.reset, chips); /* Reset On */
143 	save_flags(flags);
144 	sti();
145 	set_current_state(TASK_UNINTERRUPTIBLE);
146 	schedule_timeout((10*HZ)/1000);
147 	byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
148 	set_current_state(TASK_UNINTERRUPTIBLE);
149 	schedule_timeout((10*HZ)/1000);
150 	restore_flags(flags);
151 }
152 
153 static int
ISurf_card_msg(struct IsdnCardState * cs,int mt,void * arg)154 ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
155 {
156 	switch (mt) {
157 		case CARD_RESET:
158 			reset_isurf(cs, ISURF_RESET);
159 			return(0);
160 		case CARD_RELEASE:
161 			release_io_isurf(cs);
162 			return(0);
163 		case CARD_INIT:
164 			clear_pending_isac_ints(cs);
165 			writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
166 			initisac(cs);
167 			initisar(cs);
168 			/* Reenable ISAC IRQ */
169 			cs->writeisac(cs, ISAC_MASK, 0);
170 			/* RESET Receiver and Transmitter */
171 			cs->writeisac(cs, ISAC_CMDR, 0x41);
172 			return(0);
173 		case CARD_TEST:
174 			return(0);
175 	}
176 	return(0);
177 }
178 
179 static int
isurf_auxcmd(struct IsdnCardState * cs,isdn_ctrl * ic)180 isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
181 	int ret;
182 
183 	if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) {
184 		ret = isar_auxcmd(cs, ic);
185 		if (!ret) {
186 			reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
187 				ISURF_ARCOFI_RESET);
188 			initisac(cs);
189 			cs->writeisac(cs, ISAC_MASK, 0);
190 			cs->writeisac(cs, ISAC_CMDR, 0x41);
191 		}
192 		return(ret);
193 	}
194 	return(isar_auxcmd(cs, ic));
195 }
196 
197 #ifdef __ISAPNP__
198 static struct pci_bus *pnp_surf __devinitdata = NULL;
199 #endif
200 
201 int __init
setup_isurf(struct IsdnCard * card)202 setup_isurf(struct IsdnCard *card)
203 {
204 	int ver;
205 	struct IsdnCardState *cs = card->cs;
206 	char tmp[64];
207 
208 	strcpy(tmp, ISurf_revision);
209 	printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
210 
211  	if (cs->typ != ISDN_CTYPE_ISURF)
212  		return(0);
213 	if (card->para[1] && card->para[2]) {
214 		cs->hw.isurf.reset = card->para[1];
215 		cs->hw.isurf.phymem = card->para[2];
216 		cs->irq = card->para[0];
217 	} else {
218 #ifdef __ISAPNP__
219 		struct pci_bus *pb;
220 		struct pci_dev *pd;
221 
222 		if (isapnp_present()) {
223 			cs->subtyp = 0;
224 			if ((pb = isapnp_find_card(
225 				ISAPNP_VENDOR('S', 'I', 'E'),
226 				ISAPNP_FUNCTION(0x0010), pnp_surf))) {
227 				pnp_surf = pb;
228 				pd = NULL;
229 				if (!(pd = isapnp_find_dev(pnp_surf,
230 					ISAPNP_VENDOR('S', 'I', 'E'),
231 					ISAPNP_FUNCTION(0x0010), pd))) {
232 					printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
233 					return (0);
234 				}
235 				pd->prepare(pd);
236 				pd->deactivate(pd);
237 				pd->activate(pd);
238 				/* The ISA-PnP logic apparently
239 				 * expects upper limit address to be
240 				 * set. Since the isa-pnp module
241 				 * doesn't do this, so we have to make
242 				 * up for it.
243 				 */
244 				isapnp_cfg_begin(pd->bus->number, pd->devfn);
245 				isapnp_write_word(ISAPNP_CFG_MEM+3,
246 					pd->resource[8].end >> 8);
247 				isapnp_cfg_end();
248 				cs->hw.isurf.reset = pd->resource[0].start;
249 				cs->hw.isurf.phymem = pd->resource[8].start;
250 				cs->irq = pd->irq_resource[0].start;
251 				if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
252 					printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
253 						cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
254 					pd->deactivate(pd);
255 					return(0);
256 				}
257 			} else {
258 				printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
259 				return(0);
260 			}
261 		} else {
262 			printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
263 			return(0);
264 		}
265 #else
266 		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
267 			CardType[card->typ]);
268 		return (0);
269 #endif
270 	}
271 	if (check_region(cs->hw.isurf.reset, 1)) {
272 		printk(KERN_WARNING
273 			"HiSax: %s config port %x already in use\n",
274 			CardType[card->typ],
275 			cs->hw.isurf.reset);
276 			return (0);
277 	} else {
278 		request_region(cs->hw.isurf.reset, 1, "isurf isdn");
279 	}
280 	if (check_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE)) {
281 		printk(KERN_WARNING
282 			"HiSax: %s memory region %lx-%lx already in use\n",
283 			CardType[card->typ],
284 			cs->hw.isurf.phymem,
285 			cs->hw.isurf.phymem + ISURF_IOMEM_SIZE);
286 		release_region(cs->hw.isurf.reset, 1);
287 		return (0);
288 	} else {
289 		request_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE,
290 			"isurf iomem");
291 	}
292 	cs->hw.isurf.isar =
293 		(unsigned long) ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE);
294 	cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET;
295 	printk(KERN_INFO
296 	       "ISurf: defined at 0x%x 0x%lx IRQ %d\n",
297 	       cs->hw.isurf.reset,
298 	       cs->hw.isurf.phymem,
299 	       cs->irq);
300 
301 	cs->cardmsg = &ISurf_card_msg;
302 	cs->irq_func = &isurf_interrupt;
303 	cs->auxcmd = &isurf_auxcmd;
304 	cs->readisac = &ReadISAC;
305 	cs->writeisac = &WriteISAC;
306 	cs->readisacfifo = &ReadISACfifo;
307 	cs->writeisacfifo = &WriteISACfifo;
308 	cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
309 	cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
310 	reset_isurf(cs, ISURF_RESET);
311 	test_and_set_bit(HW_ISAR, &cs->HW_Flags);
312 	ISACVersion(cs, "ISurf:");
313 	cs->BC_Read_Reg = &ReadISAR;
314 	cs->BC_Write_Reg = &WriteISAR;
315 	cs->BC_Send_Data = &isar_fill_fifo;
316 	ver = ISARVersion(cs, "ISurf:");
317 	if (ver < 0) {
318 		printk(KERN_WARNING
319 			"ISurf: wrong ISAR version (ret = %d)\n", ver);
320 		release_io_isurf(cs);
321 		return (0);
322 	}
323 	return (1);
324 }
325