1 /* $Id: mic.c,v 1.1.4.1 2001/11/20 14:19:36 kai Exp $
2  *
3  * low level stuff for mic cards
4  *
5  * Author       Stephan von Krawczynski
6  * Copyright    by Stephan von Krawczynski <skraw@ithnet.com>
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 "hscx.h"
18 #include "isdnl1.h"
19 
20 extern const char *CardType[];
21 
22 const char *mic_revision = "$Revision: 1.1.4.1 $";
23 
24 #define byteout(addr,val) outb(val,addr)
25 #define bytein(addr) inb(addr)
26 
27 #define MIC_ISAC	2
28 #define MIC_HSCX	1
29 #define MIC_ADR		7
30 
31 /* CARD_ADR (Write) */
32 #define MIC_RESET      0x3	/* same as DOS driver */
33 
34 static inline u_char
readreg(unsigned int ale,unsigned int adr,u_char off)35 readreg(unsigned int ale, unsigned int adr, u_char off)
36 {
37 	register u_char ret;
38 	long flags;
39 
40 	save_flags(flags);
41 	cli();
42 	byteout(ale, off);
43 	ret = bytein(adr);
44 	restore_flags(flags);
45 
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.mic.adr, cs->hw.mic.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.mic.adr, cs->hw.mic.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.mic.adr, cs->hw.mic.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.mic.adr, cs->hw.mic.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.mic.adr,
109 			cs->hw.mic.hscx, 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.mic.adr,
116 		 cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value);
117 }
118 
119 /*
120  * fast interrupt HSCX stuff goes here
121  */
122 
123 #define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \
124 		cs->hw.mic.hscx, reg + (nr ? 0x40 : 0))
125 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \
126 		cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data)
127 
128 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \
129 		cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
130 
131 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \
132 		cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt)
133 
134 #include "hscx_irq.c"
135 
136 static void
mic_interrupt(int intno,void * dev_id,struct pt_regs * regs)137 mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
138 {
139 	struct IsdnCardState *cs = dev_id;
140 	u_char val;
141 
142 	if (!cs) {
143 		printk(KERN_WARNING "mic: Spurious interrupt!\n");
144 		return;
145 	}
146 	val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
147       Start_HSCX:
148 	if (val)
149 		hscx_int_main(cs, val);
150 	val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
151       Start_ISAC:
152 	if (val)
153 		isac_interrupt(cs, val);
154 	val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40);
155 	if (val) {
156 		if (cs->debug & L1_DEB_HSCX)
157 			debugl1(cs, "HSCX IntStat after IntRoutine");
158 		goto Start_HSCX;
159 	}
160 	val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA);
161 	if (val) {
162 		if (cs->debug & L1_DEB_ISAC)
163 			debugl1(cs, "ISAC IntStat after IntRoutine");
164 		goto Start_ISAC;
165 	}
166 	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF);
167 	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF);
168 	writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF);
169 	writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0);
170 	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0);
171 	writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0);
172 }
173 
174 void
release_io_mic(struct IsdnCardState * cs)175 release_io_mic(struct IsdnCardState *cs)
176 {
177 	int bytecnt = 8;
178 
179 	if (cs->hw.mic.cfg_reg)
180 		release_region(cs->hw.mic.cfg_reg, bytecnt);
181 }
182 
183 static int
mic_card_msg(struct IsdnCardState * cs,int mt,void * arg)184 mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
185 {
186 	switch (mt) {
187 		case CARD_RESET:
188 			return(0);
189 		case CARD_RELEASE:
190 			release_io_mic(cs);
191 			return(0);
192 		case CARD_INIT:
193 			inithscx(cs); /* /RTSA := ISAC RST */
194 			inithscxisac(cs, 3);
195 			return(0);
196 		case CARD_TEST:
197 			return(0);
198 	}
199 	return(0);
200 }
201 
202 int __init
setup_mic(struct IsdnCard * card)203 setup_mic(struct IsdnCard *card)
204 {
205 	int bytecnt;
206 	struct IsdnCardState *cs = card->cs;
207 	char tmp[64];
208 
209 	strcpy(tmp, mic_revision);
210 	printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp));
211 	if (cs->typ != ISDN_CTYPE_MIC)
212 		return (0);
213 
214 	bytecnt = 8;
215 	cs->hw.mic.cfg_reg = card->para[1];
216 	cs->irq = card->para[0];
217 	cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR;
218 	cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC;
219 	cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX;
220 
221 	if (check_region((cs->hw.mic.cfg_reg), bytecnt)) {
222 		printk(KERN_WARNING
223 		       "HiSax: %s config port %x-%x already in use\n",
224 		       CardType[card->typ],
225 		       cs->hw.mic.cfg_reg,
226 		       cs->hw.mic.cfg_reg + bytecnt);
227 		return (0);
228 	} else {
229 		request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn");
230 	}
231 
232 	printk(KERN_INFO
233 	       "mic: defined at 0x%x IRQ %d\n",
234 	       cs->hw.mic.cfg_reg,
235 	       cs->irq);
236 	cs->readisac = &ReadISAC;
237 	cs->writeisac = &WriteISAC;
238 	cs->readisacfifo = &ReadISACfifo;
239 	cs->writeisacfifo = &WriteISACfifo;
240 	cs->BC_Read_Reg = &ReadHSCX;
241 	cs->BC_Write_Reg = &WriteHSCX;
242 	cs->BC_Send_Data = &hscx_fill_fifo;
243 	cs->cardmsg = &mic_card_msg;
244 	cs->irq_func = &mic_interrupt;
245 	ISACVersion(cs, "mic:");
246 	if (HscxVersion(cs, "mic:")) {
247 		printk(KERN_WARNING
248 		    "mic: wrong HSCX versions check IO address\n");
249 		release_io_mic(cs);
250 		return (0);
251 	}
252 	return (1);
253 }
254