cca6867c创建于 2019年12月23日历史提交
// Queue.c: This file contains the queue entry points and callbacks.

#include <driver.h>
#include "queue.tmh"

NTSTATUS
AmtPtpDeviceQueueInitialize(
	_In_ WDFDEVICE Device
)
{

	WDFQUEUE queue;
	NTSTATUS status;
	WDF_IO_QUEUE_CONFIG    queueConfig;
	PDEVICE_CONTEXT	       deviceContext;

	deviceContext = DeviceGetContext(Device);

	//
	// Configure a default queue so that requests that are not
	// configure-fowarded using WdfDeviceConfigureRequestDispatching to goto
	// other queues get dispatched here.
	//
	WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(
		&queueConfig,
		WdfIoQueueDispatchParallel
	);

	queueConfig.EvtIoDeviceControl = AmtPtpDeviceEvtIoDeviceControl;
	queueConfig.EvtIoStop = AmtPtpDeviceEvtIoStop;

	status = WdfIoQueueCreate(
		Device,
		&queueConfig,
		WDF_NO_OBJECT_ATTRIBUTES,
		&queue
	);

	if (!NT_SUCCESS(status)) {
		TraceEvents(
			TRACE_LEVEL_ERROR, 
			TRACE_QUEUE, 
			"%!FUNC! WdfIoQueueCreate (Primary) failed %!STATUS!", 
			status
		);
		return status;
	}

	//
	// Create secondary queues for touch and mouse read requests.
	// 

	WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual);
	queueConfig.PowerManaged = WdfFalse;

	status = WdfIoQueueCreate(
		Device,
		&queueConfig,
		WDF_NO_OBJECT_ATTRIBUTES,
		&deviceContext->InputQueue
	);

	if (!NT_SUCCESS(status)) {
		TraceEvents(
			TRACE_LEVEL_ERROR, 
			TRACE_QUEUE, 
			"%!FUNC! WdfIoQueueCreate (Input) failed %!STATUS!", 
			status
		);
		return status;
	}

	return status;

}

_IRQL_requires_(PASSIVE_LEVEL)
PCHAR
DbgIoControlGetString(
	_In_ ULONG IoControlCode
)
{

	switch (IoControlCode)
	{
	case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
		return "IOCTL_HID_GET_DEVICE_DESCRIPTOR";
	case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
		return "IOCTL_HID_GET_DEVICE_ATTRIBUTES";
	case IOCTL_HID_GET_REPORT_DESCRIPTOR:
		return "IOCTL_HID_GET_REPORT_DESCRIPTOR";
	case IOCTL_HID_GET_STRING:
		return "IOCTL_HID_GET_STRING";
	case IOCTL_HID_READ_REPORT:
		return "IOCTL_HID_READ_REPORT";
	case IOCTL_HID_WRITE_REPORT:
		return "IOCTL_HID_WRITE_REPORT";
	case IOCTL_UMDF_HID_GET_INPUT_REPORT:
		return "IOCTL_UMDF_HID_GET_INPUT_REPORT";
	case IOCTL_UMDF_HID_SET_OUTPUT_REPORT:
		return "IOCTL_UMDF_HID_SET_OUTPUT_REPORT";
	case IOCTL_UMDF_HID_GET_FEATURE:
		return "IOCTL_UMDF_HID_GET_FEATURE";
	case IOCTL_UMDF_HID_SET_FEATURE:
		return "IOCTL_UMDF_HID_SET_FEATURE";
	case IOCTL_HID_ACTIVATE_DEVICE:
		return "IOCTL_HID_ACTIVATE_DEVICE";
	case IOCTL_HID_DEACTIVATE_DEVICE:
		return "IOCTL_HID_DEACTIVATE_DEVICE";
	case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
		return "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST";
	default:
		return "IOCTL_UNKNOWN";
	}

}

