www.pudn.com > usbfx2lk_v1.1.zip > usbfx2lk_sysctrl.cpp


/////////////////////////////////////////////////////////////////////////////// 
// 
//    (C) Copyright 2005 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: 
// 
//      USBFx2LK_SysCtrl.cpp 
// 
//    ABSTRACT: 
// 
//      This file contains the routines that handle IRP_MJ_SYSTEM_CONTROL processing for the  
//      OSR USB FX2 Learning Kit Device 
// 
//    AUTHOR(S): 
// 
//      OSR Open Systems Resources, Inc. 
//  
/////////////////////////////////////////////////////////////////////////////// 
#include "usbfx2lk.h" 
 
#define INITGUID 
#include  
 
 
#ifdef WPP_TRACING 
// 
// Include the necessary tmh file - this is  
//  just a matter of course if you're using WPP tracing. 
// 
extern "C" { 
#include "usbfx2lk_sysctrl.tmh" 
} 
#endif 
 
#ifdef USE_BINARY_MOF_QUERY 
 
UCHAR UsbFx2LkBinaryMofData[] = { 
#include "UsbFx2Lk.dat" 
}; 
 
#else 
 
#define MOFRESOURCENAME L"MofResourceName" 
 
#endif 
 
extern UNICODE_STRING	GlobalRegistryPath; 
 
#define UsbFx2LkPerformanceCountGuidIndex        0 
#define UsbFx2LkBinaryMofGuidGuidIndex           1 
#define UsbFx2LkDeviceWakeEnableGuidIndex        2 
#define UsbFx2LkSelectiveSuspendEnabledGuidIndex 3 
 
GUID UsbFx2LkPerformanceGuid             = USBFX2LK_STATISTICSGuid; 
GUID UsbFx2LkBinaryMofGuid               = MSWmi_MofDataGuid; 
 
// 
// Return the list of the GUID's we support of WMI.   
// 
// 
// You'll notice that if we're building for Win2K 
//  and we're doing WPP tracing, we need to add 
//  the WPP_TRACE_CONTROL_NULL_GUID. What this 
//  does is simply reserve space within the 
//  GUID structure for the tracing GUID that the 
//  WPP code will add to the structure. 
// 
WMIGUIDREGINFO UsbFx2LkWmiGuidList[] = 
{ 
    { 
        &UsbFx2LkPerformanceGuid, 1, 0 // performance information 
    }, 
 
    { 
        &UsbFx2LkBinaryMofGuid,   1, 
#ifdef USE_BINARY_MOF_QUERY 
        0 
#else 
        WMIREG_FLAG_REMOVE_GUID 
#endif 
    }, 
    { 
        &GUID_POWER_DEVICE_WAKE_ENABLE,1,0 // wait wake 
    }, 
    { 
        &GUID_POWER_DEVICE_ENABLE, 1, 0 // Selective Suspend 
    } 
#ifdef WPP_TRACING 
#ifdef W2K 
    , 
    { 
        &WPP_TRACE_CONTROL_NULL_GUID, 1, 0 
    } 
#endif  
#endif 
}; 
 
 
#define USBFX2LKGUIDCOUNT (sizeof(UsbFx2LkWmiGuidList) / sizeof(WMIGUIDREGINFO)) 
 
// 
// Forward Definitions 
// 
NTSTATUS UsbFx2LkWmiQueryDataBlock(IN PDEVICE_OBJECT DeviceObject, 
                                IN PIRP Irp, 
                                IN ULONG GuidIndex, 
                                IN ULONG InstanceIndex, 
                                IN ULONG InstanceCount, 
                                IN OUT PULONG InstanceLengthArray, 
                                IN ULONG OutBufferSize, 
                                OUT PUCHAR Buffer); 
NTSTATUS UsbFx2LkWmiQueryRegInfo(IN PDEVICE_OBJECT DeviceObject, 
                              OUT ULONG *RegFlags, 
                              OUT PUNICODE_STRING InstanceName, 
                              OUT PUNICODE_STRING *RegistryPath, 
                              OUT PUNICODE_STRING MofResourceName, 
                              OUT PDEVICE_OBJECT *Pdo); 
