📄 control.cpp
字号:
// Control.cpp -- IOCTL handlers for hidfake driver
// Copyright (C) 1999, 2000 by Walter Oney
// All rights reserved
#include "stddcls.h"
#include "driver.h"
#include "version.h"
#include "FeatureReports.h"
// The faux HID descriptor we use originates in DT.EXE (The HID descriptor
// tool from usb.org), which saves the header file we use here. Note that
// ReportDescriptor.hid, the internal representation of the descriptor, is
// part of the project but doesn't participate directly in the build.
unsigned // mates with "char" at start of the following...
#include "ReportDescriptor.h" // generated by dt.exe from ReportDescriptor.hid
///////////////////////////////////////////////////////////////////////////////
// The DispatchInternalControl callback for a HID minidriver is the primary
// way we have of communicating with the outside world.
#pragma LOCKEDCODE
NTSTATUS DispatchInternalControl(PDEVICE_OBJECT fdo, PIRP Irp)
{ // DispatchInternalControl
PDEVICE_EXTENSION pdx = PDX(fdo);
NTSTATUS status = STATUS_SUCCESS;
ULONG info = 0;
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
ULONG cbin = stack->Parameters.DeviceIoControl.InputBufferLength;
ULONG cbout = stack->Parameters.DeviceIoControl.OutputBufferLength;
ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
PVOID buffer = Irp->UserBuffer; // most codes use METHOD_NEITHER
switch (code)
{ // process HIDCLASS request
///////////////////////////////////////////////////////////////////////////
// IOCTL_HID_GET_DEVICE_DESCRIPTOR gets descriptor information about the
// device. With a USB device, this would be the standard HID class descriptor.
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
{ // IOCTL_HID_GET_DEVICE_DESCRIPTOR
KdPrint((DRIVERNAME " - IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"));
#define p ((PHID_DESCRIPTOR) buffer)
if (cbout < sizeof(HID_DESCRIPTOR))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
// Construct a dummy HID descriptor as from a USB device
RtlZeroMemory(p, sizeof(HID_DESCRIPTOR));
p->bLength = sizeof(HID_DESCRIPTOR);
p->bDescriptorType = HID_HID_DESCRIPTOR_TYPE;
p->bcdHID = HID_REVISION;
p->bCountry = 0; // not localized
p->bNumDescriptors = 1; // 1 report descriptor, no physical descriptor
p->DescriptorList[0].bReportType = HID_REPORT_DESCRIPTOR_TYPE;
p->DescriptorList[0].wReportLength = sizeof(ReportDescriptor);
#undef p
info = sizeof(HID_DESCRIPTOR);
break;
} // IOCTL_HID_GET_DEVICE_DESCRIPTOR
///////////////////////////////////////////////////////////////////////////
// IOCTL_HID_GET_REPORT_DESCRIPTOR gets the report descriptor for the device.
// With a USB device, this would be the standard report descriptor.
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
{ // IOCTL_HID_GET_REPORT_DESCRIPTOR
KdPrint((DRIVERNAME " - IOCTL_HID_GET_REPORT_DESCRIPTOR\n"));
if (cbout < sizeof(ReportDescriptor))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
RtlCopyMemory(buffer, ReportDescriptor, sizeof(ReportDescriptor));
info = sizeof(ReportDescriptor);
break;
} // IOCTL_HID_GET_REPORT_DESCRIPTOR
///////////////////////////////////////////////////////////////////////////
// IOCTL_HID_GET_DEVICE_ATTRIBUTES gets information about the device as a
// whole. With a USB device, this would come from the USB standard device
// descriptor.
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
{ // IOCTL_HID_GET_DEVICE_ATTRIBUTES
KdPrint((DRIVERNAME " - IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"));
if (cbout < sizeof(HID_DEVICE_ATTRIBUTES))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define p ((PHID_DEVICE_ATTRIBUTES) buffer)
// Note: a joystick needs unique vendor and product ids, which must dovetail
// with the subkey name used in the OEM registry. We use dummy values here to
// make it easy for the test applet to find the right collection object.
RtlZeroMemory(p, sizeof(HID_DEVICE_ATTRIBUTES));
p->Size = sizeof(HID_DEVICE_ATTRIBUTES);
p->VendorID = HIDFAKE_VID;
p->ProductID = HIDFAKE_PID;
p->VersionNumber = 1;
#undef p
info = sizeof(HID_DEVICE_ATTRIBUTES);
break;
} // IOCTL_HID_GET_DEVICE_ATTRIBUTES
///////////////////////////////////////////////////////////////////////////
// IOCTL_HID_READ_REPORT retrieves a single report from the device. There will
// be great variability in how you implement this function, depending on many
// factors that are too numerous to elaborate in code. This device has a dummy
// button whose state is continuously reflected in the ButtonDown flag in the
// the device extension.
case IOCTL_HID_READ_REPORT:
{ // IOCTL_HID_READ_REPORT
KdPrint((DRIVERNAME " - IOCTL_HID_READ_REPORT\n"));
if (cbout < sizeof(BUTTON_REPORT))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
// Fill in the report. Note that, since this device has numbered feature
// reports, the HID parser insists that the regular input report have
// an id as well. If you're writing a driver that uses feature reports
// solely for application interfacing, you would need to *add* a report id
// to each input report from the real device. Bit of a pain, actually...
#define p ((PBUTTON_REPORT) buffer)
p->id = 1;
p->Buttons = pdx->ButtonDown;
#undef p
info = sizeof(BUTTON_REPORT);
break;
} // IOCTL_HID_READ_REPORT
///////////////////////////////////////////////////////////////////////////
// IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST asks us to callback to HIDCLASS
// when it is possible or sensible to power down the device. A non-standard
// USB device should forward this IRP down the stack as a regular
// IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION. A non-USB device should
// do what this sample does, namely callback immediately to allow HIDCLASS
// to depower the device.
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
{ // IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST
KdPrint((DRIVERNAME " - IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST\n"));
PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO p = (PHID_SUBMIT_IDLE_NOTIFICATION_CALLBACK_INFO)
stack->Parameters.DeviceIoControl.Type3InputBuffer;
(*p->IdleCallback)(p->IdleContext);
break;
} // IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST
///////////////////////////////////////////////////////////////////////////
// The foregoing are the only IOCTLs that you have to support in a minimal minidriver.
// We also support the following two, which is how the test applet communicates with
// us "out of band"
case IOCTL_HID_GET_FEATURE:
{ // IOCTL_HID_GET_FEATURE
KdPrint((DRIVERNAME " - IOCTL_HID_GET_FEATURE\n"));
if (cbout < sizeof(HID_XFER_PACKET))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define p ((PHID_XFER_PACKET) buffer)
if (p->reportId != FEATURE_CODE_GET_VERSION)
{
status = STATUS_NOT_SUPPORTED;
break;
}
// This driver supports a GetFeature request to return the revision level of the
// driver. Since we are using report ids in our top-level collection, the buffer
// includes a byte for the id. (If we weren't using report ids, the buffer *we* get
// doesn't have the id byte even though HIDCLASS's caller's buffer *does*. Something
// to watch out for...)
if (p->reportBufferLen < sizeof(FEATURE_REPORT_GET_VERSION))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define q ((PFEATURE_REPORT_GET_VERSION) (p->reportBuffer))
ASSERT(q->id == FEATURE_CODE_GET_VERSION);
q->Version = (VERMAJOR << 16) | VERMINOR;
#undef q
#undef p
info = sizeof(FEATURE_REPORT_GET_VERSION);
break;
} // IOCTL_HID_GET_FEATURE
case IOCTL_HID_SET_FEATURE:
{ // IOCTL_HID_SET_FEATURE
KdPrint((DRIVERNAME " - IOCTL_HID_SET_FEATURE\n"));
// Note that *cbin* should be the size of the xfer packet, even though its address
// is at Irp->UserBuffer instead of stack->Parameters.DeviceIoControl.Type3InputBuffer.
// Like the book says, this is a *callback* function rather than a real IRP processor.
if (cbin < sizeof(HID_XFER_PACKET))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define p ((PHID_XFER_PACKET) buffer)
if (p->reportId != FEATURE_CODE_SET_BUTTON)
{
status = STATUS_NOT_SUPPORTED;
break;
}
// This driver supports a SetFeature request to set the state of the fake
// button control
if (p->reportBufferLen < sizeof(FEATURE_REPORT_SET_BUTTON))
{
status = STATUS_BUFFER_TOO_SMALL;
break;
}
#define q ((PFEATURE_REPORT_SET_BUTTON) (p->reportBuffer))
ASSERT(q->id == FEATURE_CODE_SET_BUTTON);
pdx->ButtonDown = q->ButtonDown;
KdPrint((DRIVERNAME " - Simulated button is %s\n", pdx->ButtonDown ? "down" : "up"));
#undef q
#undef p
break;
} // IOCTL_HID_SET_FEATURE
default:
status = STATUS_NOT_SUPPORTED;
break;
} // process HIDCLASS request
if (status != STATUS_PENDING)
CompleteRequest(Irp, status, info);
return status;
} // DispatchInternalControl
#pragma LOCKEDCODE // force inline functions into nonpaged code
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -