1 /* $Id: asuscom.c,v 1.11.6.3 2001/09/23 22:24:46 kai 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 extern const char *CardType
[];
25 const char *Asuscom_revision
= "$Revision: 1.11.6.3 $";
27 static spinlock_t asuscom_lock
= SPIN_LOCK_UNLOCKED
;
28 #define byteout(addr,val) outb(val,addr)
29 #define bytein(addr) inb(addr)
34 #define ASUS_CTRL_U7 3
35 #define ASUS_CTRL_POTS 5
37 #define ASUS_IPAC_ALE 0
38 #define ASUS_IPAC_DATA 1
40 #define ASUS_ISACHSCX 1
43 /* CARD_ADR (Write) */
44 #define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */
47 readreg(struct IsdnCardState
*cs
, unsigned int adr
, u8 off
)
52 spin_lock_irqsave(&asuscom_lock
, flags
);
53 byteout(cs
->hw
.asus
.adr
, off
);
55 spin_unlock_irqrestore(&asuscom_lock
, flags
);
60 writereg(struct IsdnCardState
*cs
, unsigned int adr
, u8 off
, u8 data
)
64 spin_lock_irqsave(&asuscom_lock
, flags
);
65 byteout(cs
->hw
.asus
.adr
, off
);
67 spin_unlock_irqrestore(&asuscom_lock
, flags
);
71 readfifo(struct IsdnCardState
*cs
, unsigned int adr
, u8 off
, u8
* data
, int size
)
73 byteout(cs
->hw
.asus
.adr
, off
);
74 insb(adr
, data
, size
);
79 writefifo(struct IsdnCardState
*cs
, unsigned int adr
, u8 off
, u8
* data
, int size
)
81 byteout(cs
->hw
.asus
.adr
, off
);
82 outsb(adr
, data
, size
);
86 isac_read(struct IsdnCardState
*cs
, u8 offset
)
88 return readreg(cs
, cs
->hw
.asus
.isac
, offset
);
92 isac_write(struct IsdnCardState
*cs
, u8 offset
, u8 value
)
94 writereg(cs
, cs
->hw
.asus
.isac
, offset
, value
);
98 isac_read_fifo(struct IsdnCardState
*cs
, u8
* data
, int size
)
100 readfifo(cs
, cs
->hw
.asus
.isac
, 0, data
, size
);
104 isac_write_fifo(struct IsdnCardState
*cs
, u8
* data
, int size
)
106 writefifo(cs
, cs
->hw
.asus
.isac
, 0, data
, size
);
109 static struct dc_hw_ops isac_ops
= {
110 .read_reg
= isac_read
,
111 .write_reg
= isac_write
,
112 .read_fifo
= isac_read_fifo
,
113 .write_fifo
= isac_write_fifo
,
117 hscx_read(struct IsdnCardState
*cs
, int hscx
, u8 offset
)
119 return readreg(cs
, cs
->hw
.asus
.hscx
, offset
+ (hscx
? 0x40 : 0));
123 hscx_write(struct IsdnCardState
*cs
, int hscx
, u8 offset
, u8 value
)
125 writereg(cs
, cs
->hw
.asus
.hscx
, offset
+ (hscx
? 0x40 : 0), value
);
129 hscx_read_fifo(struct IsdnCardState
*cs
, int hscx
, u8
*data
, int size
)
131 readfifo(cs
, cs
->hw
.asus
.hscx
, hscx
? 0x40 : 0, data
, size
);
135 hscx_write_fifo(struct IsdnCardState
*cs
, int hscx
, u8
*data
, int size
)
137 writefifo(cs
, cs
->hw
.asus
.hscx
, hscx
? 0x40 : 0, data
, size
);
140 static struct bc_hw_ops hscx_ops
= {
141 .read_reg
= hscx_read
,
142 .write_reg
= hscx_write
,
143 .read_fifo
= hscx_read_fifo
,
144 .write_fifo
= hscx_write_fifo
,
148 ipac_read(struct IsdnCardState
*cs
, u8 off
)
153 spin_lock_irqsave(&asuscom_lock
, flags
);
154 byteout(cs
->hw
.asus
.adr
, off
);
155 ret
= bytein(cs
->hw
.asus
.isac
);
156 spin_unlock_irqrestore(&asuscom_lock
, flags
);
161 ipac_write(struct IsdnCardState
*cs
, u8 off
, u8 data
)
165 spin_lock_irqsave(&asuscom_lock
, flags
);
166 byteout(cs
->hw
.asus
.adr
, off
);
167 byteout(cs
->hw
.asus
.isac
, data
);
168 spin_unlock_irqrestore(&asuscom_lock
, flags
);
172 ipac_readfifo(struct IsdnCardState
*cs
, u8 off
, u8
* data
, int size
)
174 byteout(cs
->hw
.asus
.adr
, off
);
175 insb(cs
->hw
.asus
.isac
, data
, size
);
180 ipac_writefifo(struct IsdnCardState
*cs
, u8 off
, u8
* data
, int size
)
182 byteout(cs
->hw
.asus
.adr
, off
);
183 outsb(cs
->hw
.asus
.isac
, data
, size
);
186 /* This will generate ipac_dc_ops and ipac_bc_ops using the functions
189 BUILD_IPAC_OPS(ipac
);
192 asuscom_reset(struct IsdnCardState
*cs
)
194 byteout(cs
->hw
.asus
.adr
, ASUS_RESET
); /* Reset On */
195 set_current_state(TASK_UNINTERRUPTIBLE
);
196 schedule_timeout((10*HZ
)/1000);
197 byteout(cs
->hw
.asus
.adr
, 0); /* Reset Off */
198 set_current_state(TASK_UNINTERRUPTIBLE
);
199 schedule_timeout((10*HZ
)/1000);
204 asuscom_ipac_reset(struct IsdnCardState
*cs
)
206 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_POTA2
, 0x20);
207 set_current_state(TASK_UNINTERRUPTIBLE
);
208 schedule_timeout((10*HZ
)/1000);
209 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_POTA2
, 0x0);
210 set_current_state(TASK_UNINTERRUPTIBLE
);
211 schedule_timeout((10*HZ
)/1000);
212 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_CONF
, 0x0);
213 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_ACFG
, 0xff);
214 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_AOE
, 0x0);
215 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_MASK
, 0xc0);
216 writereg(cs
, cs
->hw
.asus
.isac
, IPAC_PCFG
, 0x12);
220 static struct card_ops asuscom_ops
= {
221 .init
= inithscxisac
,
222 .reset
= asuscom_reset
,
223 .release
= hisax_release_resources
,
224 .irq_func
= hscxisac_irq
,
227 static struct card_ops asuscom_ipac_ops
= {
229 .reset
= asuscom_ipac_reset
,
230 .release
= hisax_release_resources
,
231 .irq_func
= ipac_irq
,
235 asuscom_probe(struct IsdnCardState
*cs
, struct IsdnCard
*card
)
240 printk(KERN_INFO
"ISDNLink: defined at %#lx IRQ %lu\n",
241 card
->para
[1], card
->para
[0]);
243 cs
->hw
.asus
.cfg_reg
= card
->para
[1];
244 cs
->irq
= card
->para
[0];
247 if (!request_io(&cs
->rs
, cs
->hw
.asus
.cfg_reg
, 8, "asuscom isdn"))
251 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_ALE
;
252 val
= readreg(cs
, cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
, IPAC_ID
);
253 if ((val
== 1) || (val
== 2)) {
254 cs
->subtyp
= ASUS_IPAC
;
255 cs
->card_ops
= &asuscom_ipac_ops
;
256 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_IPAC_DATA
;
257 if (ipac_setup(cs
, &ipac_dc_ops
, &ipac_bc_ops
))
260 cs
->subtyp
= ASUS_ISACHSCX
;
261 cs
->card_ops
= &asuscom_ops
;
262 cs
->hw
.asus
.adr
= cs
->hw
.asus
.cfg_reg
+ ASUS_ADR
;
263 cs
->hw
.asus
.isac
= cs
->hw
.asus
.cfg_reg
+ ASUS_ISAC
;
264 cs
->hw
.asus
.hscx
= cs
->hw
.asus
.cfg_reg
+ ASUS_HSCX
;
265 cs
->hw
.asus
.u7
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_U7
;
266 cs
->hw
.asus
.pots
= cs
->hw
.asus
.cfg_reg
+ ASUS_CTRL_POTS
;
267 if (hscxisac_setup(cs
, &isac_ops
, &hscx_ops
))
270 printk(KERN_INFO
"ISDNLink: resetting card\n");
271 cs
->card_ops
->reset(cs
);
275 hisax_release_resources(cs
);
280 static struct isapnp_device_id asus_ids
[] __initdata
= {
281 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
282 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
283 (unsigned long) "Asus1688 PnP" },
284 { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
285 ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
286 (unsigned long) "Asus1690 PnP" },
287 { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
288 ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
289 (unsigned long) "Isurf2 PnP" },
290 { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
291 ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
292 (unsigned long) "Iscas TE320" },
296 static struct isapnp_device_id
*adev
= &asus_ids
[0];
297 static struct pnp_card
*pnp_c __devinitdata
= NULL
;
301 setup_asuscom(struct IsdnCard
*card
)
305 strcpy(tmp
, Asuscom_revision
);
306 printk(KERN_INFO
"HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp
));
308 if (!card
->para
[1] && isapnp_present()) {
312 while(adev
->card_vendor
) {
313 if ((pb
= pnp_find_card(adev
->card_vendor
,
318 if ((pd
= pnp_find_dev(pnp_c
,
322 printk(KERN_INFO
"HiSax: %s detected\n",
323 (char *)adev
->driver_data
);
324 if (pnp_device_attach(pd
) < 0) {
325 printk(KERN_ERR
"AsusPnP: attach failed\n");
328 if (pnp_activate_dev(pd
) < 0) {
329 printk(KERN_ERR
"AsusPnP: activate failed\n");
330 pnp_device_detach(pd
);
333 if (!pnp_irq_valid(pd
, 0) || !pnp_port_valid(pd
, 0)) {
334 printk(KERN_ERR
"AsusPnP:some resources are missing %ld/%lx\n",
335 pnp_irq(pd
, 0), pnp_port_start(pd
, 0));
336 pnp_device_detach(pd
);
339 card
->para
[1] = pnp_port_start(pd
, 0);
340 card
->para
[0] = pnp_irq(pd
, 0);
343 printk(KERN_ERR
"AsusPnP: PnP error card found, no device\n");
349 if (!adev
->card_vendor
) {
350 printk(KERN_INFO
"AsusPnP: no ISAPnP card found\n");
355 if (asuscom_probe(card
->cs
, card
) < 0)