xref: /netbsd-src/sys/dev/pcmcia/if_an_pcmcia.c (revision cbab9cadce21ae72fac13910001079fff214cc29)
1*cbab9cadSchs /* $NetBSD: if_an_pcmcia.c,v 1.41 2012/10/27 17:18:36 chs Exp $ */
29c25e920Sonoe 
39c25e920Sonoe /*-
4adbea351Smycroft  * Copyright (c) 2000, 2004 The NetBSD Foundation, Inc.
59c25e920Sonoe  * All rights reserved.
69c25e920Sonoe  *
79c25e920Sonoe  * This code is derived from software contributed to The NetBSD Foundation
89c25e920Sonoe  * by Atsushi Onoe
99c25e920Sonoe  *
109c25e920Sonoe  * Redistribution and use in source and binary forms, with or without
119c25e920Sonoe  * modification, are permitted provided that the following conditions
129c25e920Sonoe  * are met:
139c25e920Sonoe  * 1. Redistributions of source code must retain the above copyright
149c25e920Sonoe  *    notice, this list of conditions and the following disclaimer.
159c25e920Sonoe  * 2. Redistributions in binary form must reproduce the above copyright
169c25e920Sonoe  *    notice, this list of conditions and the following disclaimer in the
179c25e920Sonoe  *    documentation and/or other materials provided with the distribution.
189c25e920Sonoe  *
199c25e920Sonoe  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
209c25e920Sonoe  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
219c25e920Sonoe  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
229c25e920Sonoe  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
239c25e920Sonoe  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
249c25e920Sonoe  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
259c25e920Sonoe  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
269c25e920Sonoe  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279c25e920Sonoe  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
289c25e920Sonoe  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
299c25e920Sonoe  * POSSIBILITY OF SUCH DAMAGE.
309c25e920Sonoe  */
319c25e920Sonoe 
32ab5d9d2bSlukem #include <sys/cdefs.h>
33*cbab9cadSchs __KERNEL_RCSID(0, "$NetBSD: if_an_pcmcia.c,v 1.41 2012/10/27 17:18:36 chs Exp $");
34ab5d9d2bSlukem 
359c25e920Sonoe #include <sys/param.h>
369c25e920Sonoe #include <sys/systm.h>
379c25e920Sonoe #include <sys/callout.h>
389c25e920Sonoe #include <sys/mbuf.h>
399c25e920Sonoe #include <sys/socket.h>
409c25e920Sonoe #include <sys/ioctl.h>
419c25e920Sonoe #include <sys/errno.h>
429c25e920Sonoe #include <sys/syslog.h>
439c25e920Sonoe #include <sys/select.h>
449c25e920Sonoe #include <sys/device.h>
459c25e920Sonoe 
469c25e920Sonoe #include <net/if.h>
479c25e920Sonoe #include <net/if_dl.h>
489c25e920Sonoe #include <net/if_ether.h>
499c25e920Sonoe #include <net/if_media.h>
502459b026Sdyoung 
5190634029Sdyoung #include <net80211/ieee80211_netbsd.h>
522459b026Sdyoung #include <net80211/ieee80211_var.h>
539c25e920Sonoe 
54a2a38285Sad #include <sys/cpu.h>
55a2a38285Sad #include <sys/bus.h>
56a2a38285Sad #include <sys/intr.h>
579c25e920Sonoe 
589c25e920Sonoe #include <dev/ic/anreg.h>
5999675e3dSonoe #include <dev/ic/anvar.h>
609c25e920Sonoe 
619c25e920Sonoe #include <dev/pcmcia/pcmciareg.h>
629c25e920Sonoe #include <dev/pcmcia/pcmciavar.h>
639c25e920Sonoe #include <dev/pcmcia/pcmciadevs.h>
649c25e920Sonoe 
657cf29912Scegger static int an_pcmcia_match(device_t, cfdata_t, void *);
6618db93c7Sperry static int an_pcmcia_validate_config(struct pcmcia_config_entry *);
677cf29912Scegger static void an_pcmcia_attach(device_t, device_t, void *);
687cf29912Scegger static int an_pcmcia_detach(device_t, int);
6918db93c7Sperry static int an_pcmcia_enable(struct an_softc *);
7018db93c7Sperry static void an_pcmcia_disable(struct an_softc *);
719c25e920Sonoe 
729c25e920Sonoe struct an_pcmcia_softc {
739c25e920Sonoe 	struct an_softc sc_an;			/* real "an" softc */
749c25e920Sonoe 
759c25e920Sonoe 	/* PCMCIA-specific goo */
769c25e920Sonoe 	struct pcmcia_io_handle sc_pcioh;	/* PCMCIA i/o space info */
779c25e920Sonoe 	int sc_io_window;			/* our i/o window */
789c25e920Sonoe 	struct pcmcia_function *sc_pf;		/* our PCMCIA function */
79a7125e43Sonoe 	void *sc_ih;				/* interrupt handle */
808355db5eSmycroft 
818355db5eSmycroft 	int sc_state;
828355db5eSmycroft #define	AN_PCMCIA_ATTACHED	3
839c25e920Sonoe };
849c25e920Sonoe 
85363285caSdrochner CFATTACH_DECL_NEW(an_pcmcia, sizeof(struct an_pcmcia_softc),
86b75a007dSthorpej     an_pcmcia_match, an_pcmcia_attach, an_pcmcia_detach, an_activate);
879c25e920Sonoe 
8896221eb5Smycroft static const struct pcmcia_product an_pcmcia_products[] = {
899c25e920Sonoe 	{ PCMCIA_VENDOR_AIRONET,	PCMCIA_PRODUCT_AIRONET_PC4800,
90b88b233eSmycroft 	  PCMCIA_CIS_AIRONET_PC4800 },
91aa513e63Sonoe 	{ PCMCIA_VENDOR_AIRONET,	PCMCIA_PRODUCT_AIRONET_PC4500,
92b88b233eSmycroft 	  PCMCIA_CIS_AIRONET_PC4500 },
935653ae73Sonoe 	{ PCMCIA_VENDOR_AIRONET,	PCMCIA_PRODUCT_AIRONET_350,
94b88b233eSmycroft 	  PCMCIA_CIS_AIRONET_350 },
959c25e920Sonoe };
96adbea351Smycroft static const size_t an_pcmcia_nproducts =
97adbea351Smycroft     sizeof(an_pcmcia_products) / sizeof(an_pcmcia_products[0]);
989c25e920Sonoe 
999c25e920Sonoe static int
an_pcmcia_match(device_t parent,cfdata_t match,void * aux)100*cbab9cadSchs an_pcmcia_match(device_t parent, cfdata_t match, void *aux)
1019c25e920Sonoe {
1029c25e920Sonoe 	struct pcmcia_attach_args *pa = aux;
1039c25e920Sonoe 
104adbea351Smycroft 	if (pcmcia_product_lookup(pa, an_pcmcia_products, an_pcmcia_nproducts,
105adbea351Smycroft 	    sizeof(an_pcmcia_products[0]), NULL))
106adbea351Smycroft 		return (1);
107adbea351Smycroft 	return (0);
1089c25e920Sonoe }
1099c25e920Sonoe 
1108355db5eSmycroft static int
an_pcmcia_validate_config(struct pcmcia_config_entry * cfe)111454af1c0Sdsl an_pcmcia_validate_config(struct pcmcia_config_entry *cfe)
1128355db5eSmycroft {
1138355db5eSmycroft 	if (cfe->iftype != PCMCIA_IFTYPE_IO ||
1148355db5eSmycroft 	    cfe->num_iospace < 1)
1158355db5eSmycroft 		return (EINVAL);
1168355db5eSmycroft 	return (0);
1178355db5eSmycroft }
1188355db5eSmycroft 
1199c25e920Sonoe static void
an_pcmcia_attach(device_t parent,device_t self,void * aux)120*cbab9cadSchs an_pcmcia_attach(device_t parent, device_t self, void *aux)
1219c25e920Sonoe {
122363285caSdrochner 	struct an_pcmcia_softc *psc = device_private(self);
1239c25e920Sonoe 	struct an_softc *sc = &psc->sc_an;
1249c25e920Sonoe 	struct pcmcia_attach_args *pa = aux;
1259c25e920Sonoe 	struct pcmcia_config_entry *cfe;
1268355db5eSmycroft 	int error;
1274ee7a7cdSonoe 
128363285caSdrochner 	sc->sc_dev = self;
1299c25e920Sonoe 	psc->sc_pf = pa->pf;
1308355db5eSmycroft 
1318355db5eSmycroft 	error = pcmcia_function_configure(pa->pf, an_pcmcia_validate_config);
1328355db5eSmycroft 	if (error) {
133bebbf57bScegger 		aprint_error_dev(self, "configure failed, error=%d\n",
1348355db5eSmycroft 		    error);
1358355db5eSmycroft 		return;
1369c25e920Sonoe 	}
1379c25e920Sonoe 
1388355db5eSmycroft 	cfe = pa->pf->cfe;
1398355db5eSmycroft 	sc->sc_iot = cfe->iospace[0].handle.iot;
1408355db5eSmycroft 	sc->sc_ioh = cfe->iospace[0].handle.ioh;
1419c25e920Sonoe 
1428355db5eSmycroft 	error = an_pcmcia_enable(sc);
1438355db5eSmycroft 	if (error)
1448355db5eSmycroft 		goto fail;
145684fe561Sonoe 
146684fe561Sonoe 	sc->sc_enabled = 1;
1479c25e920Sonoe 	sc->sc_enable = an_pcmcia_enable;
1489c25e920Sonoe 	sc->sc_disable = an_pcmcia_disable;
1499c25e920Sonoe 
1508355db5eSmycroft 	error = an_attach(sc);
1518355db5eSmycroft 	if (error) {
152bebbf57bScegger 		aprint_error_dev(self, "failed to attach controller\n");
1538355db5eSmycroft 		goto fail2;
1549c25e920Sonoe 	}
1558355db5eSmycroft 
156edeaa5ddStsutsui 	if (pmf_device_register(self, NULL, NULL))
1574c1d81b2Sjmcneill 		pmf_class_network_register(self, &sc->sc_if);
158edeaa5ddStsutsui 	else
159edeaa5ddStsutsui 		aprint_error_dev(self, "couldn't establish power handler\n");
1609c25e920Sonoe 
1619c25e920Sonoe 	an_pcmcia_disable(sc);
1628355db5eSmycroft 	sc->sc_enabled = 0;
1638355db5eSmycroft 	psc->sc_state = AN_PCMCIA_ATTACHED;
1649c25e920Sonoe 	return;
1659c25e920Sonoe 
166684fe561Sonoe fail2:
1678355db5eSmycroft 	an_pcmcia_disable(sc);
1688355db5eSmycroft 	sc->sc_enabled = 0;
1698355db5eSmycroft fail:
1708355db5eSmycroft 	pcmcia_function_unconfigure(pa->pf);
1719c25e920Sonoe }
1729c25e920Sonoe 
1739c25e920Sonoe 
1749c25e920Sonoe static int
an_pcmcia_detach(device_t self,int flags)1757cf29912Scegger an_pcmcia_detach(device_t self, int flags)
1769c25e920Sonoe {
177363285caSdrochner 	struct an_pcmcia_softc *psc = device_private(self);
1789c25e920Sonoe 	int error;
1799c25e920Sonoe 
1808355db5eSmycroft 	if (psc->sc_state != AN_PCMCIA_ATTACHED)
1819c25e920Sonoe 		return (0);
1829c25e920Sonoe 
1834c1d81b2Sjmcneill 	pmf_device_deregister(self);
1849c25e920Sonoe 
1859c25e920Sonoe 	error = an_detach(&psc->sc_an);
1868355db5eSmycroft 	if (error)
1879c25e920Sonoe 		return (error);
1889c25e920Sonoe 
1898355db5eSmycroft 	pcmcia_function_unconfigure(psc->sc_pf);
1909c25e920Sonoe 
1919c25e920Sonoe 	return (0);
1929c25e920Sonoe }
1938355db5eSmycroft 
1948355db5eSmycroft static int
an_pcmcia_enable(struct an_softc * sc)195454af1c0Sdsl an_pcmcia_enable(struct an_softc *sc)
1968355db5eSmycroft {
1978355db5eSmycroft 	struct an_pcmcia_softc *psc = (void *)sc;
1988355db5eSmycroft 	int error;
1998355db5eSmycroft 
2008355db5eSmycroft 	/* establish the interrupt. */
2018355db5eSmycroft 	psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, an_intr, sc);
2028355db5eSmycroft 	if (!psc->sc_ih)
2038355db5eSmycroft 		return (EIO);
2048355db5eSmycroft 
2058355db5eSmycroft 	error = pcmcia_function_enable(psc->sc_pf);
2068355db5eSmycroft 	if (error) {
2078355db5eSmycroft 		pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
2088355db5eSmycroft 		psc->sc_ih = 0;
2098355db5eSmycroft 	}
2108355db5eSmycroft 
2118355db5eSmycroft 	return (error);
2128355db5eSmycroft }
2138355db5eSmycroft 
2148355db5eSmycroft static void
an_pcmcia_disable(struct an_softc * sc)215454af1c0Sdsl an_pcmcia_disable(struct an_softc *sc)
2168355db5eSmycroft {
2178355db5eSmycroft 	struct an_pcmcia_softc *psc = (void *)sc;
2188355db5eSmycroft 
2198355db5eSmycroft 	pcmcia_function_disable(psc->sc_pf);
2208355db5eSmycroft 	pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
2218355db5eSmycroft 	psc->sc_ih = 0;
2228355db5eSmycroft }
223