• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setup_saphir(struct IsdnCard * card)243 int setup_saphir(struct IsdnCard *card)
244 {
245 	struct IsdnCardState *cs = card->cs;
246 	char tmp[64];
247 
248 	strcpy(tmp, saphir_rev);
249 	printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
250 	if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
251 		return (0);
252 
253 	/* IO-Ports */
254 	cs->hw.saphir.cfg_reg = card->para[1];
255 	cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
256 	cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
257 	cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
258 	cs->irq = card->para[0];
259 	if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) {
260 		printk(KERN_WARNING
261 		       "HiSax: HST Saphir config port %x-%x already in use\n",
262 		       cs->hw.saphir.cfg_reg,
263 		       cs->hw.saphir.cfg_reg + 5);
264 		return (0);
265 	}
266 
267 	printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n",
268 	       cs->irq, cs->hw.saphir.cfg_reg);
269 
270 	setup_isac(cs);
271 	cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
272 	cs->hw.saphir.timer.data = (long) cs;
273 	init_timer(&cs->hw.saphir.timer);
274 	cs->hw.saphir.timer.expires = jiffies + 4 * HZ;
275 	add_timer(&cs->hw.saphir.timer);
276 	if (saphir_reset(cs)) {
277 		release_io_saphir(cs);
278 		return (0);
279 	}
280 	cs->readisac = &ReadISAC;
281 	cs->writeisac = &WriteISAC;
282 	cs->readisacfifo = &ReadISACfifo;
283 	cs->writeisacfifo = &WriteISACfifo;
284 	cs->BC_Read_Reg = &ReadHSCX;
285 	cs->BC_Write_Reg = &WriteHSCX;
286 	cs->BC_Send_Data = &hscx_fill_fifo;
287 	cs->cardmsg = &saphir_card_msg;
288 	cs->irq_func = &saphir_interrupt;
289 	ISACVersion(cs, "saphir:");
290 	if (HscxVersion(cs, "saphir:")) {
291 		printk(KERN_WARNING
292 		       "saphir: wrong HSCX versions check IO address\n");
293 		release_io_saphir(cs);
294 		return (0);
295 	}
296 	return (1);
297 }
298