📄 device.cpp
字号:
if(p_irp_stack->Parameters.Power.State.DeviceState == PowerDeviceD3)
{
//Process the IRP
PDEVICE_EXTENSION p_device_extension =
GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);
p_device_extension->p_device->powerDown();
//Pass the IRP to the lower device
PoStartNextPowerIrp(p_irp);
IoCopyCurrentIrpStackLocationToNext(p_irp);
return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp);
}
//If it's a power up, we pass it to the lower device first and
// handle it in the completion routine. Power IRPs must be handled asynchronously
else if (p_irp_stack->Parameters.Power.State.DeviceState == PowerDeviceD0)
{
PIO_STACK_LOCATION p_next_stack = IoGetNextIrpStackLocation(p_irp);
//Copy the stack location to the next one
RtlCopyMemory(
p_next_stack,
p_irp_stack,
FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
//Set the completion routing
IoSetCompletionRoutine(
p_irp,
Device::static_powerUpCompletion,
NULL, // completion context
TRUE, // call on success
TRUE, // call on failure
TRUE ); // call on cancel
//Pass it to the lower device
return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp);
}
}
//We didn't handle it. Pass it down.
PoStartNextPowerIrp(p_irp);
IoCopyCurrentIrpStackLocationToNext(p_irp);
return PoCallDriver(GET_NEXT_DEVICE_OBJECT(p_device_object), p_irp);
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_powerUpCompletion
//
// This is the completion routine for static_power() when we receive a request to set the
// power to PowerDeviceD0 (powered on.) This routine should process the IRP, and then
// return the IRP's status.
//
NTSTATUS Device::static_powerUpCompletion(
PDEVICE_OBJECT p_device_object,
IN PIRP p_irp,
IN PVOID p_context)
{
//Get the device extension
PDEVICE_EXTENSION p_device_extension =
GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);
p_device_extension->p_device->powerUp();
PoStartNextPowerIrp(p_irp);
return p_irp->IoStatus.Status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_internalDeviceControl
//
// This is the DDK entry point for IRP_MJ_INTERNAL_DEVICE_CONTROL. We simply call
// the non-static Device::internalDeviceControl here.
//
NTSTATUS Device::static_internalDeviceControl(
PDEVICE_OBJECT p_device_object,
PIRP p_irp)
{
PDEVICE_EXTENSION deviceExtension = GET_MINIDRIVER_DEVICE_EXTENSION(p_device_object);
if(deviceExtension->p_device)
{
return deviceExtension->p_device->internalDeviceControl(p_irp);
}
//No device object. Fail the IRP.
p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
return STATUS_NO_SUCH_DEVICE;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::internalDeviceControl
//
// This is the handler for IRP_MJ_INTERNAL_DEVICE_CONTROL. For an HID mini-driver, the
// only IRPs received here are HID commands. We do HID processing in class HidProcessing.
// That class handles filling in the correct HID descriptors, and queuing, cancelling, and
// completing report requests.
//
// Note that we do not send it report requests if the device is not running. We do allow
// it to send back HID descriptors when the device is not started, however.
//
NTSTATUS Device::internalDeviceControl(PIRP p_irp)
{
if(_device_state == DEVICE_STATE_RUNNING)
{
//All internal device control requests are HID requests and should be processed by
//HID class
return _hid.processHidIoctl(p_irp);
}
else
{
//Don't send IRPs to HID if we aren't running
p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
return STATUS_NO_SUCH_DEVICE;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::passIrpDownSync
//
// This is a typical synchronous IRP calldown function.
//
// As is usual, the idea is to create an event that may be signalled when the IRP completes.
// Then pass the IRP down and wait on the event. This is done by setting a stub completion
// routine on the IRP and passing it a pointer to the IRP as context.
//
// Our completion routine is static_syncIrpCompletion()
//
// The completion routine returns STATUS_MORE_PROCESSING_REQUIRED which means that we can
// still touch the IRP when it comes back, but that we need to call IoCompleteRequest when
// we are done with it.
//
// Note that this is not the case if the IRP fails. In this case, we complete the IRP
// and return the failure status.
//
// THE USER MAY ONLY TOUCH THE IRP AFTER CALLING THIS ROUTINE IF IT RETURNS STATUS_SUCCESS.
//
NTSTATUS Device::passIrpDownSync(PIRP p_irp)
{
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
PIO_STACK_LOCATION current_stack = IoGetCurrentIrpStackLocation(p_irp);
PIO_STACK_LOCATION next_stack = IoGetNextIrpStackLocation(p_irp);
ASSERT(next_stack != NULL);
//Copy the stack location to the next one
RtlCopyMemory(
next_stack,
current_stack,
FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine));
//An event to wait on for when the IRP completes
KEVENT wait_event;
KeInitializeEvent(
&wait_event,
NotificationEvent,
TRUE );
//Set the completion routing
IoSetCompletionRoutine(
p_irp,
Device::static_syncIrpCompletion,
&wait_event, // completion context
TRUE, // call on success
TRUE, // call on failure
TRUE ); // call on cancel
NTSTATUS status = IoCallDriver(GET_NEXT_DEVICE_OBJECT(_p_device_object), p_irp);
if(status == STATUS_PENDING)
{
//Wait for the completion routine to signal the event.
KeWaitForSingleObject(
&wait_event,
Executive,
KernelMode,
TRUE,
NULL);
status = p_irp->IoStatus.Status;
}
if(!NT_SUCCESS(status))
{
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
}
return status;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::static_syncIrpCompletion
//
// This is the completion routine for passIrpDownSync(), and signals the event to let
// passIrpSync() know that the IRP is complete.
//
NTSTATUS Device::static_syncIrpCompletion(
PDEVICE_OBJECT p_device_object,
IN PIRP p_irp,
IN PVOID p_context)
{
PKEVENT p_event = (PKEVENT) p_context;
KeSetEvent(p_event, 0, FALSE );
return STATUS_MORE_PROCESSING_REQUIRED;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Device::getResources
//
// This is a private helper routine that gets the partial resource descriptors for our
// memory range and interrupt object from the start device IRP.
//
// *p_memory and *p_interrupt should be set to NULL before calling this. They will remain
// NULL if ther resource was not found.
//
VOID Device::getResources(
PIRP p_irp,
PCM_PARTIAL_RESOURCE_DESCRIPTOR* p_memory,
PCM_PARTIAL_RESOURCE_DESCRIPTOR* p_interrupt)
{
PIO_STACK_LOCATION p_irp_stack = IoGetCurrentIrpStackLocation(p_irp);
PCM_PARTIAL_RESOURCE_DESCRIPTOR p_partial_raw =
p_irp_stack->Parameters.StartDevice.AllocatedResources->List->PartialResourceList.PartialDescriptors;
PCM_PARTIAL_RESOURCE_DESCRIPTOR p_partial_translated =
p_irp_stack->Parameters.StartDevice.AllocatedResourcesTranslated->List->PartialResourceList.PartialDescriptors;
ULONG resource_count =
p_irp_stack->Parameters.StartDevice.AllocatedResources->List->PartialResourceList.Count;
for (USHORT j = 0; j < resource_count; j++)
{
switch(p_partial_raw->Type)
{
case CmResourceTypeMemory:
//Found our memory resource. There should only be one.
ASSERT(*p_memory == NULL);
*p_memory = p_partial_translated;
break;
case CmResourceTypeInterrupt:
//Found our interrupt resource. There should only be one
ASSERT(*p_interrupt == NULL);
*p_interrupt = p_partial_translated;
break;
default:
//Do nothing if there are any other resources in the list.
// There should not be any.
break;
}
p_partial_raw++;
p_partial_translated++;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::readRegistryDword
//
// Read a DWORD value from the device's "DriverData" registry key.
//
// Parameters
// name - Name of the DWORD to read
//
// p_value - Receives the DWORD value. Remains unchanged if the value didn't exist.
//
// The expected usage is to set the value to it's default, and then call this function
// that will override the default if the registry value exists.
//
VOID
Device::readRegistryDword(PCHAR name, PDWORD p_value)
{
HANDLE key_handle = openDriverKey(KEY_READ);
if(key_handle)
{
UNICODE_STRING key_name;
ANSI_STRING a_key_name;
RtlInitAnsiString(&a_key_name, name);
if(NT_SUCCESS(RtlAnsiStringToUnicodeString(&key_name, &a_key_name, TRUE)))
{
DWORD buffer;
if(NT_SUCCESS(getRegistryValue(key_handle, &key_name, (PCHAR)&buffer, sizeof(buffer))))
{
*p_value = buffer;
}
RtlFreeUnicodeString( &key_name );
}
ZwClose(key_handle);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::openDriverKey
//
// This is a private helper function that opens the driver's registry key.
//
// Parameters
// desired_access - KEY_READ, KEY_WRITE, etc.
//
HANDLE
Device::openDriverKey(ACCESS_MASK desired_access)
{
HANDLE dev_handle = NULL;
NTSTATUS status = IoOpenDeviceRegistryKey(
GET_PDO(_p_device_object),
PLUGPLAY_REGKEY_DRIVER,
STANDARD_RIGHTS_ALL,
&dev_handle);
HANDLE key_handle = NULL;
if (NT_SUCCESS(status))
{
OBJECT_ATTRIBUTES attr;
UNICODE_STRING dev_data_name;
PWCHAR data_name = L"DriverData";
RtlInitUnicodeString(&dev_data_name, data_name);
InitializeObjectAttributes(
&attr,
&dev_data_name,
OBJ_INHERIT,
dev_handle,
NULL);
if(!NT_SUCCESS(ZwOpenKey(&key_handle, desired_access, &attr)))
{
dbgLogInfo(("OpenDriverKey: ZwOpenKey failed!"));
}
if (!NT_SUCCESS(ZwClose(dev_handle)))
{
dbgLogInfo(("OpenDriverKey: ZwClose failed!"));
}
}
return key_handle;
}
/////////////////////////////////////////////////////////////////////////////////////////
//Adapter::getRegistryValue
//
// A private helper function for retreiving values from the registry.
//
// Parameters
// handle - Handle to the registry key
// key_name - Actually the value name
// data - buffer to receive the registry data
// data_length - length of data buffer
//
NTSTATUS
Device::getRegistryValue(
HANDLE handle,
const PUNICODE_STRING key_name,
PCHAR data,
ULONG data_length)
{
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG length = sizeof( KEY_VALUE_FULL_INFORMATION ) + data_length + key_name->MaximumLength;
PKEY_VALUE_FULL_INFORMATION full_info = (struct _KEY_VALUE_FULL_INFORMATION *)ExAllocatePool(PagedPool, length);
if (full_info)
{
status = ZwQueryValueKey(
handle,
key_name,
KeyValueFullInformation,
full_info,
length,
&length);
if (NT_SUCCESS(status))
{
if (data_length >= full_info->DataLength ) {
RtlCopyMemory(
data,
((PUCHAR) full_info) + full_info->DataOffset,
full_info->DataLength );
}
else
{
status = STATUS_BUFFER_TOO_SMALL;
} // buffer right length
} // if success
ExFreePool(full_info);
} // if fullinfo
return status;
}
VOID Device::powerDown()
{
//Notify _p_ir_control to uninitialize so the device stops interrupting.
if(_p_ir_control)
{
_p_ir_control->uninitialize();
}
//Save the power state
_power_state = PowerDeviceD3;
}
VOID Device::powerUp()
{
//Re-initialize IR_Control since the registers get reset when we power down.
if(_p_ir_control)
{
_p_ir_control->initialize();
}
//Save the power state
_power_state = PowerDeviceD0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -