1 /* $NetBSD: if_fmv_isa.c,v 1.12 2008/04/12 04:33:48 tsutsui Exp $ */
4 * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
6 * This software may be used, modified, copied, distributed, and sold, in
7 * both source and binary form provided that the above copyright, these
8 * terms and the following disclaimer are retained. The name of the author
9 * and/or the contributor may not be used to endorse or promote products
10 * derived from this software without specific prior written permission.
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
13 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
16 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * Portions copyright (C) 1993, David Greenman. This software may be used,
27 * modified, copied, distributed, and sold, in both source and binary form
28 * provided that the above copyright and these terms are retained. Under no
29 * circumstances is the author responsible for the proper functioning of this
30 * software, nor does the author assume any responsibility for damages
31 * incurred with its use.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: if_fmv_isa.c,v 1.12 2008/04/12 04:33:48 tsutsui Exp $");
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
42 #include <net/if_ether.h>
43 #include <net/if_media.h>
48 #include <dev/ic/mb86960reg.h>
49 #include <dev/ic/mb86960var.h>
50 #include <dev/ic/fmvreg.h>
51 #include <dev/ic/fmvvar.h>
53 #include <dev/isa/isavar.h>
55 int fmv_isa_match(device_t
, cfdata_t
, void *);
56 void fmv_isa_attach(device_t
, device_t
, void *);
58 struct fmv_isa_softc
{
59 struct mb86960_softc sc_mb86960
; /* real "mb86960" softc */
61 /* ISA-specific goo. */
62 void *sc_ih
; /* interrupt cookie */
65 CFATTACH_DECL_NEW(fmv_isa
, sizeof(struct fmv_isa_softc
),
66 fmv_isa_match
, fmv_isa_attach
, NULL
, NULL
);
68 struct fe_simple_probe_struct
{
69 uint8_t port
; /* Offset from the base I/O address. */
70 uint8_t mask
; /* Bits to be checked. */
71 uint8_t bits
; /* Values to be compared against. */
74 static inline int fe_simple_probe(bus_space_tag_t
, bus_space_handle_t
,
75 struct fe_simple_probe_struct
const *);
76 static int fmv_find(bus_space_tag_t
, bus_space_handle_t
, int *, int *);
78 static const int fmv_iomap
[8] = {
79 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x300, 0x340
81 #define NFMV_IOMAP __arraycount(fmv_iomap)
82 #define FMV_NPORTS 0x20
85 #define DPRINTF printf
87 #define DPRINTF while (/* CONSTCOND */0) printf
91 * Hardware probe routines.
95 * Determine if the device is present.
98 fmv_isa_match(device_t parent
, cfdata_t cf
, void *aux
)
100 struct isa_attach_args
*ia
= aux
;
101 bus_space_tag_t iot
= ia
->ia_iot
;
102 bus_space_handle_t ioh
;
103 int i
, iobase
, irq
, rv
= 0;
104 uint8_t myea
[ETHER_ADDR_LEN
];
111 if (ISA_DIRECT_CONFIG(ia
))
114 /* Disallow wildcarded values. */
115 if (ia
->ia_io
[0].ir_addr
== ISA_UNKNOWN_PORT
)
119 * See if the sepcified address is valid for FMV-180 series.
121 for (i
= 0; i
< NFMV_IOMAP
; i
++)
122 if (fmv_iomap
[i
] == ia
->ia_io
[0].ir_addr
)
124 if (i
== NFMV_IOMAP
) {
125 DPRINTF("%s: unknown iobase 0x%x\n",
126 __func__
, ia
->ia_io
[0].ir_addr
);
131 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, FMV_NPORTS
, 0, &ioh
)) {
132 DPRINTF("%s: couldn't map iospace 0x%x\n",
133 __func__
, ia
->ia_io
[0].ir_addr
);
137 if (fmv_find(iot
, ioh
, &iobase
, &irq
) == 0) {
138 DPRINTF("%s: fmv_find failed\n", __func__
);
142 if (iobase
!= ia
->ia_io
[0].ir_addr
) {
143 DPRINTF("%s: unexpected iobase in board: 0x%x\n",
148 if (fmv_detect(iot
, ioh
, myea
) == 0) { /* XXX necessary? */
149 DPRINTF("%s: fmv_detect failed\n", __func__
);
153 if (ia
->ia_irq
[0].ir_irq
!= ISA_UNKNOWN_IRQ
) {
154 if (ia
->ia_irq
[0].ir_irq
!= irq
) {
155 aprint_error("%s: irq mismatch; "
156 "kernel configured %d != board configured %d\n",
157 __func__
, ia
->ia_irq
[0].ir_irq
, irq
);
161 ia
->ia_irq
[0].ir_irq
= irq
;
164 ia
->ia_io
[0].ir_size
= FMV_NPORTS
;
174 bus_space_unmap(iot
, ioh
, FMV_NPORTS
);
179 * Check for specific bits in specific registers have specific values.
182 fe_simple_probe(bus_space_tag_t iot
, bus_space_handle_t ioh
,
183 const struct fe_simple_probe_struct
*sp
)
186 const struct fe_simple_probe_struct
*p
;
188 for (p
= sp
; p
->mask
!= 0; p
++) {
189 val
= bus_space_read_1(iot
, ioh
, p
->port
);
190 if ((val
& p
->mask
) != p
->bits
) {
191 DPRINTF("%s: %x & %x != %x\n",
192 __func__
, val
, p
->mask
, p
->bits
);
201 * Hardware (vendor) specific probe routines.
205 * Probe Fujitsu FMV-180 series boards and get iobase and irq from
209 fmv_find(bus_space_tag_t iot
, bus_space_handle_t ioh
, int *iobase
, int *irq
)
212 static const int fmv_irqmap
[4] = { 3, 7, 10, 15 };
213 static const struct fe_simple_probe_struct probe_table
[] = {
214 { FE_DLCR2
, 0x70, 0x00 },
215 { FE_DLCR4
, 0x08, 0x00 },
216 /* { FE_DLCR5, 0x80, 0x00 }, Doesn't work. */
218 { FE_FMV0
, FE_FMV0_MAGIC_MASK
, FE_FMV0_MAGIC_VALUE
},
219 { FE_FMV1
, FE_FMV1_MAGIC_MASK
, FE_FMV1_MAGIC_VALUE
},
220 { FE_FMV3
, FE_FMV3_EXTRA_MASK
, FE_FMV3_EXTRA_VALUE
},
223 * Test *vendor* part of the station address for Fujitsu.
224 * The test will gain reliability of probe process, but
225 * it rejects FMV-180 clone boards manufactured by other vendors.
226 * We have to turn the test off when such cards are made available.
228 { FE_FMV4
, 0xFF, 0x00 },
229 { FE_FMV5
, 0xFF, 0x00 },
230 { FE_FMV6
, 0xFF, 0x0E },
233 * We can always verify the *first* 2 bits (in Ehternet
234 * bit order) are "no multicast" and "no local" even for
237 { FE_FMV4
, 0x03, 0x00 },
243 if (fe_simple_probe(iot
, ioh
, probe_table
) == 0)
246 /* Check if our I/O address matches config info on EEPROM. */
247 config
= bus_space_read_1(iot
, ioh
, FE_FMV2
);
248 *iobase
= fmv_iomap
[(config
& FE_FMV2_ADDR
) >> FE_FMV2_ADDR_SHIFT
];
251 * Determine which IRQ to be used.
253 * In this version, we always get an IRQ assignment from the
254 * FMV-180's configuration EEPROM, ignoring that specified in
257 *irq
= fmv_irqmap
[(config
& FE_FMV2_IRQ
) >> FE_FMV2_IRQ_SHIFT
];
263 fmv_isa_attach(device_t parent
, device_t self
, void *aux
)
265 struct fmv_isa_softc
*isc
= device_private(self
);
266 struct mb86960_softc
*sc
= &isc
->sc_mb86960
;
267 struct isa_attach_args
*ia
= aux
;
268 bus_space_tag_t iot
= ia
->ia_iot
;
269 bus_space_handle_t ioh
;
274 if (bus_space_map(iot
, ia
->ia_io
[0].ir_addr
, FMV_NPORTS
, 0, &ioh
)) {
275 aprint_error(": can't map i/o space\n");
284 /* Establish the interrupt handler. */
285 isc
->sc_ih
= isa_intr_establish(ia
->ia_ic
, ia
->ia_irq
[0].ir_irq
,
286 IST_EDGE
, IPL_NET
, mb86960_intr
, sc
);
287 if (isc
->sc_ih
== NULL
)
288 aprint_error_dev(sc
->sc_dev
,
289 "couldn't establish interrupt handler\n");