root/dev/pci/ehci_pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ehci_pci_match
  2. ehci_pci_attach
  3. ehci_pci_detach
  4. ehci_pci_givecontroller
  5. ehci_pci_takecontroller
  6. ehci_pci_shutdown

    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 }

/* [<][>][^][v][top][bottom][index][help] */