static VOID CompleteHIDQueueRequest( PINPUT_DEVICE pContext, PINPUT_CLASS_COMMON pClass) { WDFREQUEST request; NTSTATUS status; if (!pClass->bDirty) { // nothing to do return; } status = WdfIoQueueRetrieveNextRequest(pContext->HidQueue, &request); if (NT_SUCCESS(status)) { status = RequestCopyFromBuffer( request, pClass->pHidReport, pClass->cbHidReportSize); WdfRequestComplete(request, status); if (NT_SUCCESS(status)) { pClass->bDirty = FALSE; } } }
VOID EvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: This event callback function is called when the driver receives an (KMDF) IOCTL_HID_Xxx code when handlng IRP_MJ_INTERNAL_DEVICE_CONTROL (UMDF) IOCTL_HID_Xxx, IOCTL_UMDF_HID_Xxx when handling IRP_MJ_DEVICE_CONTROL Arguments: Queue - A handle to the queue object that is associated with the I/O request Request - A handle to a framework request object. OutputBufferLength - The length, in bytes, of the request's output buffer, if an output buffer is available. InputBufferLength - The length, in bytes, of the request's input buffer, if an input buffer is available. IoControlCode - The driver or system defined IOCTL associated with the request Return Value: NTSTATUS --*/ { NTSTATUS status; BOOLEAN completeRequest = TRUE; WDFDEVICE device = WdfIoQueueGetDevice(Queue); PDEVICE_CONTEXT deviceContext = NULL; PQUEUE_CONTEXT queueContext = GetQueueContext(Queue); UNREFERENCED_PARAMETER (OutputBufferLength); UNREFERENCED_PARAMETER (InputBufferLength); deviceContext = GetDeviceContext(device); switch (IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: // METHOD_NEITHER // // Retrieves the device's HID descriptor. // _Analysis_assume_(deviceContext->HidDescriptor.bLength != 0); status = RequestCopyFromBuffer(Request, &deviceContext->HidDescriptor, deviceContext->HidDescriptor.bLength); break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: // METHOD_NEITHER // //Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure. // status = RequestCopyFromBuffer(Request, &queueContext->DeviceContext->HidDeviceAttributes, sizeof(HID_DEVICE_ATTRIBUTES)); break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: // METHOD_NEITHER // //Obtains the report descriptor for the HID device. // status = RequestCopyFromBuffer(Request, deviceContext->ReportDescriptor, deviceContext->HidDescriptor.DescriptorList[0].wReportLength); break; case IOCTL_HID_READ_REPORT: // METHOD_NEITHER // // Returns a report from the device into a class driver-supplied // buffer. // status = ReadReport(queueContext, Request, &completeRequest); break; case IOCTL_HID_WRITE_REPORT: // METHOD_NEITHER // // Transmits a class driver-supplied report to the device. // status = WriteReport(queueContext, Request); break; #ifdef _KERNEL_MODE case IOCTL_HID_GET_FEATURE: // METHOD_OUT_DIRECT status = GetFeature(queueContext, Request); break; case IOCTL_HID_SET_FEATURE: // METHOD_IN_DIRECT status = SetFeature(queueContext, Request); break; case IOCTL_HID_GET_INPUT_REPORT: // METHOD_OUT_DIRECT status = GetInputReport(queueContext, Request); break; case IOCTL_HID_SET_OUTPUT_REPORT: // METHOD_IN_DIRECT status = SetOutputReport(queueContext, Request); break; #else // UMDF specific // // HID minidriver IOCTL uses HID_XFER_PACKET which contains an embedded pointer. // // typedef struct _HID_XFER_PACKET { // PUCHAR reportBuffer; // ULONG reportBufferLen; // UCHAR reportId; // } HID_XFER_PACKET, *PHID_XFER_PACKET; // // UMDF cannot handle embedded pointers when marshalling buffers between processes. // Therefore a special driver mshidumdf.sys is introduced to convert such IRPs to // new IRPs (with new IOCTL name like IOCTL_UMDF_HID_Xxxx) where: // // reportBuffer - passed as one buffer inside the IRP // reportId - passed as a second buffer inside the IRP // // The new IRP is then passed to UMDF host and driver for further processing. // case IOCTL_UMDF_HID_GET_FEATURE: // METHOD_NEITHER status = GetFeature(queueContext, Request); break; case IOCTL_UMDF_HID_SET_FEATURE: // METHOD_NEITHER status = SetFeature(queueContext, Request); break; case IOCTL_UMDF_HID_GET_INPUT_REPORT: // METHOD_NEITHER status = GetInputReport(queueContext, Request); break; case IOCTL_UMDF_HID_SET_OUTPUT_REPORT: // METHOD_NEITHER status = SetOutputReport(queueContext, Request); break; #endif // _KERNEL_MODE case IOCTL_HID_GET_STRING: // METHOD_NEITHER status = GetString(Request); break; case IOCTL_HID_GET_INDEXED_STRING: // METHOD_OUT_DIRECT status = GetIndexedString(Request); break; case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: // METHOD_NEITHER // // This has the USBSS Idle notification callback. If the lower driver // can handle it (e.g. USB stack can handle it) then pass it down // otherwise complete it here as not inplemented. For a virtual // device, idling is not needed. // // Not implemented. fall through... // case IOCTL_HID_ACTIVATE_DEVICE: // METHOD_NEITHER case IOCTL_HID_DEACTIVATE_DEVICE: // METHOD_NEITHER case IOCTL_GET_PHYSICAL_DESCRIPTOR: // METHOD_OUT_DIRECT // // We don't do anything for these IOCTLs but some minidrivers might. // // Not implemented. fall through... // default: status = STATUS_NOT_IMPLEMENTED; break; } // // Complete the request. Information value has already been set by request // handlers. // if (completeRequest) { WdfRequestComplete(Request, status); } }
VOID EvtIoDeviceControl( WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode) { NTSTATUS status; BOOLEAN completeRequest = TRUE; WDFDEVICE device = WdfIoQueueGetDevice(Queue); PINPUT_DEVICE pContext = GetDeviceContext(device); ULONG uReportSize; HID_XFER_PACKET Packet; WDF_REQUEST_PARAMETERS params; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> %s, code = %d\n", __FUNCTION__, IoControlCode); switch (IoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"); // // Return the device's HID descriptor. // ASSERT(pContext->HidDescriptor.bLength != 0); status = RequestCopyFromBuffer(Request, &pContext->HidDescriptor, pContext->HidDescriptor.bLength); break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"); // // Return the device's attributes in a HID_DEVICE_ATTRIBUTES structure. // status = RequestCopyFromBuffer(Request, &pContext->HidDeviceAttributes, sizeof(HID_DEVICE_ATTRIBUTES)); break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n"); // // Return the report descriptor for the HID device. // status = RequestCopyFromBuffer(Request, pContext->HidReportDescriptor, pContext->HidDescriptor.DescriptorList[0].wReportLength); break; case IOCTL_HID_READ_REPORT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_READ_REPORT\n"); // // Queue up a report request. We'll complete it when we actually // receive data from the device. // status = WdfRequestForwardToIoQueue( Request, pContext->HidQueue); if (NT_SUCCESS(status)) { completeRequest = FALSE; } else { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "WdfRequestForwardToIoQueue failed with 0x%x\n", status); } break; case IOCTL_HID_WRITE_REPORT: TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "IOCTL_HID_WRITE_REPORT\n"); // // Write a report to the device, commonly used for controlling keyboard // LEDs. We'll complete the request after the host processes all virtio // buffers we add to the status queue. // WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms); if (params.Parameters.DeviceIoControl.InputBufferLength < sizeof(HID_XFER_PACKET)) { status = STATUS_BUFFER_TOO_SMALL; } else { RtlCopyMemory(&Packet, WdfRequestWdmGetIrp(Request)->UserBuffer, sizeof(HID_XFER_PACKET)); WdfRequestSetInformation(Request, Packet.reportBufferLen); status = ProcessOutputReport(pContext, Request, &Packet); if (NT_SUCCESS(status)) { completeRequest = FALSE; } } break; default: TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTLS, "Unrecognized IOCTL %d\n", IoControlCode); status = STATUS_NOT_IMPLEMENTED; break; } if (completeRequest) { WdfRequestComplete(Request, status); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- %s\n", __FUNCTION__); }