[BACK]Return to if_ep_pcmcia.c CVS log [TXT][DIR] Up to [local] / sys / dev / pcmcia

Annotation of sys/dev/pcmcia/if_ep_pcmcia.c, Revision 1.1

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

CVSweb