if_fe_pccard.c revision 189843
1/*-
2 * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
3 *
4 * This software may be used, modified, copied, distributed, and sold, in
5 * both source and binary form provided that the above copyright, these
6 * terms and the following disclaimer are retained.  The name of the author
7 * and/or the contributor may not be used to endorse or promote products
8 * derived from this software without specific prior written permission.
9 *
10 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
11 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
12 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
13 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
14 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
15 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
16 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
17 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
18 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
19 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20 * SUCH DAMAGE.
21 *
22 */
23
24#include <sys/cdefs.h>
25__FBSDID("$FreeBSD: head/sys/dev/fe/if_fe_pccard.c 189843 2009-03-15 02:31:34Z imp $");
26
27#include <sys/param.h>
28#include <sys/kernel.h>
29#include <sys/socket.h>
30#include <sys/systm.h>
31#include <sys/module.h>
32
33#include <sys/bus.h>
34#include <machine/bus.h>
35#include <sys/rman.h>
36
37#include <net/ethernet.h>
38#include <net/if.h>
39#include <net/if_mib.h>
40#include <net/if_media.h>
41
42#include <netinet/in.h>
43#include <netinet/if_ether.h>
44
45#include <dev/fe/mb86960.h>
46#include <dev/fe/if_fereg.h>
47#include <dev/fe/if_fevar.h>
48
49#include <dev/pccard/pccardvar.h>
50#include <dev/pccard/pccard_cis.h>
51
52#include "card_if.h"
53#include "pccarddevs.h"
54
55/*
56 *	PC Card (PCMCIA) specific code.
57 */
58static int fe_pccard_probe(device_t);
59static int fe_pccard_attach(device_t);
60static int fe_pccard_detach(device_t);
61
62static const struct fe_pccard_product {
63	struct pccard_product mpp_product;
64	int mpp_flags;
65	int mpp_cfe;
66#define MPP_MBH10302 1
67#define MPP_ANYFUNC 2
68#define MPP_SKIP_TO_CFE 4
69} fe_pccard_products[] = {
70	/* These need to be first */
71	{ PCMCIA_CARD(FUJITSU2, FMV_J181), MPP_MBH10302 },
72	{ PCMCIA_CARD(FUJITSU2, FMV_J182), 0 },
73	{ PCMCIA_CARD(FUJITSU2, FMV_J182A), 0 },
74	{ PCMCIA_CARD(FUJITSU2, ITCFJ182A), 0 },
75	/* These need to be second */
76	{ PCMCIA_CARD(TDK, LAK_CD021BX), 0 },
77	{ PCMCIA_CARD(TDK, LAK_CF010), 0 },
78#if 0 /* XXX 86960-based? */
79	{ PCMCIA_CARD(TDK, LAK_DFL9610), 0 },
80#endif
81	{ PCMCIA_CARD(CONTEC, CNETPC), MPP_SKIP_TO_CFE, 2 },
82	{ PCMCIA_CARD(FUJITSU, LA501), 0 },
83	{ PCMCIA_CARD(FUJITSU, LA10S), 0 },
84	{ PCMCIA_CARD(FUJITSU, NE200T), MPP_MBH10302 },/* Sold by Eagle */
85	{ PCMCIA_CARD(HITACHI, HT_4840), MPP_MBH10302 | MPP_SKIP_TO_CFE, 10 },
86	{ PCMCIA_CARD(RATOC, REX_R280), 0 },
87	{ PCMCIA_CARD(XIRCOM, CE), MPP_ANYFUNC },
88	{ { NULL } }
89};
90
91static int
92fe_pccard_probe(device_t dev)
93{
94	int		error;
95	uint32_t	fcn = PCCARD_FUNCTION_UNSPEC;
96	const struct fe_pccard_product *pp;
97	int i;
98
99	if ((pp = (const struct fe_pccard_product *)pccard_product_lookup(dev,
100		 (const struct pccard_product *)fe_pccard_products,
101		 sizeof(fe_pccard_products[0]), NULL)) != NULL) {
102		if (pp->mpp_product.pp_name != NULL)
103			device_set_desc(dev, pp->mpp_product.pp_name);
104		if (pp->mpp_flags & MPP_ANYFUNC)
105			return (0);
106		/* Make sure we're a network function */
107		error = pccard_get_function(dev, &fcn);
108		if (error != 0)
109			return (error);
110		if (fcn != PCCARD_FUNCTION_NETWORK)
111			return (ENXIO);
112		if (pp->mpp_flags & MPP_SKIP_TO_CFE) {
113			for (i = pp->mpp_cfe; i < 32; i++) {
114				if (pccard_select_cfe(dev, i) == 0)
115					goto good;
116			}
117			device_printf(dev,
118			    "Failed to map CFE %d or higher\n", pp->mpp_cfe);
119			return ENXIO;
120		}
121	good:;
122		return (0);
123	}
124	return (ENXIO);
125}
126
127static device_method_t fe_pccard_methods[] = {
128	/* Device interface */
129	DEVMETHOD(device_probe,		fe_pccard_probe),
130	DEVMETHOD(device_attach,	fe_pccard_attach),
131	DEVMETHOD(device_detach,	fe_pccard_detach),
132
133	{ 0, 0 }
134};
135
136static driver_t fe_pccard_driver = {
137	"fe",
138	fe_pccard_methods,
139	sizeof (struct fe_softc)
140};
141
142DRIVER_MODULE(fe, pccard, fe_pccard_driver, fe_devclass, 0, 0);
143MODULE_DEPEND(fe, pccard, 1, 1, 1);
144
145static int fe_probe_mbh(device_t, const struct fe_pccard_product *);
146static int fe_probe_tdk(device_t, const struct fe_pccard_product *);
147
148static int
149fe_pccard_attach(device_t dev)
150{
151	struct fe_softc *sc;
152	const struct fe_pccard_product *pp;
153	int error;
154
155	/* Prepare for the device probe process.  */
156	sc = device_get_softc(dev);
157	sc->sc_unit = device_get_unit(dev);
158
159	pp = (const struct fe_pccard_product *) pccard_product_lookup(dev,
160	    (const struct pccard_product *)fe_pccard_products,
161	    sizeof(fe_pccard_products[0]), NULL);
162	if (pp == NULL)
163		return (ENXIO);
164
165	if (pp->mpp_flags & MPP_MBH10302)
166		error = fe_probe_mbh(dev, pp);
167	else
168		error = fe_probe_tdk(dev, pp);
169	if (error != 0) {
170		fe_release_resource(dev);
171		return (error);
172	}
173	error = fe_alloc_irq(dev, 0);
174	if (error != 0) {
175		fe_release_resource(dev);
176		return (error);
177	}
178	return (fe_attach(dev));
179}
180
181/*
182 *	feunload - unload the driver and clear the table.
183 */
184static int
185fe_pccard_detach(device_t dev)
186{
187	struct fe_softc *sc = device_get_softc(dev);
188	struct ifnet *ifp = sc->ifp;
189
190	FE_LOCK(sc);
191	fe_stop(sc);
192	FE_UNLOCK(sc);
193	callout_drain(&sc->timer);
194	ether_ifdetach(ifp);
195	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
196	if_free(ifp);
197	fe_release_resource(dev);
198	mtx_destroy(&sc->lock);
199
200	return 0;
201}
202
203
204/*
205 * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface.
206 * Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk().
207 */
208static void
209fe_init_mbh(struct fe_softc *sc)
210{
211	/* Minimal initialization of 86960.  */
212	DELAY(200);
213	fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE);
214	DELAY(200);
215
216	/* Disable all interrupts.  */
217	fe_outb(sc, FE_DLCR2, 0);
218	fe_outb(sc, FE_DLCR3, 0);
219
220	/* Enable master interrupt flag.  */
221	fe_outb(sc, FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE);
222}
223
224static int
225fe_probe_mbh(device_t dev, const struct fe_pccard_product *pp)
226{
227	struct fe_softc *sc = device_get_softc(dev);
228
229	static struct fe_simple_probe_struct probe_table [] = {
230		{ FE_DLCR2, 0x58, 0x00 },
231		{ FE_DLCR4, 0x08, 0x00 },
232		{ FE_DLCR6, 0xFF, 0xB6 },
233		{ 0 }
234	};
235
236	/* MBH10302 occupies 32 I/O addresses. */
237	if (fe_alloc_port(dev, 32))
238		return ENXIO;
239
240	/* Fill the softc struct with default values.  */
241	fe_softc_defaults(sc);
242
243	/*
244	 * See if MBH10302 is on its address.
245	 * I'm not sure the following probe code works.  FIXME.
246	 */
247	if (!fe_simple_probe(sc, probe_table))
248		return ENXIO;
249
250	/* Get our station address from EEPROM.  */
251	fe_inblk(sc, FE_MBH10, sc->enaddr, ETHER_ADDR_LEN);
252
253	/* Make sure we got a valid station address.  */
254	if (!fe_valid_Ether_p(sc->enaddr, 0))
255		return ENXIO;
256
257	/* Determine the card type.  */
258	sc->type = FE_TYPE_MBH;
259	sc->typestr = "MBH10302 (PCMCIA)";
260
261	/* We seems to need our own IDENT bits...  FIXME.  */
262	sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE;
263
264	/* Setup hooks.  We need a special initialization procedure.  */
265	sc->init = fe_init_mbh;
266
267	return 0;
268}
269
270static int
271fe_pccard_xircom_mac(const struct pccard_tuple *tuple, void *argp)
272{
273	uint8_t *enaddr = argp;
274	int i;
275
276#if 1
277	/*
278	 * We fail to map the CIS twice, for reasons unknown.  We
279	 * may fix this in the future by loading the CIS with a sane
280	 * CIS from userland.
281	 */
282	static uint8_t defaultmac[ETHER_ADDR_LEN] = {
283		0x00, 0x80, 0xc7, 0xed, 0x16, 0x7b};
284
285	/* Copy the MAC ADDR and return success */
286	for (i = 0; i < ETHER_ADDR_LEN; i++)
287		enaddr[i] = defaultmac[i];
288#else
289	/* FUNCE is not after FUNCID, so we gotta go find it */
290	if (tuple->code != 0x22)
291		return (0);
292
293	/* Make sure this is a sane node */
294	if (tuple->length < ETHER_ADDR_LEN + 3)
295		return (0);
296
297	/* Copy the MAC ADDR and return success */
298	for (i = 0; i < ETHER_ADDR_LEN; i++)
299		enaddr[i] = pccard_tuple_read_1(tuple, i + 3);
300#endif
301	return (1);
302}
303
304/*
305 * Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface.
306 * by MASUI Kenji <masui@cs.titech.ac.jp>
307 *
308 * (Contec uses TDK Ethenet chip -- hosokawa)
309 *
310 * This version of fe_probe_tdk has been rewrote to handle
311 * *generic* PC Card implementation of Fujitsu MB8696x family.  The
312 * name _tdk is just for a historical reason. :-)
313 */
314static int
315fe_probe_tdk (device_t dev, const struct fe_pccard_product *pp)
316{
317	struct fe_softc *sc = device_get_softc(dev);
318
319	static struct fe_simple_probe_struct probe_table [] = {
320		{ FE_DLCR2, 0x10, 0x00 },
321		{ FE_DLCR4, 0x08, 0x00 },
322/*		{ FE_DLCR5, 0x80, 0x00 },	Does not work well.  */
323		{ 0 }
324	};
325
326
327	/* C-NET(PC)C occupies 16 I/O addresses. */
328	if (fe_alloc_port(dev, 16))
329		return ENXIO;
330
331	/* Fill the softc struct with default values.  */
332	fe_softc_defaults(sc);
333
334	/*
335	 * See if C-NET(PC)C is on its address.
336	 */
337	if (!fe_simple_probe(sc, probe_table))
338		return ENXIO;
339
340	/* Determine the card type.  */
341	sc->type = FE_TYPE_TDK;
342	sc->typestr = "Generic MB8696x/78Q837x Ethernet (PCMCIA)";
343
344	pccard_get_ether(dev, sc->enaddr);
345
346	/* Make sure we got a valid station address.  */
347	if (!fe_valid_Ether_p(sc->enaddr, 0)) {
348		pccard_cis_scan(dev, fe_pccard_xircom_mac, sc->enaddr);
349	}
350
351	/* Make sure we got a valid station address.  */
352	if (!fe_valid_Ether_p(sc->enaddr, 0))
353		return ENXIO;
354
355	return 0;
356}
357