www.pudn.com > 9054Src.rar > Driver.c


/******************************************************************************* 
 * Copyright (c) 2006 PLX Technology, Inc. 
 * 
 * PLX Technology Inc. licenses this software under specific terms and 
 * conditions.  Use of any of the software or derviatives thereof in any 
 * product without a PLX Technology chip is strictly prohibited. 
 * 
 * PLX Technology, Inc. provides this software AS IS, WITHOUT ANY WARRANTY, 
 * EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY WARRANTY OF 
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  PLX makes no guarantee 
 * or representations regarding the use of, or the results of the use of, 
 * the software and documentation in terms of correctness, accuracy, 
 * reliability, currentness, or otherwise; and you rely on the software, 
 * documentation and results solely at your own risk. 
 * 
 * IN NO EVENT SHALL PLX BE LIABLE FOR ANY LOSS OF USE, LOSS OF BUSINESS, 
 * LOSS OF PROFITS, INDIRECT, INCIDENTAL, SPECIAL OR CONSEQUENTIAL DAMAGES 
 * OF ANY KIND.  IN NO EVENT SHALL PLX'S TOTAL LIABILITY EXCEED THE SUM 
 * PAID TO PLX FOR THE PRODUCT LICENSED HEREUNDER. 
 * 
 ******************************************************************************/ 
 
/****************************************************************************** 
 * 
 * File Name: 
 * 
 *      Driver.c 
 * 
 * Description: 
 * 
 *      Contains driver entry and cleanup routines as well as device 
 *      resource initialization. 
 * 
 * Revision History: 
 * 
 *      03-01-06 : PCI SDK v4.40 
 * 
 *****************************************************************************/ 
 
 
#include  
#include "CommonApi.h" 
#include "Dispatch.h" 
#include "Driver.h" 
#include "GlobalVars.h" 
#include "PciSupport.h" 
#include "PlugPlay.h" 
#include "PlxInterrupt.h" 
#include "Power.h" 
#include "SupportFunc.h" 
 
 
#if defined(ALLOC_PRAGMA) && !defined(PLX_DEBUG) 
    #pragma alloc_text(INIT, DriverEntry) 
#endif 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  DriverEntry 
 * 
 * Description:  Entry point for the driver 
 * 
 ******************************************************************************/ 
