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
[] = {
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
= &asus_ids
[0];
315 static struct pnp_card
*pnp_c
= NULL
;
318 int setup_asuscom(struct IsdnCard
*card
)
321 struct IsdnCardState
*cs
= card
->cs
;
325 strcpy(tmp
, Asuscom_revision
);
326 printk(KERN_INFO
"HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp
));
327 if (cs
->typ
!= ISDN_CTYPE_ASUSCOM
)
330 if (!card
->para
[1] && isapnp_present()) {
331 struct pnp_dev
*pnp_d
;
332 while (ipid
->card_vendor
) {
333 if ((pnp_c
= pnp_find_card(ipid
->card_vendor
,
334 ipid
->card_device
, pnp_c
))) {
336 if ((pnp_d
= pnp_find_dev(pnp_c
,
337 ipid
->vendor
, ipid
->function
, pnp_d
))) {
340 printk(KERN_INFO
"HiSax: %s detected\n",
341 (char *)ipid
->driver_data
);
342 pnp_disable_dev(pnp_d
);
343 err
= pnp_activate_dev(pnp_d
);
345 printk(KERN_WARNING
"%s: pnp_activate_dev ret(%d)\n",
349 card
->para
[1] = pnp_port_start(pnp_d
, 0);
350 card
->para
[0] = pnp_irq(pnp_d
, 0);
351 if (!card
->para
[0] || !card
->para
[1]) {
352 printk(KERN_ERR
"AsusPnP:some resources are missing %ld/%lx\n",
353 card
->para
[0], card
->para
[1]);
354 pnp_disable_dev(pnp_d
);
359 printk(KERN_ERR
"AsusPnP: PnP error card found, no device\n");
365 if (!ipid
->card_vendor
) {
366 printk(KERN_INFO
"AsusPnP: no ISAPnP card found\n");
372 cs
->hw
.asus
.cfg_reg
= card
->para
[1];
373 cs
->irq
= card
->para
[0];
374 if (!request_region(cs
->hw
.asus
.cfg_reg
, bytecnt
, "asuscom isdn")) {
376 "HiSax: ISDNLink config port %x-%x already in use\n",
378 cs
->hw
.asus
.cfg_reg
+ bytecnt
);
381 printk(KERN_INFO
"ISDNLink: defined at 0x%x IRQ %d\n",
382 cs
->hw
.asus
.cfg_reg
, cs
->irq
);
384 cs
->BC_Read_Reg
= &ReadHSCX
;
385 cs
->BC_Write_Reg
= &WriteHSCX
;
386 cs
->BC_Send_Data
= &hscx_fill_fifo
;
387 cs
->cardmsg
= &Asus_card_msg
;
388 val
= readreg(cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_ALE
,
389 cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
, IPAC_ID
);
390 if ((val
== 1) || (val
== 2)) {
391 cs
->subtyp
= ASUS_IPAC
;
392 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_ALE
;
393 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
;
394 cs
->hw
.asus
.hscx
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
;
395 test_and_set_bit(HW_IPAC
, &cs
->HW_Flags
);
396 cs
->readisac
= &ReadISAC_IPAC
;
397 cs
->writeisac
= &WriteISAC_IPAC
;
398 cs
->readisacfifo
= &ReadISACfifo_IPAC
;
399 cs
->writeisacfifo
= &WriteISACfifo_IPAC
;
400 cs
->irq_func
= &asuscom_interrupt_ipac
;
401 printk(KERN_INFO
"Asus: IPAC version %x\n", val
);
403 cs
->subtyp
= ASUS_ISACHSCX
;
404 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_ADR
;
405 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_ISAC
;
406 cs
->hw
.asus
.hscx
= cs
->hw
.asus
.cfg_reg
+ ASUS_HSCX
;
407 cs
->hw
.asus
.u7
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_U7
;
408 cs
->hw
.asus
.pots
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_POTS
;
409 cs
->readisac
= &ReadISAC
;
410 cs
->writeisac
= &WriteISAC
;
411 cs
->readisacfifo
= &ReadISACfifo
;
412 cs
->writeisacfifo
= &WriteISACfifo
;
413 cs
->irq_func
= &asuscom_interrupt
;
414 ISACVersion(cs
, "ISDNLink:");
415 if (HscxVersion(cs
, "ISDNLink:")) {
417 "ISDNLink: wrong HSCX versions check IO address\n");
418 release_io_asuscom(cs
);