|
|
/*++
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; }
|