📄 hid.cpp
字号:
dbgLogTrace(("IOCTL_HID_READ_REPORT\n"));
ntStatus = readReport(p_irp);
break;
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
dbgLogTrace(("IOCTL_GET_DEVICE_ATTRIBUTES\n"));
ntStatus = getAttributes(p_irp);
break;
case IOCTL_HID_ACTIVATE_DEVICE: //First open of a device
case IOCTL_HID_DEACTIVATE_DEVICE: //Last close of a device
case IOCTL_HID_WRITE_REPORT: //We only handle reads
ntStatus = STATUS_SUCCESS;
break;
case IOCTL_HID_GET_STRING:
case IOCTL_HID_GET_FEATURE:
case IOCTL_HID_SET_FEATURE:
case IOCTL_GET_PHYSICAL_DESCRIPTOR:
default:
dbgLogError(("Unknown or unsupported IOCTL (%x)\n",
IrpStack->Parameters.DeviceIoControl.IoControlCode));
ntStatus = STATUS_NOT_SUPPORTED;
break;
}
// Set return status in Irp
p_irp->IoStatus.Status = ntStatus;
// Complete Irp
if (ntStatus != STATUS_PENDING)
{
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
}
else
{
IoMarkIrpPending(p_irp);
}
dbgLogInfo(("HidMiniIoctl Exit = %x\n", ntStatus));
return ntStatus;
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::getHidDescriptor
//
// This is the handler for IOCTL_HID_GET_DEVICE_DESCRIPTOR. It copies our HID descriptor
// into the user's buffer.
//
NTSTATUS HidProcessing::getHidDescriptor(PIRP p_irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(p_irp);
dbgLogTrace(("HIDCLASS Buffer = 0x%x, Buffer length = 0x%x\n",
p_irp->UserBuffer,
IrpStack->Parameters.DeviceIoControl.OutputBufferLength));
ULONG bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (bytesToCopy > _s_hid_descriptor.bLength)
{
bytesToCopy = _s_hid_descriptor.bLength;
}
dbgLogTrace(("Copying %d bytes to HIDCLASS buffer\n", bytesToCopy));
RtlCopyMemory(
(PUCHAR) p_irp->UserBuffer,
(PUCHAR) &_s_hid_descriptor,
bytesToCopy);
// Report how many bytes were copied
p_irp->IoStatus.Information = bytesToCopy;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::getReportDescriptor
//
// Copies our report descriptor into the buffer in the IRP. This is the handler for
// IOCTL_HID_GET_REPORT_DESCRIPTOR
//
NTSTATUS HidProcessing::getReportDescriptor(PIRP p_irp)
{
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(p_irp);
dbgLogTrace(("HIDCLASS Buffer = 0x%x, Buffer length = 0x%x\n",
p_irp->UserBuffer,
IrpStack->Parameters.DeviceIoControl.OutputBufferLength));
ULONG bytesToCopy = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
if (bytesToCopy > _s_hid_descriptor.wReportLength)
{
bytesToCopy = _s_hid_descriptor.wReportLength;
}
dbgLogTrace(("Copying %d bytes to HIDCLASS buffer\n", bytesToCopy));
RtlCopyMemory((PUCHAR) p_irp->UserBuffer, (PUCHAR) _s_report_descriptor, bytesToCopy);
// Report how many bytes were copied
p_irp->IoStatus.Information = bytesToCopy;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::getAttributes
//
// This is the routine for processing IOCTL_HID_GET_DEVICE_ATTRIBUTES. It just returns
// the vendor and product ID's.
//
NTSTATUS HidProcessing::getAttributes(PIRP p_irp)
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(p_irp);
PHID_DEVICE_ATTRIBUTES deviceAttributes =
(PHID_DEVICE_ATTRIBUTES) p_irp->UserBuffer;
ASSERT (sizeof (HID_DEVICE_ATTRIBUTES) ==
irpStack->Parameters.DeviceIoControl.OutputBufferLength);
// Report how many bytes were copied
p_irp->IoStatus.Information = sizeof (HID_DEVICE_ATTRIBUTES);
deviceAttributes->Size = sizeof (HID_DEVICE_ATTRIBUTES);
deviceAttributes->VendorID = HIDMINI_VID;
deviceAttributes->ProductID = HIDMINI_PID;
deviceAttributes->VersionNumber = HIDMINI_VERSION;
return STATUS_SUCCESS;
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::readReport
//
// This is the function for processing IOCTL_HID_READ_REPORT. This function puts the
// report on its IRP list to be removed and completed when there is a keystroke available.
//
NTSTATUS HidProcessing::readReport(PIRP p_irp)
{
PVOID ReportBuffer = p_irp->UserBuffer;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(p_irp);
ULONG ReportTotalSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
dbgLogTrace(("ReportBuffer = 0x%x, ReportTotalSize = 0x%x\n", ReportBuffer, ReportTotalSize));
if (ReportTotalSize && ReportBuffer)
{
// Increase the count of outstanding IOs.
_request_count.increment();
//Save our object in case the IRP gets canceled
p_irp->Tail.Overlay.DriverContext[0] = this;
//Put the IRP on the read list.
_irp_list.add(p_irp);
//Mark the IRP as cancelable
KIRQL old_irql;
IoAcquireCancelSpinLock(&old_irql);
IoSetCancelRoutine(p_irp, static_readReportCancel);
IoReleaseCancelSpinLock(old_irql);
return STATUS_PENDING;
}
else
{
// No buffer, or buffer of zero size
return STATUS_INVALID_PARAMETER;
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::submitReport
//
// This is a public function called from outside the class when a keystroke is detected
// and the driver needs to notify Windows of it.
//
// p_report - Pointer to the report structure
// report_size - Size of the report structure
//
// There are currently only two types of reports in use, KEYBOARD_USAGE_PAGE_REPORT for
// putting keys in the keyboard buffer, or CONSUMER_USAGE_PAGE_REPORT for generating
// AppCommands. This is a generic function that can send any type of report to the
// system.
//
VOID HidProcessing::submitReport(PVOID p_report, ULONG report_size)
{
//Get an IRP from the read report list
PIRP p_irp = _irp_list.remove();
if(p_irp)
{
//Take the cancel routine off the IRP
KIRQL old_irql;
IoAcquireCancelSpinLock(&old_irql);
PDRIVER_CANCEL p_cancel = IoSetCancelRoutine(p_irp, NULL);
IoReleaseCancelSpinLock(old_irql);
if(!p_cancel)
{
//IRP was cancelled
return;
}
//make sure the buffer is big enough
PIO_STACK_LOCATION p_irp_stack = IoGetCurrentIrpStackLocation(p_irp);
ULONG buffer_size =
p_irp_stack->Parameters.DeviceIoControl.OutputBufferLength;
if(buffer_size >= report_size)
{
p_irp->IoStatus.Status = STATUS_SUCCESS;
p_irp->IoStatus.Information = report_size;
RtlCopyMemory(p_irp->UserBuffer, p_report, report_size);
}
else
{
p_irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
p_irp->IoStatus.Information = 0;
}
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
_request_count.decrement();
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::cancelOutstandingRequests
//
// Cancels all read report IRPs in our queue.
//
VOID HidProcessing::cancelOutstandingRequests()
{
PIRP p_irp = _irp_list.remove();
while(p_irp)
{
//Take the cancel routine off the IRP
KIRQL old_irql;
IoAcquireCancelSpinLock(&old_irql);
PDRIVER_CANCEL p_cancel = IoSetCancelRoutine(p_irp, NULL);
IoReleaseCancelSpinLock(old_irql);
if(p_cancel)
{
//Only complete the request here if the IRP wasn't already canceled
p_irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
_request_count.decrement();
}
p_irp = _irp_list.remove();
}
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::cancelReadReport
//
// Cancel a read report in our queue. HidProcessing holds read reports in a cancelable
// state. This is a typical IRP cancel routine.
//
VOID HidProcessing::cancelReadReport(PIRP p_irp)
{
p_irp->IoStatus.Status = STATUS_CANCELLED;
//Remove the IRP from the queue
_irp_list.remove(p_irp);
//Drop the cancel spinlock
IoReleaseCancelSpinLock(p_irp->CancelIrql);
//Complete the IRP
p_irp->IoStatus.Information = 0;
IoCompleteRequest(p_irp, IO_NO_INCREMENT);
//Decrement the request count);
_request_count.decrement();
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::static_readReportCancel
//
//This is called to cancel a read report IRP. This is the static DDK entry point. It
// just calls the non-static cancelReadReport.
//
VOID HidProcessing::static_readReportCancel(
PDEVICE_OBJECT DeviceObject,
PIRP p_irp)
{
HidProcessing* p_this =
(HidProcessing*) p_irp->Tail.Overlay.DriverContext[0];
p_this->cancelReadReport(p_irp);
}
/////////////////////////////////////////////////////////////////////////////////////////
//HidProcessing::~HidProcessing (destructer)
//
// Make sure we aren't holding and HID read report requests before we exit.
//
HidProcessing::~HidProcessing()
{
//Make sure we aren't holding any read reports
cancelOutstandingRequests();
_request_count.wait();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -