1 /* $Id: saphir.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2  *
3  * low level stuff for HST Saphir 1
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  * Thanks to    HST High Soft Tech GmbH
12  *
13  */
14 
15 #define __NO_VERSION__
16 #include <linux/init.h>
17 #include "hisax.h"
18 #include "isac.h"
19 #include "hscx.h"
20 #include "isdnl1.h"
21 
22 extern const char *CardType[];
23 static char *saphir_rev = "$Revision: 1.1.4.1 $";
24 
25 #define byteout(addr,val) outb(val,addr)
26 #define bytein(addr) inb(addr)
27 
28 #define ISAC_DATA	0
29 #define HSCX_DATA	1
30 #define ADDRESS_REG	2
31 #define IRQ_REG		3
32 #define SPARE_REG	4
33 #define RESET_REG	5
34 
35 static inline u_char
readreg(unsigned int ale,unsigned int adr,u_char off)36 readreg(unsigned int ale, unsigned int adr, u_char off)
37 {
38 	register u_char ret;
39 	long flags;
40 
41 	save_flags(flags);
42 	cli();
43 	byteout(ale, off);
44 	ret = bytein(adr);
45 	restore_flags(flags);
46 	return (ret);
47 }
48 
49 static inline void
readfifo(unsigned int ale,unsigned int adr,u_char off,u_char * data,int size)50 readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
51 {
52 	/* fifo read without cli because it's allready done  */
53 
54 	byteout(ale, off);
55 	insb(adr, data, size);
56 }
57 
58 
59 static inline void
writereg(unsigned int ale,unsigned int adr,u_char off,u_char data)60 writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
61 {
62 	long flags;
63 
64 	save_flags(flags);
65 	cli();
66 	byteout(ale, off);
67 	byteout(adr, data);
68 	restore_flags(flags);
69 }
70 
71 static inline void
writefifo(unsigned int ale,unsigned int adr,u_char off,u_char * data,int size)72 writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
73 {
74 	/* fifo write without cli because it's allready done  */
75 	byteout(ale, off);
76 	outsb(adr, data, size);
77 }
78 
79 /* Interface functions */
80 
81 static u_char
ReadISAC(struct IsdnCardState * cs,u_char offset)82 ReadISAC(struct IsdnCardState *cs, u_char offset)
83 {
84 	return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
85 }
86 
87 static void
WriteISAC(struct IsdnCardState * cs,u_char offset,u_char value)88 WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
89 {
90 	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
91 }
92 
93 static void
ReadISACfifo(struct IsdnCardState * cs,u_char * data,int size)94 ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
95 {
96 	readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
97 }
98 
99 static void
WriteISACfifo(struct IsdnCardState * cs,u_char * data,int size)100 WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
101 {
102 	writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
103 }
104 
105 static u_char
ReadHSCX(struct IsdnCardState * cs,int hscx,u_char offset)106 ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
107 {
108 	return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
109 		offset + (hscx ? 0x40 : 0)));
110 }
111 
112 static void
WriteHSCX(struct IsdnCardState * cs,int hscx,u_char offset,u_char value)113 WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
114 {
115 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
116 		offset + (hscx ? 0x40 : 0), value);
117 }
118 
119 #define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
120 		cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
121 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
122 		cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
123 
124 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
125 		cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
126 
127 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
128 		cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
129 
130 #include "hscx_irq.c"
131 
132 static void
saphir_interrupt(int intno,void * dev_id,struct pt_regs * regs)133 saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
134 {
135 	struct IsdnCardState *cs = dev_id;
136 	u_char val;
137 
138 	if (!cs) {
139 		printk(KERN_WARNING "saphir: Spurious interrupt!\n");
140 		return;
141 	}
142 	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
143       Start_HSCX:
144 	if (val)
145 		hscx_int_main(cs, val);
146 	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
147       Start_ISAC:
148 	if (val)
149 		isac_interrupt(cs, val);
150 	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
151 	if (val) {
152 		if (cs->debug & L1_DEB_HSCX)
153 			debugl1(cs, "HSCX IntStat after IntRoutine");
154 		goto Start_HSCX;
155 	}
156 	val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
157 	if (val) {
158 		if (cs->debug & L1_DEB_ISAC)
159 			debugl1(cs, "ISAC IntStat after IntRoutine");
160 		goto Start_ISAC;
161 	}
162 	/* Watchdog */
163 	if (cs->hw.saphir.timer.function)
164 		mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
165 	else
166 		printk(KERN_WARNING "saphir: Spurious timer!\n");
167 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
168 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
169 	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
170 	writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
171 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
172 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
173 }
174 
175 static void
SaphirWatchDog(struct IsdnCardState * cs)176 SaphirWatchDog(struct IsdnCardState *cs)
177 {
178         /* 5 sec WatchDog, so read at least every 4 sec */
179 	cs->readisac(cs, ISAC_RBCH);
180 	mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
181 }
182 
183 void
release_io_saphir(struct IsdnCardState * cs)184 release_io_saphir(struct IsdnCardState *cs)
185 {
186 	long flags;
187 
188 	save_flags(flags);
189 	cli();
190 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
191 	del_timer(&cs->hw.saphir.timer);
192 	cs->hw.saphir.timer.function = NULL;
193 	restore_flags(flags);
194 	if (cs->hw.saphir.cfg_reg)
195 		release_region(cs->hw.saphir.cfg_reg, 6);
196 }
197 
198 static int
saphir_reset(struct IsdnCardState * cs)199 saphir_reset(struct IsdnCardState *cs)
200 {
201 	long flags;
202 	u_char irq_val;
203 
204 	switch(cs->irq) {
205 		case 5: irq_val = 0;
206 			break;
207 		case 3: irq_val = 1;
208 			break;
209 		case 11:
210 			irq_val = 2;
211 			break;
212 		case 12:
213 			irq_val = 3;
214 			break;
215 		case 15:
216 			irq_val = 4;
217 			break;
218 		default:
219 			printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
220 				cs->irq);
221 			return (1);
222 	}
223 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
224 	save_flags(flags);
225 	sti();
226 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
227 	set_current_state(TASK_UNINTERRUPTIBLE);
228 	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
229 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
230 	set_current_state(TASK_UNINTERRUPTIBLE);
231 	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
232 	restore_flags(flags);
233 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
234 	byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
235 	return (0);
236 }
237 
238 static int
saphir_card_msg(struct IsdnCardState * cs,int mt,void * arg)239 saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
240 {
241 	switch (mt) {
242 		case CARD_RESET:
243 			saphir_reset(cs);
244 			return(0);
245 		case CARD_RELEASE:
246 			release_io_saphir(cs);
247 			return(0);
248 		case CARD_INIT:
249 			inithscxisac(cs, 3);
250 			return(0);
251 		case CARD_TEST:
252 			return(0);
253 	}
254 	return(0);
255 }
256 
257 
258 int __init
setup_saphir(struct IsdnCard * card)259 setup_saphir(struct IsdnCard *card)
260 {
261 	struct IsdnCardState *cs = card->cs;
262 	char tmp[64];
263 
264 	strcpy(tmp, saphir_rev);
265 	printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
266 	if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
267 		return (0);
268 
269 	/* IO-Ports */
270 	cs->hw.saphir.cfg_reg = card->para[1];
271 	cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
272 	cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
273 	cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
274 	cs->irq = card->para[0];
275 	if (check_region((cs->hw.saphir.cfg_reg), 6)) {
276 		printk(KERN_WARNING
277 			"HiSax: %s config port %x-%x already in use\n",
278 			CardType[card->typ],
279 			cs->hw.saphir.cfg_reg,
280 			cs->hw.saphir.cfg_reg + 5);
281 		return (0);
282 	} else
283 		request_region(cs->hw.saphir.cfg_reg,6, "saphir");
284 
285 	printk(KERN_INFO
286 	       "HiSax: %s config irq:%d io:0x%X\n",
287 	       CardType[cs->typ], cs->irq,
288 	       cs->hw.saphir.cfg_reg);
289 
290 	cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
291 	cs->hw.saphir.timer.data = (long) cs;
292 	init_timer(&cs->hw.saphir.timer);
293 	cs->hw.saphir.timer.expires = jiffies + 4*HZ;
294 	add_timer(&cs->hw.saphir.timer);
295 	if (saphir_reset(cs)) {
296 		release_io_saphir(cs);
297 		return (0);
298 	}
299 	cs->readisac = &ReadISAC;
300 	cs->writeisac = &WriteISAC;
301 	cs->readisacfifo = &ReadISACfifo;
302 	cs->writeisacfifo = &WriteISACfifo;
303 	cs->BC_Read_Reg = &ReadHSCX;
304 	cs->BC_Write_Reg = &WriteHSCX;
305 	cs->BC_Send_Data = &hscx_fill_fifo;
306 	cs->cardmsg = &saphir_card_msg;
307 	cs->irq_func = &saphir_interrupt;
308 	ISACVersion(cs, "saphir:");
309 	if (HscxVersion(cs, "saphir:")) {
310 		printk(KERN_WARNING
311 		    "saphir: wrong HSCX versions check IO address\n");
312 		release_io_saphir(cs);
313 		return (0);
314 	}
315 	return (1);
316 }
317