⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pnp.c

📁 PCI驱动编程实例
💻 C
📖 第 1 页 / 共 4 页
字号:
///////////////////////////////////////////////////////////////////////////////
//
//    (C) Copyright 1995 - 1999 OSR Open Systems Resources, Inc.
//    All Rights Reserved
//
//    This sofware is supplied for instructional purposes only.
//
//    OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
//    for this software.  THIS SOFTWARE IS PROVIDED  "AS IS" WITHOUT WARRANTY
//    OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
//    THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
//    PURPOSE.  THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
//    WITH YOU.  OSR's entire liability and your exclusive remedy shall not
//    exceed the price paid for this material.  In no event shall OSR or its
//    suppliers be liable for any damages whatsoever (including, without
//    limitation, damages for loss of business profit, business interruption,
//    loss of business information, or any other pecuniary loss) arising out
//    of the use or inability to use this software, even if OSR has been
//    advised of the possibility of such damages.  Because some states/
//    jurisdictions do not allow the exclusion or limitation of liability for
//    consequential or incidental damages, the above limitation may not apply
//    to you.
//
//    OSR Open Systems Resources, Inc.
//    105 Route 101A Suite 19
//    Amherst, NH 03031  (603) 595-6500 FAX: (603) 595-6503
//    email bugs to: bugs@osr.com
//
//
//    MODULE:
//
//        PnP.C -- Plug and Play module for OSR WDM Sample PCI Driver
//
//    ABSTRACT:
//
//          This file contains the Plug and Play support routines for
//          the OSR WDM Sample PCI Driver.
//
//    AUTHOR(S):
//
//        OSR Open Systems Resources, Inc.
// 
//    REVISION:   
//
//
///////////////////////////////////////////////////////////////////////////////
//
// The GUID needs to be defined SOMEwhere!
//
#define INITGUID                // define GUID_SIMPLE

#include "osr-pci.h"

//
// Instantiate the GUID for this device
//
#if !defined(FAR)
    #define FAR
#endif // !defined(FAR)

#include <initguid.h>

DEFINE_GUID(OSR_GUID, 0xd0fbbbe6, 0x8631, 0x11d2,0xb1, 0x62, 0x00, 0x60, 0xb0, 0xef, 0xd4, 0xaa);

VOID OsrUnload(PDRIVER_OBJECT DriverObject);

#if DBG
VOID OsrPrintState(POSR_DEVICE_EXT devExt);
#endif

VOID OsrRequestIncrement(POSR_DEVICE_EXT devExt);
VOID OsrRequestDecrement(POSR_DEVICE_EXT devExt);
VOID OsrWaitForStop(POSR_DEVICE_EXT devExt);
VOID OsrWaitForRemove(POSR_DEVICE_EXT devExt);
VOID OsrReturnResources(POSR_DEVICE_EXT devExt);
NTSTATUS OsrStartDevice (IN POSR_DEVICE_EXT devExt,IN PIO_STACK_LOCATION IrpSp);
NTSTATUS OsrCanStopDevice(POSR_DEVICE_EXT devExt, PIRP Irp);
NTSTATUS OsrCanRemoveDevice(POSR_DEVICE_EXT devExt, PIRP Irp);
static NTSTATUS OsrPnpComplete (IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);

extern PUNICODE_STRING OsrWDMSample_RegistryPath;

