www.pudn.com > 9054Src.rar > PlugPlay.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: 
 * 
 *      PlugPlay.c 
 * 
 * Description: 
 * 
 *      Plug 'n' Play handler functions 
 * 
 * Revision History: 
 * 
 *      02-01-06 : PCI SDK v4.40 
 * 
 ******************************************************************************/ 
 
 
#include "Dispatch.h" 
#include "Driver.h" 
#include "GlobalVars.h" 
#include "PciSupport.h" 
#include "PlugPlay.h" 
#include "SupportFunc.h" 
 
 
/************************************************************** 
 * The following IRP minor code is erroneously not included 
 * in the Windows DDK "wdm.h" file.  It is, however, included 
 * in the "ntddk.h" file.  Until this is fixed by Microsoft, 
 * the definition is provided here so the driver will build. 
 *************************************************************/ 
#if !defined(IRP_MN_QUERY_LEGACY_BUS_INFORMATION) 
    #define IRP_MN_QUERY_LEGACY_BUS_INFORMATION        0x18 
#endif 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  Dispatch_Pnp 
 * 
 * Description:  Handle PnP requests 
 * 
 ******************************************************************************/ 
NTSTATUS 
Dispatch_Pnp( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    BOOLEAN            Unlock; 
    NTSTATUS           status; 
    PIO_STACK_LOCATION stack; 
 
 
    if (!PlxLockDevice(fdo->DeviceExtension)) 
    { 
        return PlxCompleteIrpWithInformation( 
                   pIrp, 
                   STATUS_DELETE_PENDING, 
                   0 
                   ); 
    } 
 
    DebugPrintf(( 
        "Received PNP Message (IRP=0x%p) ==> ", 
        pIrp 
        )); 
 
    Unlock = TRUE; 
 
    stack = 
        IoGetCurrentIrpStackLocation( 
            pIrp 
            ); 
 
    // Check minor code 
    switch (stack->MinorFunction) 
    { 
        case IRP_MN_START_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_START_DEVICE\n")); 
            status = 
                HandleStartDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_STOP_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_STOP_DEVICE\n")); 
            status = 
                HandleStopDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_REMOVE_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_REMOVE_DEVICE\n")); 
            Unlock = FALSE; 
            status = 
                HandleRemoveDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_REMOVE_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_REMOVE_DEVICE\n")); 
            status = 
                HandleQueryRemoveDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_CANCEL_REMOVE_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_CANCEL_REMOVE_DEVICE\n")); 
            status = 
                HandleCancelRemoveDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_STOP_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_STOP_DEVICE\n")); 
            status = 
                HandleQueryRemoveDevice( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_CANCEL_STOP_DEVICE: 
            DebugPrintf_NoInfo(("IRP_MN_CANCEL_STOP_DEVICE\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_DEVICE_RELATIONS: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_DEVICE_RELATIONS\n")); 
            status = 
                HandleQueryDeviceRelations( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_INTERFACE: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_INTERFACE\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_CAPABILITIES: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_CAPABILITIES\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_RESOURCES: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_RESOURCES\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_DEVICE_TEXT: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_DEVICE_TEXT\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: 
            DebugPrintf_NoInfo(("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_READ_CONFIG: 
            DebugPrintf_NoInfo(("IRP_MN_READ_CONFIG\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_WRITE_CONFIG: 
            DebugPrintf_NoInfo(("IRP_MN_WRITE_CONFIG\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_EJECT: 
            DebugPrintf_NoInfo(("IRP_MN_EJECT\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_SET_LOCK: 
            DebugPrintf_NoInfo(("IRP_MN_SET_LOCK\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_ID: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_ID\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_PNP_DEVICE_STATE: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_PNP_DEVICE_STATE\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_BUS_INFORMATION: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_BUS_INFORMATION\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_DEVICE_USAGE_NOTIFICATION: 
            DebugPrintf_NoInfo(("IRP_MN_DEVICE_USAGE_NOTIFICATION\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_SURPRISE_REMOVAL: 
            DebugPrintf_NoInfo(("IRP_MN_SURPRISE_REMOVAL\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        case IRP_MN_QUERY_LEGACY_BUS_INFORMATION: 
            DebugPrintf_NoInfo(("IRP_MN_QUERY_LEGACY_BUS_INFORMATION\n")); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
 
        default: 
            DebugPrintf_NoInfo(("Unsupported IRP_MN_Xxx (0x%08x)\n", stack->MinorFunction)); 
            status = 
                DefaultPnpHandler( 
                    fdo, 
                    pIrp 
                    ); 
            break; 
    } 
 
    if (Unlock == TRUE) 
    { 
        PlxUnlockDevice( 
            fdo->DeviceExtension 
            ); 
    } 
 
    return status; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  DefaultPnpHandler 
 * 
 * Description:  Handle standard PnP requests 
 * 
 ******************************************************************************/ 
NTSTATUS 
DefaultPnpHandler( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    DebugPrintf(("Forwarded IRP to next lower driver\n")); 
 
    IoSkipCurrentIrpStackLocation( 
        pIrp 
        ); 
 
    return IoCallDriver( 
               ((DEVICE_EXTENSION *)fdo->DeviceExtension)->pLowerDeviceObject, 
               pIrp 
               ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleQueryRemoveDevice 
 * 
 * Description:  Handle the IRP_MN_QUERY_REMOVE_DEVICE PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleQueryRemoveDevice( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    DEVICE_EXTENSION *pdx; 
 
 
    /******************************************************** 
     * Since the first device the driver owns is responsible 
     * for the global common buffer, it can only be removed 
     * if it is the last remaining device.  The device is 
     * identified by the serial number.  If other devices 
     * exist, the QUERY_REMOVE_DEVICE must fail. 
     *******************************************************/ 
 
    pdx = fdo->DeviceExtension; 
 
    // Check if more than one device is owned 
    if (Gbl_DeviceCount > 1) 
    { 
        // This is not the only device left, check serial number 
        if (_stricmp( 
                PLX_DRIVER_NAME "-0", 
                pdx->Device.SerialNumber 
                ) == 0) 
        { 
            DebugPrintf(( 
                "ERROR - Device owns shared resources in use, cannot remove at this time\n" 
                )); 
 
            // Device is first one, cannot be removed at this time 
            return PlxCompleteIrpWithInformation( 
                       pIrp, 
                       STATUS_DEVICE_BUSY, 
                       0 
                       ); 
        } 
    } 
 
    // Succeed the IRP and pass to next driver 
    pIrp->IoStatus.Status = STATUS_SUCCESS; 
 
    // Pass to next driver in stack 
    return DefaultPnpHandler( 
               fdo, 
               pIrp 
               ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleCancelRemoveDevice 
 * 
 * Description:  Handle the IRP_MN_CANCEL_REMOVE_DEVICE PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleCancelRemoveDevice( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    // We must succeed the IRP and pass it to the parent 
    pIrp->IoStatus.Status = STATUS_SUCCESS; 
 
    // Forward to parent driver 
    return DefaultPnpHandler( 
               fdo, 
               pIrp 
               ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleRemoveDevice 
 * 
 * Description:  Handle the IRP_MN_REMOVE_DEVICE PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleRemoveDevice( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    NTSTATUS          status; 
    DEVICE_EXTENSION *pdx; 
 
 
    // Wait for any pending I/O operations to complete 
 
    pdx           = fdo->DeviceExtension; 
    pdx->removing = TRUE; 
 
    PlxUnlockDevice(pdx);            // once for LockDevice at start of dispatch 
    PlxUnlockDevice(pdx);            // once for initialization during AddDevice 
 
    KeWaitForSingleObject( 
        &pdx->evRemove, 
        Executive, 
        KernelMode, 
        FALSE, 
        NULL 
        ); 
 
    // Halt the device and release its resources 
    StopDevice( 
        fdo 
        ); 
 
    // Succeed the IRP and pass to next driver 
    pIrp->IoStatus.Status = STATUS_SUCCESS; 
 
    // Pass to next driver in stack 
    status = 
        DefaultPnpHandler( 
            fdo, 
            pIrp 
            ); 
 
    // Remove the device object 
    RemoveDevice( 
        fdo 
        ); 
 
    return status; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleStartDevice 
 * 
 * Description:  Handle the IRP_MN_START_DEVICE PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleStartDevice( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    NTSTATUS           status; 
    PIO_STACK_LOCATION stack; 
 
 
    /******************************************************** 
     * First let all lower-level drivers handle this request, 
     * which is typically just the physical device object 
     * created by the bus driver. 
     *******************************************************/ 
 
    status = 
        ForwardAndWait( 
            fdo, 
            pIrp 
            ); 
 
    if (!NT_SUCCESS(status)) 
    { 
        return PlxCompleteIrp( 
                   pIrp, 
                   status 
                   ); 
    } 
 
    stack = 
        IoGetCurrentIrpStackLocation( 
            pIrp 
            ); 
 
    // Assign resources to the devices 
    status = 
        StartDevice( 
            fdo, 
            &stack->Parameters.StartDevice.AllocatedResources->List[0].PartialResourceList, 
            &stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].PartialResourceList 
            ); 
 
    return PlxCompleteIrpWithInformation( 
               pIrp, 
               status, 
               0 
               ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleStopDevice 
 * 
 * Description:  Handle the IRP_MN_STOP_DEVICE PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleStopDevice( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    NTSTATUS status; 
 
 
    status = 
        DefaultPnpHandler( 
            fdo, 
            pIrp 
            ); 
 
    StopDevice( 
        fdo 
        ); 
 
    return status; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  HandleQueryDeviceRelations 
 * 
 * Description:  Handle the IRP_MN_QUERY_DEVICE_RELATIONS PnP request 
 * 
 ******************************************************************************/ 
NTSTATUS 
HandleQueryDeviceRelations( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    U32                 MemNeeded; 
    PDEVICE_OBJECT      pdo; 
    PDEVICE_OBJECT      pDevice; 
    DEVICE_EXTENSION   *pdx; 
    DEVICE_RELATIONS   *pDeviceRelations; 
    PIO_STACK_LOCATION  stack; 
 
 
    /******************************************************** 
     * When a query for device relations is received and the 
     * request is for "RemovalRelations", the driver may 
     * report to the PnP manager a list of device relations. 
     *  
     * Since the first device loaded by the driver (PciXxx-0) 
     * is responsible for the common buffer, all subsequently 
     * owned devices are related to it.  An attempt to remove 
     * the primary device requires the driver to report that 
     * all other devices must be removed first.  The PnP 
     * manager determines this by the device relations 
     * provided by this driver. 
     *******************************************************/ 
 
    pdx = fdo->DeviceExtension; 
 
    // Get I/O Stack 
    stack = 
        IoGetCurrentIrpStackLocation( 
            pIrp 
            ); 
 
    // Check if this is for removal and more than one device is owned 
    if ((stack->Parameters.QueryDeviceRelations.Type == RemovalRelations) && 
        (Gbl_DeviceCount > 1)) 
    { 
        DebugPrintf(( 
            "Query for: RemovalRelations\n" 
            )); 
 
        // This is not the only device left, check if it's the primary device 
        if (_stricmp( 
                PLX_DRIVER_NAME "-0", 
                pdx->Device.SerialNumber 
                ) == 0) 
        { 
            /******************************************************** 
             * Calculate memory needed for device relations 
             * 
             * The default DEVICE_RELATIONS structure includes space 
             * for one device object.  Therefore, the memory needed 
             * is the total # of devices minus 2.  One since the 
             * primary device is not reported and one for memory 
             * already provided in the structure. 
             *******************************************************/ 
            MemNeeded = sizeof(DEVICE_RELATIONS) + 
                        ((Gbl_DeviceCount - 2) * sizeof(PDEVICE_OBJECT)); 
 
            // Allocate memory for device relations structure 
            pDeviceRelations = 
                ExAllocatePoolWithTag( 
                    PagedPool, 
                    MemNeeded, 
                    (ULONG)' XLP'       // "PLX " in reverse order 
                    ); 
 
            // Report other devices 
            DebugPrintf(( 
                "Following device(s) must be removed first:\n" 
                )); 
 
            // Get first device object 
            pDevice = fdo->DriverObject->DeviceObject; 
 
            // Reset device count 
            pDeviceRelations->Count = 0; 
 
            // Traverse driver owned devices to build relations 
            while (pDevice != NULL) 
            { 
                if (pDevice->DeviceExtension != pdx) 
                { 
                    // Get the physical device object 
                    pdo = ((DEVICE_EXTENSION*)(pDevice->DeviceExtension))->pPhysicalDeviceObject; 
 
                    DebugPrintf_NoInfo(( 
                        "           * %s (pdo=0x%p)\n", 
                        ((DEVICE_EXTENSION*)(pDevice->DeviceExtension))->Device.SerialNumber, 
                        pdo 
                        )); 
 
                    // Increment the reference count to the PDO 
                    ObReferenceObject( 
                        pdo 
                        ); 
 
                    // Add PDO to device relations 
                    pDeviceRelations->Objects[pDeviceRelations->Count] = pdo; 
 
                    // Increment number of objects 
                    pDeviceRelations->Count++; 
                } 
 
                // Jump to next device 
                pDevice = pDevice->NextDevice; 
            } 
 
            DebugPrintf_NoInfo(( 
                "\n" 
                )); 
 
            // Return address of device relations structure 
            return PlxCompleteIrpWithInformation( 
                       pIrp, 
                       STATUS_SUCCESS, 
                       (PLX_UINT_PTR)pDeviceRelations 
                       ); 
        } 
    } 
 
    // Just pass to parent 
    return DefaultPnpHandler( 
               fdo, 
               pIrp 
               ); 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  OnRequestComplete 
 * 
 * Description:  Set an event when a lower driver complete an IRP 
 * 
 ******************************************************************************/ 
NTSTATUS 
OnRequestComplete( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp, 
    PKEVENT        pKEvent 
    ) 
{ 
    KeSetEvent( 
       pKEvent, 
       0, 
       FALSE 
       ); 
 
    return STATUS_MORE_PROCESSING_REQUIRED; 
} 
 
 
 
 
/****************************************************************************** 
 * 
 * Function   :  ForwardAndWait 
 * 
 * Description:  Forward request to lower level and await completion, used 
 *               in PnP's IRP_MN_START_DEVICE 
 * 
 ******************************************************************************/ 
NTSTATUS 
ForwardAndWait( 
    PDEVICE_OBJECT fdo, 
    PIRP           pIrp 
    ) 
{ 
    KEVENT    event; 
    NTSTATUS  status; 
 
 
    /*  
       Initialize a kernel event object to use in waiting for the lower-level 
       driver to finish processing the object. It's a little known fact that the 
       kernel stack *can* be paged, but only while someone is waiting in user  
       mode for an event to finish. Since neither we nor a completion routine  
       can be in the forbidden state, it's okay to put the event object on the  
       stack. 
    */ 
    KeInitializeEvent( 
        &event, 
        NotificationEvent, 
        FALSE 
        ); 
 
    IoCopyCurrentIrpStackLocationToNext( 
        pIrp 
        ); 
 
    IoSetCompletionRoutine( 
        pIrp, 
        (PIO_COMPLETION_ROUTINE) OnRequestComplete, 
        (PVOID) &event, 
        TRUE, 
        TRUE, 
        TRUE 
        ); 
 
    status = 
        IoCallDriver( 
            ((DEVICE_EXTENSION *) fdo->DeviceExtension)->pLowerDeviceObject, 
            pIrp 
            ); 
 
    if (status == STATUS_PENDING) 
    { 
        // Wait for completion 
        KeWaitForSingleObject( 
            &event, 
            Executive, 
            KernelMode, 
            FALSE, 
            NULL 
            ); 
 
        return pIrp->IoStatus.Status; 
    } 
 
    return status; 
}