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

Annotation of sys/dev/cardbus/com_cardbus.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: com_cardbus.c,v 1.30 2007/05/08 21:28:11 deraadt Exp $ */
        !             2: /* $NetBSD: com_cardbus.c,v 1.4 2000/04/17 09:21:59 joda Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 2000 Johan Danielsson
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  *
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  *
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  *
        !            19:  * 3. Neither the name of author nor the names of any contributors may
        !            20:  *    be used to endorse or promote products derived from this
        !            21:  *    software without specific prior written permission.
        !            22:  *
        !            23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            26:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
        !            27:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
        !            28:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            29:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
        !            30:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
        !            31:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
        !            32:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
        !            33:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35:
        !            36: /* This is a driver for CardBus based serial devices. It is less
        !            37:    generic than it could be, but it keeps the complexity down. So far
        !            38:    it assumes that anything that reports itself as a `serial' device
        !            39:    is infact a 16x50 or 8250, which is not necessarily true (in
        !            40:    practice this shouldn't be a problem). It also does not handle
        !            41:    devices in the `multiport serial' or `modem' sub-classes, I've
        !            42:    never seen any of these, so I don't know what they might look like.
        !            43:
        !            44:    If the CardBus device only has one BAR (that is not also the CIS
        !            45:    BAR) listed in the CIS, it is assumed to be the one to use. For
        !            46:    devices with more than one BAR, the list of known devies has to be
        !            47:    updated below.  */
        !            48:
        !            49: #include <sys/param.h>
        !            50: #include <sys/systm.h>
        !            51: #include <sys/tty.h>
        !            52: #include <sys/device.h>
        !            53:
        !            54: #include <dev/cardbus/cardbusvar.h>
        !            55: #include <dev/pci/pcidevs.h>
        !            56:
        !            57: #include <dev/pcmcia/pcmciareg.h>
        !            58:
        !            59: #include "com.h"
        !            60: #ifdef i386
        !            61: #include "pccom.h"
        !            62: #endif
        !            63:
        !            64: #include <dev/ic/comreg.h>
        !            65: #if NPCCOM > 0
        !            66: #include <i386/isa/pccomvar.h>
        !            67: #endif
        !            68: #if NCOM > 0
        !            69: #include <dev/ic/comvar.h>
        !            70: #endif
        !            71: #include <dev/ic/ns16550reg.h>
        !            72:
        !            73: #define        com_lcr         com_cfcr
        !            74:
        !            75: struct com_cardbus_softc {
        !            76:        struct com_softc        cc_com;
        !            77:        void                    *cc_ih;
        !            78:        cardbus_devfunc_t       cc_ct;
        !            79:        bus_addr_t              cc_addr;
        !            80:        cardbusreg_t            cc_base;
        !            81:        bus_size_t              cc_size;
        !            82:        cardbusreg_t            cc_csr;
        !            83:        int                     cc_cben;
        !            84:        cardbustag_t            cc_tag;
        !            85:        cardbusreg_t            cc_reg;
        !            86:        int                     cc_type;
        !            87:        u_char                  cc_bug;
        !            88: };
        !            89:
        !            90: #define DEVNAME(CSC) ((CSC)->cc_com.sc_dev.dv_xname)
        !            91:
        !            92: int    com_cardbus_match(struct device *, void *, void *);
        !            93: void   com_cardbus_attach(struct device *, struct device *, void *);
        !            94: int    com_cardbus_detach(struct device *, int);
        !            95:
        !            96: void   com_cardbus_setup(struct com_cardbus_softc *);
        !            97: int    com_cardbus_enable(struct com_softc *);
        !            98: void   com_cardbus_disable(struct com_softc *);
        !            99: struct csdev *com_cardbus_find_csdev(struct cardbus_attach_args *);
        !           100: int    com_cardbus_gofigure(struct cardbus_attach_args *,
        !           101:     struct com_cardbus_softc *);
        !           102:
        !           103: #if NCOM_CARDBUS
        !           104: struct cfattach com_cardbus_ca = {
        !           105:        sizeof(struct com_cardbus_softc), com_cardbus_match,
        !           106:        com_cardbus_attach, com_cardbus_detach, com_activate
        !           107: };
        !           108: #elif NPCCOM_CARDBUS
        !           109: struct cfattach pccom_cardbus_ca = {
        !           110:        sizeof(struct com_cardbus_softc), com_cardbus_match,
        !           111:        com_cardbus_attach, com_cardbus_detach, com_activate
        !           112: };
        !           113: #endif
        !           114:
        !           115: #define BUG_BROADCOM   0x01
        !           116:
        !           117: static struct csdev {
        !           118:        u_short         vendor;
        !           119:        u_short         product;
        !           120:        cardbusreg_t    reg;
        !           121:        u_char          type;
        !           122:        u_char          bug;
        !           123: } csdevs[] = {
        !           124:        { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_GLOBALMODEM56,
        !           125:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           126:        { PCI_VENDOR_3COM, PCI_PRODUCT_3COM_MODEM56,
        !           127:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           128:        { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4322,
        !           129:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
        !           130:        { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL,
        !           131:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO, BUG_BROADCOM },
        !           132:        { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_SERIAL_GC,
        !           133:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           134:        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_MODEM56,
        !           135:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           136:        { PCI_VENDOR_OXFORD2, PCI_PRODUCT_OXFORD2_OXCB950,
        !           137:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           138:        { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_CBEM56G,
        !           139:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO },
        !           140:        { PCI_VENDOR_XIRCOM, PCI_PRODUCT_XIRCOM_MODEM56,
        !           141:          CARDBUS_BASE0_REG, CARDBUS_MAPREG_TYPE_IO }
        !           142: };
        !           143:
        !           144: static const int ncsdevs = sizeof(csdevs) / sizeof(csdevs[0]);
        !           145:
        !           146: struct csdev*
        !           147: com_cardbus_find_csdev(struct cardbus_attach_args *ca)
        !           148: {
        !           149:        struct csdev *cp;
        !           150:
        !           151:        for (cp = csdevs; cp < csdevs + ncsdevs; cp++)
        !           152:                if (cp->vendor == CARDBUS_VENDOR(ca->ca_id) &&
        !           153:                    cp->product == CARDBUS_PRODUCT(ca->ca_id))
        !           154:                        return (cp);
        !           155:        return (NULL);
        !           156: }
        !           157:
        !           158: int
        !           159: com_cardbus_match(struct device *parent, void *match, void *aux)
        !           160: {
        !           161:        struct cardbus_attach_args *ca = aux;
        !           162:
        !           163:        /* known devices are ok */
        !           164:        if (com_cardbus_find_csdev(ca) != NULL)
        !           165:            return (10);
        !           166:
        !           167:        /* as are serial devices with a known UART */
        !           168:        if (ca->ca_cis.funcid == PCMCIA_FUNCTION_SERIAL &&
        !           169:            ca->ca_cis.funce.serial.uart_present != 0 &&
        !           170:            (ca->ca_cis.funce.serial.uart_type == 0 ||  /* 8250 */
        !           171:            ca->ca_cis.funce.serial.uart_type == 1 ||   /* 16450 */
        !           172:            ca->ca_cis.funce.serial.uart_type == 2))    /* 16550 */
        !           173:                return (1);
        !           174:
        !           175:        return (0);
        !           176: }
        !           177:
        !           178: int
        !           179: com_cardbus_gofigure(struct cardbus_attach_args *ca,
        !           180:     struct com_cardbus_softc *csc)
        !           181: {
        !           182:        int i, index = -1;
        !           183:        cardbusreg_t cis_ptr;
        !           184:        struct csdev *cp;
        !           185:
        !           186:        /* If this device is listed above, use the known values, */
        !           187:        cp = com_cardbus_find_csdev(ca);
        !           188:        if (cp != NULL) {
        !           189:                csc->cc_reg = cp->reg;
        !           190:                csc->cc_type = cp->type;
        !           191:                csc->cc_bug = cp->bug;
        !           192:                return (0);
        !           193:        }
        !           194:
        !           195:        cis_ptr = Cardbus_conf_read(csc->cc_ct, csc->cc_tag, CARDBUS_CIS_REG);
        !           196:
        !           197:        /* otherwise try to deduce which BAR and type to use from CIS.  If
        !           198:           there is only one BAR, it must be the one we should use, if
        !           199:           there are more, we're out of luck.  */
        !           200:        for (i = 0; i < 7; i++) {
        !           201:                /* ignore zero sized BARs */
        !           202:                if (ca->ca_cis.bar[i].size == 0)
        !           203:                        continue;
        !           204:                /* ignore the CIS BAR */
        !           205:                if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
        !           206:                    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
        !           207:                        continue;
        !           208:                if (index != -1)
        !           209:                        goto multi_bar;
        !           210:                index = i;
        !           211:        }
        !           212:        if (index == -1) {
        !           213:                printf(": couldn't find any base address tuple\n");
        !           214:                return (1);
        !           215:        }
        !           216:        csc->cc_reg = CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[index].flags);
        !           217:        if ((ca->ca_cis.bar[index].flags & 0x10) == 0)
        !           218:                csc->cc_type = CARDBUS_MAPREG_TYPE_MEM;
        !           219:        else
        !           220:                csc->cc_type = CARDBUS_MAPREG_TYPE_IO;
        !           221:        return (0);
        !           222:
        !           223:   multi_bar:
        !           224:        printf(": there are more than one possible base\n");
        !           225:
        !           226:        printf("%s: address for this device, "
        !           227:            "please report the following information\n",
        !           228:            DEVNAME(csc));
        !           229:        printf("%s: vendor 0x%x product 0x%x\n", DEVNAME(csc),
        !           230:            CARDBUS_VENDOR(ca->ca_id), CARDBUS_PRODUCT(ca->ca_id));
        !           231:        for (i = 0; i < 7; i++) {
        !           232:                /* ignore zero sized BARs */
        !           233:                if (ca->ca_cis.bar[i].size == 0)
        !           234:                        continue;
        !           235:                /* ignore the CIS BAR */
        !           236:                if (CARDBUS_CIS_ASI_BAR(cis_ptr) ==
        !           237:                    CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags))
        !           238:                        continue;
        !           239:                printf("%s: base address %x type %s size %x\n",
        !           240:                    DEVNAME(csc), CARDBUS_CIS_ASI_BAR(ca->ca_cis.bar[i].flags),
        !           241:                    (ca->ca_cis.bar[i].flags & 0x10) ? "i/o" : "mem",
        !           242:                    ca->ca_cis.bar[i].size);
        !           243:        }
        !           244:        return (1);
        !           245: }
        !           246:
        !           247: void
        !           248: com_cardbus_attach(struct device *parent, struct device *self, void *aux)
        !           249: {
        !           250:        struct com_softc *sc = (struct com_softc*)self;
        !           251:        struct com_cardbus_softc *csc = (struct com_cardbus_softc*)self;
        !           252:        struct cardbus_attach_args *ca = aux;
        !           253:
        !           254:        csc->cc_ct = ca->ca_ct;
        !           255:        csc->cc_tag = Cardbus_make_tag(csc->cc_ct);
        !           256:
        !           257:        if (com_cardbus_gofigure(ca, csc) != 0)
        !           258:                return;
        !           259:
        !           260:        if (Cardbus_mapreg_map(ca->ca_ct, csc->cc_reg, csc->cc_type, 0,
        !           261:            &sc->sc_iot, &sc->sc_ioh, &csc->cc_addr, &csc->cc_size) != 0) {
        !           262:                printf("failed to map memory");
        !           263:                return;
        !           264:        }
        !           265:
        !           266:        csc->cc_base = csc->cc_addr;
        !           267:        csc->cc_csr = CARDBUS_COMMAND_MASTER_ENABLE;
        !           268:        if (csc->cc_type == CARDBUS_MAPREG_TYPE_IO) {
        !           269:                csc->cc_base |= CARDBUS_MAPREG_TYPE_IO;
        !           270:                csc->cc_csr |= CARDBUS_COMMAND_IO_ENABLE;
        !           271:                csc->cc_cben = CARDBUS_IO_ENABLE;
        !           272:        } else {
        !           273:                csc->cc_csr |= CARDBUS_COMMAND_MEM_ENABLE;
        !           274:                csc->cc_cben = CARDBUS_MEM_ENABLE;
        !           275:        }
        !           276:
        !           277:        sc->sc_iobase = csc->cc_addr;
        !           278:        sc->sc_frequency = COM_FREQ;
        !           279:
        !           280:        sc->enable = com_cardbus_enable;
        !           281:        sc->disable = com_cardbus_disable;
        !           282:        sc->enabled = 0;
        !           283:
        !           284:        if (ca->ca_cis.cis1_info[0] && ca->ca_cis.cis1_info[1]) {
        !           285:                printf(": %s %s\n", ca->ca_cis.cis1_info[0],
        !           286:                    ca->ca_cis.cis1_info[1]);
        !           287:                printf("%s", DEVNAME(csc));
        !           288:        }
        !           289:
        !           290:        if (com_cardbus_enable(sc))
        !           291:                printf(": function enable failed\n");
        !           292:        sc->enabled = 1;
        !           293:
        !           294:        sc->sc_hwflags = 0;
        !           295:        sc->sc_swflags = 0;
        !           296:
        !           297:        if (csc->cc_bug & BUG_BROADCOM)
        !           298:                sc->sc_fifolen = 15;
        !           299:
        !           300:        com_attach_subr(sc);
        !           301: }
        !           302:
        !           303: void
        !           304: com_cardbus_setup(struct com_cardbus_softc *csc)
        !           305: {
        !           306:        cardbus_devfunc_t ct = csc->cc_ct;
        !           307:        cardbus_chipset_tag_t cc = ct->ct_cc;
        !           308:        cardbus_function_tag_t cf = ct->ct_cf;
        !           309:        cardbusreg_t reg;
        !           310:
        !           311:        cardbus_conf_write(cc, cf, csc->cc_tag, csc->cc_reg, csc->cc_base);
        !           312:
        !           313:        /* enable accesses on cardbus bridge */
        !           314:        cf->cardbus_ctrl(cc, csc->cc_cben);
        !           315:        cf->cardbus_ctrl(cc, CARDBUS_BM_ENABLE);
        !           316:
        !           317:        /* and the card itself */
        !           318:        reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG);
        !           319:        reg &= ~(CARDBUS_COMMAND_IO_ENABLE | CARDBUS_COMMAND_MEM_ENABLE);
        !           320:        reg |= csc->cc_csr;
        !           321:        cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_COMMAND_STATUS_REG, reg);
        !           322:
        !           323:        /*
        !           324:         * Make sure the latency timer is set to some reasonable
        !           325:         * value.
        !           326:         */
        !           327:        reg = cardbus_conf_read(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG);
        !           328:        if (CARDBUS_LATTIMER(reg) < 0x20) {
        !           329:                        reg &= ~(CARDBUS_LATTIMER_MASK << CARDBUS_LATTIMER_SHIFT);
        !           330:                        reg |= (0x20 << CARDBUS_LATTIMER_SHIFT);
        !           331:                        cardbus_conf_write(cc, cf, csc->cc_tag, CARDBUS_BHLC_REG, reg);
        !           332:        }
        !           333: }
        !           334:
        !           335: int
        !           336: com_cardbus_enable(struct com_softc *sc)
        !           337: {
        !           338:        struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
        !           339:        struct cardbus_softc *psc =
        !           340:            (struct cardbus_softc *)sc->sc_dev.dv_parent;
        !           341:        cardbus_chipset_tag_t cc = psc->sc_cc;
        !           342:        cardbus_function_tag_t cf = psc->sc_cf;
        !           343:
        !           344:        Cardbus_function_enable(csc->cc_ct);
        !           345:
        !           346:        com_cardbus_setup(csc);
        !           347:
        !           348:        /* establish the interrupt. */
        !           349:        csc->cc_ih = cardbus_intr_establish(cc, cf, psc->sc_intrline,
        !           350:            IPL_TTY, comintr, sc, DEVNAME(csc));
        !           351:        if (csc->cc_ih == NULL) {
        !           352:                printf("%s: couldn't establish interrupt\n", DEVNAME(csc));
        !           353:                return (1);
        !           354:        }
        !           355:
        !           356:        printf(": irq %d", psc->sc_intrline);
        !           357:
        !           358:        return (0);
        !           359: }
        !           360:
        !           361: void
        !           362: com_cardbus_disable(struct com_softc *sc)
        !           363: {
        !           364:        struct com_cardbus_softc *csc = (struct com_cardbus_softc*)sc;
        !           365:        struct cardbus_softc *psc =
        !           366:            (struct cardbus_softc *)sc->sc_dev.dv_parent;
        !           367:        cardbus_chipset_tag_t cc = psc->sc_cc;
        !           368:        cardbus_function_tag_t cf = psc->sc_cf;
        !           369:
        !           370:        cardbus_intr_disestablish(cc, cf, csc->cc_ih);
        !           371:        Cardbus_function_disable(csc->cc_ct);
        !           372: }
        !           373:
        !           374: int
        !           375: com_cardbus_detach(struct device *self, int flags)
        !           376: {
        !           377:        struct com_cardbus_softc *csc = (struct com_cardbus_softc *) self;
        !           378:        struct com_softc *sc = (struct com_softc *) self;
        !           379:        struct cardbus_softc *psc = (struct cardbus_softc *)self->dv_parent;
        !           380:        int error;
        !           381:
        !           382:        if ((error = com_detach(self, flags)) != 0)
        !           383:                return (error);
        !           384:
        !           385:        cardbus_intr_disestablish(psc->sc_cc, psc->sc_cf, csc->cc_ih);
        !           386:
        !           387:        Cardbus_mapreg_unmap(csc->cc_ct, csc->cc_reg, sc->sc_iot, sc->sc_ioh,
        !           388:            csc->cc_size);
        !           389:
        !           390:        return (0);
        !           391: }

CVSweb