NTSTATUS UsbFx2LkWmiSetDataBlock(IN PDEVICE_OBJECT DeviceObject, 
                              IN PIRP Irp, 
                              IN ULONG GuidIndex, 
                              IN ULONG InstanceIndex, 
                              IN ULONG BufferSize, 
                              IN PUCHAR Buffer); 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  UsbFx2LkWmiRegistration 
// 
//      Registers with WMI as a data provider for this instance of the device. 
// 
//  Inputs: 
// 
//      PDevExt - Device object extension for this request. 
// 
//  Outputs: 
//      None. 
// 
//  Returns: 
// 
//      STATUS_SUCCESS if successful, error otherwise. 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL. 
// 
//  Notes: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkWmiRegistration(PUSBFX2LK_EXT PDevExt) 
{ 
    NTSTATUS status; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiRegistration: Entered\n")); 
 
    // 
    // Indicate how may GUID's we support. 
    // 
 
    PDevExt->WmiLibInfo.GuidCount = USBFX2LKGUIDCOUNT; 
 
    ASSERT(0 != PDevExt->WmiLibInfo.GuidCount); 
 
    // 
    // Register our WMI Handlers for each request.  
    // 
     
    PDevExt->WmiLibInfo.GuidList = UsbFx2LkWmiGuidList; 
 
    PDevExt->WmiLibInfo.QueryWmiRegInfo = UsbFx2LkWmiQueryRegInfo; 
    PDevExt->WmiLibInfo.QueryWmiDataBlock = UsbFx2LkWmiQueryDataBlock; 
    PDevExt->WmiLibInfo.SetWmiDataBlock = UsbFx2LkWmiSetDataBlock; 
     
    // 
    // We support SetWmiDataBlock, which is sufficient for our  
    //  needs. The DDK recommends only supporting SetWmiDataItem 
    //  if your application specifically requires support for it,  
    //  so we're just not going to deal with it. 
    // 
    PDevExt->WmiLibInfo.SetWmiDataItem = NULL; 
 
    // 
    // We don't have any WMI methods. 
    // 
    PDevExt->WmiLibInfo.ExecuteWmiMethod = NULL; 
 
    // 
    // And we don't have any WMI events or "expensive data" 
    // 
    PDevExt->WmiLibInfo.WmiFunctionControl = NULL; 
 
    // 
    // Register with WMI 
    // 
     
    status = IoWMIRegistrationControl(PDevExt->FunctionalDeviceObject, 
                                      WMIREG_ACTION_REGISTER); 
 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiRegistration: Exit.\n")); 
 
    return status; 
     
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  UsbFx2LkWmiDeRegistration 
// 
//      Inform WMI to remove this DeviceObject from its  
//      list of providers. This function also  
//      decrements the reference count of the deviceobject. 
// 
//  Inputs: 
// 
//      FdoData - Device object extension for this request. 
// 
//  Outputs: 
//      None. 
// 
//  Returns: 
// 
//      STATUS_SUCCESS if successful, error otherwise. 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL. 
// 
//  Notes: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkWmiDeRegistration(PUSBFX2LK_EXT PDevExt) 
{ 
    NTSTATUS status; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiDeRegistration: Entered\n")); 
 
    // 
    // We're finished with WMI (i.e. we're going away, so unregister 
    // ourselves. 
    // 
 
    status = IoWMIRegistrationControl(PDevExt->FunctionalDeviceObject, 
                                 WMIREG_ACTION_DEREGISTER 
                                 ); 
 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiDeRegistration: Exit\n")); 
 
    return status; 
 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
// UsbFx2LkSystemControl 
// 
//  This routine is called by the IO Manager to process a IRP_MJ_SYSTEM_CONTROL 
//  Irp. 
// 
// 
//  INPUTS: 
// 
//      DeviceObject  -  One of our Device Objects. 
//      Irp  -  The Irp to process. 
// 
//  OUTPUTS: 
// 
//      None 
// 
//  RETURNS: 
// 
//      None 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL 
// 
//  CONTEXT: 
// 
//      User Context 
// 
//  NOTES: 
// 
//      This is where we handle WMI Requests. 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkSystemControl(PDEVICE_OBJECT DeviceObject,PIRP Irp) 
{ 
    PUSBFX2LK_EXT           devExt; 
    SYSCTL_IRP_DISPOSITION  disposition; 
    NTSTATUS                status; 
    PIO_STACK_LOCATION      stack; 
    ULONG                   bytesReturned; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkSystemControl: Entered\n")); 
 
    stack = IoGetCurrentIrpStackLocation (Irp); 
 
    devExt = (PUSBFX2LK_EXT) DeviceObject->DeviceExtension; 
     
 
    // 
    // Increment the count of Outstanding IOs 
    // 
    OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__); 
 
#ifdef WPP_TRACING 
#ifdef W2K 
 
 
    // 
    // One of the mythical things that people tell you that 
    //  you need to do to get WPP tracing to work on Windows 
    //  2000 is to call the WPP_SYSTEMCONTROL macro in your 
    //  DriverEntry entry point. The problem with this is that 
    //  what is does is actually trash your IRP_MJ_SYSTEM_CONTROL 
    //  entry point, meaning that you can no longer expose your 
    //  driver through WMI. What we will do to get around this 
    //  is to incorporate a call to the function that the WPP  
    //  IRP_MJ_SYSTEM_CONTROL handler calls in order to handle 
    //  WPP data. By doing this, we can satisfy WPP while  
    //  also supporting our own WMI data. 
    // 
    //  You can find the code for the WPP SYSTEM_CONTROL  
    //  handler (WPPSystemControlDispatch) in the km-init.tpl 
    //  file located in the DDK's bin\wppconfig directory.  
    // 
    if (DeviceObject == (PDEVICE_OBJECT)stack->Parameters.WMI.ProviderId) { 
 
        // 
        // If this is a REG_INFO requst and we have not registered 
        //  with WMI yet, we must zero the buffer. The reason for this 
        //  is that the WPP code will just blindly use it without 
        //  verifying any of the members of the structure. We learned 
        //  this trick from the WPPSystemControl handler code in  
        //  km-init.tpl 
        // 
        if (stack->MinorFunction == IRP_MN_REGINFO && 
            !devExt->WmiRegistered) { 
 
            RtlZeroMemory(stack->Parameters.WMI.Buffer, stack->Parameters.WMI.BufferSize); 
 
        } 
 
        // 
        // Yet another nice thing about trying to get tracing and WMI 
        //  support working is that we can NOT allow an IRP_MN_REGINFO_EX 
        //  request to get to the WMI library, we must for the registering 
        //  of WMI through an IRP_MN_REGINFO request.  
        // 
        // Why? Because the W2K tracing code has no idea what an 
        //  IRP_MN_REGINFO_EX is, so it will refuse to setup the 
        //  parts necessary for WPP tracing support. So, if  
        //  we see an IRP_MN_REGINFO_EX request come in and we're 
        //  built for Windows 2000, that means that we need to  
        //  reject it to force the code to send us an IRP_MN_REGINFO 
        //  request.  
        // 
        // IRP_MN_REGINFO_EX isn't defined for Windows 2000, so we use 
        //  its constant value of 0xb here.  
        // 
        if (stack->MinorFunction == 0xb) { 
 
            // 
            // Fail the request 
            // 
            Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 
            Irp->IoStatus.Information = 0; 
            IoCompleteRequest(Irp, IO_NO_INCREMENT); 
            OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__); 
            return STATUS_INVALID_DEVICE_REQUEST; 
 
        } 
 
    } 
 
#endif // W2K 
#endif //WPP_TRACING 
 
    // 
    // Call WMILIB to process the request. 
    // 
 
    status = WmiSystemControl(&devExt->WmiLibInfo,  
                              DeviceObject,  
                              Irp, 
                              &disposition); 
 
    // 
    // Check the disposition of the request, so that we can determine 
    // what to do. 
    // 
 
    switch(disposition) { 
 
        case IrpProcessed: 
        { 
            // 
            // This irp has been processed and may be completed or pending. 
            break; 
        } 
         
        case IrpNotCompleted: 
        { 
 
#ifdef WPP_TRACING 
#ifdef W2K 
 
            // 
            // If the WMILIB didn't complete the IRP, then let's 
            //  see if WPP will 
            // 
            NTSTATUS wppStatus; 
            wppStatus = WPP_TRACE_CONTROL(stack->MinorFunction, 
                                          stack->Parameters.WMI.Buffer, 
                                          stack->Parameters.WMI.BufferSize, 
                                          bytesReturned); 
 
            if (!NT_SUCCESS(status) &&  
                NT_SUCCESS(wppStatus)) { 
                 
 
                // 
                // WMILIB failed the IRP, but WPP completed it 
                //  with success. Therefore, we'll change the IRP's 
                //  status and bytes returned count to what WPP  
                //  would like them to be 
                // 
                Irp->IoStatus.Status = wppStatus; 
                Irp->IoStatus.Information = bytesReturned; 
                status = wppStatus; 
 
            } 
 
#endif // W2K 
#endif //WPP_TRACING 
  
            // 
            // This irp has not been completed, but has been fully processed. 
            // we will complete it now 
            IoCompleteRequest(Irp, IO_NO_INCREMENT);                 
            break; 
        } 
         
        case IrpForward: 
        case IrpNotWmi: 
        { 
            // 
            // This irp is either not a WMI irp or is a WMI irp targetted 
            // at a device lower in the stack. 
            IoSkipCurrentIrpStackLocation (Irp); 
            status = IoCallDriver (devExt->DeviceToSendIrpsTo, Irp); 
            break; 
        } 
                                     
        default: 
        { 
            // 
            // We really should never get here, but if we do just forward.... 
            // 
            IoSkipCurrentIrpStackLocation (Irp); 
            status = IoCallDriver (devExt->DeviceToSendIrpsTo, Irp); 
            break; 
        }         
    } 
 
    OsrDecrementOutstandingIoCount(devExt,__FILE__,__LINE__); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkSystemControl: Exit\n")); 
 
    return(status); 
 
} 
 
