1193326Sed/* 2193326Sed * Copyright (C) 2007 JiSheng Zhang <jszhang3@gmail.com>. All rights reserved 3353358Sdim * Distributed under the terms of the MIT license. 4353358Sdim * 5353358Sdim * Kernel driver for firewire 6193326Sed */ 7193326Sed 8193326Sed#include <OS.h> 9193326Sed#include <KernelExport.h> 10193326Sed#include <SupportDefs.h> 11193326Sed#include <PCI.h> 12193326Sed 13341825Sdim#include <stdlib.h> 14249423Sdim#include <stdio.h> 15360784Sdim#include <string.h> 16193326Sed#include <malloc.h> 17338697Sdim#include <dpc.h> 18193326Sed 19360784Sdim#include "fwdebug.h" 20193326Sed#include "queue.h" 21234353Sdim#include "fwglue.h" 22193326Sed#include "firewire.h" 23249423Sdim#include "iec13213.h" 24249423Sdim#include "firewirereg.h" 25249423Sdim#include "fwdma.h" 26360784Sdim#include "fwohcireg.h" 27249423Sdim#include "fwohcivar.h" 28193326Sed#include "firewire_module.h" 29193326Sed 30193326Sedstatus_t fwohci_pci_attach(int index); 31193326Sedstatus_t fwohci_pci_detach(int index); 32193326Sedpci_info *pciInfo[MAX_CARDS]; 33193326Sedfwohci_softc_t *gFwohci_softc[MAX_CARDS]; 34193326Sedstruct firewire_softc *gFirewire_softc[MAX_CARDS]; 35193326Sedpci_module_info *gPci; 36199990Srdivackydpc_module_info *gDpc; 37193326Sed 38193326Sedstruct supported_device{ 39218893Sdim uint16 vendor_id; 40288943Sdim uint32 device_id; 41208600Srdivacky const char *name; 42218893Sdim}; 43218893Sdim 44218893Sdimstruct supported_device supported_devices[] = { 45218893Sdim {FW_VENDORID_NATSEMI, FW_DEVICE_CS4210, "National Semiconductor CS4210"}, 46239462Sdim {FW_VENDORID_NEC, FW_DEVICE_UPD861, "NEC uPD72861"}, 47239462Sdim {FW_VENDORID_NEC, FW_DEVICE_UPD871, "NEC uPD72871/2"}, 48239462Sdim {FW_VENDORID_NEC, FW_DEVICE_UPD72870, "NEC uPD72870"}, 49239462Sdim {FW_VENDORID_NEC, FW_DEVICE_UPD72873, "NEC uPD72873"}, 50218893Sdim {FW_VENDORID_NEC, FW_DEVICE_UPD72874, "NEC uPD72874"}, 51341825Sdim {FW_VENDORID_SIS, FW_DEVICE_7007, "SiS 7007"}, 52341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB22, "Texas Instruments TSB12LV22"}, 53341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB23, "Texas Instruments TSB12LV23"}, 54341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB26, "Texas Instruments TSB12LV26"}, 55341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB43, "Texas Instruments TSB43AA22"}, 56341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB43A, "Texas Instruments TSB43AB22/A"}, 57341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB43AB21, "Texas Instruments TSB43AB21/A/AI/A-EP"}, 58341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB43AB23, "Texas Instruments TSB43AB23"}, 59341825Sdim {FW_VENDORID_TI, FW_DEVICE_TITSB82AA2, "Texas Instruments TSB82AA2"}, 60193326Sed {FW_VENDORID_TI, FW_DEVICE_TIPCI4450, "Texas Instruments PCI4450"}, 61288943Sdim {FW_VENDORID_TI, FW_DEVICE_TIPCI4410A, "Texas Instruments PCI4410A"}, 62288943Sdim {FW_VENDORID_TI, FW_DEVICE_TIPCI4451, "Texas Instruments PCI4451"}, 63288943Sdim {FW_VENDORID_VIA, FW_DEVICE_VT6306, "VIA Fire II (VT6306)"}, 64193326Sed {FW_VENDORID_RICOH, FW_DEVICE_R5C551, "Ricoh R5C551"}, 65193326Sed {FW_VENDORID_RICOH, FW_DEVICE_R5C552, "Ricoh R5C552"}, 66193326Sed {FW_VENDORID_APPLE, FW_DEVICE_PANGEA, "Apple Pangea"}, 67193326Sed {FW_VENDORID_APPLE, FW_DEVICE_UNINORTH, "Apple UniNorth"}, 68193326Sed {FW_VENDORID_LUCENT, FW_DEVICE_FW322, "Lucent FW322/323"}, 69193326Sed {FW_VENDORID_INTEL, FW_DEVICE_82372FB, "Intel 82372FB"}, 70193326Sed {FW_VENDORID_ADAPTEC, FW_DEVICE_AIC5800, "Adaptec AHA-894x/AIC-5800"}, 71193326Sed {FW_VENDORID_SUN, FW_DEVICE_PCIO2FW, "Sun PCIO-2"}, 72193326Sed {FW_VENDORID_SONY, FW_DEVICE_CXD3222, "Sony i.LINK (CXD3222)"}, 73193326Sed {0, 0, NULL} 74341825Sdim}; 75341825Sdim 76341825Sdim 77341825Sdimstatic int 78341825Sdimfind_device_name(pci_info *info) 79193326Sed{ 80341825Sdim struct supported_device *device; 81341825Sdim for (device = supported_devices; device->name; device++) { 82341825Sdim if (info->vendor_id == device->vendor_id 83296417Sdim && info->device_id == device->device_id >> 16) { 84239462Sdim dprintf("%s\n", device->name); 85239462Sdim return 1; 86193326Sed } 87226633Sdim } 88208600Srdivacky return 0; 89296417Sdim} 90338697Sdim 91234353Sdim 92226633Sdim#if 0 93234353Sdimstatic status_t 94226633Sdimfw_add_child(const char *childname, 95226633Sdim const struct firewire_notify_hooks *hooks) 96226633Sdim{ 97226633Sdim status_t status; 98208600Srdivacky int i; 99208600Srdivacky TRACE("add child %s\n", childname); 100193326Sed for (i = 0; gFirewire_softc[i] != NULL; i++) { 101193326Sed status = firewire_add_child(gFirewire_softc[i], childname, hooks); 102193326Sed if (status != B_OK) 103198092Srdivacky return status; 104288943Sdim } 105288943Sdim 106288943Sdim return B_OK; 107288943Sdim} 108288943Sdim 109193326Sed 110193326Sedstatic status_t 111193326Sedfw_remove_child(const char *childname) 112193326Sed{ 113221345Sdim status_t status; 114221345Sdim int i; 115221345Sdim TRACE("remove child %s\n", childname); 116321369Sdim for (i = 0; gFirewire_softc[i] != NULL; i++) { 117321369Sdim status = firewire_remove_child(gFirewire_softc[i], childname); 118321369Sdim if (status != B_OK) 119321369Sdim return status; 120321369Sdim } 121321369Sdim 122321369Sdim return B_OK; 123193326Sed} 124224145Sdim#endif 125224145Sdim 126224145Sdim 127193326Sedstatic int 128344779Sdimfw_get_handle(int socket, struct firewire_softc **handle) 129344779Sdim{ 130344779Sdim if (handle == NULL) 131344779Sdim return B_BAD_VALUE; 132193326Sed if (socket >= 0 && socket < MAX_CARDS && gFirewire_softc[socket]) { 133327952Sdim *handle = gFirewire_softc[socket]; 134193326Sed return B_OK; 135193326Sed } 136193326Sed *handle = NULL; 137224145Sdim return ENODEV; 138193326Sed} 139193326Sed 140193326Sed 141193326Sedstatic status_t 142198092Srdivackyfw_module_init(void) 143193326Sed{ 144198092Srdivacky status_t status; 145193326Sed pci_info *info = NULL; 146198092Srdivacky int i, found; 147193326Sed fwohci_softc_t *fwohci_sc; 148193326Sed struct firewire_softc *fw_sc; 149193326Sed 150198398Srdivacky info = (pci_info*)malloc(sizeof(pci_info)); 151193326Sed if (!info) 152193326Sed return B_NO_MEMORY; 153341825Sdim 154360784Sdim if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPci)) != B_OK) { 155360784Sdim TRACE("pci module unavailable\n"); 156360784Sdim free(info); 157193326Sed return status; 158193326Sed } 159193326Sed 160193326Sed if ((status = get_module(B_DPC_MODULE_NAME,(module_info **)&gDpc)) != B_OK) { 161193326Sed TRACE("pci module unavailable\n"); 162198092Srdivacky free(info); 163288943Sdim put_module(B_PCI_MODULE_NAME); 164218893Sdim return status; 165198092Srdivacky } 166193326Sed 167314564Sdim memset(gFwohci_softc, 0, sizeof(gFwohci_softc)); 168314564Sdim 169201361Srdivacky // find devices 170288943Sdim for (i = 0, found = 0; (status = gPci->get_nth_pci_info(i, info)) == B_OK; i++) { 171193326Sed if (find_device_name(info) 172353358Sdim || ((info->class_base == PCI_serial_bus) 173193326Sed && (info->class_sub == PCI_firewire) 174193326Sed && (info->class_api == PCI_INTERFACE_OHCI))) { 175251662Sdim dprintf( "vendor=%x, device=%x, revision = %x\n", info->vendor_id, info->device_id, info->revision); 176353358Sdim pciInfo[found] = info; 177251662Sdim 178251662Sdim fwohci_sc = (fwohci_softc_t*)malloc(sizeof(fwohci_softc_t)); 179193326Sed if (!fwohci_sc) { 180193326Sed free(info); 181309124Sdim goto err_outofmem; 182234353Sdim } 183261991Sdim memset(fwohci_sc, 0, sizeof(fwohci_softc_t)); 184218893Sdim gFwohci_softc[found] = fwohci_sc; 185210299Sed 186199482Srdivacky fw_sc = (firewire_softc*)malloc(sizeof(struct firewire_softc)); 187224145Sdim if (!fw_sc) { 188218893Sdim free(info); 189218893Sdim free(fwohci_sc); 190234353Sdim goto err_outofmem; 191234353Sdim } 192234353Sdim memset(fw_sc, 0, sizeof(struct firewire_softc)); 193239462Sdim gFirewire_softc[found] = fw_sc; 194234353Sdim gFirewire_softc[found+1] = NULL; 195234353Sdim 196234353Sdim found++; 197234353Sdim info = (pci_info*)malloc(sizeof(pci_info)); 198234353Sdim if (!info) 199193326Sed goto err_outofmem; 200193326Sed 201224145Sdim if (found == MAX_CARDS) 202224145Sdim break; 203193326Sed 204200583Srdivacky } 205226633Sdim } 206296417Sdim TRACE("found %d cards\n", found); 207296417Sdim free(info); 208226633Sdim 209193326Sed if ((status = initialize_timer()) != B_OK) { 210193326Sed ERROR("timer init failed\n"); 211193326Sed goto err_timer; 212193326Sed } 213193326Sed 214193326Sed for (i = 0; i < found; i++) { 215193326Sed if (fwohci_pci_attach(i) != B_OK) { 216193326Sed ERROR("fwohci_pci_attach failed\n"); 217193326Sed goto err_pci; 218193326Sed } 219193326Sed } 220193326Sed return B_OK; 221249423Sdim 222249423Sdimerr_pci: 223288943Sdim terminate_timer(); 224261991Sdimerr_timer: 225249423Sdimerr_outofmem: 226249423Sdim for (i = 0; i < found; i++) { 227249423Sdim free(gFirewire_softc[i]); 228239462Sdim free(gFwohci_softc[i]); 229193326Sed free(pciInfo[i]); 230193326Sed } 231341825Sdim put_module(B_PCI_MODULE_NAME); 232208600Srdivacky put_module(B_DPC_MODULE_NAME); 233208600Srdivacky return B_ERROR; 234208600Srdivacky 235208600Srdivacky} 236208600Srdivacky 237208600Srdivackystatic status_t 238208600Srdivackyfw_module_uninit(void) 239208600Srdivacky{ 240249423Sdim int i; 241208600Srdivacky 242208600Srdivacky terminate_timer(); 243208600Srdivacky 244208600Srdivacky for (i = 0; gFirewire_softc[i] != NULL; i++) { 245208600Srdivacky fwohci_pci_detach(i); 246208600Srdivacky free(gFirewire_softc[i]); 247208600Srdivacky free(gFwohci_softc[i]); 248341825Sdim free(pciInfo[i]); 249341825Sdim } 250341825Sdim 251341825Sdim put_module(B_PCI_MODULE_NAME); 252341825Sdim put_module(B_DPC_MODULE_NAME); 253341825Sdim 254341825Sdim return B_OK; 255341825Sdim} 256341825Sdim 257341825Sdim 258341825Sdimstatic status_t 259341825Sdimfw_module_std_ops(int32 op, ...) 260341825Sdim{ 261341825Sdim switch (op) { 262341825Sdim case B_MODULE_INIT: 263341825Sdim TRACE("fw_module_init\n"); 264341825Sdim return fw_module_init(); 265341825Sdim 266341825Sdim case B_MODULE_UNINIT: 267341825Sdim TRACE("fw_module_uninit\n"); 268341825Sdim return fw_module_uninit(); 269341825Sdim } 270341825Sdim return B_BAD_VALUE; 271341825Sdim} 272341825Sdim 273341825Sdimstatic struct fw_module_info gModuleInfo = { 274341825Sdim { 275341825Sdim { 276341825Sdim FIREWIRE_MODULE_NAME, 277341825Sdim 0, 278341825Sdim fw_module_std_ops 279341825Sdim }, 280341825Sdim NULL 281341825Sdim }, 282341825Sdim fw_noderesolve_nodeid, 283341825Sdim fw_noderesolve_eui64, 284341825Sdim fw_asyreq, 285341825Sdim fw_xferwake, 286341825Sdim fw_xferwait, 287341825Sdim fw_bindlookup, 288341825Sdim fw_bindadd, 289341825Sdim fw_bindremove, 290341825Sdim fw_xferlist_add, 291341825Sdim fw_xferlist_remove, 292341825Sdim fw_xfer_alloc, 293341825Sdim fw_xfer_alloc_buf, 294341825Sdim fw_xfer_done, 295341825Sdim fw_xfer_unload, 296226633Sdim fw_xfer_free_buf, 297341825Sdim fw_xfer_free, 298341825Sdim fw_asy_callback_free, 299341825Sdim fw_open_isodma, 300341825Sdim fw_get_handle, 301341825Sdim fwdma_malloc_multiseg, 302341825Sdim fwdma_free_multiseg 303341825Sdim}; 304341825Sdim 305341825Sdimmodule_info *modules[] = { 306341825Sdim (module_info *)&gModuleInfo, 307210299Sed NULL 308208600Srdivacky}; 309208600Srdivacky