static PSTR pnpMinorCodes[] = 
{
    "IRP_MN_START_DEVICE",
    "IRP_MN_QUERY_REMOVE_DEVICE",
    "IRP_MN_REMOVE_DEVICE",
    "IRP_MN_CANCEL_REMOVE_DEVICE",
    "IRP_MN_STOP_DEVICE",
    "IRP_MN_QUERY_STOP_DEVICE",
    "IRP_MN_CANCEL_STOP_DEVICE",
    "IRP_MN_QUERY_DEVICE_RELATIONS",
    "IRP_MN_QUERY_INTERFACE",
    "IRP_MN_QUERY_CAPABILITIES",
    "IRP_MN_QUERY_RESOURCES",
    "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",
    "IRP_MN_QUERY_DEVICE_TEXT",
    "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",
    "***** FUNCTION 0x0e",
    "IRP_MN_READ_CONFIG",
    "IRP_MN_WRITE_CONFIG",
    "IRP_MN_EJECT",
    "IRP_MN_SET_LOCK",
    "IRP_MN_QUERY_ID",
    "IRP_MN_QUERY_PNP_DEVICE_STATE",
    "IRP_MN_QUERY_BUS_INFORMATION",
    "IRP_MN_DEVICE_USAGE_NOTIFICATION",
    "IRP_MN_SURPRISE_REMOVAL"
};


#if DBG
VOID OsrPrintResourceList(PCM_RESOURCE_LIST);
VOID OsrPrintConfig(PPCI_COMMON_CONFIG  configInfo);
#endif

///////////////////////////////////////////////////////////////////////////////
//
//  OsrAddDevice
//
//      We are called at this entry point by the Plug and Play Manager
//      to add a Functional Device Object for a Physical Device Object.
//      Note that we may NOT access the device in this routine, as the
//      Plug and Play Manager has not yet given us any hardware resoruces.
//      We get these hardware resources via the IRP_MJ_PNP IRP with
//      a minor function IRP_MN_START_DEVICE.
//
//
//  INPUTS:
//
//      DriverObj - Address of our DRIVER_OBJECT.
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//      None.
//
//  IRQL:
//
//    This routine is called at IRQL_PASSIVE_LEVEL.
//
//  NOTES:
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS OsrAddDevice(IN PDRIVER_OBJECT DriverObject,
                      IN PDEVICE_OBJECT PhysicalDeviceObject)
{
    POSR_DEVICE_EXT devExt;
    PDEVICE_OBJECT  functionalDeviceObject;
    UNICODE_STRING  devName;
    UNICODE_STRING  linkName;
    NTSTATUS code = STATUS_SUCCESS;     

#if DBG
    DbgPrint("OsrAddDevice: entered\n");
#endif

#if DBG
    DbgPrint("OsrAddDevice: PDO = 0x%0x\n", PhysicalDeviceObject);
#endif

    //
    // Initialize the UNICODE device name.  This will be the "native NT" name
    // for our device.
    //
    RtlInitUnicodeString(&devName, L"\\Device\\OSRPCI");

    //
    // Ask the I/O Manager to create the device object and
    // device extension.  In PnP terms, this is the FUNCTIONAL
    // Device Object (FDO) for the device.
    //
    code = IoCreateDevice(DriverObject,
                          sizeof(OSR_DEVICE_EXT),
                          &devName,
                          FILE_DEVICE_OSR,
                          0,       
                          FALSE,
                          &functionalDeviceObject);

        
    if(!NT_SUCCESS(code))  {
        
#if DBG
        DbgPrint("IoCreateDevice failed.  Status = 0x%0x\n", code);
#endif
        return(STATUS_UNSUCCESSFUL);
    }    

    //
    // Get a pointer to our device extension
    //
    devExt = (POSR_DEVICE_EXT)functionalDeviceObject->DeviceExtension;
    
#if DBG
    DbgPrint("OsrAddDevice: FDO = 0x%0x\n", functionalDeviceObject);
#endif

    //
    // Zero out the device extension.  While not strictly necessary
    // (the documentation says the device extension is zeroed) it's
    // better to be safe.
    //
    RtlZeroMemory(devExt, sizeof(OSR_DEVICE_EXT));

    //
    // Save the device object pointer away for future reference
    //
    devExt->FunctionalDeviceObject = functionalDeviceObject;

    //
    // Save the address of the physical device object away for future reference
    //
    devExt->PhysicalDeviceObject = PhysicalDeviceObject;

    //
    //  Clear the Device Initializing bit since the Device Object was created
    //  outside of DriverEntry.
    //
    functionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

    //
    // Create a familiar name for this device, so that non-kernel mode
    // programs can open the device.
    //
    // NOTE: WDM Drivers on Win98 MUST create this link in the 
    // \DosDevices directory.  \?? will NOT work.
    //
    RtlInitUnicodeString(&linkName, L"\\DosDevices\\OSRPCI");

    //
    // IoCreateSymbolicLink IS a WDM function...
    //
    code = IoCreateSymbolicLink(&linkName, &devName);
    
    if (!NT_SUCCESS(code))
    {

        DbgPrint("IoCreateSymbolicLink failed.  Status = 0x%x\n", code);

        code = STATUS_SUCCESS;

        //
        // Clean up the mess
        //
        OsrUnload(DriverObject);

        //
        // Indicate load failure to the I/O manager; driver image is deleted...
        //
        return(code);
    }

    //
    // Initialize our IRP queues
    //
    InitializeListHead(&devExt->ReadQueue);
    InitializeListHead(&devExt->WriteQueue);
    
    //
    // Initialize our Spin Locks
    //
    KeInitializeSpinLock(&devExt->ReadQueueLock);
    KeInitializeSpinLock(&devExt->WriteQueueLock);
    
    //
    // Ask the I/O Manager to use describe user read/write buffers using MDLs
    //
    functionalDeviceObject->Flags |= DO_DIRECT_IO;

    //
    // Set up the "Remove Event" and "Stop Event".
    //
    // Note that we can't use an official "Remove Lock" here, because
    // the Remove Lock related calls are not in WDM.
    //
    KeInitializeEvent(&devExt->RemoveEvent, NotificationEvent, FALSE);
    KeInitializeEvent(&devExt->StopEvent, NotificationEvent, TRUE);

    //
    // Init the count of in-progress I/O requests to zero.  We use this
    // to keep track of when we can remove the device.
    //
    devExt->OutstandingIO = 0;

    //
    // Internal device state flags, used for managing PnP state of device
    //
    devExt->Started = FALSE;
    devExt->HoldNewRequests = TRUE;
    devExt->Removed = FALSE;

    //
    // Set initial state
    //
    devExt->State = STATE_NEVER_STARTED;

    //
    // Attach our FDO to the underlying PDO
    //
    devExt->DeviceToSendIrpsTo = 
                     IoAttachDeviceToDeviceStack(functionalDeviceObject,
                                                 PhysicalDeviceObject);

    //
    // If that didn't work...
    //
    if (!devExt->DeviceToSendIrpsTo)
    {

        DbgPrint("IoAttachDeviceToDeviceStack failed to attach to Target Device");

        //
        // Clean up the mess
        //
        OsrUnload(DriverObject);

        //
        // Indicate load failure to the I/O manager; driver image is deleted...
        //
        return(STATUS_UNSUCCESSFUL);
    }

#if DBG
    DbgPrint("OsrAddDevice: done\n");
#endif

    return code;
}

