1 /* 2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the acknowledgement as bellow: 15 * 16 * This product includes software developed by K. Kobayashi and H. SHimokawa 17 * 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/module.h> 40 #include <sys/bus.h> 41 #include <sys/queue.h> 42 #include <machine/bus.h> 43 #include <sys/rman.h> 44 #include <machine/resource.h> 45 46 #include <pci/pcivar.h> 47 #include <pci/pcireg.h> 48 49 #include <dev/firewire/firewire.h> 50 #include <dev/firewire/firewirebusreg.h> 51 #include <dev/firewire/firewirereg.h> 52 53 #include <dev/firewire/fwohcireg.h> 54 #include <dev/firewire/fwohcivar.h> 55 56 static int fwohci_pci_attach(device_t self); 57 static int fwohci_pci_detach(device_t self); 58 59 /* 60 * The probe routine. 61 */ 62 static int 63 fwohci_pci_probe( device_t dev ) 64 { 65 #if 1 66 if ((pci_get_vendor(dev) == FW_VENDORID_NEC) && 67 (pci_get_device(dev) == FW_DEVICE_UPD861)) { 68 device_set_desc(dev, "NEC uPD72861"); 69 return 0; 70 } 71 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 72 (pci_get_device(dev) == FW_DEVICE_TITSB22)) { 73 device_set_desc(dev, "Texas Instruments TSB12LV22"); 74 return 0; 75 } 76 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 77 (pci_get_device(dev) == FW_DEVICE_TITSB23)) { 78 device_set_desc(dev, "Texas Instruments TSB12LV23"); 79 return 0; 80 } 81 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 82 (pci_get_device(dev) == FW_DEVICE_TITSB26)) { 83 device_set_desc(dev, "Texas Instruments TSB12LV26"); 84 return 0; 85 } 86 if ((pci_get_vendor(dev) == FW_VENDORID_TI) && 87 (pci_get_device(dev) == FW_DEVICE_TITSB43)) { 88 device_set_desc(dev, "Texas Instruments TSB43AA22"); 89 return 0; 90 } 91 if ((pci_get_vendor(dev) == FW_VENDORID_SONY) && 92 (pci_get_device(dev) == FW_DEVICE_CX3022)) { 93 device_set_desc(dev, "SONY CX3022"); 94 return 0; 95 } 96 if ((pci_get_vendor(dev) == FW_VENDORID_VIA) && 97 (pci_get_device(dev) == FW_DEVICE_VT6306)) { 98 device_set_desc(dev, "VIA VT6306"); 99 return 0; 100 } 101 if ((pci_get_vendor(dev) == FW_VENDORID_RICOH) && 102 (pci_get_device(dev) == FW_DEVICE_R5C552)) { 103 device_set_desc(dev, "Ricoh R5C552"); 104 return 0; 105 } 106 if ((pci_get_vendor(dev) == FW_VENDORID_APPLE) && 107 (pci_get_device(dev) == FW_DEVICE_PANGEA)) { 108 device_set_desc(dev, "Apple Pangea"); 109 return 0; 110 } 111 if ((pci_get_vendor(dev) == FW_VENDORID_APPLE) && 112 (pci_get_device(dev) == FW_DEVICE_UNINORTH)) { 113 device_set_desc(dev, "Apple UniNorth"); 114 return 0; 115 } 116 if ((pci_get_vendor(dev) == FW_VENDORID_LUCENT) && 117 (pci_get_device(dev) == FW_DEVICE_FW322)) { 118 device_set_desc(dev, "Lucent FW322/323"); 119 return 0; 120 } 121 #endif 122 if (pci_get_class(dev) == PCIC_SERIALBUS 123 && pci_get_subclass(dev) == PCIS_SERIALBUS_FW 124 && pci_get_progif(dev) == PCI_INTERFACE_OHCI) { 125 printf("XXXfw: vendid=%x, dev=%x\n", pci_get_vendor(dev), 126 pci_get_device(dev)); 127 device_set_desc(dev, "1394 Open Host Controller Interface"); 128 return 0; 129 } 130 131 return ENXIO; 132 } 133 134 #if __FreeBSD_version < 500000 135 static void 136 fwohci_dummy_intr(void *arg) 137 { 138 /* XXX do nothing */ 139 } 140 #endif 141 142 static int 143 fwohci_pci_attach(device_t self) 144 { 145 fwohci_softc_t *sc = device_get_softc(self); 146 int err; 147 int rid; 148 int intr; 149 int latency, cache_line; 150 u_int16_t cmd; 151 /* For the moment, put in a message stating what is wrong */ 152 intr = pci_read_config(self, PCIR_INTLINE, 1); 153 if (intr == 0 || intr == 255) { 154 device_printf(self, "Invalid irq %d\n", intr); 155 #ifdef __i386__ 156 device_printf(self, "Please switch PNP-OS to 'No' in BIOS\n"); 157 #endif 158 return ENXIO; 159 } 160 161 cmd = pci_read_config(self, PCIR_COMMAND, 2); 162 cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN; 163 pci_write_config(self, PCIR_COMMAND, cmd, 2); 164 165 latency = pci_read_config(self, PCIR_LATTIMER, 1); 166 #define DEF_LATENCY 250 /* Derived from Max Bulk Transfer size 512 Bytes*/ 167 if( latency < DEF_LATENCY ) { 168 latency = DEF_LATENCY; 169 device_printf(self, "PCI bus latency was changing to"); 170 pci_write_config(self, PCIR_LATTIMER,latency, 1); 171 } else 172 { 173 device_printf(self, "PCI bus latency is"); 174 } 175 printf(" %d.\n", (int) latency); 176 cache_line = pci_read_config(self, PCIR_CACHELNSZ, 1); 177 #if 0 178 #define DEF_CACHE_LINE 0xc 179 cache_line = DEF_CACHE_LINE; 180 pci_write_config(self, PCIR_CACHELNSZ, cache_line, 1); 181 #endif 182 printf("cache size %d.\n", (int) cache_line); 183 /**/ 184 rid = PCI_CBMEM; 185 sc->bsr = bus_alloc_resource(self, SYS_RES_MEMORY, &rid, 186 0, ~0, 1, RF_ACTIVE); 187 if (!sc->bsr) { 188 device_printf(self, "Could not map memory\n"); 189 return ENXIO; 190 } 191 192 sc->bst = rman_get_bustag(sc->bsr); 193 sc->bsh = rman_get_bushandle(sc->bsr); 194 195 rid = 0; 196 sc->irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, 0, ~0, 1, 197 RF_SHAREABLE | RF_ACTIVE); 198 if (sc->irq_res == NULL) { 199 device_printf(self, "Could not allocate irq\n"); 200 fwohci_pci_detach(self); 201 return ENXIO; 202 } 203 204 sc->fc.bdev = device_add_child(self, "firewire", -1); 205 if (!sc->fc.bdev) { 206 device_printf(self, "Could not add firewire device\n"); 207 fwohci_pci_detach(self); 208 return ENOMEM; 209 } 210 device_set_ivars(sc->fc.bdev, sc); 211 212 err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_NET, 213 (driver_intr_t *) fwohci_intr, sc, &sc->ih); 214 #if __FreeBSD_version < 500000 215 /* XXX splcam() should mask this irq for sbp.c*/ 216 err = bus_setup_intr(self, sc->irq_res, INTR_TYPE_CAM, 217 (driver_intr_t *) fwohci_dummy_intr, sc, &sc->ih_cam); 218 #endif 219 if (err) { 220 device_printf(self, "Could not setup irq, %d\n", err); 221 fwohci_pci_detach(self); 222 return ENXIO; 223 } 224 225 err = fwohci_init(sc, self); 226 227 if (!err) 228 err = device_probe_and_attach(sc->fc.bdev); 229 230 if (err) { 231 device_printf(self, "Firewire init failed\n"); 232 fwohci_pci_detach(self); 233 return EIO; 234 } 235 236 return 0; 237 } 238 239 static int 240 fwohci_pci_detach(device_t self) 241 { 242 fwohci_softc_t *sc = device_get_softc(self); 243 int s; 244 245 246 s = splfw(); 247 bus_generic_detach(self); 248 249 /* disable interrupts that might have been switched on */ 250 if (sc->bst && sc->bsh) 251 bus_space_write_4(sc->bst, sc->bsh, 252 FWOHCI_INTMASKCLR, OHCI_INT_EN); 253 254 if (sc->irq_res) { 255 int err = bus_teardown_intr(self, sc->irq_res, sc->ih); 256 if (err) 257 /* XXX or should we panic? */ 258 device_printf(self, "Could not tear down irq, %d\n", 259 err); 260 #if __FreeBSD_version < 500000 261 err = bus_teardown_intr(self, sc->irq_res, sc->ih_cam); 262 #endif 263 sc->ih = NULL; 264 } 265 266 if (sc->fc.bdev) { 267 device_delete_child(self, sc->fc.bdev); 268 sc->fc.bdev = NULL; 269 } 270 271 if (sc->irq_res) { 272 bus_release_resource(self, SYS_RES_IRQ, 0, sc->irq_res); 273 sc->irq_res = NULL; 274 } 275 276 if (sc->bsr) { 277 bus_release_resource(self, SYS_RES_MEMORY,PCI_CBMEM,sc->bsr); 278 sc->bsr = NULL; 279 sc->bst = 0; 280 sc->bsh = 0; 281 } 282 splx(s); 283 284 return 0; 285 } 286 287 static device_method_t fwohci_methods[] = { 288 /* Device interface */ 289 DEVMETHOD(device_probe, fwohci_pci_probe), 290 DEVMETHOD(device_attach, fwohci_pci_attach), 291 DEVMETHOD(device_detach, fwohci_pci_detach), 292 DEVMETHOD(device_shutdown, bus_generic_shutdown), 293 294 /* Bus interface */ 295 DEVMETHOD(bus_print_child, bus_generic_print_child), 296 297 { 0, 0 } 298 }; 299 300 static driver_t fwohci_driver = { 301 "fwohci", 302 fwohci_methods, 303 sizeof(fwohci_softc_t), 304 }; 305 306 static devclass_t fwohci_devclass; 307 308 DRIVER_MODULE(fwohci, pci, fwohci_driver, fwohci_devclass, 0, 0); 309 DRIVER_MODULE(fwohci, cardbus, fwohci_driver, fwohci_devclass, 0, 0); 310