Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

914 lines
25 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
ioctl.c
Abstract: Human Input Device (HID) minidriver for Infrared (IR) devices
The HID IR Minidriver (HidIr) provides an abstraction layer for the
HID Class to talk to HID IR devices.
Author:
jsenior
Environment:
Kernel mode
Revision History:
--*/
#include "pch.h"
//
// The HID descriptor has some basic device info and tells how long the report
// descriptor is.
//
HIDIR_DESCRIPTOR HidIrHidDescriptor = {
0x09, // length of HID descriptor
0x21, // descriptor type == HID
0x0100, // hid spec release
0x00, // country code == Not Specified
0x01, // number of HID class descriptors
0x22, // report descriptor type
0 // total length of report descriptor (to be set)
};
//
// The report descriptor completely lays out what read and write packets will
// look like and indicates what the semantics are for each field. This here is
// what the report descriptor looks like in a broken out format. This is
// actually retrieved from the registry (device key).
//
/*
HID_REPORT_DESCRIPTOR HidIrReportDescriptor[] = {
// Keyboard
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x85, 0x01, // Report Id (1)
0x05, 0x07, // usage page key codes
0x19, 0xe0, // usage min left control
0x29, 0xe7, // usage max keyboard right gui
0x75, 0x01, // report size 1
0x95, 0x08, // report count 8
0x81, 0x02, // input (Variable)
0x19, 0x00, // usage min 0
0x29, 0x91, // usage max 91
0x26, 0xff, 0x00, // logical max 0xff
0x75, 0x08, // report size 8
0x95, 0x01, // report count 1
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection
// Consumer Controls
0x05, 0x0c, // Usage Page (Consumer Controls),
0x09, 0x01, // Usage (Consumer Control),
0xA1, 0x01, // Collection (Application),
0x85, 0x02, // Report Id (2)
0x19, 0x00, // Usage Minimum (0),
0x2a, 0x3c, 0x02, // Usage Maximum (23c)
0x15, 0x00, // Logical Minimum (0),
0x26, 0x3c, 0x02, // Logical Maximum (23c)
0x95, 0x01, // Report Count (1),
0x75, 0x10, // Report Size (16),
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection
// Standby button
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x80, // Usage (System Control),
0xa1, 0x01, // Collection (Application),
0x85, 0x03, // Report Id (3)
0x19, 0x81, // Usage Minimum (0x81),
0x29, 0x83, // Usage Maximum (0x83),
0x25, 0x01, // Logical Maximum(1),
0x75, 0x01, // Report Size (1),
0x95, 0x03, // Report Count (3),
0x81, 0x02, // Input
0x95, 0x05, // Report Count (5),
0x81, 0x01, // Input (Constant),
0xc0 // End Collection
};
//
// The mapping table translates from what the irbus driver gives us into a
// HID report to return to hidclass. The hid report is of the correct length
// according to what the registry told us (device key).
//
USAGE_TABLE_ENTRY HidIrMappingTable[] = {
{ 0x00001808, {0x01,0x00,0x1e}}, // 1
{ 0x00001828, {0x01,0x00,0x1f}}, // 2
{ 0x00001818, {0x01,0x00,0x20}}, // 3
{ 0x0000182b, {0x01,0x02,0x20}}, // # (shift+3)
{ 0x00001804, {0x01,0x00,0x21}}, // 4
{ 0x00001824, {0x01,0x00,0x22}}, // 5
{ 0x00001814, {0x01,0x00,0x23}}, // 6
{ 0x0000180c, {0x01,0x00,0x24}}, // 7
{ 0x0000182c, {0x01,0x00,0x25}}, // 8
{ 0x00000001, {0x01,0x00,0x55}}, // Numpad *
{ 0x0000181c, {0x01,0x00,0x26}}, // 9
{ 0x00001822, {0x01,0x00,0x27}}, // 0
{ 0x00001836, {0x01,0x00,0x28}}, // return
{ 0x0000000B, {0x01,0x04,0x29}}, // alt+escape
{ 0x0000182b, {0x01,0x00,0x2a}}, // delete (backspace)
{ 0x00001806, {0x01,0x00,0x2b}}, // tab
{ 0x0000180e, {0x01,0x02,0x2b}}, // shift+tab
{ 0x00001826, {0x01,0x00,0x4b}}, // page up
{ 0x0000182e, {0x01,0x00,0x4e}}, // page down
{ 0x0000181e, {0x01,0x00,0x51}}, // down
{ 0x00001816, {0x01,0x00,0x52}}, // up
{ 0x0000181a, {0x01,0x00,0x65}}, // context
{ 0x00001813, {0x02,0x09,0x02}}, // AC Properties
{ 0x00001800, {0x02,0x24,0x02}}, // AC Back
{ 0x0000180a, {0x02,0x2a,0x02}}, // AC favorites
{ 0x00001823, {0x02,0x30,0x02}}, // AC full screen
{ 0x00001830, {0x02,0xb0,0x00}}, // AC Media play
{ 0x00001830, {0x02,0xb1,0x00}}, // AC Media pause
{ 0x0000183e, {0x02,0xb2,0x00}}, // AC Media record
{ 0x00001829, {0x02,0xb3,0x00}}, // AC FF
{ 0x00001838, {0x02,0xb4,0x00}}, // AC RW
{ 0x00001831, {0x02,0xb5,0x00}}, // AC Media next track
{ 0x00001811, {0x02,0xb6,0x00}}, // AC Media previous track
{ 0x00001821, {0x02,0xb7,0x00}}, // AC Media Stop
{ 0x0000000B, {0x02,0xe9,0x00}}, // AC volume up
{ 0x0000000B, {0x02,0xea,0x00}}, // AC volume down
{ 0x0000000B, {0x02,0xe2,0x00}}, // AC volume mute
{ 0x00001803, {0x02,0x8d,0x00}}, // AC select program guide
{ 0x00001801, {0x02,0x9c,0x00}}, // AC channel up
{ 0x0000183c, {0x02,0x9d,0x00}}}; // AC channel down
*/
NTSTATUS
HidIrRemoveDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
HidIrCleanupDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
HidIrStopDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
HidIrStopCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
HidIrStartCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
HidIrInitDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
HidIrStartDevice(
IN PDEVICE_OBJECT DeviceObject
);
#ifdef ALLOC_PRAGMA
// NOTE: Every single function in this file is pageable.
#pragma alloc_text(PAGE, HidIrStartDevice)
#pragma alloc_text(PAGE, HidIrPnP)
#pragma alloc_text(PAGE, HidIrRemoveDevice)
#pragma alloc_text(PAGE, HidIrCleanupDevice)
#pragma alloc_text(PAGE, HidIrStopDevice)
#pragma alloc_text(PAGE, HidIrStopCompletion)
#pragma alloc_text(PAGE, HidIrStartCompletion)
#pragma alloc_text(PAGE, HidIrInitDevice)
#endif
NTSTATUS
HidIrStartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Begins initialization a given instance of a HID device. Work done here occurs before
the parent node gets to do anything.
Arguments:
DeviceObject - pointer to the device object for this instance.
Return Value:
NT status code
--*/
{
PHIDIR_EXTENSION devExt;
NTSTATUS ntStatus = STATUS_SUCCESS;
ULONG oldDeviceState;
PAGED_CODE();
// Get a pointer to the device extension
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
HidIrKdPrint((3, "HidIrStartDevice devExt = %x", devExt));
// Start the device
oldDeviceState = devExt->DeviceState;
devExt->DeviceState = DEVICE_STATE_STARTING;
KeResetEvent(&devExt->AllRequestsCompleteEvent);
if ((oldDeviceState == DEVICE_STATE_STOPPING) ||
(oldDeviceState == DEVICE_STATE_STOPPED) ||
(oldDeviceState == DEVICE_STATE_REMOVING)){
/*
* We did an extra decrement when the device was stopped.
* Now that we're restarting, we need to bump it back to zero.
*/
NTSTATUS incStat = HidIrIncrementPendingRequestCount(devExt);
ASSERT(NT_SUCCESS(incStat));
ASSERT(devExt->NumPendingRequests == 0);
HidIrKdPrint((2, "Got start-after-stop; re-incremented pendingRequestCount"));
}
HidIrKdPrint((3, "HidIrStartDevice Exit = %x", ntStatus));
return ntStatus;
}
NTSTATUS
HidIrQueryDeviceKey (
IN HANDLE Handle,
IN PWCHAR ValueNameString,
OUT PVOID *Data,
OUT ULONG *DataLength
)
{
NTSTATUS status;
UNICODE_STRING valueName;
ULONG length;
KEY_VALUE_FULL_INFORMATION info;
ASSERT(Data);
ASSERT(DataLength);
// Init
*Data = NULL;
*DataLength = 0;
RtlInitUnicodeString (&valueName, ValueNameString);
status = ZwQueryValueKey (Handle,
&valueName,
KeyValueFullInformation,
&info,
sizeof(info),
&length);
if (STATUS_BUFFER_TOO_SMALL == status ||
STATUS_BUFFER_OVERFLOW == status) {
PKEY_VALUE_FULL_INFORMATION fullInfo;
fullInfo = ALLOCATEPOOL (PagedPool, length);
if (fullInfo) {
status = ZwQueryValueKey (Handle,
&valueName,
KeyValueFullInformation,
fullInfo,
length,
&length);
if (NT_SUCCESS(status)) {
*DataLength = fullInfo->DataLength;
*Data = ALLOCATEPOOL (NonPagedPool, fullInfo->DataLength);
if (*Data) {
RtlCopyMemory (*Data,
((PUCHAR) fullInfo) + fullInfo->DataOffset,
fullInfo->DataLength);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
ExFreePool (fullInfo);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
} else if (NT_SUCCESS(status)) {
HIR_TRAP(); // we didn't alloc any space. This is bad.
status = STATUS_UNSUCCESSFUL;
}
return status;
}
#define HIDIR_REPORT_LENGTH L"ReportLength"
#define HIDIR_REPORT_DESCRIPTOR L"ReportDescriptor"
#define HIDIR_MAPPING_TABLE L"ReportMappingTable"
#define HIDIR_VENDOR_ID L"VendorID"
#define HIDIR_PRODUCT_ID L"ProductID"
NTSTATUS
HidIrInitDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Get the device information and attempt to initialize a configuration
for a device. If we cannot identify this as a valid HID device or
configure the device, our start device function is failed.
Arguments:
DeviceObject - pointer to a device object.
Return Value:
NT status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PHIDIR_EXTENSION devExt;
PHID_DEVICE_EXTENSION hidExtension;
HANDLE devInstRegKey = NULL;
ULONG dataLen;
PAGED_CODE();
HidIrKdPrint((3, "HidIrInitDevice Entry"));
hidExtension = DeviceObject->DeviceExtension;
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
devExt->HidDescriptor = HidIrHidDescriptor;
status = IoOpenDeviceRegistryKey (hidExtension->PhysicalDeviceObject,
PLUGPLAY_REGKEY_DEVICE,
STANDARD_RIGHTS_READ,
&devInstRegKey);
if (NT_SUCCESS (status)) {
PULONG reportLength;
status = HidIrQueryDeviceKey (devInstRegKey,
HIDIR_REPORT_LENGTH,
&reportLength,
&dataLen);
if (NT_SUCCESS (status)) {
if (dataLen == sizeof(ULONG)) {
devExt->ReportLength = *reportLength;
} else {
status = STATUS_INVALID_BUFFER_SIZE;
}
ExFreePool(reportLength);
}
}
if (NT_SUCCESS(status)) {
status = HidIrQueryDeviceKey (devInstRegKey,
HIDIR_REPORT_DESCRIPTOR,
&devExt->ReportDescriptor,
&dataLen);
if (NT_SUCCESS(status)) {
ASSERT(dataLen);
devExt->HidDescriptor.DescriptorList[0].wDescriptorLength = (USHORT)dataLen;
}
}
if (NT_SUCCESS(status)) {
PULONG vendorID;
status = HidIrQueryDeviceKey (devInstRegKey,
HIDIR_VENDOR_ID,
&vendorID,
&dataLen);
if (NT_SUCCESS (status)) {
if (dataLen == sizeof(ULONG)) {
devExt->VendorID = (USHORT)*vendorID;
} else {
status = STATUS_INVALID_BUFFER_SIZE;
}
ExFreePool(vendorID);
}
}
if (NT_SUCCESS(status)) {
PULONG productID;
status = HidIrQueryDeviceKey (devInstRegKey,
HIDIR_PRODUCT_ID,
&productID,
&dataLen);
if (NT_SUCCESS (status)) {
if (dataLen == sizeof(ULONG)) {
devExt->ProductID = (USHORT)*productID;
} else {
status = STATUS_INVALID_BUFFER_SIZE;
}
ExFreePool(productID);
}
}
if (NT_SUCCESS (status)) {
PUCHAR mappingTable;
status = HidIrQueryDeviceKey (devInstRegKey,
HIDIR_MAPPING_TABLE,
&mappingTable,
&dataLen);
if (NT_SUCCESS(status)) {
ULONG i;
ULONG entrySize = HIDIR_TABLE_ENTRY_SIZE(devExt->ReportLength);
ASSERT(dataLen > sizeof(ULONG)+devExt->ReportLength); // at least one entry
ASSERT((dataLen % (sizeof(ULONG)+devExt->ReportLength)) == 0); // not malformed data
// This will round down for malformed data.
devExt->NumUsages = dataLen / (sizeof(ULONG)+devExt->ReportLength);
// I have to do all this for 64-bit.
devExt->MappingTable = ALLOCATEPOOL(NonPagedPool, devExt->NumUsages*entrySize);
if (devExt->MappingTable) {
// Fill in the table
for (i = 0; i < devExt->NumUsages; i++) {
RtlCopyMemory(devExt->MappingTable+(entrySize*i),
mappingTable+((sizeof(ULONG)+devExt->ReportLength)*i),
sizeof(ULONG));
RtlCopyMemory(devExt->MappingTable+(entrySize*i)+sizeof(ULONG),
mappingTable+((sizeof(ULONG)+devExt->ReportLength)*i)+sizeof(ULONG),
devExt->ReportLength);
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
ExFreePool(mappingTable);
}
}
if (devInstRegKey) {
ZwClose(devInstRegKey);
}
if (NT_SUCCESS(status)) {
HIDP_DEVICE_DESC deviceDesc; // 0x30 bytes
// Find the keyboard and standby button collections and their associated report IDs.
ASSERT(!devExt->KeyboardReportIdValid);
if (NT_SUCCESS(HidP_GetCollectionDescription(
devExt->ReportDescriptor,
devExt->HidDescriptor.DescriptorList[0].wDescriptorLength,
NonPagedPool,
&deviceDesc))) {
ULONG i,j;
UCHAR nCollectionKbd, nCollectionStandby;
BOOLEAN foundKbd = FALSE, foundStandby = FALSE;
for (i = 0; i < deviceDesc.CollectionDescLength; i++) {
PHIDP_COLLECTION_DESC collection = &deviceDesc.CollectionDesc[i];
if (collection->UsagePage == HID_USAGE_PAGE_GENERIC &&
(collection->Usage == HID_USAGE_GENERIC_KEYBOARD ||
collection->Usage == HID_USAGE_GENERIC_KEYPAD)) {
// Found the collection, onto the report id!
nCollectionKbd = collection->CollectionNumber;
foundKbd = TRUE;
} else if (collection->UsagePage == HID_USAGE_PAGE_GENERIC &&
collection->Usage == HID_USAGE_GENERIC_SYSTEM_CTL) {
nCollectionStandby = collection->CollectionNumber;
foundStandby = TRUE;
}
}
for (j = 0; j < deviceDesc.ReportIDsLength; j++) {
if (foundKbd && deviceDesc.ReportIDs[j].CollectionNumber == nCollectionKbd) {
// I make the assumption that there is only one report id on this collection.
devExt->KeyboardReportId = deviceDesc.ReportIDs[j].ReportID;
devExt->KeyboardReportIdValid = TRUE;
} else if (foundStandby && deviceDesc.ReportIDs[j].CollectionNumber == nCollectionStandby) {
// I make the assumption that there is only one report id on this collection.
devExt->StandbyReportId = deviceDesc.ReportIDs[j].ReportID;
devExt->StandbyReportIdValid = TRUE;
}
}
HidP_FreeCollectionDescription(&deviceDesc);
}
}
return status;
}
NTSTATUS
HidIrStartCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Completes initialization a given instance of a HID device. Work done here occurs
after the parent node has done its StartDevice.
Arguments:
DeviceObject - pointer to the device object for this instance.
Return Value:
NT status code
--*/
{
PHIDIR_EXTENSION devExt;
NTSTATUS ntStatus;
PAGED_CODE();
HidIrKdPrint((3, "HidIrStartCompletion Enter"));
//
// Get a pointer to the device extension
//
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
devExt->DeviceState = DEVICE_STATE_RUNNING;
HidIrKdPrint((3, "DeviceObject (%x) was started!", DeviceObject));
ntStatus = HidIrInitDevice(DeviceObject);
if(NT_SUCCESS(ntStatus)) {
HidIrKdPrint((3, "DeviceObject (%x) was configured!", DeviceObject));
} else {
HidIrKdPrint((1, "'HIDIR.SYS: DeviceObject (%x) configuration failed!", DeviceObject));
devExt->DeviceState = DEVICE_STATE_STOPPING;
}
HidIrKdPrint((3, "HidIrStartCompletion Exit = %x", ntStatus));
return ntStatus;
}
NTSTATUS
HidIrStopDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Stops a given instance of a device. Work done here occurs before the parent
does its stop device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PHIDIR_EXTENSION devExt;
PAGED_CODE();
HidIrKdPrint((3, "HidIrStopDevice Enter"));
//
// Get a pointer to the device extension
//
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
HidIrKdPrint((3, "DeviceExtension = %x", devExt));
devExt->DeviceState = DEVICE_STATE_STOPPING;
HidIrDecrementPendingRequestCount(devExt);
KeWaitForSingleObject( &devExt->AllRequestsCompleteEvent,
Executive,
KernelMode,
FALSE,
NULL );
//
// Stop the device
//
HidIrKdPrint((3, "HidIrStopDevice = %x", ntStatus));
return ntStatus;
}
VOID
HidIrFreeResources(
PHIDIR_EXTENSION DevExt
)
{
PAGED_CODE();
if (DevExt->ReportDescriptor) {
ExFreePool(DevExt->ReportDescriptor);
DevExt->ReportDescriptor = NULL;
}
if (DevExt->MappingTable) {
ExFreePool(DevExt->MappingTable);
DevExt->MappingTable = NULL;
}
DevExt->KeyboardReportIdValid = FALSE;
DevExt->StandbyReportIdValid = FALSE;
}
NTSTATUS
HidIrStopCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Stops a given instance of a device. Work done here occurs after the parent
has done its stop device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
PHIDIR_EXTENSION devExt;
NTSTATUS ntStatus;
PAGED_CODE();
HidIrKdPrint((3, "HidIrStopCompletion Enter"));
//
// Get a pointer to the device extension
//
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
HidIrKdPrint((3, "DeviceExtension = %x", devExt));
ntStatus = Irp->IoStatus.Status;
if(NT_SUCCESS(ntStatus)) {
HidIrKdPrint((3, "DeviceObject (%x) was stopped!", DeviceObject));
} else {
//
// The PnP call failed!
//
HidIrKdPrint((3, "DeviceObject (%x) failed to stop!", DeviceObject));
}
HidIrFreeResources(devExt);
devExt->DeviceState = DEVICE_STATE_STOPPED;
HidIrKdPrint((3, "HidIrStopCompletion Exit = %x", ntStatus));
return ntStatus;
}
NTSTATUS
HidIrCleanupDevice(
IN PDEVICE_OBJECT DeviceObject
)
{
PHIDIR_EXTENSION devExt;
ULONG oldDeviceState;
PAGED_CODE();
HidIrKdPrint((3, "HidIrCleanupDevice Enter"));
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
oldDeviceState = devExt->DeviceState;
devExt->DeviceState = DEVICE_STATE_REMOVING;
if (devExt->QueryRemove) {
// We are severing our relationship with this device
// through a disable/uninstall in device manager.
// If the device is virtually cabled, we must "unplug"
// that device so that it can go elsewhere.
}
if (oldDeviceState == DEVICE_STATE_RUNNING) {
HidIrDecrementPendingRequestCount(devExt);
} else {
ASSERT( devExt->NumPendingRequests == -1 );
}
return STATUS_SUCCESS;
}
NTSTATUS
HidIrRemoveDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
Removes a given instance of a device.
Arguments:
DeviceObject - pointer to the device object.
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PHIDIR_EXTENSION devExt;
PAGED_CODE();
HidIrKdPrint((3, "HidIrRemoveDevice Enter"));
//
// Get a pointer to the device extension
//
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
HidIrKdPrint((3, "DeviceExtension = %x", devExt));
HidIrCleanupDevice(DeviceObject);
KeWaitForSingleObject( &devExt->AllRequestsCompleteEvent,
Executive,
KernelMode,
FALSE,
NULL );
KeCancelTimer( &devExt->IgnoreStandbyTimer );
HidIrFreeResources(devExt);
ASSERT(devExt->NumPendingRequests == -1);
HidIrKdPrint((3, "HidIrRemoveDevice = %x", ntStatus));
return ntStatus;
}
NTSTATUS
HidIrPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the PnP IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code.
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
PIO_STACK_LOCATION IrpStack;
PIO_STACK_LOCATION NextStack;
PHIDIR_EXTENSION devExt;
PAGED_CODE();
//
// Get a pointer to the device extension
//
devExt = GET_MINIDRIVER_HIDIR_EXTENSION(DeviceObject);
//
// Get a pointer to the current location in the Irp
//
IrpStack = IoGetCurrentIrpStackLocation (Irp);
HidIrKdPrint((3, "HidIrPnP fn %x DeviceObject = %x DeviceExtension = %x", IrpStack->MinorFunction, DeviceObject, devExt));
switch(IrpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
ntStatus = HidIrStartDevice(DeviceObject);
break;
case IRP_MN_STOP_DEVICE:
ntStatus = HidIrStopDevice(DeviceObject);
break;
case IRP_MN_SURPRISE_REMOVAL:
ntStatus = HidIrCleanupDevice(DeviceObject);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
devExt->QueryRemove = TRUE;
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
devExt->QueryRemove = FALSE;
break;
case IRP_MN_REMOVE_DEVICE:
ntStatus = HidIrRemoveDevice(DeviceObject);
break;
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = HidIrCallDriverSynchronous(DeviceObject, Irp);
switch(IrpStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
if (NT_SUCCESS(ntStatus)) {
ntStatus = HidIrStartCompletion(DeviceObject, Irp);
Irp->IoStatus.Status = ntStatus;
}
if (!NT_SUCCESS(ntStatus)) {
HidIrDecrementPendingRequestCount(devExt);
}
break;
case IRP_MN_STOP_DEVICE:
ntStatus = HidIrStopCompletion(DeviceObject, Irp);
break;
default:
break;
}
}
// Set the status of the Irp
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
HidIrKdPrint((3, "HidIrPnP Exit status %x", ntStatus));
return ntStatus;
}