1 /* $NetBSD: if_mbe_pcmcia.c,v 1.45 2008/04/28 20:23:56 martin Exp $ */
4 * Copyright (c) 1998, 2000, 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_mbe_pcmcia.c,v 1.45 2008/04/28 20:23:56 martin Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
38 #include <sys/socket.h>
41 #include <net/if_ether.h>
42 #include <net/if_media.h>
47 #include <dev/ic/mb86960reg.h>
48 #include <dev/ic/mb86960var.h>
50 #include <dev/pcmcia/pcmciareg.h>
51 #include <dev/pcmcia/pcmciavar.h>
52 #include <dev/pcmcia/pcmciadevs.h>
54 int mbe_pcmcia_match(device_t
, cfdata_t
, void *);
55 int mbe_pcmcia_validate_config(struct pcmcia_config_entry
*);
56 void mbe_pcmcia_attach(device_t
, device_t
, void *);
57 int mbe_pcmcia_detach(device_t
, int);
59 struct mbe_pcmcia_softc
{
60 struct mb86960_softc sc_mb86960
; /* real "mb" softc */
62 struct pcmcia_function
*sc_pf
; /* our PCMCIA function */
63 void *sc_ih
; /* interrupt cookie */
66 #define MBE_PCMCIA_ATTACHED 3
69 CFATTACH_DECL_NEW(mbe_pcmcia
, sizeof(struct mbe_pcmcia_softc
),
70 mbe_pcmcia_match
, mbe_pcmcia_attach
, mbe_pcmcia_detach
, mb86960_activate
);
72 int mbe_pcmcia_enable(struct mb86960_softc
*);
73 void mbe_pcmcia_disable(struct mb86960_softc
*);
75 struct mbe_pcmcia_get_enaddr_args
{
76 uint8_t enaddr
[ETHER_ADDR_LEN
];
79 int mbe_pcmcia_get_enaddr_from_cis(struct pcmcia_tuple
*, void *);
80 int mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc
*,
81 struct mbe_pcmcia_get_enaddr_args
*);
82 int mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc
*,
83 struct mbe_pcmcia_get_enaddr_args
*);
85 static const struct mbe_pcmcia_product
{
86 struct pcmcia_product mpp_product
;
89 #define MBH10302 0x0001 /* FUJITSU MBH10302 */
90 } mbe_pcmcia_products
[] = {
91 { { PCMCIA_VENDOR_TDK
, PCMCIA_PRODUCT_TDK_LAK_CD021BX
,
92 PCMCIA_CIS_TDK_LAK_CD021BX
},
95 { { PCMCIA_VENDOR_TDK
, PCMCIA_PRODUCT_TDK_LAK_CF010
,
96 PCMCIA_CIS_TDK_LAK_CF010
},
99 #if 0 /* XXX 86960-based? */
100 { { PCMCIA_VENDOR_TDK
, PCMCIA_PRODUCT_TDK_LAK_DFL9610
,
101 PCMCIA_CIS_TDK_DFL9610
},
102 -1, MBH10302
/* XXX */ },
105 { { PCMCIA_VENDOR_CONTEC
, PCMCIA_PRODUCT_CONTEC_CNETPC
,
106 PCMCIA_CIS_CONTEC_CNETPC
},
109 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_LA501
,
110 PCMCIA_CIS_FUJITSU_LA501
},
113 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_FMV_J181
,
114 PCMCIA_CIS_FUJITSU_FMV_J181
},
117 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_FMV_J182
,
118 PCMCIA_CIS_FUJITSU_FMV_J182
},
121 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_FMV_J182A
,
122 PCMCIA_CIS_FUJITSU_FMV_J182A
},
125 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_ITCFJ182A
,
126 PCMCIA_CIS_FUJITSU_ITCFJ182A
},
129 { { PCMCIA_VENDOR_FUJITSU
, PCMCIA_PRODUCT_FUJITSU_LA10S
,
130 PCMCIA_CIS_FUJITSU_LA10S
},
133 { { PCMCIA_VENDOR_RATOC
, PCMCIA_PRODUCT_RATOC_REX_R280
,
134 PCMCIA_CIS_RATOC_REX_R280
},
137 static const size_t mbe_pcmcia_nproducts
= __arraycount(mbe_pcmcia_products
);
140 mbe_pcmcia_match(device_t parent
, cfdata_t cf
, void *aux
)
142 struct pcmcia_attach_args
*pa
= aux
;
144 if (pcmcia_product_lookup(pa
, mbe_pcmcia_products
, mbe_pcmcia_nproducts
,
145 sizeof(mbe_pcmcia_products
[0]), NULL
))
151 mbe_pcmcia_validate_config(struct pcmcia_config_entry
*cfe
)
154 if (cfe
->iftype
!= PCMCIA_IFTYPE_IO
||
155 cfe
->num_iospace
< 1)
161 mbe_pcmcia_attach(device_t parent
, device_t self
, void *aux
)
163 struct mbe_pcmcia_softc
*psc
= device_private(self
);
164 struct mb86960_softc
*sc
= &psc
->sc_mb86960
;
165 struct pcmcia_attach_args
*pa
= aux
;
166 struct pcmcia_config_entry
*cfe
;
167 struct mbe_pcmcia_get_enaddr_args pgea
;
168 const struct mbe_pcmcia_product
*mpp
;
174 error
= pcmcia_function_configure(pa
->pf
, mbe_pcmcia_validate_config
);
176 aprint_error_dev(self
, "configure failed, error=%d\n",
182 sc
->sc_bst
= cfe
->iospace
[0].handle
.iot
;
183 sc
->sc_bsh
= cfe
->iospace
[0].handle
.ioh
;
185 mpp
= pcmcia_product_lookup(pa
, mbe_pcmcia_products
,
186 mbe_pcmcia_nproducts
, sizeof(mbe_pcmcia_products
[0]), NULL
);
188 panic("%s: impossible", __func__
);
190 /* Read station address from io/mem or CIS. */
191 if (mpp
->mpp_enet_maddr
>= 0) {
192 pgea
.maddr
= mpp
->mpp_enet_maddr
;
193 if (mbe_pcmcia_get_enaddr_from_mem(psc
, &pgea
) != 0) {
194 aprint_error_dev(self
, "couldn't get ethernet address "
198 } else if (mpp
->mpp_flags
& MBH10302
) {
199 bus_space_write_1(sc
->sc_bst
, sc
->sc_bsh
, FE_MBH0
,
200 FE_MBH0_MASK
| FE_MBH0_INTR_ENABLE
);
201 if (mbe_pcmcia_get_enaddr_from_io(psc
, &pgea
) != 0) {
202 aprint_error_dev(self
,
203 "couldn't get ethernet address from i/o\n");
207 if (pa
->pf
->pf_funce_lan_nidlen
!= ETHER_ADDR_LEN
) {
208 aprint_error_dev(self
,
209 "couldn't get ethernet address from CIS\n");
212 memcpy(pgea
.enaddr
, pa
->pf
->pf_funce_lan_nid
, ETHER_ADDR_LEN
);
215 /* Perform generic initialization. */
216 if (mpp
->mpp_flags
& MBH10302
)
217 sc
->sc_flags
|= FE_FLAGS_MB86960
;
219 sc
->sc_enable
= mbe_pcmcia_enable
;
220 sc
->sc_disable
= mbe_pcmcia_disable
;
222 error
= mbe_pcmcia_enable(sc
);
226 mb86960_attach(sc
, pgea
.enaddr
);
227 mb86960_config(sc
, NULL
, 0, 0);
229 mbe_pcmcia_disable(sc
);
230 psc
->sc_state
= MBE_PCMCIA_ATTACHED
;
234 pcmcia_function_unconfigure(pa
->pf
);
238 mbe_pcmcia_detach(device_t self
, int flags
)
240 struct mbe_pcmcia_softc
*psc
= device_private(self
);
243 if (psc
->sc_state
!= MBE_PCMCIA_ATTACHED
)
246 error
= mb86960_detach(&psc
->sc_mb86960
);
250 pcmcia_function_unconfigure(psc
->sc_pf
);
256 mbe_pcmcia_enable(struct mb86960_softc
*sc
)
258 struct mbe_pcmcia_softc
*psc
= (struct mbe_pcmcia_softc
*)sc
;
261 /* Establish the interrupt handler. */
262 psc
->sc_ih
= pcmcia_intr_establish(psc
->sc_pf
, IPL_NET
, mb86960_intr
,
267 error
= pcmcia_function_enable(psc
->sc_pf
);
269 pcmcia_intr_disestablish(psc
->sc_pf
, psc
->sc_ih
);
277 mbe_pcmcia_disable(struct mb86960_softc
*sc
)
279 struct mbe_pcmcia_softc
*psc
= (struct mbe_pcmcia_softc
*)sc
;
281 pcmcia_function_disable(psc
->sc_pf
);
282 pcmcia_intr_disestablish(psc
->sc_pf
, psc
->sc_ih
);
287 mbe_pcmcia_get_enaddr_from_io(struct mbe_pcmcia_softc
*psc
,
288 struct mbe_pcmcia_get_enaddr_args
*ea
)
290 struct mb86960_softc
*sc
= &psc
->sc_mb86960
;
293 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
294 ea
->enaddr
[i
] = bus_space_read_1(sc
->sc_bst
, sc
->sc_bsh
,
300 mbe_pcmcia_get_enaddr_from_mem(struct mbe_pcmcia_softc
*psc
,
301 struct mbe_pcmcia_get_enaddr_args
*ea
)
303 struct mb86960_softc
*sc
= &psc
->sc_mb86960
;
304 struct pcmcia_mem_handle pcmh
;
306 int i
, mwindow
, rv
= 1;
311 if (pcmcia_mem_alloc(psc
->sc_pf
, ETHER_ADDR_LEN
* 2, &pcmh
)) {
312 aprint_error_dev(sc
->sc_dev
, "can't alloc mem for enet addr\n");
313 goto memalloc_failed
;
316 if (pcmcia_mem_map(psc
->sc_pf
, PCMCIA_MEM_ATTR
, ea
->maddr
,
317 ETHER_ADDR_LEN
* 2, &pcmh
, &offset
, &mwindow
)) {
318 aprint_error_dev(sc
->sc_dev
, "can't map mem for enet addr\n");
322 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
323 ea
->enaddr
[i
] = bus_space_read_1(pcmh
.memt
, pcmh
.memh
,
327 pcmcia_mem_unmap(psc
->sc_pf
, mwindow
);
329 pcmcia_mem_free(psc
->sc_pf
, &pcmh
);