915 lines
25 KiB
C
915 lines
25 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|