VOID
AmtPtpDeviceEvtIoDeviceControl(
	_In_ WDFQUEUE Queue,
	_In_ WDFREQUEST Request,
	_In_ size_t OutputBufferLength,
	_In_ size_t InputBufferLength,
	_In_ ULONG IoControlCode
)
{
	
	NTSTATUS status = STATUS_SUCCESS;
	WDFDEVICE device = WdfIoQueueGetDevice(Queue);
	BOOLEAN requestPending = FALSE;

	TraceEvents(
		TRACE_LEVEL_INFORMATION,
		TRACE_QUEUE,
		"%!FUNC!: Queue 0x%p, Request 0x%p OutputBufferLength %d InputBufferLength %d IoControlCode %d",
		Queue, 
		Request, 
		(int) OutputBufferLength, 
		(int) InputBufferLength, 
		IoControlCode
	);

	switch (IoControlCode)
	{
		case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
			status = AmtPtpGetHidDescriptor(
				device, 
				Request
			);
			break;
		case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
			status = AmtPtpGetDeviceAttribs(
				device, 
				Request
			);
			break;
		case IOCTL_HID_GET_REPORT_DESCRIPTOR:
			status = AmtPtpGetReportDescriptor(
				device, 
				Request
			);
			break;
		case IOCTL_HID_GET_STRING:
			status = AmtPtpGetStrings(
				device, 
				Request
			);
			break;
		case IOCTL_HID_READ_REPORT:
			status = AmtPtpDispatchReadReportRequests(
				device, 
				Request, 
				&requestPending
			);
			break;
		case IOCTL_UMDF_HID_GET_FEATURE:
			status = AmtPtpReportFeatures(
				device, 
				Request
			);
			break;
		case IOCTL_UMDF_HID_SET_FEATURE:
			status = AmtPtpSetFeatures(
				device, 
				Request
			);
			break;
		case IOCTL_HID_WRITE_REPORT:
		case IOCTL_UMDF_HID_SET_OUTPUT_REPORT:
		case IOCTL_UMDF_HID_GET_INPUT_REPORT:
		case IOCTL_HID_ACTIVATE_DEVICE:
		case IOCTL_HID_DEACTIVATE_DEVICE:
		case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
		default:
			status = STATUS_NOT_SUPPORTED;
			TraceEvents(
				TRACE_LEVEL_WARNING, 
				TRACE_QUEUE, 
				"%!FUNC!: %s is not yet implemented", 
				DbgIoControlGetString(IoControlCode)
			);
			break;
	}

	if (requestPending != TRUE) {
		WdfRequestComplete(
			Request, 
			status
		);
	}

	return;
}

VOID
AmtPtpDeviceEvtIoStop(
	_In_ WDFQUEUE Queue,
	_In_ WDFREQUEST Request,
	_In_ ULONG ActionFlags
)
{

	TraceEvents(
		TRACE_LEVEL_INFORMATION,
		TRACE_QUEUE,
		"%!FUNC! Queue 0x%p, Request 0x%p ActionFlags %d",
		Queue, 
		Request, 
		ActionFlags
	);

	//
	// In most cases, the EvtIoStop callback function completes, cancels, or postpones
	// further processing of the I/O request.
	//
	// Typically, the driver uses the following rules:
	//
	// - If the driver owns the I/O request, it either postpones further processing
	//   of the request and calls WdfRequestStopAcknowledge, or it calls WdfRequestComplete
	//   with a completion status value of STATUS_SUCCESS or STATUS_CANCELLED.
	//  
	//   The driver must call WdfRequestComplete only once, to either complete or cancel
	//   the request. To ensure that another thread does not call WdfRequestComplete
	//   for the same request, the EvtIoStop callback must synchronize with the driver's
	//   other event callback functions, for instance by using interlocked operations.
	//
	// - If the driver has forwarded the I/O request to an I/O target, it either calls
	//   WdfRequestCancelSentRequest to attempt to cancel the request, or it postpones
	//   further processing of the request and calls WdfRequestStopAcknowledge.
	//
	// A driver might choose to take no action in EvtIoStop for requests that are
	// guaranteed to complete in a small amount of time. For example, the driver might
	// take no action for requests that are completed in one of the driver�s request handlers.
	//

	return;

}

NTSTATUS
AmtPtpDispatchReadReportRequests(
	_In_ WDFDEVICE Device,
	_In_ WDFREQUEST Request,
	_Out_ BOOLEAN *Pending
)
{

	NTSTATUS status;
	PDEVICE_CONTEXT devContext;

	status = STATUS_SUCCESS;
	devContext = DeviceGetContext(Device);

	status = WdfRequestForwardToIoQueue(
		Request, 
		devContext->InputQueue
	);
	

	if (!NT_SUCCESS(status)) {
		TraceEvents(
			TRACE_LEVEL_ERROR, 
			TRACE_DRIVER, 
			"%!FUNC! WdfRequestForwardToIoQueue failed with %!STATUS!", 
			status
		);
		return status;
	} else {
		TraceEvents(
			TRACE_LEVEL_INFORMATION, 
			TRACE_DRIVER,
			"%!FUNC! A report has been forwarded to input queue"
		);
	}

	if (NULL != Pending) {
		*Pending = TRUE;
	}

	return status;

}