///////////////////////////////////////////////////////////////////////////////
//
//  OsrPnp
//
//    This is the dispatch entry point for IRP_MJ_PNP requests.  The
//    driver processes these requets, based on the current state of
//    the device.
//
//
//  INPUTS:
//
//      DeviceObject - Address of the Functional DEVICE_OBJECT for our device.
//  
//      Irp - Address of the IRP representing the IRP_MJ_PNP request.
//
//  OUTPUTS:
//
//      None.
//
//  RETURNS:
//
//
//  IRQL:
//
//    This routine is called at IRQL_PASSIVE_LEVEL.
//
//  NOTES:
//
//      There are several difficulties implementing Plug and Play.
//      Perhaps the greatest difficulty is deciding precisely how you
//      want your device to work, given the various requests the driver
//      can receive and the states the device can be in.  In our driver,
//      we've decided to implement the following policies:
//
//      1) When a removal of the device is requested, we will reject
//         any new IRPs we receive (completing them with an error
//         status in the dispatch routine).  We will wait until all IRPs
//         that are already present on the device's queue are complete
//         and then allow the remove.
//
//      2) When a stop of the device is requested, we'll queue any
//         newly received IRPs, but not initiate them.  We will wait
//         until any IRPs that are presently ACTIVE in progress on the
//         device complete, and then allow the stop.
//
//      3) When a SUPRISE removal of the device is indicated, we
//         immediately cancel any requests that are queued, reject any
//         newly arriving requests.
//
//      Of course, the second complexity in implementing plug and play
//      is getting the logic in your driver correct, so that it works
//      as you intend. According to our experience, this is easier said
//      than done.
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS 
OsrPnp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    PIO_STACK_LOCATION ioStackLocation;
    NTSTATUS code = STATUS_SUCCESS;
    POSR_DEVICE_EXT devExt;
    KEVENT eventWaitLowerDrivers;
    PDEVICE_OBJECT targetDevice;