// 
// WMI System Call back functions 
// 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  UsbFx2LkWmiSetDataBlock 
// 
//      This routine is a callback into the driver to set the contents of 
//      a data block. When the driver has finished filling the data block it 
//      must call WmiCompleteRequest to complete the irp. The driver can 
//      return STATUS_PENDING if the irp cannot be completed immediately. 
// 
//  Inputs: 
// 
//      DeviceObject is the device whose data block is being queried 
// 
//      Irp is the Irp that makes this request 
// 
//      GuidIndex is the index into the list of guids provided when the 
//        device registered 
// 
//      InstanceIndex is the index that denotes which instance of the data block 
//        is being queried. 
//             
//      DataItemId has the id of the data item being set 
// 
//      BufferSize has the size of the data item passed 
// 
//      Buffer has the new values for the data item 
// 
//  Outputs: 
// 
//      None. 
// 
//  Returns: 
// 
//      STATUS_SUCCESS if successful, error otherwise. 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL. 
// 
//  Notes: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkWmiSetDataBlock(IN PDEVICE_OBJECT DeviceObject, 
                              IN PIRP Irp, 
                              IN ULONG GuidIndex, 
                              IN ULONG InstanceIndex, 
                              IN ULONG BufferSize, 
                              IN PUCHAR Buffer) 
{ 
    PUSBFX2LK_EXT   devExt; 
    NTSTATUS        status; 
    ULONG           info; 
    KIRQL           oldIrql; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiSetDataBlock: Entered\n")); 
 
    devExt = (PUSBFX2LK_EXT) DeviceObject->DeviceExtension; 
 
    ASSERT(InstanceIndex == 0); 
 
    switch(GuidIndex) { 
 
        case UsbFx2LkDeviceWakeEnableGuidIndex: { 
            BOOLEAN* pBoolean = (BOOLEAN*) Buffer; 
 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                ("UsbFx2LkWmiSetDataBlock: UsbFx2LkDeviceWakeEnable\n")); 
 
            info = sizeof(BOOLEAN); 
 
            if (BufferSize < info) { 
                status = STATUS_BUFFER_TOO_SMALL; 
                break; 
 
            } 
 
            // 
            // Can't do anything with WW IRPs if the device 
            //  isn't powered up. 
            // 
            SSPowerDeviceIfSuspended(devExt); 
 
            // 
            // See if the setting of WaitWakeEnable is changing. 
            // 
            if(devExt->WaitWakeEnable != *pBoolean) { 
                if(*pBoolean) { 
                    // 
                    // Wait Wake is being enabled.  First determine 
                    // if this is possible, and if it is, then enable it. 
                    // Otherwise we have to return an error. 
                    // 
                    if(devExt->UsbConfigurationDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { 
                        // 
                        // The device is capable of Remote Wake up, so we will enable it. 
                        // 
                        devExt->WaitWakeEnable = *pBoolean; 
                        IssueWaitWake(devExt); 
                    } else { 
                        // 
                        // The device is not capable of Remote Wake up, so we have to 
                        // inform the user of the error. 
                        // 
                        status = STATUS_INVALID_DEVICE_REQUEST; 
                        break; 
                    } 
                } else { 
                    // 
                    // Wait Wake is being disabled.  
                    // 
                    devExt->WaitWakeEnable = *pBoolean; 
                    CancelWaitWake(devExt); 
                } 
            } 
            status = STATUS_SUCCESS; 
            break; 
        } 
 
        case UsbFx2LkSelectiveSuspendEnabledGuidIndex: { 
            BOOLEAN* pBoolean = (BOOLEAN*) Buffer; 
 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                ("UsbFx2LkWmiSetDataBlock: UsbFx2LkSelectiveSuspendEnabledGuidIndex\n")); 
 
            info = sizeof(BOOLEAN); 
 
            if (BufferSize < info) { 
                status = STATUS_BUFFER_TOO_SMALL; 
                break; 
            } 
 
            // 
            // Get the SS code into a known state by 
            //  powering up the device if we're suspended 
            // 
            SSPowerDeviceIfSuspended(devExt); 
 
            // 
            // We'll need the SS lock for this  
            // 
            KeAcquireSpinLock(&devExt->SSLock,&oldIrql); 
 
            // 
            // Update the field that indicates whether or not 
            //  SS is enabled by ths ueer 
            // 
            devExt->SSEnabledByUser = *pBoolean; 
 
            KeReleaseSpinLock(&devExt->SSLock, oldIrql); 
 
            // 
            // And let the SS code deal with whether else  
            //  needs to be done 
            // 
            if (*pBoolean) { 
 
                OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                    ("UsbFx2LkWmiSetDataBlock: User wants to enable selective suspend\n")); 
 
                EnableSelectiveSuspend(devExt); 
 
            } else { 
 
                OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                    ("UsbFx2LkWmiSetDataBlock: User wants to disable selective suspend\n")); 
 
                DisableSelectiveSuspend(devExt); 
 
            } 
 
            status = STATUS_SUCCESS; 
            break; 
 
        } 
 
        default: { 
            status = STATUS_WMI_GUID_NOT_FOUND; 
            break; 
 
        } 
 
    } 
 
 
    status = WmiCompleteRequest(  DeviceObject, 
                                  Irp, 
                                  status, 
                                  0, 
                                  IO_NO_INCREMENT); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiSetDataBlock: Exit\n")); 
 
    return(status); 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  UsbFx2LkWmiQueryDataBlock 
