[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

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