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

Annotation of sys/dev/pci/ehci_pci.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: ehci_pci.c,v 1.12 2007/06/10 14:49:01 mbalmer Exp $ */
                      2: /*     $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $     */
                      3:
                      4: /*
                      5:  * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This code is derived from software contributed to The NetBSD Foundation
                      9:  * by Lennart Augustsson (lennart@augustsson.net).
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *        This product includes software developed by the NetBSD
                     22:  *        Foundation, Inc. and its contributors.
                     23:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     24:  *    contributors may be used to endorse or promote products derived
                     25:  *    from this software without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     28:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     29:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     30:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     31:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     32:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     33:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     34:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     35:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     36:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     37:  * POSSIBILITY OF SUCH DAMAGE.
                     38:  */
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/systm.h>
                     42: #include <sys/kernel.h>
                     43: #include <sys/rwlock.h>
                     44: #include <sys/device.h>
                     45: #include <sys/proc.h>
                     46: #include <sys/queue.h>
                     47:
                     48: #include <machine/bus.h>
                     49:
                     50: #include <dev/pci/pcidevs.h>
                     51: #include <dev/pci/pcivar.h>
                     52:
                     53: #include <dev/usb/usb.h>
                     54: #include <dev/usb/usbdi.h>
                     55: #include <dev/usb/usbdivar.h>
                     56: #include <dev/usb/usb_mem.h>
                     57:
                     58: #include <dev/usb/ehcireg.h>
                     59: #include <dev/usb/ehcivar.h>
                     60:
                     61: #ifdef EHCI_DEBUG
                     62: #define DPRINTF(x)     if (ehcidebug) printf x
                     63: extern int ehcidebug;
                     64: #else
                     65: #define DPRINTF(x)
                     66: #endif
                     67:
                     68: struct ehci_pci_softc {
                     69:        ehci_softc_t            sc;
                     70:        pci_chipset_tag_t       sc_pc;
                     71:        pcitag_t                sc_tag;
                     72:        void                    *sc_ih;         /* interrupt vectoring */
                     73: };
                     74:
                     75: int    ehci_pci_match(struct device *, void *, void *);
                     76: void   ehci_pci_attach(struct device *, struct device *, void *);
                     77: int    ehci_pci_detach(struct device *, int);
                     78: void   ehci_pci_givecontroller(struct ehci_pci_softc *);
                     79: void   ehci_pci_takecontroller(struct ehci_pci_softc *);
                     80: void   ehci_pci_shutdown(void *);
                     81:
                     82: struct cfattach ehci_pci_ca = {
                     83:        sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach,
                     84:        ehci_pci_detach, ehci_activate
                     85: };
                     86:
                     87:
                     88: int
                     89: ehci_pci_match(struct device *parent, void *match, void *aux)
                     90: {
                     91:        struct pci_attach_args *pa = (struct pci_attach_args *) aux;
                     92:
                     93:        if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
                     94:            PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB &&
                     95:            PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI)
                     96:                return (1);
                     97:
                     98:        return (0);
                     99: }
                    100:
                    101: void
                    102: ehci_pci_attach(struct device *parent, struct device *self, void *aux)
                    103: {
                    104:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
                    105:        struct pci_attach_args *pa = (struct pci_attach_args *)aux;
                    106:        pci_chipset_tag_t pc = pa->pa_pc;
                    107:        pcitag_t tag = pa->pa_tag;
                    108:        char const *intrstr;
                    109:        pci_intr_handle_t ih;
                    110:        const char *vendor;
                    111:        char *devname = sc->sc.sc_bus.bdev.dv_xname;
                    112:        usbd_status r;
                    113:        int s;
                    114:
                    115:        /* Map I/O registers */
                    116:        if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0,
                    117:                           &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size, 0)) {
                    118:                printf(": can't map memory space\n");
                    119:                return;
                    120:        }
                    121:
                    122:        sc->sc_pc = pc;
                    123:        sc->sc_tag = tag;
                    124:        sc->sc.sc_bus.dmatag = pa->pa_dmat;
                    125:
                    126:        /* Disable interrupts, so we don't get any spurious ones. */
                    127:        s = splhardusb();
                    128:        sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
                    129:        DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs));
                    130:        EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
                    131:
                    132:        /* Map and establish the interrupt. */
                    133:        if (pci_intr_map(pa, &ih)) {
                    134:                printf(": couldn't map interrupt\n");
                    135:                goto unmap_ret;
                    136:        }
                    137:        intrstr = pci_intr_string(pc, ih);
                    138:        sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc, devname);
                    139:        if (sc->sc_ih == NULL) {
                    140:                printf(": couldn't establish interrupt");
                    141:                if (intrstr != NULL)
                    142:                        printf(" at %s", intrstr);
                    143:                printf("\n");
                    144:                goto unmap_ret;
                    145:        }
                    146:        printf(": %s\n", intrstr);
                    147:
                    148:        switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) {
                    149:        case PCI_USBREV_PRE_1_0:
                    150:        case PCI_USBREV_1_0:
                    151:        case PCI_USBREV_1_1:
                    152:                sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
                    153:                printf("%s: pre-2.0 USB rev\n", devname);
                    154:                goto unmap_ret;
                    155:        case PCI_USBREV_2_0:
                    156:                sc->sc.sc_bus.usbrev = USBREV_2_0;
                    157:                break;
                    158:        default:
                    159:                sc->sc.sc_bus.usbrev = USBREV_UNKNOWN;
                    160:                break;
                    161:        }
                    162:
                    163:        /* Figure out vendor for root hub descriptor. */
                    164:        vendor = pci_findvendor(pa->pa_id);
                    165:        sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id);
                    166:        if (vendor)
                    167:                strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor));
                    168:        else
                    169:                snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor),
                    170:                    "vendor 0x%04x", PCI_VENDOR(pa->pa_id));
                    171:
                    172:        /* Enable workaround for dropped interrupts as required */
                    173:        if (sc->sc.sc_id_vendor == PCI_VENDOR_VIATECH)
                    174:                sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND;
                    175:
                    176:        ehci_pci_takecontroller(sc);
                    177:        r = ehci_init(&sc->sc);
                    178:        if (r != USBD_NORMAL_COMPLETION) {
                    179:                printf("%s: init failed, error=%d\n", devname, r);
                    180:                goto unmap_ret;
                    181:        }
                    182:
                    183:        sc->sc.sc_shutdownhook = shutdownhook_establish(ehci_pci_shutdown, sc);
                    184:        splx(s);
                    185:
                    186:        /* Attach usb device. */
                    187:        sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
                    188:                                       usbctlprint);
                    189:
                    190:        return;
                    191:
                    192: unmap_ret:
                    193:        bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
                    194:        splx(s);
                    195: }
                    196:
                    197: int
                    198: ehci_pci_detach(struct device *self, int flags)
                    199: {
                    200:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self;
                    201:        int rv;
                    202:
                    203:        rv = ehci_detach(&sc->sc, flags);
                    204:        if (rv)
                    205:                return (rv);
                    206:        if (sc->sc_ih != NULL) {
                    207:                pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
                    208:                sc->sc_ih = NULL;
                    209:        }
                    210:        if (sc->sc.sc_size) {
                    211:                bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
                    212:                sc->sc.sc_size = 0;
                    213:        }
                    214:        return (0);
                    215: }
                    216:
                    217: void
                    218: ehci_pci_givecontroller(struct ehci_pci_softc *sc)
                    219: {
                    220:        u_int32_t cparams, eec, legsup;
                    221:        int eecp;
                    222:
                    223:        cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
                    224:        for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
                    225:            eecp = EHCI_EECP_NEXT(eec)) {
                    226:                eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
                    227:                if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
                    228:                        continue;
                    229:                legsup = eec;
                    230:                pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
                    231:                    legsup & ~EHCI_LEGSUP_OSOWNED);
                    232:        }
                    233: }
                    234:
                    235: void
                    236: ehci_pci_takecontroller(struct ehci_pci_softc *sc)
                    237: {
                    238:        u_int32_t cparams, eec, legsup;
                    239:        int eecp, i;
                    240:
                    241:        cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS);
                    242:        /* Synchronise with the BIOS if it owns the controller. */
                    243:        for (eecp = EHCI_HCC_EECP(cparams); eecp != 0;
                    244:            eecp = EHCI_EECP_NEXT(eec)) {
                    245:                eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp);
                    246:                if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP)
                    247:                        continue;
                    248:                legsup = eec;
                    249:                pci_conf_write(sc->sc_pc, sc->sc_tag, eecp,
                    250:                    legsup | EHCI_LEGSUP_OSOWNED);
                    251:                if (legsup & EHCI_LEGSUP_BIOSOWNED) {
                    252:                        DPRINTF(("%s: waiting for BIOS to give up control\n",
                    253:                            sc->sc.sc_bus.bdev.dv_xname));
                    254:                        for (i = 0; i < 5000; i++) {
                    255:                                legsup = pci_conf_read(sc->sc_pc, sc->sc_tag,
                    256:                                    eecp);
                    257:                                if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0)
                    258:                                        break;
                    259:                                DELAY(1000);
                    260:                        }
                    261:                        if (legsup & EHCI_LEGSUP_BIOSOWNED)
                    262:                                printf("%s: timed out waiting for BIOS\n",
                    263:                                    sc->sc.sc_bus.bdev.dv_xname);
                    264:                }
                    265:        }
                    266: }
                    267:
                    268: void
                    269: ehci_pci_shutdown(void *v)
                    270: {
                    271:        struct ehci_pci_softc *sc = (struct ehci_pci_softc *)v;
                    272:
                    273:        ehci_shutdown(&sc->sc);
                    274:        ehci_pci_givecontroller(sc);
                    275: }

CVSweb