1 /* $NetBSD: if_trtcm_isa.c,v 1.18 2009/05/12 08:44:19 cegger Exp $ */
3 /* XXXJRT verify doens't change isa_attach_args too early */
6 * Copyright (c) 1999 The NetBSD Foundation, Inc.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Onno van der Linden.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: if_trtcm_isa.c,v 1.18 2009/05/12 08:44:19 cegger Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
46 #include <net/if_ether.h>
47 #include <net/if_media.h>
51 #include <dev/isa/isavar.h>
52 #include <dev/isa/elink.h>
54 #include <dev/ic/tropicreg.h>
55 #include <dev/ic/tropicvar.h>
57 #include <dev/ic/elink3reg.h>
59 u_int16_t
tcmreadeeprom(bus_space_tag_t
, bus_space_handle_t
, int);
61 void tcmdumpeeprom(bus_space_tag_t
, bus_space_handle_t
);
64 int trtcm_isa_probe(device_t
, cfdata_t
, void *);
66 int trtcm_isa_mediachange(struct tr_softc
*);
67 void trtcm_isa_mediastatus(struct tr_softc
*, struct ifmediareq
*);
72 * if_media handling in the 3com case
73 * mediachange() and mediastatus() function
74 * certain newer cards can set their speed on the fly via
75 * DIR_SET_DEFAULT_RING_SPEED or set the speed in the eeprom ??
78 static void tcmaddcard(int, int, int, int, u_int
, int, int);
81 * This keeps track of which ISAs have been through a 3com probe sequence.
82 * A simple static variable isn't enough, since it's conceivable that
83 * a system might have more than one ISA bus.
85 * The "tcm_bus" member is the unit number of the parent ISA bus, e.g. "0"
88 struct tcm_isa_done_probe
{
89 LIST_ENTRY(tcm_isa_done_probe
) tcm_link
;
92 static LIST_HEAD(, tcm_isa_done_probe
) tcm_isa_all_probes
;
93 static int tcm_isa_probes_initialized
;
95 #define MAXTCMCARDS 20 /* if you have more than 20, you lose */
97 static struct tcmcard
{
106 } tcmcards
[MAXTCMCARDS
];
108 static int ntcmcards
= 0;
111 tcmaddcard(int bus
, int iobase
, int irq
, int maddr
, u_int msiz
, int model
, int pnpmode
)
114 if (ntcmcards
>= MAXTCMCARDS
)
116 tcmcards
[ntcmcards
].bus
= bus
;
117 tcmcards
[ntcmcards
].iobase
= iobase
;
118 tcmcards
[ntcmcards
].irq
= irq
;
119 tcmcards
[ntcmcards
].maddr
= maddr
;
120 tcmcards
[ntcmcards
].msize
= msiz
;
121 tcmcards
[ntcmcards
].model
= model
;
122 tcmcards
[ntcmcards
].available
= 1;
123 tcmcards
[ntcmcards
].pnpmode
= pnpmode
;
128 * We get eeprom data from the id_port given an offset into the
129 * eeprom. Basically; after the ID_sequence is sent to all of
130 * the cards; they enter the ID_CMD state where they will accept
131 * command requests. 0x80-0xbf loads the eeprom data. We then
132 * read the port 16 times and with every read; the cards check
133 * for contention (ie: if one card writes a 0 bit and another
134 * writes a 1 bit then the host sees a 0. At the end of the cycle;
135 * each card compares the data on the bus; if there is a difference
136 * then that card goes into ID_WAIT state again). In the meantime;
137 * one bit of data is returned in the AX register which is conveniently
138 * returned to us by bus_space_read_1(). Hence; we read 16 times getting one
139 * bit of data with each read.
141 * NOTE: the caller must provide an i/o handle for ELINK_ID_PORT!
144 tcmreadeeprom(bus_space_tag_t iot
, bus_space_handle_t ioh
, int offset
)
149 bus_space_write_1(iot
, ioh
, 0, 0x80 + offset
);
151 for (i
= 0; i
< 16; i
++)
152 data
= (data
<< 1) | (bus_space_read_2(iot
, ioh
, 0) & 1);
158 * Dump the contents of the EEPROM to the console.
161 tcmdumpeeprom(bus_space_tag_t iot
, bus_space_handle_t ioh
)
163 unsigned int off
, val
;
165 printf("EEPROM contents:");
166 for (off
=0; off
< 32; off
++) {
167 val
= tcmreadeeprom(iot
, ioh
, off
);
170 printf("%04x ", val
);
177 trtcm_isa_mediachange(struct tr_softc
*sc
)
183 trtcm_isa_mediastatus(struct tr_softc
*sc
, struct ifmediareq
*ifmr
)
185 struct ifmedia
*ifm
= &sc
->sc_media
;
187 ifmr
->ifm_active
= ifm
->ifm_cur
->ifm_media
;
190 /* XXX hard coded constants in readeeprom elink_idseq */
193 trtcm_isa_probe(device_t parent
, cfdata_t match
, void *aux
)
195 struct isa_attach_args
*ia
= aux
;
196 int bus
= device_unit(parent
);
197 bus_space_tag_t iot
= ia
->ia_iot
;
198 bus_space_handle_t ioh
;
200 int slot
, iobase
, irq
, i
, maddr
, rsrccfg
, pnpmode
;
201 u_int16_t vendor
, model
;
202 struct tcm_isa_done_probe
*tcm
;
203 static int irqs
[] = { 7, 15, 6, 11, 3, 10, 9, 5 };
205 if (ISA_DIRECT_CONFIG(ia
))
208 if (tcm_isa_probes_initialized
== 0) {
209 LIST_INIT(&tcm_isa_all_probes
);
210 tcm_isa_probes_initialized
= 1;
214 * Probe this bus if we haven't done so already.
216 for (tcm
= tcm_isa_all_probes
.lh_first
; tcm
!= NULL
;
217 tcm
= tcm
->tcm_link
.le_next
)
218 if (tcm
->tcm_bus
== bus
)
222 * Mark this bus so we don't probe it again.
224 tcm
= (struct tcm_isa_done_probe
*)
225 malloc(sizeof(struct tcm_isa_done_probe
), M_DEVBUF
, M_NOWAIT
);
227 printf("trtcm_isa_probe: can't allocate state storage");
232 LIST_INSERT_HEAD(&tcm_isa_all_probes
, tcm
, tcm_link
);
235 * Map the TokenLink ID port for the probe sequence.
237 if (bus_space_map(iot
, ELINK_ID_PORT
, 1, 0, &ioh
)) {
238 printf("trtcm_isa_probe: can't map TokenLink ID port\n");
242 for (slot
= 0; slot
< MAXTCMCARDS
; slot
++) {
244 elink_reset(iot
, ioh
, bus
);
245 elink_idseq(iot
, ioh
, TLINK_619_POLY
);
247 /* Untag all the adapters so they will talk to us. */
249 bus_space_write_1(iot
, ioh
, 0, TAG_ADAPTER
+ 0);
251 vendor
= htons(tcmreadeeprom(iot
, ioh
, EEPROM_MFG_ID
));
252 if (vendor
!= MFG_ID
)
255 model
= htons(tcmreadeeprom(iot
, ioh
, EEPROM_PROD_ID
));
256 if (((model
& 0xfff0) != 0x6190) &&
257 ((model
& 0xfff0) != 0x3190)) { /* XXX hardcoded */
259 printf("trtcm: unknown model 0x%04x\n", model
);
264 tcmdumpeeprom(iot
, ioh
);
266 printf("speed: %d\n", (tcmreadeeprom(iot
,ioh
,8) & 2) ? 4 : 16);
269 rsrccfg
= iobase
= tcmreadeeprom(iot
, ioh
, EEPROM_RESOURCE_CFG
);
271 iobase
= tcmreadeeprom(iot
, ioh
, EEPROM_ADDR_CFG
) & 1 ?
274 iobase
= (iobase
& 0x1f) * 0x10 + 0x200;
276 maddr
= ((tcmreadeeprom(iot
, ioh
, EEPROM_OEM_ADDR0
) & 0xfc00)
278 msiz
= 65536 >> ((tcmreadeeprom(iot
, ioh
, 8) & 0x0c) >> 2);
280 irq
= tcmreadeeprom(iot
, ioh
, EEPROM_ADDR_CFG
) & 0x180;
281 irq
|= (tcmreadeeprom(iot
, ioh
, EEPROM_RESOURCE_CFG
) & 0x40);
282 irq
= irqs
[irq
>> 6];
284 /* Tag card so it will not respond to contention again. */
285 bus_space_write_1(iot
, ioh
, 0, TAG_ADAPTER
+ 1);
288 * Don't attach a 3c319 in PnP mode.
290 * XXX Testing for the 13th bit in iobase being 0 might not
291 * be the right thing to do, but the EEPROM of the 3C319 is
292 * undocumented according to 3COM and this is one of the
293 * three bits that changed when I put the card in PnP mode. -chb
295 if (((model
& 0xffff0) == 0x3190) &&
296 ((rsrccfg
& 0x1000) == 0)) {
297 printf("3COM 3C319 TokenLink Velocity in PnP mode\n");
302 * XXX: this should probably not be done here
303 * because it enables the drq/irq lines from
304 * the board. Perhaps it should be done after
305 * we have checked for irq/drq collisions?
307 bus_space_write_1(iot
, ioh
, 0,
308 ACTIVATE_ADAPTER_TO_CONFIG
);
310 tcmaddcard(bus
, iobase
, irq
, maddr
, msiz
, model
, pnpmode
);
312 bus_space_unmap(iot
, ioh
, 1);
318 if (ia
->ia_niomem
< 1)
323 for (i
= 0; i
< ntcmcards
; i
++) {
324 if (tcmcards
[i
].bus
!= bus
)
326 if (tcmcards
[i
].available
== 0)
328 if (ia
->ia_io
[0].ir_addr
!= ISA_UNKNOWN_PORT
&&
329 ia
->ia_io
[0].ir_addr
!= tcmcards
[i
].iobase
)
331 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
&&
332 ia
->ia_irq
[0].ir_irq
!= tcmcards
[i
].irq
)
339 tcmcards
[i
].available
= 0;
340 if (tcmcards
[i
].pnpmode
)
341 return -1; /* XXX Don't actually probe this card. */
344 ia
->ia_io
[0].ir_addr
= tcmcards
[i
].iobase
;
345 /* XXX probably right, but ...... */
346 if (ia
->ia_io
[0].ir_addr
== 0xa20 || ia
->ia_io
[0].ir_addr
== 0xa24)
347 ia
->ia_io
[0].ir_size
= 4;
349 ia
->ia_io
[0].ir_size
= 16;
352 ia
->ia_iomem
[0].ir_addr
= tcmcards
[i
].maddr
;
353 ia
->ia_iomem
[0].ir_size
= tcmcards
[i
].msize
;
356 ia
->ia_irq
[0].ir_irq
= tcmcards
[i
].irq
;
360 ia
->ia_aux
= (void *) tcmcards
[i
].model
;