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 timer_list * t)162 SaphirWatchDog(struct timer_list *t)
163 {
164 	struct IsdnCardState *cs = from_timer(cs, t, hw.saphir.timer);
165 	u_long flags;
166 
167 	spin_lock_irqsave(&cs->lock, flags);
168 	/* 5 sec WatchDog, so read at least every 4 sec */
169 	cs->readisac(cs, ISAC_RBCH);
170 	spin_unlock_irqrestore(&cs->lock, flags);
171 	mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ);
172 }
173 
174 static void
release_io_saphir(struct IsdnCardState * cs)175 release_io_saphir(struct IsdnCardState *cs)
176 {
177 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
178 	del_timer(&cs->hw.saphir.timer);
179 	cs->hw.saphir.timer.function = NULL;
180 	if (cs->hw.saphir.cfg_reg)
181 		release_region(cs->hw.saphir.cfg_reg, 6);
182 }
183 
184 static int
saphir_reset(struct IsdnCardState * cs)185 saphir_reset(struct IsdnCardState *cs)
186 {
187 	u_char irq_val;
188 
189 	switch (cs->irq) {
190 	case 5: irq_val = 0;
191 		break;
192 	case 3: irq_val = 1;
193 		break;
194 	case 11:
195 		irq_val = 2;
196 		break;
197 	case 12:
198 		irq_val = 3;
199 		break;
200 	case 15:
201 		irq_val = 4;
202 		break;
203 	default:
204 		printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
205 		       cs->irq);
206 		return (1);
207 	}
208 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
209 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
210 	mdelay(10);
211 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
212 	mdelay(10);
213 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
214 	byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
215 	return (0);
216 }
217 
218 static int
saphir_card_msg(struct IsdnCardState * cs,int mt,void * arg)219 saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
220 {
221 	u_long flags;
222 
223 	switch (mt) {
224 	case CARD_RESET:
225 		spin_lock_irqsave(&cs->lock, flags);
226 		saphir_reset(cs);
227 		spin_unlock_irqrestore(&cs->lock, flags);
228 		return (0);
229 	case CARD_RELEASE:
230 		release_io_saphir(cs);
231 		return (0);
232 	case CARD_INIT:
233 		spin_lock_irqsave(&cs->lock, flags);
234 		inithscxisac(cs, 3);
235 		spin_unlock_irqrestore(&cs->lock, flags);
236 		return (0);
237 	case CARD_TEST:
238 		return (0);
239 	}
240 	return (0);
241 }
242 
243 
setup_saphir(struct IsdnCard * card)244 int 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 	timer_setup(&cs->hw.saphir.timer, SaphirWatchDog, 0);
273 	cs->hw.saphir.timer.expires = jiffies + 4 * HZ;
274 	add_timer(&cs->hw.saphir.timer);
275 	if (saphir_reset(cs)) {
276 		release_io_saphir(cs);
277 		return (0);
278 	}
279 	cs->readisac = &ReadISAC;
280 	cs->writeisac = &WriteISAC;
281 	cs->readisacfifo = &ReadISACfifo;
282 	cs->writeisacfifo = &WriteISACfifo;
283 	cs->BC_Read_Reg = &ReadHSCX;
284 	cs->BC_Write_Reg = &WriteHSCX;
285 	cs->BC_Send_Data = &hscx_fill_fifo;
286 	cs->cardmsg = &saphir_card_msg;
287 	cs->irq_func = &saphir_interrupt;
288 	ISACVersion(cs, "saphir:");
289 	if (HscxVersion(cs, "saphir:")) {
290 		printk(KERN_WARNING
291 		       "saphir: wrong HSCX versions check IO address\n");
292 		release_io_saphir(cs);
293 		return (0);
294 	}
295 	return (1);
296 }
297