xref: /netbsd-src/sys/dev/pcmcia/if_cs_pcmcia.c (revision 8bc54e5be648e06e7c6b48f7611f8bccfda032d4)
1*8bc54e5bSmsaitoh /* $NetBSD: if_cs_pcmcia.c,v 1.22 2016/07/07 06:55:42 msaitoh Exp $ */
2b43f7a47Syamt 
3b43f7a47Syamt /*-
4b43f7a47Syamt  * Copyright (c)2001 YAMAMOTO Takashi,
5b43f7a47Syamt  * All rights reserved.
6b43f7a47Syamt  *
7b43f7a47Syamt  * Redistribution and use in source and binary forms, with or without
8b43f7a47Syamt  * modification, are permitted provided that the following conditions
9b43f7a47Syamt  * are met:
10b43f7a47Syamt  * 1. Redistributions of source code must retain the above copyright
11b43f7a47Syamt  *    notice, this list of conditions and the following disclaimer.
12b43f7a47Syamt  * 2. Redistributions in binary form must reproduce the above copyright
13b43f7a47Syamt  *    notice, this list of conditions and the following disclaimer in the
14b43f7a47Syamt  *    documentation and/or other materials provided with the distribution.
15b43f7a47Syamt  *
16b43f7a47Syamt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17b43f7a47Syamt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b43f7a47Syamt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b43f7a47Syamt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20b43f7a47Syamt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21b43f7a47Syamt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22b43f7a47Syamt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23b43f7a47Syamt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24b43f7a47Syamt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25b43f7a47Syamt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26b43f7a47Syamt  * SUCH DAMAGE.
27b43f7a47Syamt  */
28b43f7a47Syamt 
29b43f7a47Syamt #include <sys/cdefs.h>
30*8bc54e5bSmsaitoh __KERNEL_RCSID(0, "$NetBSD: if_cs_pcmcia.c,v 1.22 2016/07/07 06:55:42 msaitoh Exp $");
31b43f7a47Syamt 
32b43f7a47Syamt #include <sys/param.h>
33b43f7a47Syamt #include <sys/systm.h>
34b43f7a47Syamt #include <sys/device.h>
35b43f7a47Syamt #include <sys/socket.h>
36b43f7a47Syamt #include <sys/queue.h>
37b43f7a47Syamt 
38b43f7a47Syamt #include <net/if.h>
39b43f7a47Syamt #include <net/if_ether.h>
40b43f7a47Syamt #include <net/if_media.h>
41b43f7a47Syamt 
42a2a38285Sad #include <sys/bus.h>
43a2a38285Sad #include <sys/intr.h>
44b43f7a47Syamt 
45b43f7a47Syamt #include <dev/pcmcia/pcmciareg.h>
46b43f7a47Syamt #include <dev/pcmcia/pcmciavar.h>
47b43f7a47Syamt #include <dev/pcmcia/pcmciadevs.h>
48b43f7a47Syamt 
49dbaca003Syamt #include <dev/ic/cs89x0reg.h>
50dbaca003Syamt #include <dev/ic/cs89x0var.h>
51b43f7a47Syamt 
52b43f7a47Syamt struct cs_pcmcia_softc;
53b43f7a47Syamt 
547cf29912Scegger static int cs_pcmcia_match(device_t, cfdata_t, void *);
558355db5eSmycroft static int cs_pcmcia_validate_config(struct pcmcia_config_entry *);
567cf29912Scegger static void cs_pcmcia_attach(device_t, device_t, void *);
577cf29912Scegger static int cs_pcmcia_detach(device_t, int);
58b43f7a47Syamt static int cs_pcmcia_enable(struct cs_softc *);
59b43f7a47Syamt static void cs_pcmcia_disable(struct cs_softc *);
60b43f7a47Syamt 
61b43f7a47Syamt struct cs_pcmcia_softc {
62b43f7a47Syamt 	struct cs_softc sc_cs; /* real "cs" softc */
63b43f7a47Syamt 
64b43f7a47Syamt 	struct pcmcia_function *sc_pf;
65b43f7a47Syamt 
668355db5eSmycroft 	int sc_state;
678355db5eSmycroft #define	CS_PCMCIA_ATTACHED	3
688355db5eSmycroft };
69b43f7a47Syamt 
70cbab9cadSchs CFATTACH_DECL_NEW(cs_pcmcia, sizeof(struct cs_pcmcia_softc),
71b75a007dSthorpej     cs_pcmcia_match, cs_pcmcia_attach, cs_pcmcia_detach, cs_activate);
72b43f7a47Syamt 
73b43f7a47Syamt static int
cs_pcmcia_match(device_t parent,cfdata_t match,void * aux)747cf29912Scegger cs_pcmcia_match(device_t parent, cfdata_t match,
754d595fd7Schristos     void *aux)
76b43f7a47Syamt {
77b43f7a47Syamt 	struct pcmcia_attach_args *pa = aux;
78b43f7a47Syamt 
798355db5eSmycroft 	if (pa->manufacturer == PCMCIA_VENDOR_IBM &&
808355db5eSmycroft 	    pa->product == PCMCIA_PRODUCT_IBM_ETHERJET)
818355db5eSmycroft 		return (1);
828355db5eSmycroft 	return (0);
838355db5eSmycroft }
84b43f7a47Syamt 
858355db5eSmycroft static int
cs_pcmcia_validate_config(struct pcmcia_config_entry * cfe)868355db5eSmycroft cs_pcmcia_validate_config(struct pcmcia_config_entry *cfe)
878355db5eSmycroft {
888355db5eSmycroft 	if (cfe->iftype != PCMCIA_IFTYPE_IO ||
898355db5eSmycroft 	    cfe->num_memspace != 0 ||
908355db5eSmycroft 	    cfe->num_iospace != 1 ||
918355db5eSmycroft 	    cfe->iospace[0].length < CS8900_IOSIZE)
928355db5eSmycroft 		return (EINVAL);
938355db5eSmycroft 	return (0);
94b43f7a47Syamt }
95b43f7a47Syamt 
96b43f7a47Syamt static void
cs_pcmcia_attach(device_t parent,device_t self,void * aux)977cf29912Scegger cs_pcmcia_attach(device_t parent, device_t self, void *aux)
98b43f7a47Syamt {
99cbab9cadSchs 	struct cs_pcmcia_softc *psc = device_private(self);
100cbab9cadSchs 	struct cs_softc *sc = &psc->sc_cs;
101b43f7a47Syamt 	struct pcmcia_attach_args *pa = aux;
102b43f7a47Syamt 	struct pcmcia_config_entry *cfe;
103b43f7a47Syamt 	struct pcmcia_function *pf;
1048355db5eSmycroft 	int error;
105b43f7a47Syamt 
106cbab9cadSchs 	sc->sc_dev = self;
107b43f7a47Syamt 	pf = psc->sc_pf = pa->pf;
108b43f7a47Syamt 
1098355db5eSmycroft 	error = pcmcia_function_configure(pa->pf, cs_pcmcia_validate_config);
1108355db5eSmycroft 	if (error) {
111*8bc54e5bSmsaitoh 		aprint_error_dev(self, "configure failed, error=%d\n", error);
1128355db5eSmycroft 		return;
113b43f7a47Syamt 	}
114b43f7a47Syamt 
1158355db5eSmycroft 	cfe = pf->cfe;
1168355db5eSmycroft 	sc->sc_iot = cfe->iospace[0].handle.iot;
1178355db5eSmycroft 	sc->sc_ioh = cfe->iospace[0].handle.ioh;
118b43f7a47Syamt 	sc->sc_irq = -1;
119b43f7a47Syamt #define CS_PCMCIA_HACK_FOR_CARDBUS
120b43f7a47Syamt #ifdef CS_PCMCIA_HACK_FOR_CARDBUS
121b43f7a47Syamt 	/*
122b43f7a47Syamt 	 * XXX is there a generic way to know if it's a cardbus or not?
123b43f7a47Syamt 	 */
124b43f7a47Syamt 	sc->sc_cfgflags |= CFGFLG_CARDBUS_HACK;
125b43f7a47Syamt #endif
1268355db5eSmycroft 
1278355db5eSmycroft 	error = cs_pcmcia_enable(sc);
1288355db5eSmycroft 	if (error)
1298355db5eSmycroft 		goto fail;
1308355db5eSmycroft 
131b43f7a47Syamt 	sc->sc_enable = cs_pcmcia_enable;
132b43f7a47Syamt 	sc->sc_disable = cs_pcmcia_disable;
133b43f7a47Syamt 
134b43f7a47Syamt 	/* chip attach */
1358355db5eSmycroft 	error = cs_attach(sc, 0, 0, 0, 0);
1368355db5eSmycroft 	if (error)
1378355db5eSmycroft 		goto fail2;
138b43f7a47Syamt 
139b43f7a47Syamt 	cs_pcmcia_disable(sc);
1408355db5eSmycroft 	psc->sc_state = CS_PCMCIA_ATTACHED;
141b43f7a47Syamt 	return;
142b43f7a47Syamt 
1438355db5eSmycroft fail2:
1448355db5eSmycroft 	cs_pcmcia_disable(sc);
145b43f7a47Syamt fail:
1468355db5eSmycroft 	pcmcia_function_unconfigure(pf);
147b43f7a47Syamt }
148b43f7a47Syamt 
149b43f7a47Syamt static int
cs_pcmcia_detach(device_t self,int flags)1507cf29912Scegger cs_pcmcia_detach(device_t self, int flags)
151b43f7a47Syamt {
152cbab9cadSchs 	struct cs_pcmcia_softc *psc = device_private(self);
153b43f7a47Syamt 	struct cs_softc *sc = &psc->sc_cs;
1548355db5eSmycroft 	int error;
155b43f7a47Syamt 
1568355db5eSmycroft 	if (psc->sc_state != CS_PCMCIA_ATTACHED)
1578355db5eSmycroft 		return (0);
158b43f7a47Syamt 
1598355db5eSmycroft 	error = cs_detach(sc);
1608355db5eSmycroft 	if (error)
1618355db5eSmycroft 		return (error);
162b43f7a47Syamt 
1638355db5eSmycroft 	pcmcia_function_unconfigure(psc->sc_pf);
164b43f7a47Syamt 
1658355db5eSmycroft 	return (0);
166b43f7a47Syamt }
167b43f7a47Syamt 
168b43f7a47Syamt static int
cs_pcmcia_enable(struct cs_softc * sc)169b43f7a47Syamt cs_pcmcia_enable(struct cs_softc *sc)
170b43f7a47Syamt {
171b43f7a47Syamt 	struct cs_pcmcia_softc *psc = (void *)sc;
1728355db5eSmycroft 	int error;
173b43f7a47Syamt 
1748355db5eSmycroft 	sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, cs_intr, sc);
1758355db5eSmycroft 	if (!sc->sc_ih)
1768355db5eSmycroft 		return (EIO);
177b43f7a47Syamt 
1788355db5eSmycroft 	error = pcmcia_function_enable(psc->sc_pf);
1798355db5eSmycroft 	if (error) {
1808355db5eSmycroft 		pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
1818355db5eSmycroft 		sc->sc_ih = 0;
182b43f7a47Syamt 	}
183b43f7a47Syamt 
1848355db5eSmycroft 	return (error);
185b43f7a47Syamt }
186b43f7a47Syamt 
187b43f7a47Syamt static void
cs_pcmcia_disable(struct cs_softc * sc)188b43f7a47Syamt cs_pcmcia_disable(struct cs_softc *sc)
189b43f7a47Syamt {
190b43f7a47Syamt 	struct cs_pcmcia_softc *psc = (void *)sc;
191b43f7a47Syamt 
1928355db5eSmycroft 	pcmcia_function_disable(psc->sc_pf);
1938355db5eSmycroft 	pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
194b43f7a47Syamt 	sc->sc_ih = 0;
195b43f7a47Syamt }
196