xref: /openbsd/sys/dev/pcmcia/if_ep_pcmcia.c (revision db3296cf)
1 /*	$OpenBSD: if_ep_pcmcia.c,v 1.30 2003/07/08 20:17:05 mickey 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 
109 #include <dev/mii/mii.h>
110 #include <dev/mii/miivar.h>
111 
112 #include <dev/ic/elink3var.h>
113 #include <dev/ic/elink3reg.h>
114 
115 #include <dev/pcmcia/pcmciareg.h>
116 #include <dev/pcmcia/pcmciavar.h>
117 #include <dev/pcmcia/pcmciadevs.h>
118 
119 int	ep_pcmcia_match(struct device *, void *, void *);
120 void	ep_pcmcia_attach(struct device *, struct device *, void *);
121 int	ep_pcmcia_detach(struct device *, int);
122 int	ep_pcmcia_activate(struct device *, enum devact);
123 
124 int	ep_pcmcia_get_enaddr(struct pcmcia_tuple *, void *);
125 int	ep_pcmcia_enable(struct ep_softc *);
126 void	ep_pcmcia_disable(struct ep_softc *);
127 
128 int	ep_pcmcia_enable1(struct ep_softc *);
129 void	ep_pcmcia_disable1(struct ep_softc *);
130 
131 struct ep_pcmcia_softc {
132 	struct ep_softc sc_ep;			/* real "ep" softc */
133 
134 	/* PCMCIA-specific goo */
135 	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
136 	int sc_io_window;			/* our i/o window */
137 	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
138 };
139 
140 struct cfattach ep_pcmcia_ca = {
141 	sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach,
142 	ep_pcmcia_detach, ep_pcmcia_activate
143 };
144 
145 struct ep_pcmcia_product {
146 	u_int16_t	epp_product;	/* PCMCIA product ID */
147 	u_short		epp_chipset;	/* 3Com chipset used */
148 	int		epp_flags;	/* initial softc flags */
149 	int		epp_expfunc;	/* expected function */
150 } ep_pcmcia_prod[] = {
151 	{ PCMCIA_PRODUCT_3COM_3C562,	EP_CHIPSET_3C509,
152 	  0,				0 },
153 
154 	{ PCMCIA_PRODUCT_3COM_3C589,	EP_CHIPSET_3C509,
155 	  0,				0 },
156 
157 	{ PCMCIA_PRODUCT_3COM_3CXEM556,	EP_CHIPSET_3C509,
158 	  0,				0 },
159 
160 	{ PCMCIA_PRODUCT_3COM_3CXEM556B,EP_CHIPSET_3C509,
161 	  0,				0 },
162 
163 	{ PCMCIA_PRODUCT_3COM_3C1,	EP_CHIPSET_3C509,
164 	  0,				0 },
165 
166 	{ PCMCIA_PRODUCT_3COM_3CCFEM556BI, EP_CHIPSET_ROADRUNNER,
167 	  EP_FLAGS_MII,			0 },
168 
169 	{ PCMCIA_PRODUCT_3COM_3C574,	EP_CHIPSET_ROADRUNNER,
170 	  EP_FLAGS_MII,			0 }
171 };
172 
173 struct ep_pcmcia_product *ep_pcmcia_lookup(struct pcmcia_attach_args *);
174 
175 struct ep_pcmcia_product *
176 ep_pcmcia_lookup(pa)
177 	struct pcmcia_attach_args *pa;
178 {
179 	int i;
180 
181 	for (i = 0; i < sizeof(ep_pcmcia_prod)/sizeof(ep_pcmcia_prod[0]); i++)
182 		if (pa->product == ep_pcmcia_prod[i].epp_product &&
183 		    pa->pf->number == ep_pcmcia_prod[i].epp_expfunc)
184 			return &ep_pcmcia_prod[i];
185 
186 	return (NULL);
187 }
188 
189 int
190 ep_pcmcia_match(parent, match, aux)
191 	struct device *parent;
192 	void *match, *aux;
193 {
194 	struct pcmcia_attach_args *pa = aux;
195 
196 	if (pa->manufacturer != PCMCIA_VENDOR_3COM)
197 		return (0);
198 
199 	if (ep_pcmcia_lookup(pa) != NULL)
200 		return (1);
201 
202 	return (0);
203 }
204 
205 int
206 ep_pcmcia_enable(sc)
207 	struct ep_softc *sc;
208 {
209 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
210 	struct pcmcia_function *pf = psc->sc_pf;
211 
212 	/* establish the interrupt. */
213 	sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr,
214 	    sc, sc->sc_dev.dv_xname);
215 	if (sc->sc_ih == NULL) {
216 		printf("%s: couldn't establish interrupt\n",
217 		    sc->sc_dev.dv_xname);
218 		return (1);
219 	}
220 
221 	return (ep_pcmcia_enable1(sc));
222 }
223 
224 int
225 ep_pcmcia_enable1(sc)
226 	struct ep_softc *sc;
227 {
228 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
229 	struct pcmcia_function *pf = psc->sc_pf;
230 	int ret;
231 
232 	if ((ret = pcmcia_function_enable(pf)))
233 		return (ret);
234 
235 	if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) ||
236 	    (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) ||
237 	    (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) {
238 		int reg;
239 
240 		/* turn off the serial-disable bit */
241 
242 		reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
243 		if (reg & 0x08) {
244 			reg &= ~0x08;
245 			pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
246 		}
247 
248 	}
249 
250 	return (ret);
251 }
252 
253 void
254 ep_pcmcia_disable(sc)
255 	struct ep_softc *sc;
256 {
257 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
258 
259 	pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
260 	ep_pcmcia_disable1(sc);
261 }
262 
263 void
264 ep_pcmcia_disable1(sc)
265 	struct ep_softc *sc;
266 {
267 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
268 
269 	pcmcia_function_disable(psc->sc_pf);
270 }
271 
272 void
273 ep_pcmcia_attach(parent, self, aux)
274 	struct device  *parent, *self;
275 	void           *aux;
276 {
277 	struct ep_pcmcia_softc *psc = (void *) self;
278 	struct ep_softc *sc = &psc->sc_ep;
279 	struct pcmcia_attach_args *pa = aux;
280 	struct pcmcia_config_entry *cfe;
281 	struct ep_pcmcia_product *epp;
282 	u_int8_t myla[ETHER_ADDR_LEN];
283 	u_int8_t *enaddr = NULL;
284 	int i;
285 
286 	psc->sc_pf = pa->pf;
287 	cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
288 
289 	/* Enable the card. */
290 	pcmcia_function_init(pa->pf, cfe);
291 	if (ep_pcmcia_enable1(sc))
292 		printf(": function enable failed\n");
293 
294 #ifdef notyet
295 	sc->enabled = 1;
296 #endif
297 
298 	if (cfe->num_memspace != 0)
299 		printf(": unexpected number of memory spaces %d should be 0\n",
300 		    cfe->num_memspace);
301 
302 	if (cfe->num_iospace != 1)
303 		printf(": unexpected number of I/O spaces %d should be 1\n",
304 		    cfe->num_iospace);
305 
306 	if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
307 		bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize);
308 
309 		for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) {
310 			/*
311 			 * the 3c562 can only use 0x??00-0x??7f
312 			 * according to the Linux driver
313 			 */
314 			if (i & 0x80)
315 				continue;
316 			if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length,
317 			    cfe->iospace[0].length, &psc->sc_pcioh) == 0)
318 				break;
319 		}
320 		if (i >= maxaddr) {
321 			printf(": can't allocate i/o space\n");
322 			return;
323 		}
324 	} else {
325 		if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
326 		    cfe->iospace[0].length, &psc->sc_pcioh))
327 			printf(": can't allocate i/o space\n");
328 	}
329 
330 	sc->sc_iot = psc->sc_pcioh.iot;
331 	sc->sc_ioh = psc->sc_pcioh.ioh;
332 
333 	if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
334 	    PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length,
335 	    &psc->sc_pcioh, &psc->sc_io_window)) {
336 		printf(": can't map i/o space\n");
337 		return;
338 	}
339 
340 	printf(" port 0x%lx/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size);
341 
342 	switch (pa->product) {
343 	case PCMCIA_PRODUCT_3COM_3C562:
344 		/*
345 		 * 3c562a-c use this; 3c562d does it in the regular way.
346 		 * we might want to check the revision and produce a warning
347 		 * in the future.
348 		 */
349 		/* FALLTHROUGH */
350 	case PCMCIA_PRODUCT_3COM_3C574:
351 	case PCMCIA_PRODUCT_3COM_3CCFEM556BI:
352 		/*
353 		 * Apparently, some 3c574s do it this way, as well.
354 		 */
355 		if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla))
356 			enaddr = myla;
357 		break;
358 	}
359 
360 	sc->bustype = EP_BUS_PCMCIA;
361 
362 	epp = ep_pcmcia_lookup(pa);
363 	if (epp == NULL)
364 		panic("ep_pcmcia_attach: impossible");
365 
366 	sc->ep_flags = epp->epp_flags;
367 
368 #ifdef notyet
369 	sc->enable = ep_pcmcia_enable;
370 	sc->disable = ep_pcmcia_disable;
371 #endif
372 
373 	/* establish the interrupt. */
374 	sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr,
375 	    sc, "");
376 	if (sc->sc_ih == NULL)
377 		printf(", couldn't establish interrupt");
378 
379 	printf(":");
380 
381 	epconfig(sc, epp->epp_chipset, enaddr);
382 
383 #ifdef notyet
384 	sc->enabled = 0;
385 
386 	ep_pcmcia_disable1(sc);
387 #endif
388 }
389 
390 int
391 ep_pcmcia_detach(dev, flags)
392 	struct device *dev;
393 	int flags;
394 {
395 	int rv;
396 	struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *)dev;
397 
398 	if ((rv = ep_detach(dev)) != 0)
399 		return (rv);
400 
401 	pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
402 	pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
403 
404 	return (0);
405 }
406 
407 int
408 ep_pcmcia_activate(dev, act)
409 	struct device *dev;
410 	enum devact act;
411 {
412 	struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev;
413 	struct ep_softc *esc = &sc->sc_ep;
414 	struct ifnet *ifp = &esc->sc_arpcom.ac_if;
415 	int s;
416 
417 	s = splnet();
418 	switch (act) {
419 	case DVACT_ACTIVATE:
420 		pcmcia_function_enable(sc->sc_pf);
421 		sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
422 		    epintr, sc, esc->sc_dev.dv_xname);
423 		epinit(esc);
424 		break;
425 
426 	case DVACT_DEACTIVATE:
427 		ifp->if_timer = 0;
428 		if (ifp->if_flags & IFF_RUNNING)
429 			epstop(esc);
430 		pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
431 		pcmcia_function_disable(sc->sc_pf);
432 		break;
433 	}
434 	splx(s);
435 	return (0);
436 }
437 
438 int
439 ep_pcmcia_get_enaddr(tuple, arg)
440 	struct pcmcia_tuple *tuple;
441 	void *arg;
442 {
443 	u_int8_t *myla = arg;
444 	int i;
445 
446 	/* this is 3c562a-c magic */
447 	if (tuple->code == 0x88) {
448 		if (tuple->length < ETHER_ADDR_LEN)
449 			return (0);
450 
451 		for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
452 			myla[i] = pcmcia_tuple_read_1(tuple, i + 1);
453 			myla[i + 1] = pcmcia_tuple_read_1(tuple, i);
454 		}
455 
456 		return (1);
457 	}
458 	return (0);
459 }
460