if_ep_pcmcia.c revision 1.11
1/*	$OpenBSD: if_ep_pcmcia.c,v 1.11 1998/09/19 10:08:06 maja Exp $	*/
2/*	$NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $  */
3
4/*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
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.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the NetBSD
23 *	Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 *    contributors may be used to endorse or promote products derived
26 *    from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41/*
42 * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
43 *
44 * Redistribution and use in source and binary forms, with or without
45 * modification, are permitted provided that the following conditions
46 * are met:
47 * 1. Redistributions of source code must retain the above copyright
48 *    notice, this list of conditions and the following disclaimer.
49 * 2. Redistributions in binary form must reproduce the above copyright
50 *    notice, this list of conditions and the following disclaimer in the
51 *    documentation and/or other materials provided with the distribution.
52 * 3. All advertising materials mentioning features or use of this software
53 *    must display the following acknowledgement:
54 *	This product includes software developed by Marc Horowitz.
55 * 4. The name of the author may not be used to endorse or promote products
56 *    derived from this software without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
59 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
60 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
61 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
62 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
63 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
64 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
65 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
66 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
67 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68 */
69
70#include "bpfilter.h"
71
72#include <sys/param.h>
73#include <sys/systm.h>
74#include <sys/mbuf.h>
75#include <sys/socket.h>
76#include <sys/ioctl.h>
77#include <sys/errno.h>
78#include <sys/syslog.h>
79#include <sys/select.h>
80#include <sys/device.h>
81
82#include <net/if.h>
83#include <net/if_dl.h>
84#include <net/if_types.h>
85#include <net/netisr.h>
86#include <net/if_media.h>
87
88#ifdef INET
89#include <netinet/in.h>
90#include <netinet/in_systm.h>
91#include <netinet/in_var.h>
92#include <netinet/ip.h>
93#include <netinet/if_ether.h>
94#endif
95
96#ifdef NS
97#include <netns/ns.h>
98#include <netns/ns_if.h>
99#endif
100
101#if NBPFILTER > 0
102#include <net/bpf.h>
103#include <net/bpfdesc.h>
104#endif
105
106#include <machine/cpu.h>
107#include <machine/bus.h>
108#include <machine/intr.h>
109
110#include <dev/ic/elink3var.h>
111#include <dev/ic/elink3reg.h>
112
113#include <dev/pcmcia/pcmciareg.h>
114#include <dev/pcmcia/pcmciavar.h>
115#include <dev/pcmcia/pcmciadevs.h>
116
117int	ep_pcmcia_match __P((struct device *, void *, void *));
118void	ep_pcmcia_attach __P((struct device *, struct device *, void *));
119
120int	ep_pcmcia_get_enaddr __P((struct pcmcia_tuple *, void *));
121int	ep_pcmcia_enable __P((struct ep_softc *));
122void	ep_pcmcia_disable __P((struct ep_softc *));
123
124int	ep_pcmcia_enable1 __P((struct ep_softc *));
125void	ep_pcmcia_disable1 __P((struct ep_softc *));
126
127struct ep_pcmcia_softc {
128	struct ep_softc sc_ep;			/* real "ep" softc */
129
130	/* PCMCIA-specific goo */
131	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
132	int sc_io_window;			/* our i/o window */
133	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
134};
135
136struct cfattach ep_pcmcia_ca = {
137	sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach
138};
139
140struct ep_pcmcia_product {
141	u_int32_t	epp_product;	/* PCMCIA product ID */
142	u_short		epp_chipset;	/* 3Com chipset used */
143	int		epp_flags;	/* initial softc flags */
144	int		epp_expfunc;	/* expected function */
145	const char	*epp_name;	/* device name */
146} ep_pcmcia_products[] = {
147	{ PCMCIA_PRODUCT_3COM_3C562,	EP_CHIPSET_3C509,
148	  0,				0,
149	  PCMCIA_STR_3COM_3C562 },
150	{ PCMCIA_PRODUCT_3COM_3C589,	EP_CHIPSET_3C509,
151	  0,				0,
152	  PCMCIA_STR_3COM_3C589 },
153
154	{ PCMCIA_PRODUCT_3COM_3C574,	EP_CHIPSET_BOOMERANG,
155	  EP_FLAGS_MII,			0,
156	  PCMCIA_STR_3COM_3C574 },
157
158	{ 0,				0,
159	  0,				0,
160	  NULL },
161};
162
163struct ep_pcmcia_product *ep_pcmcia_lookup __P((struct pcmcia_attach_args *));
164
165struct ep_pcmcia_product *
166ep_pcmcia_lookup(pa)
167	struct pcmcia_attach_args *pa;
168{
169	struct ep_pcmcia_product *epp;
170
171	for (epp = ep_pcmcia_products; epp->epp_name != NULL; epp++)
172		if (pa->product == epp->epp_product &&
173		    pa->pf->number == epp->epp_expfunc)
174			return (epp);
175
176	return (NULL);
177}
178
179int
180ep_pcmcia_match(parent, match, aux)
181	struct device *parent;
182	void *match, *aux;
183{
184	struct pcmcia_attach_args *pa = aux;
185
186	if (pa->manufacturer != PCMCIA_VENDOR_3COM)
187		return (0);
188
189	if (ep_pcmcia_lookup(pa) != NULL)
190		return (1);
191
192	return (0);
193}
194
195int
196ep_pcmcia_enable(sc)
197	struct ep_softc *sc;
198{
199	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
200	struct pcmcia_function *pf = psc->sc_pf;
201
202	/* establish the interrupt. */
203	sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr, sc);
204	if (sc->sc_ih == NULL) {
205		printf("%s: couldn't establish interrupt\n",
206		    sc->sc_dev.dv_xname);
207		return (1);
208	}
209
210	return (ep_pcmcia_enable1(sc));
211}
212
213int
214ep_pcmcia_enable1(sc)
215	struct ep_softc *sc;
216{
217	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
218	struct pcmcia_function *pf = psc->sc_pf;
219	int ret;
220
221	if ((ret = pcmcia_function_enable(pf)))
222		return (ret);
223
224	if (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) {
225		int reg;
226
227		/* turn off the serial-disable bit */
228
229		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
230		if (reg & 0x08) {
231			reg &= ~0x08;
232			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
233		}
234
235	}
236
237	return (ret);
238}
239
240void
241ep_pcmcia_disable(sc)
242	struct ep_softc *sc;
243{
244	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
245
246	ep_pcmcia_disable1(sc);
247	pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
248}
249
250void
251ep_pcmcia_disable1(sc)
252	struct ep_softc *sc;
253{
254	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
255
256	pcmcia_function_disable(psc->sc_pf);
257}
258
259void
260ep_pcmcia_attach(parent, self, aux)
261	struct device  *parent, *self;
262	void           *aux;
263{
264	struct ep_pcmcia_softc *psc = (void *) self;
265	struct ep_softc *sc = &psc->sc_ep;
266	struct pcmcia_attach_args *pa = aux;
267	struct pcmcia_config_entry *cfe;
268	struct ep_pcmcia_product *epp;
269	u_int8_t myla[ETHER_ADDR_LEN];
270	u_int8_t *enaddr = NULL;
271	int i;
272
273	psc->sc_pf = pa->pf;
274	cfe = pa->pf->cfe_head.sqh_first;
275
276	/* Enable the card. */
277	pcmcia_function_init(pa->pf, cfe);
278	if (ep_pcmcia_enable1(sc))
279		printf(": function enable failed\n");
280
281#ifdef notyet
282	sc->enabled = 1;
283#endif
284
285	if (cfe->num_memspace != 0)
286		printf(": unexpected number of memory spaces %d should be 0\n",
287		    cfe->num_memspace);
288
289	if (cfe->num_iospace != 1)
290		printf(": unexpected number of I/O spaces %d should be 1\n",
291		    cfe->num_iospace);
292
293	if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
294		bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize);
295
296		for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) {
297			/*
298			 * the 3c562 can only use 0x??00-0x??7f
299			 * according to the Linux driver
300			 */
301			if (i & 0x80)
302				continue;
303			if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length,
304			    0, &psc->sc_pcioh) == 0)
305				break;
306		}
307		if (i >= maxaddr) {
308			printf(": can't allocate i/o space\n");
309			return;
310		}
311	} else {
312		if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
313		    cfe->iospace[0].length, &psc->sc_pcioh))
314			printf(": can't allocate i/o space\n");
315	}
316
317	sc->sc_iot = psc->sc_pcioh.iot;
318	sc->sc_ioh = psc->sc_pcioh.ioh;
319
320	if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
321	    PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length,
322	    &psc->sc_pcioh, &psc->sc_io_window)) {
323		printf(": can't map i/o space\n");
324		return;
325	}
326
327	switch (pa->product) {
328	case PCMCIA_PRODUCT_3COM_3C562:
329		/*
330		 * 3c562a-c use this; 3c562d does it in the regular way.
331		 * we might want to check the revision and produce a warning
332		 * in the future.
333		 */
334		/* FALLTHROUGH */
335	case PCMCIA_PRODUCT_3COM_3C574:
336		/*
337		 * Apparently, some 3c574s do it this way, as well.
338		 */
339		if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla))
340			enaddr = myla;
341		break;
342	}
343
344	sc->bustype = EP_BUS_PCMCIA;
345
346	epp = ep_pcmcia_lookup(pa);
347	if (epp == NULL)
348		panic("ep_pcmcia_attach: impossible");
349
350	printf(": %s,", epp->epp_name);
351
352#ifdef notyet
353	sc->enable = ep_pcmcia_enable;
354	sc->disable = ep_pcmcia_disable;
355#endif
356
357	epconfig(sc, epp->epp_chipset, enaddr);
358
359	/* establish the interrupt. */
360	sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc);
361	if (sc->sc_ih == NULL)
362		printf("%s: couldn't establish interrupt\n",
363		    sc->sc_dev.dv_xname);
364
365#ifdef notyet
366	sc->enabled = 0;
367
368	ep_pcmcia_disable1(sc);
369#endif
370}
371
372int
373ep_pcmcia_get_enaddr(tuple, arg)
374	struct pcmcia_tuple *tuple;
375	void *arg;
376{
377	u_int8_t *myla = arg;
378	int i;
379
380	/* this is 3c562a-c magic */
381	if (tuple->code == 0x88) {
382		if (tuple->length < ETHER_ADDR_LEN)
383			return (0);
384
385		for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
386			myla[i] = pcmcia_tuple_read_1(tuple, i + 1);
387			myla[i + 1] = pcmcia_tuple_read_1(tuple, i);
388		}
389
390		return (1);
391	}
392	return (0);
393}
394