14535495dSIngo Weinhold /*
24535495dSIngo Weinhold * Copyright (C) 2007 JiSheng Zhang <jszhang3@gmail.com>. All rights reserved
34535495dSIngo Weinhold * Distributed under the terms of the MIT license.
44535495dSIngo Weinhold *
54535495dSIngo Weinhold * Kernel driver for firewire
64535495dSIngo Weinhold */
74535495dSIngo Weinhold
84535495dSIngo Weinhold #include <OS.h>
94535495dSIngo Weinhold #include <KernelExport.h>
104535495dSIngo Weinhold #include <SupportDefs.h>
114535495dSIngo Weinhold #include <PCI.h>
124535495dSIngo Weinhold
134535495dSIngo Weinhold #include <stdlib.h>
144535495dSIngo Weinhold #include <stdio.h>
154535495dSIngo Weinhold #include <string.h>
164535495dSIngo Weinhold #include <malloc.h>
174535495dSIngo Weinhold #include <dpc.h>
184535495dSIngo Weinhold
194535495dSIngo Weinhold #include "fwdebug.h"
204535495dSIngo Weinhold #include "queue.h"
214535495dSIngo Weinhold #include "fwglue.h"
224535495dSIngo Weinhold #include "firewire.h"
234535495dSIngo Weinhold #include "iec13213.h"
244535495dSIngo Weinhold #include "firewirereg.h"
254535495dSIngo Weinhold #include "fwdma.h"
264535495dSIngo Weinhold #include "fwohcireg.h"
274535495dSIngo Weinhold #include "fwohcivar.h"
284535495dSIngo Weinhold #include "firewire_module.h"
294535495dSIngo Weinhold
304535495dSIngo Weinhold status_t fwohci_pci_attach(int index);
314535495dSIngo Weinhold status_t fwohci_pci_detach(int index);
324535495dSIngo Weinhold pci_info *pciInfo[MAX_CARDS];
334535495dSIngo Weinhold fwohci_softc_t *gFwohci_softc[MAX_CARDS];
344535495dSIngo Weinhold struct firewire_softc *gFirewire_softc[MAX_CARDS];
354535495dSIngo Weinhold pci_module_info *gPci;
364535495dSIngo Weinhold dpc_module_info *gDpc;
374535495dSIngo Weinhold
384535495dSIngo Weinhold struct supported_device{
394535495dSIngo Weinhold uint16 vendor_id;
404535495dSIngo Weinhold uint32 device_id;
414535495dSIngo Weinhold const char *name;
424535495dSIngo Weinhold };
434535495dSIngo Weinhold
444535495dSIngo Weinhold struct supported_device supported_devices[] = {
454535495dSIngo Weinhold {FW_VENDORID_NATSEMI, FW_DEVICE_CS4210, "National Semiconductor CS4210"},
464535495dSIngo Weinhold {FW_VENDORID_NEC, FW_DEVICE_UPD861, "NEC uPD72861"},
474535495dSIngo Weinhold {FW_VENDORID_NEC, FW_DEVICE_UPD871, "NEC uPD72871/2"},
484535495dSIngo Weinhold {FW_VENDORID_NEC, FW_DEVICE_UPD72870, "NEC uPD72870"},
494535495dSIngo Weinhold {FW_VENDORID_NEC, FW_DEVICE_UPD72873, "NEC uPD72873"},
504535495dSIngo Weinhold {FW_VENDORID_NEC, FW_DEVICE_UPD72874, "NEC uPD72874"},
514535495dSIngo Weinhold {FW_VENDORID_SIS, FW_DEVICE_7007, "SiS 7007"},
524535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB22, "Texas Instruments TSB12LV22"},
534535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB23, "Texas Instruments TSB12LV23"},
544535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB26, "Texas Instruments TSB12LV26"},
554535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB43, "Texas Instruments TSB43AA22"},
564535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB43A, "Texas Instruments TSB43AB22/A"},
574535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB43AB21, "Texas Instruments TSB43AB21/A/AI/A-EP"},
584535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB43AB23, "Texas Instruments TSB43AB23"},
594535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TITSB82AA2, "Texas Instruments TSB82AA2"},
604535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TIPCI4450, "Texas Instruments PCI4450"},
614535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TIPCI4410A, "Texas Instruments PCI4410A"},
624535495dSIngo Weinhold {FW_VENDORID_TI, FW_DEVICE_TIPCI4451, "Texas Instruments PCI4451"},
634535495dSIngo Weinhold {FW_VENDORID_VIA, FW_DEVICE_VT6306, "VIA Fire II (VT6306)"},
644535495dSIngo Weinhold {FW_VENDORID_RICOH, FW_DEVICE_R5C551, "Ricoh R5C551"},
654535495dSIngo Weinhold {FW_VENDORID_RICOH, FW_DEVICE_R5C552, "Ricoh R5C552"},
664535495dSIngo Weinhold {FW_VENDORID_APPLE, FW_DEVICE_PANGEA, "Apple Pangea"},
674535495dSIngo Weinhold {FW_VENDORID_APPLE, FW_DEVICE_UNINORTH, "Apple UniNorth"},
684535495dSIngo Weinhold {FW_VENDORID_LUCENT, FW_DEVICE_FW322, "Lucent FW322/323"},
694535495dSIngo Weinhold {FW_VENDORID_INTEL, FW_DEVICE_82372FB, "Intel 82372FB"},
704535495dSIngo Weinhold {FW_VENDORID_ADAPTEC, FW_DEVICE_AIC5800, "Adaptec AHA-894x/AIC-5800"},
714535495dSIngo Weinhold {FW_VENDORID_SUN, FW_DEVICE_PCIO2FW, "Sun PCIO-2"},
724535495dSIngo Weinhold {FW_VENDORID_SONY, FW_DEVICE_CXD3222, "Sony i.LINK (CXD3222)"},
734535495dSIngo Weinhold {0, 0, NULL}
744535495dSIngo Weinhold };
754535495dSIngo Weinhold
764535495dSIngo Weinhold
774535495dSIngo Weinhold static int
find_device_name(pci_info * info)784535495dSIngo Weinhold find_device_name(pci_info *info)
794535495dSIngo Weinhold {
804535495dSIngo Weinhold struct supported_device *device;
814535495dSIngo Weinhold for (device = supported_devices; device->name; device++) {
824535495dSIngo Weinhold if (info->vendor_id == device->vendor_id
834535495dSIngo Weinhold && info->device_id == device->device_id >> 16) {
844535495dSIngo Weinhold dprintf("%s\n", device->name);
854535495dSIngo Weinhold return 1;
864535495dSIngo Weinhold }
874535495dSIngo Weinhold }
884535495dSIngo Weinhold return 0;
894535495dSIngo Weinhold }
904535495dSIngo Weinhold
914535495dSIngo Weinhold
924535495dSIngo Weinhold #if 0
934535495dSIngo Weinhold static status_t
944535495dSIngo Weinhold fw_add_child(const char *childname,
954535495dSIngo Weinhold const struct firewire_notify_hooks *hooks)
964535495dSIngo Weinhold {
974535495dSIngo Weinhold status_t status;
984535495dSIngo Weinhold int i;
994535495dSIngo Weinhold TRACE("add child %s\n", childname);
1004535495dSIngo Weinhold for (i = 0; gFirewire_softc[i] != NULL; i++) {
1014535495dSIngo Weinhold status = firewire_add_child(gFirewire_softc[i], childname, hooks);
1024535495dSIngo Weinhold if (status != B_OK)
1034535495dSIngo Weinhold return status;
1044535495dSIngo Weinhold }
1054535495dSIngo Weinhold
1064535495dSIngo Weinhold return B_OK;
1074535495dSIngo Weinhold }
1084535495dSIngo Weinhold
1094535495dSIngo Weinhold
1104535495dSIngo Weinhold static status_t
1114535495dSIngo Weinhold fw_remove_child(const char *childname)
1124535495dSIngo Weinhold {
1134535495dSIngo Weinhold status_t status;
1144535495dSIngo Weinhold int i;
1154535495dSIngo Weinhold TRACE("remove child %s\n", childname);
1164535495dSIngo Weinhold for (i = 0; gFirewire_softc[i] != NULL; i++) {
1174535495dSIngo Weinhold status = firewire_remove_child(gFirewire_softc[i], childname);
1184535495dSIngo Weinhold if (status != B_OK)
1194535495dSIngo Weinhold return status;
1204535495dSIngo Weinhold }
1214535495dSIngo Weinhold
1224535495dSIngo Weinhold return B_OK;
1234535495dSIngo Weinhold }
1244535495dSIngo Weinhold #endif
1254535495dSIngo Weinhold
1264535495dSIngo Weinhold
1274535495dSIngo Weinhold static int
fw_get_handle(int socket,struct firewire_softc ** handle)1284535495dSIngo Weinhold fw_get_handle(int socket, struct firewire_softc **handle)
1294535495dSIngo Weinhold {
1304535495dSIngo Weinhold if (handle == NULL)
1314535495dSIngo Weinhold return B_BAD_VALUE;
1324535495dSIngo Weinhold if (socket >= 0 && socket < MAX_CARDS && gFirewire_softc[socket]) {
1334535495dSIngo Weinhold *handle = gFirewire_softc[socket];
1344535495dSIngo Weinhold return B_OK;
1354535495dSIngo Weinhold }
1364535495dSIngo Weinhold *handle = NULL;
1374535495dSIngo Weinhold return ENODEV;
1384535495dSIngo Weinhold }
1394535495dSIngo Weinhold
1404535495dSIngo Weinhold
1414535495dSIngo Weinhold static status_t
fw_module_init(void)1424535495dSIngo Weinhold fw_module_init(void)
1434535495dSIngo Weinhold {
1444535495dSIngo Weinhold status_t status;
1454535495dSIngo Weinhold int i, found;
1464535495dSIngo Weinhold fwohci_softc_t *fwohci_sc;
1474535495dSIngo Weinhold struct firewire_softc *fw_sc;
1484535495dSIngo Weinhold
1493fb9ab7fSMurai Takashi pci_info *info = (pci_info*)malloc(sizeof(pci_info));
1504535495dSIngo Weinhold if (!info)
1514535495dSIngo Weinhold return B_NO_MEMORY;
1524535495dSIngo Weinhold
1534535495dSIngo Weinhold if ((status = get_module(B_PCI_MODULE_NAME,(module_info **)&gPci)) != B_OK) {
1544535495dSIngo Weinhold TRACE("pci module unavailable\n");
1554535495dSIngo Weinhold free(info);
1564535495dSIngo Weinhold return status;
1574535495dSIngo Weinhold }
1584535495dSIngo Weinhold
1594535495dSIngo Weinhold if ((status = get_module(B_DPC_MODULE_NAME,(module_info **)&gDpc)) != B_OK) {
1604535495dSIngo Weinhold TRACE("pci module unavailable\n");
1614535495dSIngo Weinhold free(info);
1624535495dSIngo Weinhold put_module(B_PCI_MODULE_NAME);
1634535495dSIngo Weinhold return status;
1644535495dSIngo Weinhold }
1654535495dSIngo Weinhold
1664535495dSIngo Weinhold memset(gFwohci_softc, 0, sizeof(gFwohci_softc));
1674535495dSIngo Weinhold
1684535495dSIngo Weinhold // find devices
1694535495dSIngo Weinhold for (i = 0, found = 0; (status = gPci->get_nth_pci_info(i, info)) == B_OK; i++) {
1704535495dSIngo Weinhold if (find_device_name(info)
1714535495dSIngo Weinhold || ((info->class_base == PCI_serial_bus)
1724535495dSIngo Weinhold && (info->class_sub == PCI_firewire)
1734535495dSIngo Weinhold && (info->class_api == PCI_INTERFACE_OHCI))) {
1744535495dSIngo Weinhold dprintf( "vendor=%x, device=%x, revision = %x\n", info->vendor_id, info->device_id, info->revision);
1754535495dSIngo Weinhold pciInfo[found] = info;
1764535495dSIngo Weinhold
1774535495dSIngo Weinhold fwohci_sc = (fwohci_softc_t*)malloc(sizeof(fwohci_softc_t));
1784535495dSIngo Weinhold if (!fwohci_sc) {
1794535495dSIngo Weinhold free(info);
1804535495dSIngo Weinhold goto err_outofmem;
1814535495dSIngo Weinhold }
1824535495dSIngo Weinhold memset(fwohci_sc, 0, sizeof(fwohci_softc_t));
1834535495dSIngo Weinhold gFwohci_softc[found] = fwohci_sc;
1844535495dSIngo Weinhold
1854535495dSIngo Weinhold fw_sc = (firewire_softc*)malloc(sizeof(struct firewire_softc));
1864535495dSIngo Weinhold if (!fw_sc) {
1874535495dSIngo Weinhold free(info);
1884535495dSIngo Weinhold free(fwohci_sc);
1894535495dSIngo Weinhold goto err_outofmem;
1904535495dSIngo Weinhold }
1914535495dSIngo Weinhold memset(fw_sc, 0, sizeof(struct firewire_softc));
1924535495dSIngo Weinhold gFirewire_softc[found] = fw_sc;
193*7dec2bffSMurai Takashi if (found < MAX_CARDS - 1)
1944535495dSIngo Weinhold gFirewire_softc[found + 1] = NULL;
1954535495dSIngo Weinhold
1964535495dSIngo Weinhold found++;
1974535495dSIngo Weinhold info = (pci_info*)malloc(sizeof(pci_info));
1984535495dSIngo Weinhold if (!info)
1994535495dSIngo Weinhold goto err_outofmem;
2004535495dSIngo Weinhold
2014535495dSIngo Weinhold if (found == MAX_CARDS)
2024535495dSIngo Weinhold break;
2034535495dSIngo Weinhold
2044535495dSIngo Weinhold }
2054535495dSIngo Weinhold }
2064535495dSIngo Weinhold TRACE("found %d cards\n", found);
2074535495dSIngo Weinhold free(info);
2084535495dSIngo Weinhold
2094535495dSIngo Weinhold if ((status = initialize_timer()) != B_OK) {
2104535495dSIngo Weinhold ERROR("timer init failed\n");
2114535495dSIngo Weinhold goto err_timer;
2124535495dSIngo Weinhold }
2134535495dSIngo Weinhold
2144535495dSIngo Weinhold for (i = 0; i < found; i++) {
2154535495dSIngo Weinhold if (fwohci_pci_attach(i) != B_OK) {
2164535495dSIngo Weinhold ERROR("fwohci_pci_attach failed\n");
2174535495dSIngo Weinhold goto err_pci;
2184535495dSIngo Weinhold }
2194535495dSIngo Weinhold }
2204535495dSIngo Weinhold return B_OK;
2214535495dSIngo Weinhold
2224535495dSIngo Weinhold err_pci:
2234535495dSIngo Weinhold terminate_timer();
2244535495dSIngo Weinhold err_timer:
2254535495dSIngo Weinhold err_outofmem:
2264535495dSIngo Weinhold for (i = 0; i < found; i++) {
2274535495dSIngo Weinhold free(gFirewire_softc[i]);
2284535495dSIngo Weinhold free(gFwohci_softc[i]);
2294535495dSIngo Weinhold free(pciInfo[i]);
2304535495dSIngo Weinhold }
2314535495dSIngo Weinhold put_module(B_PCI_MODULE_NAME);
2324535495dSIngo Weinhold put_module(B_DPC_MODULE_NAME);
2334535495dSIngo Weinhold return B_ERROR;
2344535495dSIngo Weinhold
2354535495dSIngo Weinhold }
2364535495dSIngo Weinhold
2374535495dSIngo Weinhold static status_t
fw_module_uninit(void)2384535495dSIngo Weinhold fw_module_uninit(void)
2394535495dSIngo Weinhold {
2404535495dSIngo Weinhold int i;
2414535495dSIngo Weinhold
2424535495dSIngo Weinhold terminate_timer();
2434535495dSIngo Weinhold
244*7dec2bffSMurai Takashi for (i = 0; i < MAX_CARDS && gFirewire_softc[i] != NULL; i++) {
2454535495dSIngo Weinhold fwohci_pci_detach(i);
2464535495dSIngo Weinhold free(gFirewire_softc[i]);
2474535495dSIngo Weinhold free(gFwohci_softc[i]);
2484535495dSIngo Weinhold free(pciInfo[i]);
2494535495dSIngo Weinhold }
2504535495dSIngo Weinhold
2514535495dSIngo Weinhold put_module(B_PCI_MODULE_NAME);
2524535495dSIngo Weinhold put_module(B_DPC_MODULE_NAME);
2534535495dSIngo Weinhold
2544535495dSIngo Weinhold return B_OK;
2554535495dSIngo Weinhold }
2564535495dSIngo Weinhold
2574535495dSIngo Weinhold
2584535495dSIngo Weinhold static status_t
fw_module_std_ops(int32 op,...)2594535495dSIngo Weinhold fw_module_std_ops(int32 op, ...)
2604535495dSIngo Weinhold {
2614535495dSIngo Weinhold switch (op) {
2624535495dSIngo Weinhold case B_MODULE_INIT:
2634535495dSIngo Weinhold TRACE("fw_module_init\n");
2644535495dSIngo Weinhold return fw_module_init();
2654535495dSIngo Weinhold
2664535495dSIngo Weinhold case B_MODULE_UNINIT:
2674535495dSIngo Weinhold TRACE("fw_module_uninit\n");
2684535495dSIngo Weinhold return fw_module_uninit();
2694535495dSIngo Weinhold }
2704535495dSIngo Weinhold return B_BAD_VALUE;
2714535495dSIngo Weinhold }
2724535495dSIngo Weinhold
2734535495dSIngo Weinhold static struct fw_module_info gModuleInfo = {
2744535495dSIngo Weinhold {
2754535495dSIngo Weinhold {
2764535495dSIngo Weinhold FIREWIRE_MODULE_NAME,
2774535495dSIngo Weinhold 0,
2784535495dSIngo Weinhold fw_module_std_ops
2794535495dSIngo Weinhold },
2804535495dSIngo Weinhold NULL
2814535495dSIngo Weinhold },
2824535495dSIngo Weinhold fw_noderesolve_nodeid,
2834535495dSIngo Weinhold fw_noderesolve_eui64,
2844535495dSIngo Weinhold fw_asyreq,
2854535495dSIngo Weinhold fw_xferwake,
2864535495dSIngo Weinhold fw_xferwait,
2874535495dSIngo Weinhold fw_bindlookup,
2884535495dSIngo Weinhold fw_bindadd,
2894535495dSIngo Weinhold fw_bindremove,
2904535495dSIngo Weinhold fw_xferlist_add,
2914535495dSIngo Weinhold fw_xferlist_remove,
2924535495dSIngo Weinhold fw_xfer_alloc,
2934535495dSIngo Weinhold fw_xfer_alloc_buf,
2944535495dSIngo Weinhold fw_xfer_done,
2954535495dSIngo Weinhold fw_xfer_unload,
2964535495dSIngo Weinhold fw_xfer_free_buf,
2974535495dSIngo Weinhold fw_xfer_free,
2984535495dSIngo Weinhold fw_asy_callback_free,
2994535495dSIngo Weinhold fw_open_isodma,
3004535495dSIngo Weinhold fw_get_handle,
3014535495dSIngo Weinhold fwdma_malloc_multiseg,
3024535495dSIngo Weinhold fwdma_free_multiseg
3034535495dSIngo Weinhold };
3044535495dSIngo Weinhold
3054535495dSIngo Weinhold module_info *modules[] = {
3064535495dSIngo Weinhold (module_info *)&gModuleInfo,
3074535495dSIngo Weinhold NULL
3084535495dSIngo Weinhold };
309