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