1 /* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $
3 * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
6 * Copyright by Karsten Keil <keil@isdn4linux.de>
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
11 * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information
15 #include <linux/init.h>
16 #include <linux/isapnp.h>
23 static const char *Asuscom_revision
= "$Revision: 1.14.2.4 $";
25 #define byteout(addr,val) outb(val,addr)
26 #define bytein(addr) inb(addr)
31 #define ASUS_CTRL_U7 3
32 #define ASUS_CTRL_POTS 5
34 #define ASUS_IPAC_ALE 0
35 #define ASUS_IPAC_DATA 1
37 #define ASUS_ISACHSCX 1
40 /* CARD_ADR (Write) */
41 #define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
44 readreg(unsigned int ale
, unsigned int adr
, u_char off
)
54 readfifo(unsigned int ale
, unsigned int adr
, u_char off
, u_char
* data
, int size
)
57 insb(adr
, data
, size
);
62 writereg(unsigned int ale
, unsigned int adr
, u_char off
, u_char data
)
69 writefifo(unsigned int ale
, unsigned int adr
, u_char off
, u_char
* data
, int size
)
72 outsb(adr
, data
, size
);
75 /* Interface functions */
78 ReadISAC(struct IsdnCardState
*cs
, u_char offset
)
80 return (readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, offset
));
84 WriteISAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
86 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, offset
, value
);
90 ReadISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
92 readfifo(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, 0, data
, size
);
96 WriteISACfifo(struct IsdnCardState
*cs
, u_char
* data
, int size
)
98 writefifo(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, 0, data
, size
);
102 ReadISAC_IPAC(struct IsdnCardState
*cs
, u_char offset
)
104 return (readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, offset
|0x80));
108 WriteISAC_IPAC(struct IsdnCardState
*cs
, u_char offset
, u_char value
)
110 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, offset
|0x80, value
);
114 ReadISACfifo_IPAC(struct IsdnCardState
*cs
, u_char
* data
, int size
)
116 readfifo(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, 0x80, data
, size
);
120 WriteISACfifo_IPAC(struct IsdnCardState
*cs
, u_char
* data
, int size
)
122 writefifo(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, 0x80, data
, size
);
126 ReadHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
)
128 return (readreg(cs
->hw
.asus
.adr
,
129 cs
->hw
.asus
.hscx
, offset
+ (hscx
? 0x40 : 0)));
133 WriteHSCX(struct IsdnCardState
*cs
, int hscx
, u_char offset
, u_char value
)
135 writereg(cs
->hw
.asus
.adr
,
136 cs
->hw
.asus
.hscx
, offset
+ (hscx
? 0x40 : 0), value
);
140 * fast interrupt HSCX stuff goes here
143 #define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \
144 cs->hw.asus.hscx, reg + (nr ? 0x40 : 0))
145 #define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \
146 cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data)
148 #define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \
149 cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
151 #define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \
152 cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt)
154 #include "hscx_irq.c"
157 asuscom_interrupt(int intno
, void *dev_id
)
159 struct IsdnCardState
*cs
= dev_id
;
163 spin_lock_irqsave(&cs
->lock
, flags
);
164 val
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_ISTA
+ 0x40);
167 hscx_int_main(cs
, val
);
168 val
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, ISAC_ISTA
);
171 isac_interrupt(cs
, val
);
172 val
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_ISTA
+ 0x40);
174 if (cs
->debug
& L1_DEB_HSCX
)
175 debugl1(cs
, "HSCX IntStat after IntRoutine");
178 val
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, ISAC_ISTA
);
180 if (cs
->debug
& L1_DEB_ISAC
)
181 debugl1(cs
, "ISAC IntStat after IntRoutine");
184 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_MASK
, 0xFF);
185 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_MASK
+ 0x40, 0xFF);
186 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, ISAC_MASK
, 0xFF);
187 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, ISAC_MASK
, 0x0);
188 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_MASK
, 0x0);
189 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_MASK
+ 0x40, 0x0);
190 spin_unlock_irqrestore(&cs
->lock
, flags
);
195 asuscom_interrupt_ipac(int intno
, void *dev_id
)
197 struct IsdnCardState
*cs
= dev_id
;
198 u_char ista
, val
, icnt
= 5;
201 spin_lock_irqsave(&cs
->lock
, flags
);
202 ista
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_ISTA
);
204 if (cs
->debug
& L1_DEB_IPAC
)
205 debugl1(cs
, "IPAC ISTA %02X", ista
);
207 val
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.hscx
, HSCX_ISTA
+ 0x40);
215 hscx_int_main(cs
, val
);
218 val
= 0xfe & readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, ISAC_ISTA
| 0x80);
220 isac_interrupt(cs
, val
);
225 isac_interrupt(cs
, val
);
227 ista
= readreg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_ISTA
);
228 if ((ista
& 0x3f) && icnt
) {
233 printk(KERN_WARNING
"ASUS IRQ LOOP\n");
234 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_MASK
, 0xFF);
235 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_MASK
, 0xC0);
236 spin_unlock_irqrestore(&cs
->lock
, flags
);
241 release_io_asuscom(struct IsdnCardState
*cs
)
245 if (cs
->hw
.asus
.cfg_reg
)
246 release_region(cs
->hw
.asus
.cfg_reg
, bytecnt
);
250 reset_asuscom(struct IsdnCardState
*cs
)
252 if (cs
->subtyp
== ASUS_IPAC
)
253 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_POTA2
, 0x20);
255 byteout(cs
->hw
.asus
.adr
, ASUS_RESET
); /* Reset On */
257 if (cs
->subtyp
== ASUS_IPAC
)
258 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_POTA2
, 0x0);
260 byteout(cs
->hw
.asus
.adr
, 0); /* Reset Off */
262 if (cs
->subtyp
== ASUS_IPAC
) {
263 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_CONF
, 0x0);
264 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_ACFG
, 0xff);
265 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_AOE
, 0x0);
266 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_MASK
, 0xc0);
267 writereg(cs
->hw
.asus
.adr
, cs
->hw
.asus
.isac
, IPAC_PCFG
, 0x12);
272 Asus_card_msg(struct IsdnCardState
*cs
, int mt
, void *arg
)
278 spin_lock_irqsave(&cs
->lock
, flags
);
280 spin_unlock_irqrestore(&cs
->lock
, flags
);
283 release_io_asuscom(cs
);
286 spin_lock_irqsave(&cs
->lock
, flags
);
287 cs
->debug
|= L1_DEB_IPAC
;
289 spin_unlock_irqrestore(&cs
->lock
, flags
);
298 static struct isapnp_device_id asus_ids
[] __devinitdata
= {
299 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
300 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
301 (unsigned long) "Asus1688 PnP" },
302 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
303 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
304 (unsigned long) "Asus1690 PnP" },
305 { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
306 ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
307 (unsigned long) "Isurf2 PnP" },
308 { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
309 ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
310 (unsigned long) "Iscas TE320" },
314 static struct isapnp_device_id
*ipid __devinitdata
= &asus_ids
[0];
315 static struct pnp_card
*pnp_c __devinitdata
= NULL
;
319 setup_asuscom(struct IsdnCard
*card
)
322 struct IsdnCardState
*cs
= card
->cs
;
326 strcpy(tmp
, Asuscom_revision
);
327 printk(KERN_INFO
"HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp
));
328 if (cs
->typ
!= ISDN_CTYPE_ASUSCOM
)
331 if (!card
->para
[1] && isapnp_present()) {
332 struct pnp_dev
*pnp_d
;
333 while(ipid
->card_vendor
) {
334 if ((pnp_c
= pnp_find_card(ipid
->card_vendor
,
335 ipid
->card_device
, pnp_c
))) {
337 if ((pnp_d
= pnp_find_dev(pnp_c
,
338 ipid
->vendor
, ipid
->function
, pnp_d
))) {
341 printk(KERN_INFO
"HiSax: %s detected\n",
342 (char *)ipid
->driver_data
);
343 pnp_disable_dev(pnp_d
);
344 err
= pnp_activate_dev(pnp_d
);
346 printk(KERN_WARNING
"%s: pnp_activate_dev ret(%d)\n",
350 card
->para
[1] = pnp_port_start(pnp_d
, 0);
351 card
->para
[0] = pnp_irq(pnp_d
, 0);
352 if (!card
->para
[0] || !card
->para
[1]) {
353 printk(KERN_ERR
"AsusPnP:some resources are missing %ld/%lx\n",
354 card
->para
[0], card
->para
[1]);
355 pnp_disable_dev(pnp_d
);
360 printk(KERN_ERR
"AsusPnP: PnP error card found, no device\n");
366 if (!ipid
->card_vendor
) {
367 printk(KERN_INFO
"AsusPnP: no ISAPnP card found\n");
373 cs
->hw
.asus
.cfg_reg
= card
->para
[1];
374 cs
->irq
= card
->para
[0];
375 if (!request_region(cs
->hw
.asus
.cfg_reg
, bytecnt
, "asuscom isdn")) {
377 "HiSax: ISDNLink config port %x-%x already in use\n",
379 cs
->hw
.asus
.cfg_reg
+ bytecnt
);
382 printk(KERN_INFO
"ISDNLink: defined at 0x%x IRQ %d\n",
383 cs
->hw
.asus
.cfg_reg
, cs
->irq
);
385 cs
->BC_Read_Reg
= &ReadHSCX
;
386 cs
->BC_Write_Reg
= &WriteHSCX
;
387 cs
->BC_Send_Data
= &hscx_fill_fifo
;
388 cs
->cardmsg
= &Asus_card_msg
;
389 val
= readreg(cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_ALE
,
390 cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
, IPAC_ID
);
391 if ((val
== 1) || (val
== 2)) {
392 cs
->subtyp
= ASUS_IPAC
;
393 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_ALE
;
394 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
;
395 cs
->hw
.asus
.hscx
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
;
396 test_and_set_bit(HW_IPAC
, &cs
->HW_Flags
);
397 cs
->readisac
= &ReadISAC_IPAC
;
398 cs
->writeisac
= &WriteISAC_IPAC
;
399 cs
->readisacfifo
= &ReadISACfifo_IPAC
;
400 cs
->writeisacfifo
= &WriteISACfifo_IPAC
;
401 cs
->irq_func
= &asuscom_interrupt_ipac
;
402 printk(KERN_INFO
"Asus: IPAC version %x\n", val
);
404 cs
->subtyp
= ASUS_ISACHSCX
;
405 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_ADR
;
406 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_ISAC
;
407 cs
->hw
.asus
.hscx
= cs
->hw
.asus
.cfg_reg
+ ASUS_HSCX
;
408 cs
->hw
.asus
.u7
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_U7
;
409 cs
->hw
.asus
.pots
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_POTS
;
410 cs
->readisac
= &ReadISAC
;
411 cs
->writeisac
= &WriteISAC
;
412 cs
->readisacfifo
= &ReadISACfifo
;
413 cs
->writeisacfifo
= &WriteISACfifo
;
414 cs
->irq_func
= &asuscom_interrupt
;
415 ISACVersion(cs
, "ISDNLink:");
416 if (HscxVersion(cs
, "ISDNLink:")) {
418 "ISDNLink: wrong HSCX versions check IO address\n");
419 release_io_asuscom(cs
);