1 /* $Id: avm_a1p.c,v 2.3 1998/11/15 23:54:22 keil Exp $
3 * avm_a1p.c low level stuff for the following AVM cards:
6 * FRITZ!Card PCMCIA 2.0
8 * Author Carsten Paeth (calle@calle.in-berlin.de)
11 * Revision 2.3 1998/11/15 23:54:22 keil
14 * Revision 2.2 1998/08/13 23:36:13 keil
15 * HiSax 3.1 - don't work stable with current LinkLevel
17 * Revision 2.1 1998/07/15 15:01:23 calle
18 * Support for AVM passive PCMCIA cards:
19 * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
21 * Revision 1.1.2.1 1998/07/15 14:43:26 calle
22 * Support for AVM passive PCMCIA cards:
23 * A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
27 #define __NO_VERSION__
33 /* register offsets */
34 #define ADDRREG_OFFSET 0x02
35 #define DATAREG_OFFSET 0x03
36 #define ASL0_OFFSET 0x04
37 #define ASL1_OFFSET 0x05
38 #define MODREG_OFFSET 0x06
39 #define VERREG_OFFSET 0x07
42 #define ISAC_FIFO_OFFSET 0x00
43 #define ISAC_REG_OFFSET 0x20
44 #define HSCX_CH_DIFF 0x40
45 #define HSCX_FIFO_OFFSET 0x80
46 #define HSCX_REG_OFFSET 0xa0
49 #define ASL0_R_TIMER 0x10 /* active low */
50 #define ASL0_R_ISAC 0x20 /* active low */
51 #define ASL0_R_HSCX 0x40 /* active low */
52 #define ASL0_R_TESTBIT 0x80
53 #define ASL0_R_IRQPENDING (ASL0_R_ISAC|ASL0_R_HSCX|ASL0_R_TIMER)
56 #define ASL0_W_RESET 0x01
57 #define ASL0_W_TDISABLE 0x02
58 #define ASL0_W_TRESET 0x04
59 #define ASL0_W_IRQENABLE 0x08
60 #define ASL0_W_TESTBIT 0x80
63 #define ASL1_W_LED0 0x10
64 #define ASL1_W_LED1 0x20
65 #define ASL1_W_ENABLE_S0 0xC0
67 #define byteout(addr,val) outb(val,addr)
68 #define bytein(addr) inb(addr)
70 static const char *avm_revision
= "$Revision: 2.3 $";
73 ReadISAC(struct IsdnCardState
*cs
, u_char offset
)
81 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_REG_OFFSET
+offset
);
82 ret
= bytein(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
);
88 WriteISAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
96 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_REG_OFFSET
+offset
);
97 byteout(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, value
);
102 ReadISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
108 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_FIFO_OFFSET
);
109 insb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
110 restore_flags(flags
);
114 WriteISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
120 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,ISAC_FIFO_OFFSET
);
121 outsb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
122 restore_flags(flags
);
126 ReadHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
)
135 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
136 HSCX_REG_OFFSET
+hscx
*HSCX_CH_DIFF
+offset
);
137 ret
= bytein(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
);
138 restore_flags(flags
);
143 WriteHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
, u_char value
)
151 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
152 HSCX_REG_OFFSET
+hscx
*HSCX_CH_DIFF
+offset
);
153 byteout(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, value
);
154 restore_flags(flags
);
158 ReadHSCXfifo(struct IsdnCardState
*cs
, int hscx
, u_char
* data
, int size
)
164 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
165 HSCX_FIFO_OFFSET
+hscx
*HSCX_CH_DIFF
);
166 insb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
167 restore_flags(flags
);
171 WriteHSCXfifo(struct IsdnCardState
*cs
, int hscx
, u_char
* data
, int size
)
177 byteout(cs
->hw
.avm
.cfg_reg
+ADDRREG_OFFSET
,
178 HSCX_FIFO_OFFSET
+hscx
*HSCX_CH_DIFF
);
179 outsb(cs
->hw
.avm
.cfg_reg
+DATAREG_OFFSET
, data
, size
);
180 restore_flags(flags
);
184 * fast interrupt HSCX stuff goes here
187 #define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg)
188 #define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data)
189 #define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt)
190 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt)
192 #include "hscx_irq.c"
195 avm_a1p_interrupt(int intno
, void *dev_id
, struct pt_regs
*regs
)
197 struct IsdnCardState
*cs
= dev_id
;
198 u_char val
, sval
, stat
= 0;
201 printk(KERN_WARNING
"AVM A1 PCMCIA: Spurious interrupt!\n");
204 while ((sval
= (~bytein(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
) & ASL0_R_IRQPENDING
))) {
205 if (cs
->debug
& L1_DEB_INTSTAT
)
206 debugl1(cs
, "avm IntStatus %x", sval
);
207 if (sval
& ASL0_R_HSCX
) {
208 val
= ReadHSCX(cs
, 1, HSCX_ISTA
);
210 hscx_int_main(cs
, val
);
214 if (sval
& ASL0_R_ISAC
) {
215 val
= ReadISAC(cs
, ISAC_ISTA
);
217 isac_interrupt(cs
, val
);
223 WriteHSCX(cs
, 0, HSCX_MASK
, 0xff);
224 WriteHSCX(cs
, 1, HSCX_MASK
, 0xff);
225 WriteHSCX(cs
, 0, HSCX_MASK
, 0x00);
226 WriteHSCX(cs
, 1, HSCX_MASK
, 0x00);
229 WriteISAC(cs
, ISAC_MASK
, 0xff);
230 WriteISAC(cs
, ISAC_MASK
, 0x00);
235 AVM_card_msg(struct IsdnCardState
*cs
, int mt
, void *arg
)
240 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
242 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
244 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
248 /* free_irq is done in HiSax_closecard(). */
249 /* free_irq(cs->irq, cs); */
253 ret
= request_irq(cs
->irq
, &avm_a1p_interrupt
,
254 I4L_IRQ_FLAG
, "HiSax", cs
);
257 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,
258 ASL0_W_TDISABLE
|ASL0_W_TRESET
|ASL0_W_IRQENABLE
);
262 clear_pending_isac_ints(cs
);
263 clear_pending_hscx_ints(cs
);
269 /* we really don't need it for the PCMCIA Version */
273 /* all card drivers ignore others, so we do the same */
280 setup_avm_a1_pcmcia(struct IsdnCard
*card
))
283 struct IsdnCardState
*cs
= card
->cs
;
288 strcpy(tmp
, avm_revision
);
289 printk(KERN_INFO
"HiSax: AVM A1 PCMCIA driver Rev. %s\n",
291 if (cs
->typ
!= ISDN_CTYPE_A1_PCMCIA
)
294 cs
->hw
.avm
.cfg_reg
= card
->para
[1];
295 cs
->irq
= card
->para
[0];
299 outb(cs
->hw
.avm
.cfg_reg
+ASL1_OFFSET
, ASL1_W_ENABLE_S0
);
302 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
304 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,ASL0_W_RESET
);
306 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
,0x00);
308 byteout(cs
->hw
.avm
.cfg_reg
+ASL0_OFFSET
, ASL0_W_TDISABLE
|ASL0_W_TRESET
);
310 restore_flags(flags
);
312 model
= bytein(cs
->hw
.avm
.cfg_reg
+MODREG_OFFSET
);
313 vers
= bytein(cs
->hw
.avm
.cfg_reg
+VERREG_OFFSET
);
315 printk(KERN_INFO
"AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n",
316 cs
->hw
.avm
.cfg_reg
, cs
->irq
, model
, vers
);
318 cs
->readisac
= &ReadISAC
;
319 cs
->writeisac
= &WriteISAC
;
320 cs
->readisacfifo
= &ReadISACfifo
;
321 cs
->writeisacfifo
= &WriteISACfifo
;
322 cs
->BC_Read_Reg
= &ReadHSCX
;
323 cs
->BC_Write_Reg
= &WriteHSCX
;
324 cs
->BC_Send_Data
= &hscx_fill_fifo
;
325 cs
->cardmsg
= &AVM_card_msg
;
327 ISACVersion(cs
, "AVM A1 PCMCIA:");
328 if (HscxVersion(cs
, "AVM A1 PCMCIA:")) {
330 "AVM A1 PCMCIA: wrong HSCX versions check IO address\n");