NTSTATUS 
DriverEntry( 
    PDRIVER_OBJECT  pDriverObject, 
    PUNICODE_STRING pRegistryPath 
    ) 
{ 
    S8                   MinorVersion; 
    WCHAR                Win9x_RegistryPath[100]; 
    BOOLEAN              bVersionFound; 
    NTSTATUS             status; 
    UNICODE_STRING       Win9x_RegistryPath_Unicode; 
    REGISTRY_INFORMATION RegistryInfo; 
 
 
    DebugPrintf_NoInfo(("\n")); 
    DebugPrintf(("<========================================================>\n")); 
    DebugPrintf(( 
        "PLX Driver v%d.%d%d - built on %s %s\n", 
        PLX_SDK_VERSION_MAJOR, PLX_SDK_VERSION_MINOR, 
        PLX_SDK_VERSION_REVISION, __DATE__, __TIME__ 
        )); 
 
    DebugPrintf(( 
        "Supports WDM v%x.%x\n", 
        WDM_MAJORVERSION, WDM_MINORVERSION 
        )); 
 
    // Set starting version 
    MinorVersion = 0x41; 
 
    // Determine the highest WDM version supported 
    do 
    { 
        // Decrement to lower version 
        MinorVersion--; 
 
        bVersionFound = 
            IoIsWdmVersionAvailable( 
                0x01,              // Just check for version 1.x for now 
                MinorVersion 
                ); 
    } 
    while ((bVersionFound == FALSE) && (MinorVersion >= 0)); 
 
    // Display possible OS version 
    DebugPrintf(("OS supports WDM 1.%02x ", MinorVersion)); 
 
    if (MinorVersion >= 0x30) 
    { 
        DebugPrintf_NoInfo(("(Windows 2003 Server or higher)\n")); 
    } 
    else if (MinorVersion >= 0x20) 
    { 
        DebugPrintf_NoInfo(("(Windows XP or higher)\n")); 
    } 
    else if (MinorVersion >= 0x10) 
    { 
        DebugPrintf_NoInfo(("(Windows 2000 or higher)\n")); 
    } 
    else 
    { 
        DebugPrintf_NoInfo(("(Windows 98 or higher)\n")); 
 
        // Use the centralized PLX registry path for driver options 
        swprintf( 
            Win9x_RegistryPath, 
            WIN9X_REGISTRY_PATH_UNICODE L"\\" PLX_DRIVER_NAME_UNICODE 
            ); 
 
        RtlInitUnicodeString( 
            &Win9x_RegistryPath_Unicode, 
            Win9x_RegistryPath 
            ); 
 
        // Override assigned path 
        pRegistryPath = &Win9x_RegistryPath_Unicode; 
    } 
 
    DebugPrintf(( 
        "Driver Registry path = \"%ws\"\n", 
        pRegistryPath->Buffer 
        )); 
 
    // Get configuration information from registry 
    PlxRegistryInformationGet( 
        pRegistryPath, 
        &RegistryInfo 
        ); 
 
    // Fill in the appropriate dispatch handlers 
    pDriverObject->DriverUnload                         = DriverUnload; 
    pDriverObject->MajorFunction[IRP_MJ_CREATE]         = Dispatch_Create; 
    pDriverObject->MajorFunction[IRP_MJ_CLOSE]          = Dispatch_Close; 
    pDriverObject->MajorFunction[IRP_MJ_CLEANUP]        = Dispatch_Cleanup; 
    pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch_IoControl; 
    pDriverObject->MajorFunction[IRP_MJ_PNP]            = Dispatch_Pnp; 
    pDriverObject->MajorFunction[IRP_MJ_POWER]          = Dispatch_Power; 
    pDriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Dispatch_SystemControl; 
    pDriverObject->DriverExtension->AddDevice           = AddDevice; 
 
    // Initialize device count 
    Gbl_DeviceCount = 0; 
 
    // Initialize Common buffer pointer 
    pGbl_CommonBuffer = NULL; 
 
    // Set common buffer requested size 
    Gbl_CommonBufferSize = RegistryInfo.CommonBufferSize; 
 
    // Set cacheability of physical buffers 
    Gbl_PhysicalMemoryCacheable = RegistryInfo.PhysicalMemoryCacheable; 
 
    return STATUS_SUCCESS; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  DriverUnload 
 * 
 * Description:  Unload the driver 
 * 
 ******************************************************************************/ 
VOID 
DriverUnload( 
    PDRIVER_OBJECT pDriverObject 
    ) 
{ 
    DebugPrintf_NoInfo(("\n")); 
    DebugPrintf(("Unloading Driver...\n")); 
 
    DebugPrintf(("...Driver unloaded\n")); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  AddDevice 
 * 
 * Description:  Add a new device object to the driver 
 * 
 ******************************************************************************/ 
NTSTATUS 
AddDevice( 
    PDRIVER_OBJECT pDriverObject, 
    PDEVICE_OBJECT pdo 
    ) 
{ 
    U8                i; 
    WCHAR             DeviceName[PLX_MAX_NAME_LENGTH]; 
    WCHAR             DeviceLinkName[PLX_MAX_NAME_LENGTH]; 
    NTSTATUS          status; 
    POWER_STATE       PowerState; 
    UNICODE_STRING    DeviceName_Unicode; 
    UNICODE_STRING    DeviceLinkName_Unicode; 
    PDEVICE_OBJECT    fdo; 
    DEVICE_EXTENSION *pdx; 
 
 
    // Build a device name and attempt to create it 
    for (i=0; i < 64; i++) 
    { 
        swprintf( 
            DeviceName, 
            L"\\Device\\" PLX_DRIVER_NAME_UNICODE L"-%d", 
            i 
            ); 
 
        RtlInitUnicodeString( 
            &DeviceName_Unicode, 
            DeviceName 
            ); 
 
        // Create the device object 
        status = 
            IoCreateDevice( 
                pDriverObject, 
                sizeof(DEVICE_EXTENSION), 
                &DeviceName_Unicode, 
                FILE_DEVICE_UNKNOWN, 
                0, 
                FALSE,            // Shared by applications 
                &fdo 
                ); 
 
        // IoCreateDevice() will fail if the same object already exists 
        if (NT_SUCCESS(status)) 
        { 
            break; 
        } 
    } 
 
    // Check if the creation succeeded 
    if ( !NT_SUCCESS(status) ) 
    { 
        DebugPrintf(("ERROR - Unable to create Device\n")); 
        return status; 
    } 
 
    DebugPrintf_NoInfo(("\n")); 
    DebugPrintf(( 
        "Created Device (%ws)...\n", 
        DeviceName 
        )); 
 
    // Link a Win32 name for user applications 
    swprintf( 
        DeviceLinkName, 
        L"\\DosDevices\\" PLX_DRIVER_NAME_UNICODE L"-%d", 
        i 
        ); 
 
    RtlInitUnicodeString( 
        &DeviceLinkName_Unicode, 
        DeviceLinkName 
        ); 
 
    DebugPrintf(( 
        "Creating Win32 symbolic link (%ws)...\n", 
        DeviceLinkName 
        )); 
 
    status = 
        IoCreateSymbolicLink( 
            &DeviceLinkName_Unicode, 
            &DeviceName_Unicode 
            ); 
 
    if ( !NT_SUCCESS(status) ) 
    { 
        DebugPrintf(("WARNING - Unable to create symbolic link for Win32 Apps\n")); 
        swprintf(DeviceLinkName, L""); 
    } 
 
    // 
    // Initialize the device extension 
    // 
 
    pdx = fdo->DeviceExtension; 
 
    // Clear device extension 
    RtlZeroMemory( 
        pdx, 
        sizeof(DEVICE_EXTENSION) 
        ); 
 
    // Save the parent device object 
    pdx->pDeviceObject         = fdo; 
    pdx->pPhysicalDeviceObject = pdo; 
    pdx->usage                 = 1;          // Locked until RemoveDevice 
 
    sprintf( 
        pdx->Device.SerialNumber, 
        PLX_DRIVER_NAME "-%d", 
        i 
        ); 
 
    wcscpy( 
        pdx->LinkName, 
        DeviceLinkName 
        ); 
 
    // Initialize PCI BAR variables 
    for (i = 0 ; i < PCI_NUM_BARS_TYPE_00; i++) 
    { 
        pdx->PciBar[i].pVa               = NULL; 
        pdx->PciBar[i].Physical.QuadPart = 0; 
        pdx->PciBar[i].Size              = 0; 
        pdx->PciBar[i].bIsIoSpace        = FALSE; 
        pdx->PciBar[i].pMdl              = NULL; 
 
        InitializeListHead( 
            &(pdx->PciBar[i].List_Mappings) 
            ); 
 
        KeInitializeSpinLock( 
            &(pdx->PciBar[i].Lock_MappingsList) 
            ); 
    } 
 
    KeInitializeSpinLock( 
        &(pdx->Lock_HwAccess) 
        ); 
 
    InitializeListHead( 
        &(pdx->List_WaitObjects) 
        ); 
 
    KeInitializeSpinLock( 
        &(pdx->Lock_WaitObjectsList) 
        ); 
 
    InitializeListHead( 
        &(pdx->List_PhysicalMem) 
        ); 
 
    KeInitializeSpinLock( 
        &(pdx->Lock_PhysicalMemList) 
        ); 
 
    InitializeListHead( 
        &(pdx->List_BarMappings) 
        ); 
 
    KeInitializeSpinLock( 
        &(pdx->Lock_BarMappingsList) 
        ); 
 
    // Initialize the interrupt DPC 
    KeInitializeDpc( 
        &(pdx->DpcForIsr), 
        DpcForIsr, 
        pdx 
        ); 
 
#if defined(DMA_SUPPORT) 
    // Initialize DMA management variables 
    for (i = 0 ; i < NUMBER_OF_DMA_CHANNELS; i++) 
    {  
        pdx->DmaInfo[i].state              = DmaStateClosed; 
        pdx->DmaInfo[i].bLocalAddrConstant = FALSE; 
    } 
 
    KeInitializeSpinLock( 
        &(pdx->Lock_DmaChannel) 
        ); 
#endif  // DMA_SUPPORT 
 
    KeInitializeEvent( 
        &pdx->evRemove, 
        NotificationEvent, 
        FALSE 
        ); 
 
    /* 
     *  Since we must pass PNP requests down to the next device object in the 
     *  chain (namely the physical device object created by the bus enumerator), 
     *  we have to remember what that device is. That's why we defined the 
     *  LowerDeviceObject member in our device extension. 
     */ 
    pdx->pLowerDeviceObject = 
        IoAttachDeviceToDeviceStack( 
            fdo, 
            pdo 
            ); 
 
    DebugPrintf(( 
        "Attached device to stack\n" 
        "            Functional DevObj: 0x%p\n" 
        "            Lower      DevObj: 0x%p\n" 
        "            Physical   DevObj: 0x%p\n", 
        fdo, pdx->pLowerDeviceObject, pdo 
        )); 
 
    // Notify the power manager of the initial power state 
    pdx->PowerState        = PowerDeviceD0;      // Start device in full power state 
    PowerState.DeviceState = PowerDeviceD0; 
    PoSetPowerState( 
        fdo, 
        DevicePowerState, 
        PowerState 
        ); 
 
    // Indicate the I/O Manager buffer management method 
    fdo->Flags |= DO_BUFFERED_IO; 
 
    // Manually clear the Device Initialzing flag 
    fdo->Flags &= ~DO_DEVICE_INITIALIZING; 
 
    return STATUS_SUCCESS; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  RemoveDevice 
 * 
 * Description:  Remove a functional device object 
 * 
 ******************************************************************************/ 
VOID 
RemoveDevice( 
    PDEVICE_OBJECT fdo 
    ) 
{ 
    NTSTATUS           status; 
    UNICODE_STRING     DeviceLinkName_Unicode; 
    DEVICE_EXTENSION  *pdx; 
 
 
    pdx = fdo->DeviceExtension; 
 
    // Remove Win32 link name 
    if (wcslen(pdx->LinkName) != 0) 
    { 
        DebugPrintf(( 
            "Removing Win32 link (%ws)\n", 
            pdx->LinkName 
            )); 
 
        RtlInitUnicodeString( 
            &DeviceLinkName_Unicode, 
            pdx->LinkName 
            ); 
 
        status = 
            IoDeleteSymbolicLink( 
                &DeviceLinkName_Unicode 
                ); 
 
        if ( !NT_SUCCESS(status) ) 
            DebugPrintf(("WARNING - Unable to remove Win32 link\n")); 
    } 
 
    // Detach device from the device object stack 
    if (pdx->pLowerDeviceObject) 
    { 
        IoDetachDevice( 
            pdx->pLowerDeviceObject 
            ); 
    } 
 
    DebugPrintf(("Deleting device object...\n")); 
 
    // Delete the functional device object 
    IoDeleteDevice( 
        fdo 
        ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  StartDevice 
 * 
 * Description:  Start a device 
 * 
 ******************************************************************************/ 
NTSTATUS 
StartDevice( 
    PDEVICE_OBJECT            fdo, 
    PCM_PARTIAL_RESOURCE_LIST ResourceListRaw, 
    PCM_PARTIAL_RESOURCE_LIST ResourceList 
    ) 
{ 
    U8                               i; 
    U8                               BarIndex; 
    U32                              vector; 
    KIRQL                            IrqL; 
    BOOLEAN                          bIntPresent; 
    NTSTATUS                         status; 
    KAFFINITY                        affinity; 
    KINTERRUPT_MODE                  mode; 
    PLX_PHYSICAL_MEM                 PciMem; 
    DEVICE_EXTENSION                *pdx; 
    PCI_COMMON_CONFIG                PciRegs; 
    PCM_PARTIAL_RESOURCE_DESCRIPTOR  ResourceRaw; 
    PCM_PARTIAL_RESOURCE_DESCRIPTOR  Resource; 
 
 
    pdx         = fdo->DeviceExtension; 
    bIntPresent = FALSE; 
    ResourceRaw = ResourceListRaw->PartialDescriptors; 
    Resource    = ResourceList->PartialDescriptors; 
 
    // Get the PCI base addresses 
    PciRegisterBufferRead( 
        fdo, 
        0, 
        &PciRegs, 
        sizeof(PCI_COMMON_CONFIG) 
        ); 
 
    DebugPrintf(( 
        "Resource list contains %d descriptors\n", 
        ResourceListRaw->Count 
        )); 
 
    for (i = 0; i < ResourceListRaw->Count; ++i, ++Resource, ++ResourceRaw) 
    { 
        DebugPrintf_NoInfo(("            Resource %02d\n", i)); 
 
        switch (ResourceRaw->Type) 
        { 
            case CmResourceTypeInterrupt: 
                bIntPresent = TRUE; 
                IrqL        = (KIRQL) Resource->u.Interrupt.Level; 
                vector      = Resource->u.Interrupt.Vector; 
                affinity    = Resource->u.Interrupt.Affinity; 
 
                DebugPrintf_NoInfo(( 
                    "              Type     : Interrupt\n" 
                    "              Vector   : 0x%02x        (Translated = 0x%02x)\n" 
                    "              IRQL     : 0x%02x        (Translated = 0x%02x)\n" 
                    "              Affinity : 0x%08x\n", 
                    ResourceRaw->u.Interrupt.Vector, vector, 
                    ResourceRaw->u.Interrupt.Level, IrqL, 
                    ResourceRaw->u.Interrupt.Affinity 
                    )); 
 
                if (ResourceRaw->Flags == CM_RESOURCE_INTERRUPT_LATCHED) 
                { 
                    mode = Latched; 
                    DebugPrintf_NoInfo(("              Mode     : Latched\n")); 
                } 
                else 
                { 
                    mode = LevelSensitive; 
                    DebugPrintf_NoInfo(("              Mode     : Level Sensitive\n")); 
                } 
                break; 
 
            case CmResourceTypePort: 
                DebugPrintf_NoInfo(( 
                    "              Type     : I/O Port\n" 
                    "              Address  : 0x%08lx  (Translated = 0x%08lx)\n" 
                    "              Size     : 0x%08x  ", 
                    ResourceRaw->u.Port.Start, 
                    Resource->u.Port.Start, 
                    ResourceRaw->u.Port.Length 
                    )); 
 
                if (ResourceRaw->u.Port.Length >= (1 << 10)) 
                { 
                    DebugPrintf_NoInfo(( 
                        "(%d Kb)\n", 
                        ResourceRaw->u.Port.Length >> 10 
                        )); 
                } 
                else 
                { 
                    DebugPrintf_NoInfo(( 
                        "(%d Bytes)\n", 
                        ResourceRaw->u.Port.Length 
                        )); 
                } 
 
                BarIndex = 
                    GetBarIndex( 
                        ResourceRaw->u.Port.Start, 
                        &PciRegs 
                        ); 
 
                DebugPrintf_NoInfo(( 
                    "              PCI BAR  : " 
                    )); 
 
                if (BarIndex != (U8)-1) 
                { 
                    DebugPrintf_NoInfo(( 
                        "%d\n", 
                        BarIndex 
                        )); 
 
                    pdx->PciBar[BarIndex].Physical   = ResourceRaw->u.Port.Start; 
                    pdx->PciBar[BarIndex].Size       = ResourceRaw->u.Port.Length; 
                    pdx->PciBar[BarIndex].pVa        = NULL; 
                    pdx->PciBar[BarIndex].bIsIoSpace = TRUE; 
                } 
                else 
                { 
                    DebugPrintf_NoInfo(( 
                        "??\n" 
                        )); 
                } 
                break; 
 
            case CmResourceTypeMemory: 
                DebugPrintf_NoInfo(( 
                    "              Type     : Memory Space\n" 
                    "              Address  : 0x%08lx  (Translated = 0x%08lx)\n" 
                    "              Size     : 0x%08x  ", 
                    ResourceRaw->u.Memory.Start, 
                    Resource->u.Memory.Start, 
                    ResourceRaw->u.Memory.Length 
                    )); 
 
                if (ResourceRaw->u.Memory.Length >= (1 << 10)) 
                { 
                    DebugPrintf_NoInfo(( 
                        "(%d Kb)\n", 
                        ResourceRaw->u.Memory.Length >> 10 
                        )); 
                } 
                else 
                { 
                    DebugPrintf_NoInfo(( 
                        "(%d Bytes)\n", 
                        ResourceRaw->u.Memory.Length 
                        )); 
                } 
 
                BarIndex = 
                    GetBarIndex( 
                        ResourceRaw->u.Memory.Start, 
                        &PciRegs 
                        ); 
 
                DebugPrintf_NoInfo(( 
                    "              PCI BAR  : " 
                    )); 
 
                if (BarIndex != (U8)-1) 
                { 
                    DebugPrintf_NoInfo(( 
                        "%d\n", 
                        BarIndex 
                        )); 
 
                    DebugPrintf_NoInfo(("              Kernel VA: ")); 
 
                    // Record resources 
                    pdx->PciBar[BarIndex].Physical   = ResourceRaw->u.Memory.Start; 
                    pdx->PciBar[BarIndex].Size       = ResourceRaw->u.Memory.Length; 
                    pdx->PciBar[BarIndex].bIsIoSpace = FALSE; 
 
                    status = 
                        PlxPciBarResourceMap( 
                            pdx, 
                            BarIndex 
                            ); 
 
                    if ( NT_SUCCESS(status) ) 
                    { 
                        DebugPrintf_NoInfo(( 
                            "0x%p\n", 
                            pdx->PciBar[BarIndex].pVa 
                            )); 
                    } 
                    else 
                    { 
                        DebugPrintf_NoInfo(( 
                            "ERROR - Unable to map 0x%08lx ==> Kernel VA\n", 
                            ResourceRaw->u.Memory.Start 
                            )); 
                    } 
                } 
                else 
                { 
                    DebugPrintf_NoInfo(( 
                        "??\n" 
                        )); 
                } 
                break; 
 
            case CmResourceTypeNull: 
                DebugPrintf_NoInfo(("              Type: Null (unsupported)\n")); 
                break; 
 
            case CmResourceTypeDma: 
                DebugPrintf_NoInfo(("              Type: DMA (unsupported)\n")); 
                break; 
 
            case CmResourceTypeDeviceSpecific: 
                DebugPrintf_NoInfo(("              Type: Device Specific (unsupported)\n")); 
                break; 
 
            case CmResourceTypeBusNumber: 
                DebugPrintf_NoInfo(("              Type: Bus Number (unsupported)\n")); 
                break; 
 
            // NonArbitrated & ConfigData are currently #defined as the same number 
            case CmResourceTypeConfigData: 
                DebugPrintf_NoInfo(("              Type: Non-Arbitrated or Config Data (unsupported)\n")); 
                break; 
 
            case CmResourceTypeDevicePrivate: 
                DebugPrintf_NoInfo(("              Type: Device Private Data (unsupported)\n")); 
                break; 
 
            case CmResourceTypePcCardConfig: 
                DebugPrintf_NoInfo(("              Type: PC Card Configuration (unsupported)\n")); 
                break; 
 
            case CmResourceTypeMfCardConfig: 
                DebugPrintf_NoInfo(("              Type: Multi-function Card Configuration (unsupported)\n")); 
                break; 
 
            default: 
                DebugPrintf_NoInfo(("              Type: ?Unknown Resource Type?\n")); 
                break; 
        } 
    } 
 
    // Make sure BAR 0 exists or the device can't be started 
    if (pdx->PciBar[0].pVa == NULL) 
    { 
        ErrorPrintf(("ERROR - BAR 0 address not configured, unable to load driver\n")); 
        return STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    // Record the Vendor and Device ID 
    pdx->Device.VendorId = PciRegs.VendorID; 
    pdx->Device.DeviceId = PciRegs.DeviceID; 
 
    // Get bus and slot numbers of the device 
    status = 
        GetBusSlotNumber( 
            pdx->pPhysicalDeviceObject, 
            pdx, 
            PciRegs.u.type0.BaseAddresses[0] 
            ); 
 
    if (!NT_SUCCESS(status)) 
    { 
        DebugPrintf(("WARNING - Unable to get bus and slot number\n")); 
    } 
 
    if (bIntPresent) 
    { 
        // Disable the PCI interrupt 
        PlxChipPciInterruptDisable( 
            pdx 
            ); 
 
        status = 
            IoConnectInterrupt( 
                &pdx->pInterruptObject, 
                OnInterrupt, 
                pdx, 
                NULL, 
                vector, 
                IrqL, 
                IrqL, 
                mode, 
                TRUE, 
                affinity, 
                FALSE 
                ); 
 
        if ( !NT_SUCCESS(status) ) 
        { 
            ErrorPrintf(( 
                "ERROR - IoConnectInterrupt() failed, status = 0x%08x\n", 
                status 
                )); 
 
            pdx->pInterruptObject = NULL; 
        } 
        else 
        { 
            DebugPrintf(("Connected to interrupt vector\n")); 
 
            // Re-enable the PCI Interrupt 
            KeSynchronizeExecution( 
                pdx->pInterruptObject, 
                PlxChipPciInterruptEnable, 
                pdx 
                ); 
        } 
    } 
    else 
    { 
        DebugPrintf(("No interrupt found\n")); 
        pdx->pInterruptObject = NULL; 
    } 
 
    // Allocate a DMA adapter object for physical memory allocations 
    PlxDmaAdapterAllocate( 
        pdx 
        ); 
 
    // If this is the first device, allocate buffers 
    if (Gbl_DeviceCount == 0) 
    { 
        if (Gbl_CommonBufferSize != 0) 
        { 
            DebugPrintf(( 
                "Allocating common buffer...\n" 
                )); 
 
            // Set requested size 
            PciMem.Size = Gbl_CommonBufferSize; 
 
            // Allocate common buffer 
            PlxPciPhysicalMemoryAllocate( 
                pdx, 
                &PciMem, 
                TRUE,                   // Smaller buffer is ok 
                pdx                     // Assign owner as the device 
                ); 
        } 
 
        /******************************************************** 
         * Since this is the first device, make sure to invalidate 
         * its removal relations.  This forces the PnP Manager 
         * to eventually query for removal relations before 
         * attempting to remove the device.  Devices added after 
         * this one rely on it for the Common DMA and SGL buffers; 
         * therefore, it can only be removed last. 
         *******************************************************/ 
 
        IoInvalidateDeviceRelations( 
            pdx->pPhysicalDeviceObject, 
            RemovalRelations 
            ); 
    } 
 
    // Relay Common buffer properties to device 
    if (pGbl_CommonBuffer != NULL) 
    { 
        PlxChipPostCommonBufferProperties( 
            pdx, 
            (U32)pGbl_CommonBuffer->BusPhysical, 
            pGbl_CommonBuffer->Size 
            ); 
    } 
 
    // Increment our device count 
    InterlockedIncrement( 
        &Gbl_DeviceCount 
        ); 
 
    return STATUS_SUCCESS; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  StopDevice 
 * 
 * Description:  Stop a device 
 * 
 ******************************************************************************/ 
VOID 
StopDevice( 
    PDEVICE_OBJECT fdo 
    ) 
{ 
    PLX_PHYSICAL_MEM  PciMem; 
    DEVICE_EXTENSION *pdx; 
 
 
    pdx = fdo->DeviceExtension; 
 
    // Free all interrupt resources 
    if (pdx->pInterruptObject != NULL) 
    { 
        // Disable the PCI interrupt 
        KeSynchronizeExecution( 
            pdx->pInterruptObject, 
            (PKSYNCHRONIZE_ROUTINE)PlxChipPciInterruptDisable, 
            (PVOID)pdx 
            ); 
 
        // Remove the ISR 
        IoDisconnectInterrupt( 
            pdx->pInterruptObject 
            ); 
 
        pdx->pInterruptObject = NULL; 
    } 
 
    // Release the common buffer if this device owns it 
    if (pGbl_CommonBuffer != NULL) 
    { 
        if (pGbl_CommonBuffer->pOwner == pdx) 
        { 
            // Release common buffer 
            DebugPrintf(( 
                "De-allocating Common Buffer...\n" 
                )); 
 
            // Prepare buffer properties for parameter 
            PciMem.PhysicalAddr = pGbl_CommonBuffer->BusPhysical; 
            PciMem.Size         = pGbl_CommonBuffer->Size; 
 
            // Release the buffer 
            PlxPciPhysicalMemoryFree( 
                pdx, 
                &PciMem 
                ); 
 
            // Mark buffer as released 
            pGbl_CommonBuffer = NULL; 
        } 
    } 
 
    // Remove relayed Common buffer properties 
    PlxChipPostCommonBufferProperties( 
        pdx, 
        0, 
        0 
        ); 
 
    // Release the DMA adapter object 
    PlxDmaAdapterFree( 
        pdx 
        ); 
 
    // Unmap I/O regions from kernel space (No local register access after this) 
    PlxPciBarResourcesUnmap( 
        pdx 
        ); 
 
    // Decrement our device count 
    InterlockedDecrement( 
        &Gbl_DeviceCount 
        ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  PlxDmaAdapterAllocate 
 * 
 * Description:  Allocate a DMA adapter object which will provide support for 
 *               later allocation of physically contiguous page-locked memory. 
 * 
 ******************************************************************************/ 
NTSTATUS 
PlxDmaAdapterAllocate( 
    DEVICE_EXTENSION *pdx 
    ) 
{ 
    ULONG               NumMapRegisters; 
    DEVICE_DESCRIPTION  DeviceDescription; 
 
 
    DebugPrintf(( 
        "Allocating DMA Adapter object...\n" 
        )); 
 
    // Verify object not already created 
    if (pdx->pDmaAdapter != NULL) 
    { 
        DebugPrintf(("ERROR - DMA Adapter object already exist, unable to allocate\n")); 
        return STATUS_OBJECT_NAME_EXISTS; 
    } 
 
    // Clear device description 
    RtlZeroMemory( 
        &DeviceDescription, 
        sizeof(DEVICE_DESCRIPTION) 
        ); 
 
    // Set device DMA properties 
    DeviceDescription.Version            = DEVICE_DESCRIPTION_VERSION; 
    DeviceDescription.Master             = TRUE;                    // Device is bus master 
    DeviceDescription.ScatterGather      = TRUE;                    // Device supports SGL 
    DeviceDescription.Dma32BitAddresses  = TRUE;                    // Device supports 32-bit addressing 
    DeviceDescription.Reserved1          = FALSE;                   // For future use, must be FALSE 
    DeviceDescription.Dma64BitAddresses  = FALSE;                   // Don't use 64-bit addressing 
    DeviceDescription.InterfaceType      = PCIBus;                  // Device is PCI 
    DeviceDescription.MaximumLength      = PHYS_MEM_MAX_SIZE_ALL; 
 
    // OS will assign map register count 
    NumMapRegisters = 0; 
 
    // Allocate a DMA adapter object 
    pdx->pDmaAdapter = 
        IoGetDmaAdapter( 
            pdx->pPhysicalDeviceObject, 
            &DeviceDescription, 
            &NumMapRegisters 
            ); 
 
    if (pdx->pDmaAdapter == NULL) 
    { 
        DebugPrintf(("ERROR - DMA Adapter allocation failed\n")); 
        return STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    return STATUS_SUCCESS; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  PlxDmaAdapterFree 
 * 
 * Description:  Frees the device DMA adapter object 
 * 
 ******************************************************************************/ 
NTSTATUS 
PlxDmaAdapterFree( 
    DEVICE_EXTENSION *pdx 
    ) 
{ 
    DebugPrintf(( 
        "Releasing DMA Adapter object...\n" 
        )); 
 
    // Verify DMA Adapter was created 
    if (pdx->pDmaAdapter == NULL) 
    { 
        DebugPrintf(("ERROR - DMA Adapter object doesn't exist, unable to free object\n")); 
        return STATUS_RESOURCE_TYPE_NOT_FOUND; 
    } 
 
    // Delete the DMA Adapter 
    pdx->pDmaAdapter->DmaOperations->PutDmaAdapter( 
        pdx->pDmaAdapter 
        ); 
 
    // DMA adapter object deleted, no longer available 
    pdx->pDmaAdapter = NULL; 
 
    return STATUS_SUCCESS; 
}