File: /usr/src/linux/drivers/isdn/hisax/avm_a1p.c

1     /* $Id: avm_a1p.c,v 2.7.6.1 2001/02/16 16:43:25 kai Exp $
2      *
3      * avm_a1p.c    low level stuff for the following AVM cards:
4      *              A1 PCMCIA
5      *		FRITZ!Card PCMCIA
6      *		FRITZ!Card PCMCIA 2.0
7      *
8      * Author       Carsten Paeth (calle@calle.in-berlin.de)
9      *
10      *  This file is (c) under GNU General Public License
11      */
12     #define __NO_VERSION__
13     #include <linux/init.h>
14     #include "hisax.h"
15     #include "isac.h"
16     #include "hscx.h"
17     #include "isdnl1.h"
18     
19     /* register offsets */
20     #define ADDRREG_OFFSET		0x02
21     #define DATAREG_OFFSET		0x03
22     #define ASL0_OFFSET		0x04
23     #define ASL1_OFFSET		0x05
24     #define MODREG_OFFSET		0x06
25     #define VERREG_OFFSET		0x07
26     
27     /* address offsets */
28     #define ISAC_FIFO_OFFSET	0x00
29     #define ISAC_REG_OFFSET		0x20
30     #define HSCX_CH_DIFF		0x40
31     #define HSCX_FIFO_OFFSET	0x80
32     #define HSCX_REG_OFFSET		0xa0
33     
34     /* read bits ASL0 */
35     #define	 ASL0_R_TIMER		0x10 /* active low */
36     #define	 ASL0_R_ISAC		0x20 /* active low */
37     #define	 ASL0_R_HSCX		0x40 /* active low */
38     #define	 ASL0_R_TESTBIT		0x80
39     #define  ASL0_R_IRQPENDING	(ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER)
40     
41     /* write bits ASL0 */
42     #define	 ASL0_W_RESET		0x01
43     #define	 ASL0_W_TDISABLE	0x02
44     #define	 ASL0_W_TRESET		0x04
45     #define	 ASL0_W_IRQENABLE	0x08
46     #define	 ASL0_W_TESTBIT		0x80
47     
48     /* write bits ASL1 */
49     #define	 ASL1_W_LED0		0x10
50     #define	 ASL1_W_LED1		0x20
51     #define	 ASL1_W_ENABLE_S0	0xC0
52      
53     #define byteout(addr,val) outb(val,addr)
54     #define bytein(addr) inb(addr)
55     
56     static const char *avm_revision = "$Revision: 2.7.6.1 $";
57     
58     static inline u_char
59     ReadISAC(struct IsdnCardState *cs, u_char offset)
60     {
61     	long flags;
62             u_char ret;
63     
64             offset -= 0x20;
65     	save_flags(flags);
66     	cli();
67             byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
68     	ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
69     	restore_flags(flags);
70     	return ret;
71     }
72     
73     static inline void
74     WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
75     {
76     	long flags;
77     
78             offset -= 0x20;
79     
80     	save_flags(flags);
81     	cli();
82             byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_REG_OFFSET+offset);
83     	byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
84     	restore_flags(flags);
85     }
86     
87     static inline void
88     ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
89     {
90     	long flags;
91     
92     	save_flags(flags);
93     	cli();
94     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
95     	insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
96     	restore_flags(flags);
97     }
98     
99     static inline void
100     WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
101     {
102     	long flags;
103     
104     	save_flags(flags);
105     	cli();
106     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,ISAC_FIFO_OFFSET);
107     	outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
108     	restore_flags(flags);
109     }
110     
111     static inline u_char
112     ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
113     {
114     	u_char ret;
115     	long flags;
116     
117             offset -= 0x20;
118     
119     	save_flags(flags);
120     	cli();
121     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
122     			HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
123     	ret = bytein(cs->hw.avm.cfg_reg+DATAREG_OFFSET);
124     	restore_flags(flags);
125     	return ret;
126     }
127     
128     static inline void
129     WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
130     {
131     	long flags;
132     
133             offset -= 0x20;
134     
135     	save_flags(flags);
136     	cli();
137     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
138     			HSCX_REG_OFFSET+hscx*HSCX_CH_DIFF+offset);
139     	byteout(cs->hw.avm.cfg_reg+DATAREG_OFFSET, value);
140     	restore_flags(flags);
141     }
142     
143     static inline void
144     ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
145     {
146     	long flags;
147     
148     	save_flags(flags);
149     	cli();
150     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
151     			HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
152     	insb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
153     	restore_flags(flags);
154     }
155     
156     static inline void
157     WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
158     {
159     	long flags;
160     
161     	save_flags(flags);
162     	cli();
163     	byteout(cs->hw.avm.cfg_reg+ADDRREG_OFFSET,
164     			HSCX_FIFO_OFFSET+hscx*HSCX_CH_DIFF);
165     	outsb(cs->hw.avm.cfg_reg+DATAREG_OFFSET, data, size);
166     	restore_flags(flags);
167     }
168     
169     /*
170      * fast interrupt HSCX stuff goes here
171      */
172     
173     #define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
174     #define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
175     #define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) 
176     #define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
177     
178     #include "hscx_irq.c"
179     
180     static void
181     avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
182     {
183     	struct IsdnCardState *cs = dev_id;
184     	u_char val, sval;
185     
186     	if (!cs) {
187     		printk(KERN_WARNING "AVM A1 PCMCIA: Spurious interrupt!\n");
188     		return;
189     	}
190     	while ((sval = (~bytein(cs->hw.avm.cfg_reg+ASL0_OFFSET) & ASL0_R_IRQPENDING))) {
191     		if (cs->debug & L1_DEB_INTSTAT)
192     			debugl1(cs, "avm IntStatus %x", sval);
193     		if (sval & ASL0_R_HSCX) {
194                             val = ReadHSCX(cs, 1, HSCX_ISTA);
195     			if (val)
196     				hscx_int_main(cs, val);
197     		}
198     		if (sval & ASL0_R_ISAC) {
199     			val = ReadISAC(cs, ISAC_ISTA);
200     			if (val)
201     				isac_interrupt(cs, val);
202     		}
203     	}
204     	WriteHSCX(cs, 0, HSCX_MASK, 0xff);
205     	WriteHSCX(cs, 1, HSCX_MASK, 0xff);
206     	WriteISAC(cs, ISAC_MASK, 0xff);
207     	WriteISAC(cs, ISAC_MASK, 0x00);
208     	WriteHSCX(cs, 0, HSCX_MASK, 0x00);
209     	WriteHSCX(cs, 1, HSCX_MASK, 0x00);
210     }
211     
212     static int
213     AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
214     {
215     	switch (mt) {
216     		case CARD_RESET:
217     			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
218     			HZDELAY(HZ / 5 + 1);
219     			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
220     			HZDELAY(HZ / 5 + 1);
221     			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
222     			return 0;
223     
224     		case CARD_RELEASE:
225     			/* free_irq is done in HiSax_closecard(). */
226     		        /* free_irq(cs->irq, cs); */
227     			return 0;
228     
229     		case CARD_INIT:
230     			byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_TDISABLE|ASL0_W_TRESET|ASL0_W_IRQENABLE);
231     			clear_pending_isac_ints(cs);
232     			clear_pending_hscx_ints(cs);
233     			inithscxisac(cs, 1);
234     			inithscxisac(cs, 2);
235     			return 0;
236     
237     		case CARD_TEST:
238     			/* we really don't need it for the PCMCIA Version */
239     			return 0;
240     
241     		default:
242     			/* all card drivers ignore others, so we do the same */
243     			return 0;
244     	}
245     	return 0;
246     }
247     
248     int __devinit
249     setup_avm_a1_pcmcia(struct IsdnCard *card)
250     {
251     	u_char model, vers;
252     	struct IsdnCardState *cs = card->cs;
253     	long flags;
254     	char tmp[64];
255     
256     
257     	strcpy(tmp, avm_revision);
258     	printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n",
259     						 HiSax_getrev(tmp));
260     	if (cs->typ != ISDN_CTYPE_A1_PCMCIA)
261     		return (0);
262     
263     	cs->hw.avm.cfg_reg = card->para[1];
264     	cs->irq = card->para[0];
265     
266     
267     	save_flags(flags);
268     	outb(cs->hw.avm.cfg_reg+ASL1_OFFSET, ASL1_W_ENABLE_S0);
269             sti();
270     
271     	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
272     	HZDELAY(HZ / 5 + 1);
273     	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,ASL0_W_RESET);
274     	HZDELAY(HZ / 5 + 1);
275     	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET,0x00);
276     
277     	byteout(cs->hw.avm.cfg_reg+ASL0_OFFSET, ASL0_W_TDISABLE|ASL0_W_TRESET);
278     
279     	restore_flags(flags);
280     
281     	model = bytein(cs->hw.avm.cfg_reg+MODREG_OFFSET);
282     	vers = bytein(cs->hw.avm.cfg_reg+VERREG_OFFSET);
283     
284     	printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
285     				cs->hw.avm.cfg_reg, cs->irq, model, vers);
286     
287     	cs->readisac = &ReadISAC;
288     	cs->writeisac = &WriteISAC;
289     	cs->readisacfifo = &ReadISACfifo;
290     	cs->writeisacfifo = &WriteISACfifo;
291     	cs->BC_Read_Reg = &ReadHSCX;
292     	cs->BC_Write_Reg = &WriteHSCX;
293     	cs->BC_Send_Data = &hscx_fill_fifo;
294     	cs->cardmsg = &AVM_card_msg;
295     	cs->irq_func = &avm_a1p_interrupt;
296     
297     	ISACVersion(cs, "AVM A1 PCMCIA:");
298     	if (HscxVersion(cs, "AVM A1 PCMCIA:")) {
299     		printk(KERN_WARNING
300     		       "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");
301     		return (0);
302     	}
303     	return (1);
304     }
305