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