// 
//      This routine is a callback into the driver to set the contents of 
//      a data block. When the driver has finished filling the data block it 
//      must call WmiCompleteRequest to complete the irp. The driver can 
//      return STATUS_PENDING if the irp cannot be completed immediately. 
// 
//  Inputs: 
// 
//      DeviceObject is the device whose data block is being queried 
// 
//      Irp is the Irp that makes this request 
// 
//      GuidIndex is the index into the list of guids provided when the 
//        device registered 
// 
//      InstanceIndex is the index that denotes which instance of the data block 
//        is being queried. 
//             
//      DataItemId has the id of the data item being set 
// 
//      BufferSize has the size of the data item passed 
// 
//      Buffer has the new values for the data item 
// 
//  Outputs: 
// 
//      None. 
// 
//  Returns: 
// 
//      STATUS_SUCCESS if successful, error otherwise. 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL. 
// 
//  Notes: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkWmiQueryDataBlock(IN PDEVICE_OBJECT DeviceObject, 
                                IN PIRP Irp, 
                                IN ULONG GuidIndex, 
                                IN ULONG InstanceIndex, 
                                IN ULONG InstanceCount, 
                                IN OUT PULONG InstanceLengthArray, 
                                IN ULONG OutBufferSize, 
                                OUT PUCHAR Buffer) 
{ 
    PUSBFX2LK_EXT   devExt; 
    NTSTATUS        status; 
    ULONG           size; 
    ULONG           sizeNeeded = 0; 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiQueryDataBlock: Entered\n")); 
 
    // 
    // we only ever register 1 instance per guid 
    // 
     
    ASSERT((InstanceIndex == 0) && (InstanceCount == 1)); 
     
    devExt = (PUSBFX2LK_EXT) DeviceObject->DeviceExtension; 
 
    switch (GuidIndex) { 
 
        case UsbFx2LkPerformanceCountGuidIndex: { 
                OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                    ("UsbFx2LkWmiQueryDataBlock: UsbFx2LkPerformanceCountGuidIndex\n")); 
 
                sizeNeeded = sizeof(USBFX2LK_STATISTICS); 
 
                if (OutBufferSize >= sizeNeeded) { 
                    PUSBFX2LK_STATISTICS pStatistics = (PUSBFX2LK_STATISTICS)Buffer; 
 
                    RtlCopyMemory(pStatistics,&devExt->WmiStatistics,sizeNeeded); 
 
                    *InstanceLengthArray = sizeNeeded; 
 
                    status = STATUS_SUCCESS; 
                } else { 
                    status = STATUS_BUFFER_TOO_SMALL; 
                } 
                break; 
            } 
 
#ifdef USE_BINARY_MOF_QUERY 
        case UsbFx2LkBinaryMofGuidGuidIndex: { 
                OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                    ("UsbFx2LkWmiQueryDataBlock: UsbFx2LkBinaryMofGuidGuidIndex\n")); 
                sizeNeeded = sizeof(UsbFx2LkBinaryMofData); 
 
                if (OutBufferSize < sizeNeeded) 
                { 
                    status = STATUS_BUFFER_TOO_SMALL; 
                } else { 
                    RtlCopyMemory(Buffer, UsbFx2LkBinaryMofData, sizeNeeded); 
                    *InstanceLengthArray = sizeNeeded; 
                    status = STATUS_SUCCESS; 
                } 
                break; 
            } 