#if DBG
    DbgPrint("OsrPnp: called\n");
#endif

    //
    // Get a pointer to our (FUNCTIONAL) device object's device
    // extension.
    //
    devExt = (POSR_DEVICE_EXT)DeviceObject->DeviceExtension;

    //
    // Up the count of in-progress requests
    //
    OsrRequestIncrement(devExt);

    ioStackLocation = IoGetCurrentIrpStackLocation(Irp);

    KeInitializeEvent(&eventWaitLowerDrivers, NotificationEvent, FALSE);

#if DBG
    DbgPrint("OsrPnp: Current state: ");
    OsrPrintState(devExt);

    DbgPrint("OsrPnp: *** PNP Minor Function is %s\n", 
                        pnpMinorCodes[ioStackLocation->MinorFunction]);
#endif

    switch( devExt->State + ioStackLocation->MinorFunction ) {


        //
        // STATE:   STOPPED or NEVER_STARTED
        // IRP_MN:  _START_DEVICE
        //
        // We're here if we've received an AddDevice() call, but we
        // do not have a set of hardware resources from the PnP Manager.
        //
        // The PnP Manager is now giving us a set of resources, and 
        // asking us to start the device.
        //
        // In this case, we pass the IRP all the way down.  When it's
        // done (and our completion routine is called) we can then
        // read the list of device resources pointed to in the IRP
        // Stack Location.
        //
        case STATE_STOPPED + IRP_MN_START_DEVICE:
        case STATE_NEVER_STARTED + IRP_MN_START_DEVICE:

#if DBG
            DbgPrint("OsrPnp: PROCESSING START_DEVICE\n");
#endif
            //
            // The BUS DRIVER handles this IRP before we do
            //
            IoCopyCurrentIrpStackLocationToNext(Irp);

            //
            // Call OsrPnpComplete() when this IRP is done...
            //
            IoSetCompletionRoutine(Irp,
                                  OsrPnpComplete,
                                  &eventWaitLowerDrivers,
                                  TRUE,
                                  TRUE,
                                  TRUE);

            //
            // Send the IRP to the bus driver.  Let's see what HE
            // thinks.
            //
            code = IoCallDriver(devExt->DeviceToSendIrpsTo, Irp);

            if (STATUS_PENDING == code) {

                KeWaitForSingleObject(&eventWaitLowerDrivers,
                                   Executive,
                                   KernelMode,
                                   FALSE,
                                   NULL);

                code = Irp->IoStatus.Status;
            }

            //
            // Can the bus driver do the start?
            //
            if (NT_SUCCESS (code)) {

                //
                // Yup.  Go initialize the device.  The CmResourceLists
                // are pointed to by the IoStackLocation.
                //
                code = OsrStartDevice(devExt, ioStackLocation);

                //
                // If the our StartDevice function succeeded, the
                // device is now "officially" started!
                //
                if(NT_SUCCESS(code)) {

                    devExt->State = STATE_STARTED;

                }

            } else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -