1 /* $OpenBSD: ohci_cardbus.c,v 1.22 2019/01/07 03:41:06 dlg Exp $ */ 2 /* $NetBSD: ohci_cardbus.c,v 1.19 2004/08/02 19:14:28 mycroft 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 Lennart Augustsson (lennart@augustsson.net) at 10 * Carlstedt Research & Technology. 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 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * USB Open Host Controller driver. 36 * 37 * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf 38 * USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl 39 */ 40 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/device.h> 46 47 #include <machine/bus.h> 48 49 #include <dev/cardbus/cardbusvar.h> 50 51 #include <dev/usb/usb.h> 52 #include <dev/usb/usbdi.h> 53 #include <dev/usb/usbdivar.h> 54 #include <dev/usb/usb_mem.h> 55 56 #include <dev/usb/ohcireg.h> 57 #include <dev/usb/ohcivar.h> 58 59 int ohci_cardbus_match(struct device *, void *, void *); 60 void ohci_cardbus_attach(struct device *, struct device *, void *); 61 int ohci_cardbus_detach(struct device *, int); 62 63 struct ohci_cardbus_softc { 64 struct ohci_softc sc; 65 cardbus_chipset_tag_t sc_cc; 66 cardbus_function_tag_t sc_cf; 67 cardbus_devfunc_t sc_ct; 68 void *sc_ih; /* interrupt vectoring */ 69 }; 70 71 struct cfattach ohci_cardbus_ca = { 72 sizeof(struct ohci_cardbus_softc), ohci_cardbus_match, 73 ohci_cardbus_attach, ohci_cardbus_detach, ohci_activate 74 }; 75 76 #define CARDBUS_CBMEM PCI_CBMEM 77 #define cardbus_findvendor pci_findvendor 78 79 int 80 ohci_cardbus_match(struct device *parent, void *match, void *aux) 81 { 82 struct cardbus_attach_args *ca = (struct cardbus_attach_args *)aux; 83 84 if (PCI_CLASS(ca->ca_class) == PCI_CLASS_SERIALBUS && 85 PCI_SUBCLASS(ca->ca_class) == PCI_SUBCLASS_SERIALBUS_USB && 86 PCI_INTERFACE(ca->ca_class) == PCI_INTERFACE_OHCI) 87 return (1); 88 89 return (0); 90 } 91 92 void 93 ohci_cardbus_attach(struct device *parent, struct device *self, void *aux) 94 { 95 struct ohci_cardbus_softc *sc = (struct ohci_cardbus_softc *)self; 96 struct cardbus_attach_args *ca = aux; 97 cardbus_devfunc_t ct = ca->ca_ct; 98 cardbus_chipset_tag_t cc = ct->ct_cc; 99 pci_chipset_tag_t pc = ca->ca_pc; 100 cardbus_function_tag_t cf = ct->ct_cf; 101 pcireg_t csr; 102 usbd_status r; 103 const char *vendor; 104 const char *devname = sc->sc.sc_bus.bdev.dv_xname; 105 106 /* Map I/O registers */ 107 if (Cardbus_mapreg_map(ct, CARDBUS_CBMEM, PCI_MAPREG_TYPE_MEM, 0, 108 &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) { 109 printf(": can't map mem space\n"); 110 return; 111 } 112 113 /* Disable interrupts, so we don't get any spurious ones. */ 114 bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, 115 OHCI_MIE); 116 117 sc->sc_cc = cc; 118 sc->sc_cf = cf; 119 sc->sc_ct = ct; 120 sc->sc.sc_bus.dmatag = ca->ca_dmat; 121 122 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 123 (ct->ct_cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 124 125 /* Enable the device. */ 126 csr = pci_conf_read(pc, ca->ca_tag, 127 PCI_COMMAND_STATUS_REG); 128 pci_conf_write(pc, ca->ca_tag, PCI_COMMAND_STATUS_REG, 129 csr | PCI_COMMAND_MASTER_ENABLE 130 | PCI_COMMAND_MEM_ENABLE); 131 132 sc->sc_ih = cardbus_intr_establish(cc, cf, ca->ca_intrline, 133 IPL_USB, ohci_intr, sc, devname); 134 if (sc->sc_ih == NULL) { 135 printf(": couldn't establish interrupt\n"); 136 return; 137 } 138 printf(": irq %d, ", ca->ca_intrline); 139 140 /* Figure out vendor for root hub descriptor. */ 141 vendor = cardbus_findvendor(ca->ca_id); 142 sc->sc.sc_id_vendor = PCI_VENDOR(ca->ca_id); 143 if (vendor) 144 strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor)); 145 else 146 snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor), 147 "vendor 0x%04x", PCI_VENDOR(ca->ca_id)); 148 149 /* Display revision and perform legacy emulation handover. */ 150 if (ohci_checkrev(&sc->sc) != USBD_NORMAL_COMPLETION || 151 ohci_handover(&sc->sc) != USBD_NORMAL_COMPLETION) { 152 cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih); 153 sc->sc_ih = 0; 154 return; 155 } 156 157 r = ohci_init(&sc->sc); 158 if (r != USBD_NORMAL_COMPLETION) { 159 printf("%s: init failed, error=%d\n", devname, r); 160 161 /* Avoid spurious interrupts. */ 162 cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih); 163 sc->sc_ih = 0; 164 165 return; 166 } 167 168 /* Attach usb device. */ 169 config_found(self, &sc->sc.sc_bus, usbctlprint); 170 } 171 172 int 173 ohci_cardbus_detach(struct device *self, int flags) 174 { 175 struct ohci_cardbus_softc *sc = (struct ohci_cardbus_softc *)self; 176 struct cardbus_devfunc *ct = sc->sc_ct; 177 int rv; 178 179 rv = ohci_detach(self, flags); 180 if (rv) 181 return (rv); 182 183 if (sc->sc_ih != NULL) { 184 cardbus_intr_disestablish(sc->sc_cc, sc->sc_cf, sc->sc_ih); 185 sc->sc_ih = NULL; 186 } 187 if (sc->sc.sc_size) { 188 Cardbus_mapreg_unmap(ct, CARDBUS_CBMEM, sc->sc.iot, 189 sc->sc.ioh, sc->sc.sc_size); 190 sc->sc.sc_size = 0; 191 } 192 193 return (0); 194 } 195