⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 control.cpp

📁 一本在讲述USB驱动程式的书 及其范例原码
💻 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 + -