#endif 
 
        case UsbFx2LkDeviceWakeEnableGuidIndex: { 
 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                ("UsbFx2LkWmiQueryDataBlock: UsbFx2LkDeviceWakeEnableGuidIndex\n")); 
 
            sizeNeeded = sizeof(BOOLEAN); 
 
            // 
            // Only registers 1 instance for this guid 
            // 
            if ((0 != InstanceIndex) || (1 != InstanceCount)) { 
                status = STATUS_INVALID_DEVICE_REQUEST; 
                break; 
            } 
            size = sizeof(BOOLEAN); 
 
            if (OutBufferSize < size) { 
                status = STATUS_BUFFER_TOO_SMALL; 
                break; 
            } 
 
            *((PBOOLEAN) Buffer) = (BOOLEAN) devExt->WaitWakeEnable;  
            *InstanceLengthArray = size; 
            status = STATUS_SUCCESS; 
            break; 
        } 
 
        case UsbFx2LkSelectiveSuspendEnabledGuidIndex: { 
 
            OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_WMI_INFO, 
                ("UsbFx2LkWmiQueryDataBlock: UsbFx2LkSelectiveSuspendEnabledGuidIndex\n")); 
 
            sizeNeeded = sizeof(BOOLEAN); 
 
            // 
            // Only registers 1 instance for this guid 
            // 
            if ((0 != InstanceIndex) || (1 != InstanceCount)) { 
                status = STATUS_INVALID_DEVICE_REQUEST; 
                break; 
            } 
 
            size = sizeof(BOOLEAN); 
 
            if (OutBufferSize < size) { 
                status = STATUS_BUFFER_TOO_SMALL; 
                break; 
            } 
 
            *((PBOOLEAN) Buffer) = devExt->SSEnabledByUser; 
            *InstanceLengthArray = size; 
            status = STATUS_SUCCESS; 
            break; 
        } 
 
        default: 
 
            OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_WMI_INFO, 
                ("UsbFx2LkWmiQueryDataBlock: unknown %d\n",GuidIndex)); 
 
            status = STATUS_WMI_GUID_NOT_FOUND; 
            break; 
 
    } 
 
    status = WmiCompleteRequest(  DeviceObject, 
                                  Irp, 
                                  status, 
                                  sizeNeeded, 
                                  IO_NO_INCREMENT); 
 
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiQueryDataBlock: Exit\n")); 
 
    return status; 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  UsbFx2LkWmiQueryRegInfo 
