1 /* 2 * Copyright (C) 2007 JiSheng Zhang <jszhang3@gmail.com>. All rights reserved 3 * Distributed under the terms of the MIT license. 4 * 5 * Kernel driver for firewire 6 */ 7 8 #include <OS.h> 9 #include <KernelExport.h> 10 #include <SupportDefs.h> 11 #include <PCI.h> 12 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <string.h> 16 #include <malloc.h> 17 #include <dpc.h> 18 19 #include "fwdebug.h" 20 #include "queue.h" 21 #include "fwglue.h" 22 #include "firewire.h" 23 #include "iec13213.h" 24 #include "firewirereg.h" 25 #include "fwdma.h" 26 #include "fwohcireg.h" 27 #include "fwohcivar.h" 28 #include "firewire_module.h" 29 30 status_t fwohci_pci_attach(int index); 31 status_t fwohci_pci_detach(int index); 32 pci_info *pciInfo[MAX_CARDS]; 33 fwohci_softc_t *gFwohci_softc[MAX_CARDS]; 34 struct firewire_softc *gFirewire_softc[MAX_CARDS]; 35 pci_module_info *gPci; 36 dpc_module_info *gDpc; 37 38 struct supported_device{ 39 uint16 vendor_id; 40 uint32 device_id; 41 const char *name; 42 }; 43 44 struct supported_device supported_devices[] = { 45 {FW_VENDORID_NATSEMI, FW_DEVICE_CS4210, "National Semiconductor CS4210"}, 46 {FW_VENDORID_NEC, FW_DEVICE_UPD861, "NEC uPD72861"}, 47 {FW_VENDORID_NEC, FW_DEVICE_UPD871, "NEC uPD72871/2"}, 48 {FW_VENDORID_NEC, FW_DEVICE_UPD72870, "NEC uPD72870"}, 49 {FW_VENDORID_NEC, FW_DEVICE_UPD72873, "NEC uPD72873"}, 50 {FW_VENDORID_NEC, FW_DEVICE_UPD72874, "NEC uPD72874"}, 51 {FW_VENDORID_SIS, FW_DEVICE_7007, "SiS 7007"}, 52 {FW_VENDORID_TI, FW_DEVICE_TITSB22, "Texas Instruments TSB12LV22"}, 53 {FW_VENDORID_TI, FW_DEVICE_TITSB23, "Texas Instruments TSB12LV23"}, 54 {FW_VENDORID_TI, FW_DEVICE_TITSB26, "Texas Instruments TSB12LV26"}, 55 {FW_VENDORID_TI, FW_DEVICE_TITSB43, "Texas Instruments TSB43AA22"}, 56 {FW_VENDORID_TI, FW_DEVICE_TITSB43A, "Texas Instruments TSB43AB22/A"}, 57 {FW_VENDORID_TI, FW_DEVICE_TITSB43AB21, "Texas Instruments TSB43AB21/A/AI/A-EP"}, 58 {FW_VENDORID_TI, FW_DEVICE_TITSB43AB23, "Texas Instruments TSB43AB23"}, 59 {FW_VENDORID_TI, FW_DEVICE_TITSB82AA2, "Texas Instruments TSB82AA2"}, 60 {FW_VENDORID_TI, FW_DEVICE_TIPCI4450, "Texas Instruments PCI4450"}, 61 {FW_VENDORID_TI, FW_DEVICE_TIPCI4410A, "Texas Instruments PCI4410A"}, 62 {FW_VENDORID_TI, FW_DEVICE_TIPCI4451, "Texas Instruments PCI4451"}, 63 {FW_VENDORID_VIA, FW_DEVICE_VT6306, "VIA Fire II (VT6306)"}, 64 {FW_VENDORID_RICOH, FW_DEVICE_R5C551, "Ricoh R5C551"}, 65 {FW_VENDORID_RICOH, FW_DEVICE_R5C552, "Ricoh R5C552"}, 66 {FW_VENDORID_APPLE, FW_DEVICE_PANGEA, "Apple Pangea"}, 67 {FW_VENDORID_APPLE, FW_DEVICE_UNINORTH, "Apple UniNorth"}, 68 {FW_VENDORID_LUCENT, FW_DEVICE_FW322, "Lucent FW322/323"}, 69 {FW_VENDORID_INTEL, FW_DEVICE_82372FB, "Intel 82372FB"}, 70 {FW_VENDORID_ADAPTEC, FW_DEVICE_AIC5800, "Adaptec AHA-894x/AIC-5800"}, 71 {FW_VENDORID_SUN, FW_DEVICE_PCIO2FW, "Sun PCIO-2"}, 72 {FW_VENDORID_SONY, FW_DEVICE_CXD3222, "Sony i.LINK (CXD3222)"}, 73 {0, 0, NULL} 74 }; 75 76 77 static int 78 find_device_name(pci_info *info) 79 { 80 struct supported_device *device; 81 for (device = supported_devices; device->name; device++) { 82 if (info->vendor_id == device->vendor_id 83 && info->device_id == device->device_id >> 16) { 84 dprintf("%s\n", device->name); 85 return 1; 86 } 87 } 88 return 0; 89 } 90 91 92 #if 0 93 static status_t 94 fw_add_child(const char *childname, 95 const struct firewire_notify_hooks *hooks) 96 { 97 status_t status; 98 int i; 99 TRACE("add child %s\n", childname); 100 for (i = 0; gFirewire_softc[i] != NULL; i++) { 101 status = firewire_add_child(gFirewire_softc[i], childname, hooks); 102 if (status != B_OK) 103 return status; 104 } 105 106 return B_OK; 107 } 108 109 110 static status_t 111 fw_remove_child(const char *childname) 112 { 113 status_t status; 114 int i; 115 TRACE("remove child %s\n", childname); 116 for (i = 0; gFirewire_softc[i] != NULL; i++) { 117 status = firewire_remove_child(gFirewire_softc[i], childname); 118 if (status != B_OK) 119 return status; 120 } 121 122 return B_OK; 123 } 124 #endif 125 126 127 static int 128 fw_get_handle(int socket, struct firewire_softc **handle) 129 { 130 if (handle == NULL) 131 return B_BAD_VALUE; 132 if (socket >= 0 && socket < MAX_CARDS && gFirewire_softc[socket]) { 133 *handle = gFirewire_softc[socket]; 134 return B_OK; 135 } 136 *handle = NULL; 137 return ENODEV; 138 } 139 140 141 static status_t 142 fw_module_init(void) 143 { 144 status_t status; 145 int i, found; 146 fwohci_softc_t *fwohci_sc; 147 struct firewire_softc *fw_sc; 148 149 pci_info *info = (pci_info*)malloc(sizeof(pci_info)); 150 if (!info) 151 return B_NO_MEMORY; 152 153 if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPci)) != B_OK) { 154 TRACE("pci module unavailable\n"); 155 free(info); 156 return status; 157 } 158 159 if ((status = get_module(B_DPC_MODULE_NAME,(module_info **)&gDpc)) != B_OK) { 160 TRACE("pci module unavailable\n"); 161 free(info); 162 put_module(B_PCI_MODULE_NAME); 163 return status; 164 } 165 166 memset(gFwohci_softc, 0, sizeof(gFwohci_softc)); 167 168 // find devices 169 for (i = 0, found = 0; (status = gPci->get_nth_pci_info(i, info)) == B_OK; i++) { 170 if (find_device_name(info) 171 || ((info->class_base == PCI_serial_bus) 172 && (info->class_sub == PCI_firewire) 173 && (info->class_api == PCI_INTERFACE_OHCI))) { 174 dprintf( "vendor=%x, device=%x, revision = %x\n", info->vendor_id, info->device_id, info->revision); 175 pciInfo[found] = info; 176 177 fwohci_sc = (fwohci_softc_t*)malloc(sizeof(fwohci_softc_t)); 178 if (!fwohci_sc) { 179 free(info); 180 goto err_outofmem; 181 } 182 memset(fwohci_sc, 0, sizeof(fwohci_softc_t)); 183 gFwohci_softc[found] = fwohci_sc; 184 185 fw_sc = (firewire_softc*)malloc(sizeof(struct firewire_softc)); 186 if (!fw_sc) { 187 free(info); 188 free(fwohci_sc); 189 goto err_outofmem; 190 } 191 memset(fw_sc, 0, sizeof(struct firewire_softc)); 192 gFirewire_softc[found] = fw_sc; 193 if (found < MAX_CARDS - 1) 194 gFirewire_softc[found + 1] = NULL; 195 196 found++; 197 info = (pci_info*)malloc(sizeof(pci_info)); 198 if (!info) 199 goto err_outofmem; 200 201 if (found == MAX_CARDS) 202 break; 203 204 } 205 } 206 TRACE("found %d cards\n", found); 207 free(info); 208 209 if ((status = initialize_timer()) != B_OK) { 210 ERROR("timer init failed\n"); 211 goto err_timer; 212 } 213 214 for (i = 0; i < found; i++) { 215 if (fwohci_pci_attach(i) != B_OK) { 216 ERROR("fwohci_pci_attach failed\n"); 217 goto err_pci; 218 } 219 } 220 return B_OK; 221 222 err_pci: 223 terminate_timer(); 224 err_timer: 225 err_outofmem: 226 for (i = 0; i < found; i++) { 227 free(gFirewire_softc[i]); 228 free(gFwohci_softc[i]); 229 free(pciInfo[i]); 230 } 231 put_module(B_PCI_MODULE_NAME); 232 put_module(B_DPC_MODULE_NAME); 233 return B_ERROR; 234 235 } 236 237 static status_t 238 fw_module_uninit(void) 239 { 240 int i; 241 242 terminate_timer(); 243 244 for (i = 0; i < MAX_CARDS && gFirewire_softc[i] != NULL; i++) { 245 fwohci_pci_detach(i); 246 free(gFirewire_softc[i]); 247 free(gFwohci_softc[i]); 248 free(pciInfo[i]); 249 } 250 251 put_module(B_PCI_MODULE_NAME); 252 put_module(B_DPC_MODULE_NAME); 253 254 return B_OK; 255 } 256 257 258 static status_t 259 fw_module_std_ops(int32 op, ...) 260 { 261 switch (op) { 262 case B_MODULE_INIT: 263 TRACE("fw_module_init\n"); 264 return fw_module_init(); 265 266 case B_MODULE_UNINIT: 267 TRACE("fw_module_uninit\n"); 268 return fw_module_uninit(); 269 } 270 return B_BAD_VALUE; 271 } 272 273 static struct fw_module_info gModuleInfo = { 274 { 275 { 276 FIREWIRE_MODULE_NAME, 277 0, 278 fw_module_std_ops 279 }, 280 NULL 281 }, 282 fw_noderesolve_nodeid, 283 fw_noderesolve_eui64, 284 fw_asyreq, 285 fw_xferwake, 286 fw_xferwait, 287 fw_bindlookup, 288 fw_bindadd, 289 fw_bindremove, 290 fw_xferlist_add, 291 fw_xferlist_remove, 292 fw_xfer_alloc, 293 fw_xfer_alloc_buf, 294 fw_xfer_done, 295 fw_xfer_unload, 296 fw_xfer_free_buf, 297 fw_xfer_free, 298 fw_asy_callback_free, 299 fw_open_isodma, 300 fw_get_handle, 301 fwdma_malloc_multiseg, 302 fwdma_free_multiseg 303 }; 304 305 module_info *modules[] = { 306 (module_info *)&gModuleInfo, 307 NULL 308 }; 309