// 
//      This routine is a callback into the driver to retrieve the list of 
//      guids or data blocks that the driver wants to register with WMI. This 
//      routine may not pend or block. Driver should NOT call 
//      WmiCompleteRequest. 
// 
//  Inputs: 
// 
//      DeviceObject is the device whose data block is being queried 
// 
//      *RegFlags returns with a set of flags that describe the guids being 
//          registered for this device. If the device wants enable and disable 
//          collection callbacks before receiving queries for the registered 
//          guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the 
//          returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case 
//          the instance name is determined from the PDO associated with the 
//          device object. Note that the PDO must have an associated devnode. If 
//          WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique 
//          name for the device. 
// 
//     InstanceName returns with the instance name for the guids if 
//         WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The 
//          caller will call ExFreePool with the buffer returned. 
// 
//      *RegistryPath returns with the registry path of the driver 
// 
//      *MofResourceName returns with the name of the MOF resource attached to 
//          the binary file. If the driver does not have a mof resource attached 
//          then this can be returned as NULL. 
// 
//      *Pdo returns with the device object for the PDO associated with this 
//          device if the WMIREG_FLAG_INSTANCE_PDO flag is retured in  
//          *RegFlags. 
// 
// 
//  Outputs: 
// 
//      None. 
// 
//  Returns: 
// 
//      STATUS_SUCCESS if successful, error otherwise. 
// 
//  IRQL: 
// 
//      IRQL == PASSIVE_LEVEL. 
// 
//  Notes: 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS UsbFx2LkWmiQueryRegInfo(IN PDEVICE_OBJECT DeviceObject, 
                                OUT ULONG *RegFlags, 
                                OUT PUNICODE_STRING InstanceName, 
                                OUT PUNICODE_STRING *RegistryPath, 
                                OUT PUNICODE_STRING MofResourceName, 
                                OUT PDEVICE_OBJECT *Pdo) 
{ 
    PUSBFX2LK_EXT pDevExt; 
         
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiQueryRegInfo: Entered\n")); 
 
    pDevExt = (PUSBFX2LK_EXT) DeviceObject->DeviceExtension; 
 
    *RegFlags = WMIREG_FLAG_INSTANCE_PDO; 
    *RegistryPath = &GlobalRegistryPath; 
    *Pdo = pDevExt->PhysicalDeviceObject; 
 
#ifndef USE_BINARY_MOF_QUERY 
    RtlInitUnicodeString(MofResourceName, MOFRESOURCENAME); 
#endif  
 
    pDevExt->WmiRegistered = TRUE; 
     
    OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_WMI_INFO,("UsbFx2LkWmiQueryRegInfo: Exit\n")); 
 
    return STATUS_SUCCESS; 
}