/*++ Routine Description: Write to mail box in a serialize manner Arguments: DeviceContextPtr - Pointer to device context Channel - Mailbox Channel Value - Value to be written Request - Optional WDF request object associated with this mailbox transaction Return Value: NTSTATUS --*/ _Use_decl_annotations_ NTSTATUS RpiqMailboxWrite ( DEVICE_CONTEXT* DeviceContextPtr, ULONG Channel, ULONG Value, WDFREQUEST Request ) { NTSTATUS status; ULONG count = 0, reg; LARGE_INTEGER timeOut = { 0 }; PAGED_CODE(); WdfWaitLockAcquire(DeviceContextPtr->WriteLock, NULL); timeOut.QuadPart = WDF_REL_TIMEOUT_IN_MS(1); reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status); // Poll until mailbox is available. It doesn't seem like // the mailbox is full often so polling is sufficient for now // rather than enable mailbox empty interrupt while (reg & MAILBOX_STATUS_FULL) { if (count > MAX_POLL) { RPIQ_LOG_ERROR( "Exit Fail Status 0x%08x", DeviceContextPtr->Mailbox->Status); status = STATUS_IO_TIMEOUT; goto End; } KeDelayExecutionThread(KernelMode, FALSE, &timeOut); reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status); ++count; } if (Request) { status = WdfRequestForwardToIoQueue( Request, DeviceContextPtr->ChannelQueue[Channel]); if (!NT_SUCCESS(status)) { RPIQ_LOG_ERROR( "WdfRequestForwardToIoQueue failed ( %!STATUS!)", status); goto End; } } WRITE_REGISTER_NOFENCE_ULONG( &DeviceContextPtr->Mailbox->Write, (Value & ~MAILBOX_CHANNEL_MASK) | Channel); status = STATUS_SUCCESS; End: WdfWaitLockRelease(DeviceContextPtr->WriteLock); return status; }
VOID OnTopLevelIoDefault( _In_ WDFQUEUE FxQueue, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: Accepts all incoming requests and pends or forwards appropriately. Arguments: FxQueue - Handle to the framework queue object that is associated with the I/O request. FxRequest - Handle to a framework request object. Return Value: None. --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxQueue); WDFDEVICE device; PDEVICE_CONTEXT pDevice; WDF_REQUEST_PARAMETERS params; NTSTATUS status; device = WdfIoQueueGetDevice(FxQueue); pDevice = GetDeviceContext(device); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(FxRequest, ¶ms); status = WdfRequestForwardToIoQueue(FxRequest, pDevice->SpbQueue); if (!NT_SUCCESS(status)) { CyapaPrint( DEBUG_LEVEL_ERROR, DBG_IOCTL, "Failed to forward WDFREQUEST %p to SPB queue %p - %!STATUS!", FxRequest, pDevice->SpbQueue, status); WdfRequestComplete(FxRequest, status); } FuncExit(TRACE_FLAG_SPBAPI); }
static VOID XenBus_EvtIoRead(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); KIRQL old_irql; UNREFERENCED_PARAMETER(queue); FUNCTION_ENTER(); status = WdfRequestForwardToIoQueue(request, xpdid->xenbus.io_queue); if (!NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME " could not forward request (%08x)\n", status)); } KeAcquireSpinLock(&xpdid->lock, &old_irql); if (!IsListEmpty(&xpdid->xenbus.read_list_head)) { status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &request); if (NT_SUCCESS(status)) { KdPrint((__DRIVER_NAME " found pending read\n")); XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, request, length); KeReleaseSpinLock(&xpdid->lock, old_irql); WdfRequestComplete(request, STATUS_SUCCESS); } else { KdPrint((__DRIVER_NAME " no pending read (%08x)\n", status)); KeReleaseSpinLock(&xpdid->lock, old_irql); } } else { KdPrint((__DRIVER_NAME " no data to read\n")); KeReleaseSpinLock(&xpdid->lock, old_irql); } FUNCTION_EXIT(); return; }
VOID FireShockEvtIoRead( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t Length ) { NTSTATUS status; PDEVICE_CONTEXT pDeviceContext; UNREFERENCED_PARAMETER(Length); pDeviceContext = DeviceGetContext(WdfIoQueueGetDevice(Queue)); status = WdfRequestForwardToIoQueue(Request, pDeviceContext->IoReadQueue); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, TRACE_QUEUE, "WdfRequestForwardToIoQueue failed with status %!STATUS!", status); WdfRequestComplete(Request, status); } }
static VOID XenUsb_EvtIoInternalDeviceControl( WDFQUEUE queue, WDFREQUEST request, size_t output_buffer_length, size_t input_buffer_length, ULONG io_control_code) { WDFDEVICE device = WdfIoQueueGetDevice(queue); PXENUSB_DEVICE_DATA xudd = GetXudd(device); //WDF_REQUEST_PARAMETERS wrp; //pvusb_urb_t *urb; UNREFERENCED_PARAMETER(input_buffer_length); UNREFERENCED_PARAMETER(output_buffer_length); FUNCTION_ENTER(); //WDF_REQUEST_PARAMETERS_INIT(&wrp); //WdfRequestGetParameters(request, &wrp); switch(io_control_code) { case IOCTL_INTERNAL_PVUSB_SUBMIT_URB: FUNCTION_MSG("IOCTL_INTERNAL_PVUSB_SUBMIT_URB\n"); //urb = (pvusb_urb_t *)wrp.Parameters.Others.Arg1; //FUNCTION_MSG("urb = %p\n", urb); WdfRequestForwardToIoQueue(request, xudd->pvurb_queue); break; default: FUNCTION_MSG("Unknown IOCTL %08x\n", io_control_code); WdfRequestComplete(request, WdfRequestGetStatus(request)); break; } FUNCTION_EXIT(); }
VOID SerialStartOrQueue( IN PSERIAL_DEVICE_EXTENSION Extension, IN WDFREQUEST Request, IN WDFQUEUE QueueToExamine, IN WDFREQUEST *CurrentOpRequest, IN PSERIAL_START_ROUTINE Starter ) /*++ Routine Description: This routine is used to either start or queue any requst that can be queued in the driver. Arguments: Extension - Points to the serial device extension. Request - The request to either queue or start. In either case the request will be marked pending. QueueToExamine - The queue the request will be place on if there is already an operation in progress. CurrentOpRequest - Pointer to a pointer to the request the is current for the queue. The pointer pointed to will be set with to Request if what CurrentOpRequest points to is NULL. Starter - The routine to call if the queue is empty. Return Value: --*/ { NTSTATUS status; PREQUEST_CONTEXT reqContext; WDF_REQUEST_PARAMETERS params; reqContext = SerialGetRequestContext(Request); WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters( Request, ¶ms); // // If this is a write request then take the amount of characters // to write and add it to the count of characters to write. // if (params.Type == WdfRequestTypeWrite) { Extension->TotalCharsQueued += reqContext->Length; } else if ((params.Type == WdfRequestTypeDeviceControl) && ((params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) || (params.Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) { reqContext->IoctlCode = params.Parameters.DeviceIoControl.IoControlCode; // We need this in the destroy callback Extension->TotalCharsQueued++; } if (IsQueueEmpty(QueueToExamine) && !(*CurrentOpRequest)) { // // There were no current operation. Mark this one as // current and start it up. // *CurrentOpRequest = Request; Starter(Extension); return; } else { // // We don't know how long the request will be in the // queue. If it gets cancelled while waiting in the queue, we will // be notified by EvtCanceledOnQueue callback so that we can readjust // the lenght or free the buffer. // reqContext->Extension = Extension; // We need this in the destroy callback status = WdfRequestForwardToIoQueue(Request, QueueToExamine); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "WdfRequestForwardToIoQueue failed%X\n", status); ASSERTMSG("WdfRequestForwardToIoQueue failed ", FALSE); SerialCompleteRequest(Request, status, 0); } return; } }
// This event is called when the framework receives IRP_MJ_INTERNAL DEVICE_CONTROL requests from the system. // void HidFx2EvtInternalDeviceControl( _In_ WDFQUEUE hQueue, _In_ WDFREQUEST hRequest, _In_ size_t cOutputBufferLength, _In_ size_t cInputBufferLength, _In_ ULONG ulIoControlCode ) { NTSTATUS status = STATUS_SUCCESS; WDFDEVICE hDevice; PDEVICE_EXTENSION pDevContext = NULL; UNREFERENCED_PARAMETER(cOutputBufferLength); UNREFERENCED_PARAMETER(cInputBufferLength); TraceVerbose(DBG_IOCTL, "(%!FUNC!) Enter\n"); hDevice = WdfIoQueueGetDevice(hQueue); pDevContext = GetDeviceContext(hDevice); TraceInfo(DBG_IOCTL, "(%!FUNC!) Queue:0x%p, Request:0x%p\n", hQueue, hRequest); switch (ulIoControlCode) { case IOCTL_HID_GET_DEVICE_DESCRIPTOR: TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_DESCRIPTOR\n"); status = HidFx2GetHidDescriptor(hDevice, hRequest); WdfRequestComplete(hRequest, status); break; case IOCTL_HID_GET_DEVICE_ATTRIBUTES: TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_DEVICE_ATTRIBUTES\n"); status = HidFx2GetDeviceAttributes(hRequest); WdfRequestComplete(hRequest, status); break; case IOCTL_HID_GET_REPORT_DESCRIPTOR: TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_REPORT_DESCRIPTOR\n"); status = HidFx2GetReportDescriptor(hDevice, hRequest); WdfRequestComplete(hRequest, status); break; case IOCTL_HID_READ_REPORT: TraceInfo(DBG_IOCTL, "IOCTL_HID_READ_REPORT\n"); status = WdfRequestForwardToIoQueue(hRequest, pDevContext->hInterruptMsgQueue); if (!NT_SUCCESS(status)) { TraceErr(DBG_IOCTL, "WdfRequestForwardToIoQueue failed with status: %!STATUS!\n", status); WdfRequestComplete(hRequest, status); } break; case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST: TraceInfo(DBG_IOCTL, "IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST\n"); status = HidFx2SendIdleNotification(hRequest); if (!NT_SUCCESS(status)) { TraceErr(DBG_IOCTL, "SendIdleNotification failed with status: %!STATUS!\n", status); WdfRequestComplete(hRequest, status); } break; case IOCTL_HID_GET_INPUT_REPORT: TraceInfo(DBG_IOCTL, "IOCTL_HID_GET_INPUT_REPORT\n"); HidFx2GetInput(hRequest); WdfRequestComplete(hRequest, status); break; case IOCTL_HID_SET_OUTPUT_REPORT: TraceInfo(DBG_IOCTL, "IOCTL_HID_SET_OUTPUT_REPORT\n"); status = HidFx2SetOutput(hRequest); WdfRequestComplete(hRequest, status); break; default: TraceInfo(DBG_IOCTL, "IOCTL Not Supported 0x%X\n", ulIoControlCode); status = STATUS_NOT_SUPPORTED; WdfRequestComplete(hRequest, status); break; } TraceVerbose(DBG_IOCTL, "(%!FUNC!) Exit\n"); return; }
/////////////////////////////////////////////////////////////////////////////// // // BasicUsbEvtDeviceControl // // This routine is called by the framework when there is a // device control request for us to process // // INPUTS: // // Queue - Our default queue // // Request - A device control request // // OutputBufferLength - The length of the output buffer // // InputBufferLength - The length of the input buffer // // IoControlCode - The operation being performed // // OUTPUTS: // // None. // // RETURNS: // // None. // // IRQL: // // This routine is called at IRQL == PASSIVE_LEVEL, due to // our PASSIVE_LEVEL execution level contraint // // NOTES: // // /////////////////////////////////////////////////////////////////////////////// VOID BasicUsbEvtDeviceControl(WDFQUEUE Queue, WDFREQUEST Request, size_t OutputBufferLength, size_t InputBufferLength, ULONG IoControlCode) { NTSTATUS status; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDFMEMORY inputMemory; WDF_MEMORY_DESCRIPTOR inputMemoryDescriptor; PBASICUSB_DEVICE_CONTEXT devContext; #if DBG DbgPrint("BasicUsbEvtDeviceControl\n"); #endif devContext = BasicUsbGetContextFromDevice( WdfIoQueueGetDevice(Queue) ); switch (IoControlCode) { case IOCTL_OSR_BASICUSB_SET_BAR_GRAPH: { // // Validate the buffers for this request: // // OutputBufferLength - Must be zero // if (OutputBufferLength != 0) { #if DBG DbgPrint("Invalid parameter - output buffer supplied in "\ "SET_BAR_GRAPH IOCTL (%u bytes)\n", (ULONG)OutputBufferLength); #endif WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } // // InputBufferLength - Must be at least 1 byte // if (InputBufferLength == 0) { #if DBG DbgPrint("No input buffer supplied in SET_BAR_GRAPH IOCTL\n"); #endif WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_TOO_SMALL, sizeof(UCHAR)); return; } // // We need the input memory from the request so that we can pass // it to the bus driver. // status = WdfRequestRetrieveInputMemory(Request, &inputMemory); if (!NT_SUCCESS(status)) { #if DBG DbgPrint("WdfRequestRetrieveInputMemory failed 0x%0x\n", status); #endif WdfRequestComplete(Request, status); return; } // // The routine we want to call takes a memory descriptor, so // initialize that now with the handle to the user memory. // WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemoryDescriptor, inputMemory, NULL); // // Initialize the vendor command (defined by the device) that // allows us to light the bar graph. // WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR( &controlSetupPacket, BmRequestHostToDevice, BmRequestToDevice, USBFX2LK_SET_BARGRAPH_DISPLAY, 0, 0); // // And send the vendor command as a control transfer. This // shouldn't take very long, so we'll just send it synchronously // to the device. // // // We've specified an execution level restraint of // PASSIVE_LEVEL, so we're allowed to send this request // synchronously. // ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); status = WdfUsbTargetDeviceSendControlTransferSynchronously( devContext->BasicUsbUsbDevice, WDF_NO_HANDLE, NULL, &controlSetupPacket, &inputMemoryDescriptor, NULL); if (NT_SUCCESS(status)) { // // If the request succeeded, complete the request with success // and indicate to the user how much data was transferred (in // this case a single byte was sent to the device) // WdfRequestCompleteWithInformation(Request, status, sizeof(UCHAR)); } else { // // Bad news! Just complete the request with the failure status. // #if DBG DbgPrint("WdfUsbTargetDeviceSendControlTransferSynchronously "\ "failed 0x%0x\n", status); #endif WdfRequestComplete(Request, status); } return; } case IOCTL_OSR_BASICUSB_GET_SWITCHPACK_STATE: { // // Validate the buffers for this request: // // InputBufferLength - Must be zero // if (InputBufferLength != 0) { #if DBG DbgPrint("Invalid parameter - input buffer supplied in "\ "SWITCHPACK_STATE_CHANGE_NOTIFY IOCTL (%u bytes)\n", (ULONG)InputBufferLength); #endif WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } // // OutputBufferLength - Must be at least 1 byte // if (OutputBufferLength == 0) { #if DBG DbgPrint("No input buffer supplied in "\ "SWITCHPACK_STATE_CHANGE_NOTIFY IOCTL\n"); #endif WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_TOO_SMALL, sizeof(UCHAR)); return; } // // Forward the request to our switchpack state change requests // queue // status = WdfRequestForwardToIoQueue( Request, devContext->SwitchPackStateChangeQueue); if (!NT_SUCCESS(status)) { // // Bad news! Print out the status and fail the request. // #if DBG DbgPrint("WdfRequestForwardToIoQueue failed with Status "\ "code 0x%x", status); #endif WdfRequestComplete(Request, status); return; } return; } default: { #if DBG DbgPrint("Unknown IOCTL: 0x%x\n", IoControlCode); #endif WdfRequestCompleteWithInformation(Request, STATUS_INVALID_DEVICE_REQUEST, 0); return; } } return; }
VOID XenUsb_EvtIoInternalDeviceControl_ROOTHUB_SUBMIT_URB( WDFQUEUE queue, WDFREQUEST request, size_t output_buffer_length, size_t input_buffer_length, ULONG io_control_code) { //NTSTATUS status; WDFDEVICE device = WdfIoQueueGetDevice(queue); PXENUSB_PDO_DEVICE_DATA xupdd = GetXupdd(device); PXENUSB_DEVICE_DATA xudd = GetXudd(xupdd->wdf_device_bus_fdo); WDF_REQUEST_PARAMETERS wrp; PURB urb; PUSBD_INTERFACE_INFORMATION interface_information; ULONG i, j; xenusb_device_t *usb_device; xenusb_endpoint_t *endpoint; //USB_DEFAULT_PIPE_SETUP_PACKET setup_packet; urb_decode_t decode_data; ULONG decode_retval; UNREFERENCED_PARAMETER(input_buffer_length); UNREFERENCED_PARAMETER(output_buffer_length); UNREFERENCED_PARAMETER(io_control_code); //FUNCTION_ENTER(); WDF_REQUEST_PARAMETERS_INIT(&wrp); WdfRequestGetParameters(request, &wrp); urb = (PURB)wrp.Parameters.Others.Arg1; ASSERT(urb); #if 0 FUNCTION_MSG("urb = %p\n", urb); FUNCTION_MSG(" Length = %d\n", urb->UrbHeader.Length); FUNCTION_MSG(" Function = %d\n", urb->UrbHeader.Function); FUNCTION_MSG(" Status = %d\n", urb->UrbHeader.Status); FUNCTION_MSG(" UsbdDeviceHandle = %p\n", urb->UrbHeader.UsbdDeviceHandle); FUNCTION_MSG(" UsbdFlags = %08x\n", urb->UrbHeader.UsbdFlags); #endif usb_device = urb->UrbHeader.UsbdDeviceHandle; if (!usb_device) usb_device = xupdd->usb_device; decode_retval = XenUsb_DecodeControlUrb(urb, &decode_data); if (decode_retval == URB_DECODE_UNKNOWN) { FUNCTION_MSG("Unknown URB - Calling WdfRequestCompletestatus with status = %08x\n", STATUS_UNSUCCESSFUL); //STATUS_UNSUCCESSFUL); urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION; WdfRequestComplete(request, STATUS_UNSUCCESSFUL); return; } urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION; if (decode_retval != URB_DECODE_NOT_CONTROL) { FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B); FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type); FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir); FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest); FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte); FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte); FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength); } switch(urb->UrbHeader.Function) { case URB_FUNCTION_SELECT_CONFIGURATION: FUNCTION_MSG("URB_FUNCTION_SELECT_CONFIGURATION\n"); FUNCTION_MSG(" ConfigurationDescriptor = %p\n", urb->UrbSelectConfiguration.ConfigurationDescriptor); if (urb->UrbSelectConfiguration.ConfigurationDescriptor) { FUNCTION_MSG(" bLength = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bLength); FUNCTION_MSG(" bDescriptorType = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bDescriptorType); FUNCTION_MSG(" wTotalLength = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->wTotalLength); FUNCTION_MSG(" bNumInterfaces = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bNumInterfaces); FUNCTION_MSG(" bConfigurationValue = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bConfigurationValue); FUNCTION_MSG(" iConfiguration = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->iConfiguration); FUNCTION_MSG(" bmAttributes = %04x\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->bmAttributes); FUNCTION_MSG(" MaxPower = %d\n", urb->UrbSelectConfiguration.ConfigurationDescriptor->MaxPower); } FUNCTION_MSG(" ConfigurationHandle = %p\n", urb->UrbSelectConfiguration.ConfigurationHandle); if (urb->UrbSelectConfiguration.ConfigurationDescriptor) { urb->UrbSelectConfiguration.ConfigurationHandle = xupdd->usb_device->configs[0]; interface_information = &urb->UrbSelectConfiguration.Interface; for (i = 0; i < urb->UrbSelectConfiguration.ConfigurationDescriptor->bNumInterfaces; i++) { FUNCTION_MSG("InterfaceInformation[%d]\n", i); FUNCTION_MSG(" Length = %d\n", interface_information->Length); FUNCTION_MSG(" InterfaceNumber = %d\n", interface_information->InterfaceNumber); FUNCTION_MSG(" AlternateSetting = %d\n", interface_information->AlternateSetting); FUNCTION_MSG(" Class = %02x\n", (ULONG)interface_information->Class); FUNCTION_MSG(" SubClass = %02x\n", (ULONG)interface_information->SubClass); FUNCTION_MSG(" Protocol = %02x\n", (ULONG)interface_information->Protocol); FUNCTION_MSG(" Reserved = %02x\n", (ULONG)interface_information->Reserved); FUNCTION_MSG(" InterfaceHandle = %p\n", interface_information->InterfaceHandle); FUNCTION_MSG(" NumberOfPipes = %d\n", interface_information->NumberOfPipes); interface_information->InterfaceHandle = xupdd->usb_device->configs[0]->interfaces[0]; interface_information->Class = 0x09; interface_information->SubClass = 0x00; interface_information->SubClass = 0x00; for (j = 0; j < interface_information->NumberOfPipes; j++) { FUNCTION_MSG(" Pipe[%d]\n", i); FUNCTION_MSG(" MaximumPacketSize = %d\n", interface_information->Pipes[j].MaximumPacketSize); FUNCTION_MSG(" EndpointAddress = %d\n", interface_information->Pipes[j].EndpointAddress); FUNCTION_MSG(" Interval = %d\n", interface_information->Pipes[j].Interval); FUNCTION_MSG(" PipeType = %d\n", interface_information->Pipes[j].PipeType); FUNCTION_MSG(" PipeHandle = %d\n", interface_information->Pipes[j].PipeHandle); FUNCTION_MSG(" MaximumTransferSize = %d\n", interface_information->Pipes[j].MaximumTransferSize); FUNCTION_MSG(" PipeFlags = %08x\n", interface_information->Pipes[j].PipeFlags); interface_information->Pipes[j].MaximumPacketSize = 2; interface_information->Pipes[j].EndpointAddress = 0x81; interface_information->Pipes[j].Interval = 12; interface_information->Pipes[j].PipeType = UsbdPipeTypeInterrupt; interface_information->Pipes[j].PipeHandle = xupdd->usb_device->configs[0]->interfaces[0]->endpoints[j]; interface_information->Pipes[j].MaximumTransferSize = 4096; /* made up number - possibly not used */ // this is input actually interface_information->Pipes[j].PipeFlags = 0; } interface_information = (PUSBD_INTERFACE_INFORMATION)((PUCHAR)interface_information + interface_information->Length); } } urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case URB_FUNCTION_SELECT_INTERFACE: FUNCTION_MSG("URB_FUNCTION_SELECT_INTERFACE\n"); interface_information = &urb->UrbSelectInterface.Interface; FUNCTION_MSG("InterfaceInformation\n"); FUNCTION_MSG(" Length = %d\n", interface_information->Length); FUNCTION_MSG(" InterfaceNumber = %d\n", interface_information->InterfaceNumber); FUNCTION_MSG(" AlternateSetting = %d\n", interface_information->AlternateSetting); FUNCTION_MSG(" Class = %02x\n", (ULONG)interface_information->Class); FUNCTION_MSG(" SubClass = %02x\n", (ULONG)interface_information->SubClass); FUNCTION_MSG(" Protocol = %02x\n", (ULONG)interface_information->Protocol); FUNCTION_MSG(" Reserved = %02x\n", (ULONG)interface_information->Reserved); FUNCTION_MSG(" InterfaceHandle = %p\n", interface_information->InterfaceHandle); FUNCTION_MSG(" NumberOfPipes = %d\n", interface_information->NumberOfPipes); for (i = 0; i < interface_information->NumberOfPipes; i++) { FUNCTION_MSG(" Pipe[%d]\n", i); FUNCTION_MSG(" MaximumPacketSize = %d\n", interface_information->Pipes[i].MaximumPacketSize); FUNCTION_MSG(" EndpointAddress = %d\n", interface_information->Pipes[i].EndpointAddress); FUNCTION_MSG(" Interval = %d\n", interface_information->Pipes[i].Interval); FUNCTION_MSG(" PipeType = %d\n", interface_information->Pipes[i].PipeType); FUNCTION_MSG(" PipeHandle = %d\n", interface_information->Pipes[i].PipeHandle); FUNCTION_MSG(" MaximumTransferSize = %d\n", interface_information->Pipes[i].MaximumTransferSize); FUNCTION_MSG(" PipeFlags = %08x\n", interface_information->Pipes[i].PipeFlags); } urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION; break; #if (NTDDI_VERSION >= NTDDI_VISTA) case URB_FUNCTION_CONTROL_TRANSFER_EX: #endif case URB_FUNCTION_CONTROL_TRANSFER: case URB_FUNCTION_CLASS_DEVICE: case URB_FUNCTION_CLASS_OTHER: case URB_FUNCTION_CLASS_INTERFACE: case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: case URB_FUNCTION_GET_STATUS_FROM_DEVICE: switch(decode_data.setup_packet.default_pipe_setup_packet.bRequest) { case USB_REQUEST_GET_STATUS: // switch device, interface, endpoint switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type) { case BMREQUEST_STANDARD: FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n"); FUNCTION_MSG(" Type=Standard\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_DEVICE: FUNCTION_MSG(" Recipient=Device\n"); ((PUSHORT)decode_data.buffer)[0] = 0x0001; /* self powered */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; default: FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; case BMREQUEST_CLASS: switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_DEVICE: ((PUSHORT)decode_data.buffer)[0] = 0x0000; ((PUSHORT)decode_data.buffer)[1] = 0x0000; urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case BMREQUEST_TO_OTHER: FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n"); FUNCTION_MSG(" Type=Class\n"); FUNCTION_MSG(" Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); ((PUSHORT)decode_data.buffer)[0] = xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status; ((PUSHORT)decode_data.buffer)[1] = xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change; urb->UrbHeader.Status = USBD_STATUS_SUCCESS; FUNCTION_MSG(" status = %04x, change = %04x\n", xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status, xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change); break; default: FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n"); FUNCTION_MSG(" Type=Class\n"); FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; default: FUNCTION_MSG(" USB_REQUEST_GET_STATUS\n"); FUNCTION_MSG(" Type=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type); break; } break; case USB_REQUEST_GET_DESCRIPTOR: FUNCTION_MSG(" USB_REQUEST_GET_DESCRIPTOR\n"); // should separate into Standard and Class switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte) { case USB_DEVICE_DESCRIPTOR_TYPE: FUNCTION_MSG(" USB_DEVICE_DESCRIPTOR_TYPE\n"); FUNCTION_MSG(" length = %d\n", *decode_data.length); memcpy(decode_data.buffer, &usb_device->device_descriptor, sizeof(USB_DEVICE_DESCRIPTOR)); *decode_data.length = sizeof(USB_DEVICE_DESCRIPTOR); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case USB_CONFIGURATION_DESCRIPTOR_TYPE: { xenusb_config_t *usb_config; PUCHAR ptr; FUNCTION_MSG(" USB_CONFIGURATION_DESCRIPTOR_TYPE\n"); FUNCTION_MSG(" length = %d\n", *decode_data.length); usb_config = usb_device->active_config; ptr = (PUCHAR)decode_data.buffer; memcpy(ptr, &usb_config->config_descriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR)); ptr += sizeof(USB_CONFIGURATION_DESCRIPTOR); ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength = sizeof(USB_CONFIGURATION_DESCRIPTOR); if (*decode_data.length > 9) { for (i = 0; i < usb_config->config_descriptor.bNumInterfaces; i++) { memcpy(ptr, &usb_config->interfaces[i]->interface_descriptor, sizeof(USB_INTERFACE_DESCRIPTOR)); ptr += sizeof(USB_INTERFACE_DESCRIPTOR); ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength += sizeof(USB_INTERFACE_DESCRIPTOR); for (j = 0; j < usb_config->interfaces[i]->interface_descriptor.bNumEndpoints; j++) { memcpy(ptr, &usb_config->interfaces[i]->endpoints[j]->endpoint_descriptor, sizeof(USB_ENDPOINT_DESCRIPTOR)); ptr += sizeof(USB_ENDPOINT_DESCRIPTOR); ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength += sizeof(USB_ENDPOINT_DESCRIPTOR); } } } *decode_data.length = ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength; //if (urb->UrbControlDescriptorRequest.TransferBufferLength == 9) // ((PUSB_CONFIGURATION_DESCRIPTOR)decode_data.buffer)->wTotalLength = 32; urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; } case 0x00: // unknown... doing the same as 0x29 seems to work FUNCTION_MSG(" USB_00_DESCRIPTOR_TYPE (doesn't exist)\n"); urb->UrbHeader.Status = USBD_STATUS_BAD_DESCRIPTOR; break; case 0x29: // Hub Descriptor { PUSB_HUB_DESCRIPTOR uhd; FUNCTION_MSG(" USB_HUB_DESCRIPTOR_TYPE\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte); FUNCTION_MSG(" length = %d\n", *decode_data.length); uhd = decode_data.buffer; // TODO adjust for real number of ports *decode_data.length = FIELD_OFFSET(USB_HUB_DESCRIPTOR, bRemoveAndPowerMask[0]) + 2 + 1; uhd->bDescriptorLength = (UCHAR)*decode_data.length; uhd->bDescriptorType = 0x29; uhd->bNumberOfPorts = (UCHAR)xudd->num_ports; uhd->wHubCharacteristics = 0x0012; // no power switching no overcurrent protection uhd->bPowerOnToPowerGood = 1; // 2ms units uhd->bHubControlCurrent = 0; // DeviceRemovable bits (includes an extra bit at the start) uhd->bRemoveAndPowerMask[0] = 0; uhd->bRemoveAndPowerMask[1] = 0; // PortPwrCtrlMask uhd->bRemoveAndPowerMask[2] = 0xFF; urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; } default: FUNCTION_MSG(" USB_%02x_DESCRIPTOR_TYPE\n", (ULONG)decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte); FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B); FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type); FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir); FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest); FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte); FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte); FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength); break; } break; case USB_REQUEST_CLEAR_FEATURE: FUNCTION_MSG(" USB_REQUEST_CLEAR_FEATURE\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type) { case BMREQUEST_STANDARD: /* Standard */ FUNCTION_MSG(" Type=Standard\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_DEVICE: FUNCTION_MSG(" Recipient=Device\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W) { case 1: /* DEVICE_REMOTE_WAKEUP */ FUNCTION_MSG(" Feature=DEVICE_REMOTE_WAKEUP\n"); /* fake this */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; default: FUNCTION_MSG(__DRIVER_NAME " Feature=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); break; } break; default: FUNCTION_MSG(__DRIVER_NAME " Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; break; case BMREQUEST_CLASS: /* Class */ FUNCTION_MSG(" Type=Class\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_OTHER: FUNCTION_MSG(" Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); switch (urb->UrbControlVendorClassRequest.Value) { case PORT_ENABLE: FUNCTION_MSG(" PORT_ENABLE\n"); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status &= ~(1 << PORT_ENABLE); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case PORT_SUSPEND: FUNCTION_MSG(" PORT_SUSPEND (NOOP)\n"); /* do something here */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case C_PORT_CONNECTION: FUNCTION_MSG(" C_PORT_CONNECTION\n"); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_CONNECTION); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case C_PORT_ENABLE: FUNCTION_MSG(" C_PORT_ENABLE\n"); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_ENABLE); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case C_PORT_RESET: FUNCTION_MSG(" C_PORT_RESET\n"); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change &= ~(1 << PORT_RESET); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; default: FUNCTION_MSG(" Unknown Value %04X\n", urb->UrbControlVendorClassRequest.Value); break; } FUNCTION_MSG(" status = %04x, change = %04x\n", xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status, xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change); break; default: FUNCTION_MSG(" Recipient=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; default: FUNCTION_MSG(" Type=%d\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type); break; } break; case USB_REQUEST_SET_FEATURE: FUNCTION_MSG(" USB_REQUEST_SET_FEATURE\n"); FUNCTION_MSG(" SetPortFeature\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type) { case 0: /* Standard */ FUNCTION_MSG(" Type=Standard\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_DEVICE: FUNCTION_MSG(" Recipient=Device\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W) { case 1: /* DEVICE_REMOTE_WAKEUP */ FUNCTION_MSG(" Feature=DEVICE_REMOTE_WAKEUP\n"); /* fake this */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; default: FUNCTION_MSG(__DRIVER_NAME " Feature=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); break; } break; default: FUNCTION_MSG(__DRIVER_NAME " Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; case 1: /* Class */ FUNCTION_MSG(" Type=Class\n"); switch (decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient) { case BMREQUEST_TO_OTHER: FUNCTION_MSG(" Recipient=Other (port = %d)\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); switch (decode_data.setup_packet.default_pipe_setup_packet.wValue.W) { case PORT_ENABLE: FUNCTION_MSG(" PORT_ENABLE (NOOP)\n"); /* do something here */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case PORT_SUSPEND: FUNCTION_MSG(" PORT_SUSPEND (NOOP)\n"); /* do something here */ urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case PORT_RESET: FUNCTION_MSG(" PORT_RESET\n"); /* just fake the reset by setting the status bit to indicate that the reset is complete*/ //xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_RESET); //xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].reset_counter = 10; // TODO: maybe fake a 10ms time here... xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status &= ~(1 << PORT_RESET); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_ENABLE); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_change |= (1 << PORT_RESET); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; endpoint = xupdd->usb_device->configs[0]->interfaces[0]->endpoints[0]; XenUsbHub_ProcessHubInterruptEvent(endpoint); break; case PORT_POWER: FUNCTION_MSG(" PORT_POWER\n"); xudd->ports[decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte - 1].port_status |= (1 << PORT_POWER); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; default: FUNCTION_MSG(" PORT_%04X\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); break; } FUNCTION_MSG(" status = %04x, change = %04x\n", xudd->ports[urb->UrbControlVendorClassRequest.Index - 1].port_status, xudd->ports[urb->UrbControlVendorClassRequest.Index - 1].port_change); break; default: FUNCTION_MSG(__DRIVER_NAME " Recipient=%d (not valid)\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); break; } break; } break; default: FUNCTION_MSG(" USB_REQUEST_%02x\n", (ULONG)decode_data.setup_packet.default_pipe_setup_packet.bRequest); FUNCTION_MSG(" TransferBufferLength returned = %d\n", urb->UrbControlDescriptorRequest.TransferBufferLength); break; } break; case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: FUNCTION_MSG("URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL\n"); FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbPipeRequest.PipeHandle); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case URB_FUNCTION_ABORT_PIPE: FUNCTION_MSG("URB_FUNCTION_ABORT_PIPE\n"); FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbPipeRequest.PipeHandle); urb->UrbHeader.Status = USBD_STATUS_SUCCESS; break; case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: /* 11.12.4 */ #if 0 FUNCTION_MSG("URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER\n"); FUNCTION_MSG(" PipeHandle = %p\n", urb->UrbBulkOrInterruptTransfer.PipeHandle); FUNCTION_MSG(" TransferFlags = %08x\n", urb->UrbBulkOrInterruptTransfer.TransferFlags); FUNCTION_MSG(" TransferBufferLength = %d\n", urb->UrbBulkOrInterruptTransfer.TransferBufferLength); FUNCTION_MSG(" TransferBuffer = %p\n", urb->UrbBulkOrInterruptTransfer.TransferBuffer); FUNCTION_MSG(" TransferBufferMdl = %p\n", urb->UrbBulkOrInterruptTransfer.TransferBufferMDL); #endif endpoint = urb->UrbBulkOrInterruptTransfer.PipeHandle; //WdfSpinLockAcquire(endpoint->lock); WdfRequestForwardToIoQueue(request, endpoint->queue); XenUsbHub_ProcessHubInterruptEvent(endpoint); //WdfSpinLockRelease(endpoint->lock); //FUNCTION_EXIT(); return; default: FUNCTION_MSG("URB_FUNCTION_%04x\n", urb->UrbHeader.Function); if (decode_retval != URB_DECODE_NOT_CONTROL) { FUNCTION_MSG("bmRequestType = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.B); FUNCTION_MSG(" Recipient = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Recipient); FUNCTION_MSG(" Type = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Type); FUNCTION_MSG(" Dir = %x\n", decode_data.setup_packet.default_pipe_setup_packet.bmRequestType.Dir); FUNCTION_MSG("bRequest = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.bRequest); FUNCTION_MSG("wValue = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.W); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wValue.HiByte); FUNCTION_MSG("wIndex = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex); FUNCTION_MSG(" Low = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.LowByte); FUNCTION_MSG(" High = %02x\n", decode_data.setup_packet.default_pipe_setup_packet.wIndex.HiByte); FUNCTION_MSG("wLength = %04x\n", decode_data.setup_packet.default_pipe_setup_packet.wLength); } urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION; break; } if (urb->UrbHeader.Status == USBD_STATUS_SUCCESS) { //FUNCTION_MSG("Calling WdfRequestCompletestatus with status = %08x\n", STATUS_SUCCESS); WdfRequestComplete(request, STATUS_SUCCESS); } else { FUNCTION_MSG("Calling WdfRequestCompletestatus with status = %08x\n", STATUS_UNSUCCESSFUL); WdfRequestComplete(request, STATUS_UNSUCCESSFUL); } //FUNCTION_EXIT(); return; }
VOID OsrFxEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { WDFDEVICE device; PDEVICE_CONTEXT pDevContext; size_t bytesReturned = 0; PBAR_GRAPH_STATE barGraphState = NULL; PSWITCH_STATE switchState = NULL; PUCHAR sevenSegment = NULL; BOOLEAN requestPending = FALSE; NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(OutputBufferLength); PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "--> OsrFxEvtIoDeviceControl\n"); // // initialize variables // device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR: { PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL; USHORT requiredSize = 0; // // First get the size of the config descriptor // status = WdfUsbTargetDeviceRetrieveConfigDescriptor( pDevContext->UsbDevice, NULL, &requiredSize); if (status != STATUS_BUFFER_TOO_SMALL) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); break; } // // Get the buffer - make sure the buffer is big enough // status = WdfRequestRetrieveOutputBuffer(Request, (size_t)requiredSize, // MinimumRequired &configurationDescriptor, NULL); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfRequestRetrieveOutputBuffer failed 0x%x\n", status); break; } status = WdfUsbTargetDeviceRetrieveConfigDescriptor( pDevContext->UsbDevice, configurationDescriptor, &requiredSize); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfUsbTargetDeviceRetrieveConfigDescriptor failed 0x%x\n", status); break; } bytesReturned = requiredSize; } break; case IOCTL_OSRUSBFX2_RESET_DEVICE: status = ResetDevice(device); break; case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE: // // Otherwise, call our function to reenumerate the // device // status = ReenumerateDevice(pDevContext); bytesReturned = 0; break; case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY: // // Make sure the caller's output buffer is large enough // to hold the state of the bar graph // status = WdfRequestRetrieveOutputBuffer(Request, sizeof(BAR_GRAPH_STATE), &barGraphState, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "User's output buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); break; } // // Call our function to get the bar graph state // status = GetBarGraphState(pDevContext, barGraphState); // // If we succeeded return the user their data // if (NT_SUCCESS(status)) { bytesReturned = sizeof(BAR_GRAPH_STATE); } else { bytesReturned = 0; } break; case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: status = WdfRequestRetrieveInputBuffer(Request, sizeof(BAR_GRAPH_STATE), &barGraphState, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "User's input buffer is too small for this IOCTL, expecting an BAR_GRAPH_STATE\n"); break; } // // Call our routine to set the bar graph state // status = SetBarGraphState(pDevContext, barGraphState); // // There's no data returned for this call // bytesReturned = 0; break; case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY: status = WdfRequestRetrieveOutputBuffer(Request, sizeof(UCHAR), &sevenSegment, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "User's output buffer is too small for this IOCTL, expecting an UCHAR\n"); break; } // // Call our function to get the 7 segment state // status = GetSevenSegmentState(pDevContext, sevenSegment); // // If we succeeded return the user their data // if (NT_SUCCESS(status)) { bytesReturned = sizeof(UCHAR); } else { bytesReturned = 0; } break; case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY: status = WdfRequestRetrieveInputBuffer(Request, sizeof(UCHAR), &sevenSegment, NULL); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "User's input buffer is too small for this IOCTL, expecting an UCHAR\n"); bytesReturned = sizeof(UCHAR); break; } // // Call our routine to set the 7 segment state // status = SetSevenSegmentState(pDevContext, sevenSegment); // // There's no data returned for this call // bytesReturned = 0; break; case IOCTL_OSRUSBFX2_READ_SWITCHES: status = WdfRequestRetrieveOutputBuffer(Request, sizeof(SWITCH_STATE), &switchState, NULL);// BufferLength if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "User's output buffer is too small for this IOCTL, expecting a SWITCH_STATE\n"); bytesReturned = sizeof(SWITCH_STATE); break; } // // Call our routine to get the state of the switches // status = GetSwitchState(pDevContext, switchState); // // If successful, return the user their data // if (NT_SUCCESS(status)) { bytesReturned = sizeof(SWITCH_STATE); } else { // // Don't return any data // bytesReturned = 0; } break; case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: // // Forward the request to an interrupt message queue and dont complete // the request until an interrupt from the USB device occurs. // status = WdfRequestForwardToIoQueue(Request, pDevContext->InterruptMsgQueue); if (NT_SUCCESS(status)) { requestPending = TRUE; } break; default : status = STATUS_INVALID_DEVICE_REQUEST; break; } if (requestPending == FALSE) { WdfRequestCompleteWithInformation(Request, status, bytesReturned); } TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL, "<-- OsrFxEvtIoDeviceControl\n"); return; }
BOOLEAN NICEvtProgramDmaFunction( IN WDFDMATRANSACTION Transaction, IN WDFDEVICE Device, IN PVOID Context, IN WDF_DMA_DIRECTION Direction, IN PSCATTER_GATHER_LIST ScatterGather ) /*++ Routine Description: Arguments: Return Value: --*/ { PFDO_DATA fdoData; WDFREQUEST request; NTSTATUS status; UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Direction ); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICEvtProgramDmaFunction\n"); fdoData = FdoGetData(Device); request = WdfDmaTransactionGetRequest(Transaction); WdfSpinLockAcquire(fdoData->SendLock); // // If tcb or link is not available, queue the request // if (!MP_TCB_RESOURCES_AVAIABLE(fdoData)) { TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "Resource is not available: queue Request %p\n", request); // // Must abort the transaction before deleting. // (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); // // Queue the request for later processing. // status = WdfRequestForwardToIoQueue(request, fdoData->PendingWriteQueue); if(!NT_SUCCESS(status)) { ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } fdoData->nWaitSend++; } else { status = NICWritePacket(fdoData, Transaction, ScatterGather); if(!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, "<-- NICEvtProgramDmaFunction returning %!STATUS!\n", status); // // Must abort the transaction before deleting. // (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); ASSERT(NT_SUCCESS(status)); WdfObjectDelete( Transaction ); WdfSpinLockRelease(fdoData->SendLock); WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); return FALSE; } } WdfSpinLockRelease(fdoData->SendLock); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICEvtProgramDmaFunction\n"); return TRUE; }
VOID NdisProtEvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This event is called when the framework receives IRP_MJ_DEVICE_CONTROL requests from the system. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { NTSTATUS NtStatus; NDIS_STATUS Status; PNDISPROT_OPEN_CONTEXT pOpenContext; ULONG BytesReturned; PVOID sysBuffer; WDFFILEOBJECT fileObject = WdfRequestGetFileObject(Request); size_t bufSize; UNREFERENCED_PARAMETER(Queue); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); DEBUGP(DL_LOUD, ("IoControl: Irp %p\n", Request)); pOpenContext = GetFileObjectContext(fileObject)->OpenContext; BytesReturned = 0; switch (IoControlCode) { case IOCTL_NDISPROT_BIND_WAIT: // // Block until we have seen a NetEventBindsComplete event, // meaning that we have finished binding to all running // adapters that we are supposed to bind to. // // If we don't get this event in 5 seconds, time out. // NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (NPROT_WAIT_EVENT(&Globals.BindsComplete, 5000)) { NtStatus = STATUS_SUCCESS; } else { NtStatus = STATUS_TIMEOUT; } DEBUGP(DL_INFO, ("IoControl: BindWait returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_QUERY_BINDING: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_BINDING), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } Status = ndisprotQueryBinding( sysBuffer, (ULONG) bufSize, (ULONG) bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); DEBUGP(DL_LOUD, ("IoControl: QueryBinding returning %x\n", NtStatus)); break; case IOCTL_NDISPROT_OPEN_DEVICE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NPROT_STRUCT_ASSERT(pOpenContext, oc); DEBUGP(DL_WARN, ("IoControl: OPEN_DEVICE: FileObj %p already" " associated with open %p\n", fileObject, pOpenContext)); NtStatus = STATUS_DEVICE_BUSY; break; } NtStatus = WdfRequestRetrieveInputBuffer(Request, 0, &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } NtStatus = ndisprotOpenDevice( sysBuffer, (ULONG)bufSize, fileObject, &pOpenContext ); if (NT_SUCCESS(NtStatus)) { DEBUGP(DL_VERY_LOUD, ("IoControl OPEN_DEVICE: Open %p <-> FileObject %p\n", pOpenContext, fileObject)); } break; case IOCTL_NDISPROT_QUERY_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveOutputBuffer(Request, sizeof(NDISPROT_QUERY_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveOutputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotQueryOidValue( pOpenContext, sysBuffer, (ULONG)bufSize, &BytesReturned ); NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_SET_OID_VALUE: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); NtStatus = WdfRequestRetrieveInputBuffer(Request, sizeof(NDISPROT_SET_OID), &sysBuffer, &bufSize); if( !NT_SUCCESS(NtStatus) ) { DEBUGP(DL_FATAL, ("WdfRequestRetrieveInputBuffer failed %x\n", NtStatus)); break; } if (pOpenContext != NULL) { Status = ndisprotSetOidValue( pOpenContext, sysBuffer, (ULONG)bufSize ); BytesReturned = 0; NDIS_STATUS_TO_NT_STATUS(Status, &NtStatus); } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; case IOCTL_NDISPROT_INDICATE_STATUS: NPROT_ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); if (pOpenContext != NULL) { NtStatus = WdfRequestForwardToIoQueue(Request, pOpenContext->StatusIndicationQueue ); if(NT_SUCCESS(NtStatus)) { NtStatus = STATUS_PENDING; } } else { NtStatus = STATUS_DEVICE_NOT_CONNECTED; } break; default: NtStatus = STATUS_NOT_SUPPORTED; break; } if (NtStatus != STATUS_PENDING) { WdfRequestCompleteWithInformation(Request, NtStatus, BytesReturned); } return; }
VOID vJoy_EvtIoDeviceControlForRawPdo( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) /*++ Routine Description: This routine is the dispatch routine for device control requests. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - length of the request's output buffer, if an output buffer is available. InputBufferLength - length of the request's input buffer, if an input buffer is available. IoControlCode - the driver-defined or system-defined I/O control code (IOCTL) that is associated with the request. Return Value: VOID --*/ { NTSTATUS status = STATUS_SUCCESS; WDFDEVICE parent; WDF_REQUEST_FORWARD_OPTIONS forwardOptions; PDEVICE_EXTENSION pDevContext = NULL; WDFMEMORY inMemory, outMemory; PVOID buffer; size_t bufSize; WDFDEVICE hRawDevice = WdfIoQueueGetDevice(Queue); PRPDO_DEVICE_DATA pdoData = PdoGetData(hRawDevice); WDF_REQUEST_SEND_OPTIONS RequestOptions; WDFIOTARGET TargetOnParent; JOYSTICK_POSITION_V2 * iReport; WDFFILEOBJECT FileObj; USHORT id=0; PFILEOBJECT_EXTENSION pExtension=NULL; WDFREQUEST requestForceFeedback; PHID_XFER_PACKET transferPacket = NULL; PVOID ForceFeedbackBuffer = NULL; PVOID GenBuffer = NULL; size_t bytesReturned = 0; WDF_REQUEST_PARAMETERS Params; BOOLEAN FfbStat = FALSE; ULONG bytesToCopy = 0; BYTE Byte_tmp; UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtIoDeviceControlForRawPdo\n"); // // Process the ioctl and complete it when you are done. // Since the queue is configured for serial dispatch, you will // not receive another ioctl request until you complete this one. // switch (IoControlCode) { case 1234: // TODO: Remove for production //RequestOptions.Flags = WDF_REQUEST_SEND_OPTION_TIMEOUT; //RequestOptions.Size = sizeof(WDF_REQUEST_SEND_OPTIONS); //WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&RequestOptions, WDF_REL_TIMEOUT_IN_SEC(1)); //status = WdfIoTargetSendInternalIoctlSynchronously(pdoData->IoTargetToParent, Request, IoControlCode , NULL, NULL, &RequestOptions, NULL); break; // Testing case GET_DEV_STAT: // Get information for a device by device ID TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DEV_STAT\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy<5) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesToCopy=%d\n", bytesToCopy); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the buffer status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<5) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed - bytesReturned=%d\n", bytesReturned); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the id number from input buffer status = WdfRequestRetrieveInputBuffer(Request, sizeof(BYTE), &buffer, &bufSize); if (!NT_SUCCESS(status) || (bufSize!=1)) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: failed to retrieve input buffer\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get target ID id = *(BYTE *)buffer; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: id=%d\n", id); // Put data into output buffer // Byte 1: // Bit 0: Implemented? // Bit 1: FFB Device Enabled? // Bit 2: File Object associated with this device? pDevContext = GetDeviceContext(pdoData->hParentDevice); Byte_tmp = 0; // Implemented mask if (pDevContext->DeviceImplemented[id - 1]) Byte_tmp |= 1; else Byte_tmp &= 0xFE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Implemented=%x\n", pDevContext->DeviceImplemented[id - 1]); // FFB mask TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Dev Enabled=%x\n", pDevContext->FfbEnable[id - 1]); if (pDevContext->FfbEnable[id - 1]) Byte_tmp |= 2; else Byte_tmp &= 0xFD; // File Object if (pDevContext->DeviceFileObject[id - 1]) Byte_tmp |= 4; else Byte_tmp &= 0xFB; ((BYTE *)GenBuffer)[0] = Byte_tmp; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: Buffer[0]=%x\n", ((BYTE *)GenBuffer)[0]); // Byte2-5: Process ID // Get the context FileObj = pDevContext->DeviceFileObject[id - 1]; if (FileObj) *(DWORD *)(&((BYTE *)GenBuffer)[1]) = GetFileObjectContext(FileObj)->CallingProcessId; else *(DWORD *)(&((BYTE *)GenBuffer)[1]) = 0; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo[GET_DEV_STAT]: ProcessID=%x\n", *(DWORD *)(&((BYTE *)GenBuffer)[1])); // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case GET_DRV_INFO: // Get information for this driver TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO]\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); // Number of bytes to copy must be at least one byte bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy <1 ) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesToCopy <1\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Output buffer must be at least one byte status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - bytesReturned <1\n"); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; pDevContext = GetDeviceContext(pdoData->hParentDevice); // Return the data in the output buffer // BYTE 0 ////////////////////////////// // Bit 0 : Supports FFB? // Bit 1 : Reserved // Bit 2 : Mode: Multi-device // Bit 3 : Mode: FFB // BYTE 1 ////////////////////////////// // Bits 0-7 : Maximum number of possible devices (16 ==> 255) not regarding to mode // BYTE 2 ////////////////////////////// // Bits 0-7 : Number of existing devices // BYTE 3 ////////////////////////////// // Bits 0-7 : Number of devices that can still be implemented (This is the number of possible devices for the current mode minus the number of already existing devices). ////////////////////////////////// // Byte 0 Byte_tmp = 0; Byte_tmp |= 0x01; // FFB Supported Byte_tmp |= 0x00; // Default Mode (TODO: Change to real mode when Implemented) Multi-Device=0x04; FFB=0x80 ((BYTE *)GenBuffer)[0] = Byte_tmp; // Byte 1 if (bytesToCopy >= 2 && bytesReturned >= 2) { ((BYTE *)GenBuffer)[1] = MAX_N_DEVICES; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[1]=%02x\n", ((BYTE *)GenBuffer)[1]); } // Byte 2 if (bytesToCopy >= 3 && bytesReturned >= 3) { ((BYTE *)GenBuffer)[2] = (BYTE)(pDevContext->nDevices); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[2]=%02x\n", ((BYTE *)GenBuffer)[2]); } // Byte 3 - TODO: Change according to mode if (bytesToCopy >= 4 && bytesReturned >= 4) { ((BYTE *)GenBuffer)[3] = MAX_N_DEVICES - (BYTE)(pDevContext->nDevices); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: [GET_DRV_INFO] - Data byte[3]=%02x\n", ((BYTE *)GenBuffer)[3]); } ////////////////////////////////// // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case GET_DEV_INFO: // Get information for this device (and for the driver) // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; if (bytesToCopy<6) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (bytesReturned<6) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Copy the state to the buffer pDevContext = GetDeviceContext(pdoData->hParentDevice); ((BYTE *)GenBuffer)[0] = (BYTE)id; ((BYTE *)GenBuffer)[1] = (BYTE)(pDevContext->nDevices); ((BYTE *)GenBuffer)[2] = pDevContext->DeviceImplemented ? 1:0; ((BYTE *)GenBuffer)[3] = MAX_N_DEVICES; ((BYTE *)GenBuffer)[4] = 1; // Driver does support FFB ((BYTE *)GenBuffer)[5] = pDevContext->FfbEnable[id - 1]; // Device support FFB // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case 0x910: // Backward compatibility value of LOAD_POSITIONS case LOAD_POSITIONS: // KdBreakPoint(); Break When loading position status = WdfRequestRetrieveInputBuffer( Request, sizeof(JOYSTICK_POSITION), &buffer, &bufSize); if(!NT_SUCCESS(status)) break; // Get interface that this IRP came from, // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id==0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the incoming report and compare the id in the report // to the implicated id of the top-level collection // They should match iReport = buffer; if (iReport->bDevice != id) { WdfRequestComplete(Request, STATUS_CANCELLED); return; }; pDevContext = GetDeviceContext(pdoData->hParentDevice); LoadPositions(iReport, pDevContext, bufSize); status = vJoyCompleteReadReport(pdoData->hParentDevice, (BYTE)id); break; case GET_FFB_STAT: /* Get the status of the FFB mechanism */ // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); if (!bytesReturned) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Copy the state to the buffer pDevContext = GetDeviceContext(pdoData->hParentDevice); ((BYTE *)GenBuffer)[0] = pDevContext->FfbEnable[id-1]; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); return; case SET_FFB_STAT: /*Set the status of the FFB mechanism - Obsolete*/ // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); // Get interface that this IRP came from, // then get the implicated id of the top-level collection // Get the context, id and the status id = GetIdFromRawPdoRequest(Request, pExtension); // Illegal ID if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the data, process the data and complete the transaction //pDevContext = GetDeviceContext(pdoData->hParentDevice); - Obsolete //FfbActiveSet(*(BOOLEAN *)Params.Parameters.DeviceIoControl.Type3InputBuffer, id, pDevContext); - Obsolete WdfRequestComplete(Request, status); return; case GET_FFB_DATA: // Get interface that this IRP came from, // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); // If FFB is not active then just reject this request pDevContext = GetDeviceContext(pdoData->hParentDevice); if (id == 0xFFFF || !pDevContext->FfbEnable[id - 1]) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // If FFB is active then forward this request to the ReadQ and return status = WdfRequestForwardToIoQueue(Request, pDevContext->FfbReadQ[id - 1]); if(!NT_SUCCESS(status)){ TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTL, "WdfRequestForwardToIoQueue (FfbWriteQ[%d]) failed with status: 0x%x\n", id - 1, status); WdfRequestComplete(Request, status); } return; case GET_DRV_DEV_EN: // Get the number of devices that are currently enabled TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_EN\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; if (!pdoData) break; pDevContext = GetDeviceContext(pdoData->hParentDevice); if (!pDevContext) break; // The number of the max supported devices ((BYTE *)GenBuffer)[0] = (BYTE)(pDevContext->nDevices); // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case GET_DRV_DEV_MAX: // Get the max possible number of devices that this driver supports TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case GET_DRV_DEV_MAX\n"); // Get the buffer from the request // Get the data from the request WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // The number of the max supported devices ((BYTE *)GenBuffer)[0] = MAX_N_DEVICES; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case IS_DRV_FFB_CAP: // Test is this version of vJoy driver supports FFB TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case IS_DRV_FFB_CAP\n"); // Get the data from the request (Bytes to copy) WDF_REQUEST_PARAMETERS_INIT(&Params); WdfRequestGetParameters(Request, &Params); bytesToCopy = Params.Parameters.DeviceIoControl.OutputBufferLength; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d\n", bytesToCopy); if (bytesToCopy<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesToCopy=%d (Failed)\n", bytesToCopy); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the buffer from the request status = WdfRequestRetrieveOutputBuffer(Request, bytesToCopy, &GenBuffer, &bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d\n", bytesReturned); if (bytesReturned<1) { TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: bytesReturned=%d (Failed)\n", bytesReturned); WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Yes, this driver supports FFB ((BYTE *)GenBuffer)[0] = 1; // Complete the transaction WdfRequestCompleteWithInformation(Request, status, bytesReturned); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: GenBuffer[0]=%d\n", ((BYTE *)GenBuffer)[0]); return; case RESET_DEV: /* Resets device(s) to predefined values */ TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: Case RESET_DEV\n"); // then get the implicated id of the top-level collection id = GetIdFromRawPdoRequest(Request, pExtension); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtIoDeviceControlForRawPdo: ID=%d\n", id); // Sanity check if (id == 0xFFFF) { WdfRequestComplete(Request, STATUS_NO_SUCH_DEVICE); return; }; // Get the context of vJoy device pDevContext = GetDeviceContext(pdoData->hParentDevice); // Reset device(s) status = ResetDevice(id, pDevContext); WdfRequestCompleteWithInformation(Request, status, 0); return; default: break; } WdfRequestComplete(Request, status); return; }
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__); }
VOID tgwinkEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) { WDFMEMORY mem; NTSTATUS status; WDFDEVICE dev; PDEVICE_CONTEXT context; void *uBase = NULL; LARGE_INTEGER offset; size_t size; dev = WdfIoQueueGetDevice(Queue); context = DeviceGetContext(dev); switch (IoControlCode) { case IOCTL_TGWINK_SAY_HELLO: if (OutputBufferLength != 4) { WdfRequestComplete(Request, STATUS_BAD_DATA); break; } status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, status); break; } *((DWORD32 *)(WdfMemoryGetBuffer(mem, NULL))) = 0x5a5aa5a5; WdfRequestComplete(Request, STATUS_SUCCESS); break; case IOCTL_TGWINK_MAP_BAR_0: if (sizeof(void *) > OutputBufferLength) { KdPrint("tgwinkEvtIoDeviceControl needs a larger buffer (%d > %d)!\n", sizeof(void *), OutputBufferLength); WdfRequestComplete(Request, STATUS_BUFFER_TOO_SMALL); break; } offset = context->bar[0].phyAddr; size = context->bar[0].length; status = ZwMapViewOfSection(context->hMemory, ZwCurrentProcess(), &uBase, 0, 0, &offset, &size, ViewUnmap, 0, PAGE_READWRITE); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not map view of section, status "); switch (status) { case STATUS_CONFLICTING_ADDRESSES: KdPrint("STATUS_CONFLICTING_ADDRESSES\n"); break; case STATUS_INVALID_PAGE_PROTECTION: KdPrint("STATUS_INVALID_PAGE_PROTECTION\n"); break; case STATUS_SECTION_PROTECTION: KdPrint("STATUS_SECTION_PROTECTION\n"); break; default: KdPrint("0x % x\n", status); break; } WdfRequestComplete(Request, status); break; } status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfVerifierDbgBreakPoint(); WdfRequestComplete(Request, status); break; } *((void **)(WdfMemoryGetBuffer(mem, NULL))) = uBase; WdfRequestComplete(Request, STATUS_SUCCESS); break; case IOCTL_TGWINK_READ_PHYS: { PVOID buf; ULONG_PTR page, ofs, vtgt = 0; SIZE_T vsz = 0; if (InputBufferLength != sizeof(PVOID)) { KdPrint("tgwinkEvtIoDeviceControl requires a %d-byte buffer for this ioctl (got %d)\n", sizeof(PVOID), OutputBufferLength); WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); break; } status = WdfRequestRetrieveInputBuffer(Request, sizeof(PVOID), &buf, NULL); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } ofs = *((ULONG_PTR *)buf); page = ofs & ~0xfff; vsz = OutputBufferLength + (page ^ ofs); buf = NULL; status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not get request memory buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } status = ZwMapViewOfSection(context->hMemory, (HANDLE)-1, (PVOID *)&vtgt, 0, 0, (PLARGE_INTEGER)&page, &vsz, ViewUnmap, 0, PAGE_READONLY); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl could not map view of physical memory section, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } ofs -= page; status = WdfMemoryCopyFromBuffer(mem, 0, (PVOID)(vtgt + ofs), OutputBufferLength); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to copy data from memory to buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } status = ZwUnmapViewOfSection((HANDLE)-1, (PVOID)vtgt); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to unmap view of physical memory section, status 0x%x\n", status); WdfRequestComplete(Request, status); break; } WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, OutputBufferLength); } break; case IOCTL_TGWINK_PEND_INTR: { WdfWaitLockAcquire(context->nnLock, NULL); if (context->notifyNext) { PINTERRUPT_CONTEXT pCtx = InterruptGetContext(context->hIrq); status = WdfRequestRetrieveOutputMemory(Request, &mem); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to retrieve output memory, status 0x%x\n", status); WdfRequestComplete(Request, status); } status = WdfMemoryCopyFromBuffer(mem, 0, &pCtx->serial, 8); if (!NT_SUCCESS(status)) { KdPrint("tgwinkEvtIoDeviceControl failed to copy interrupt number to buffer, status 0x%x\n", status); WdfRequestComplete(Request, status); } WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, 8); context->notifyNext = 0; KdPrint("tgwinkEvtIoDeviceControl satisfied interrupt notification request synchronously.\n"); //WdfInterruptEnable(context->hIrq); } else { KdPrint("tgwinkEvtIoDeviceControl forwarding PEND_INTR request to notification queue\n"); WdfRequestForwardToIoQueue(Request, context->NotificationQueue); } WdfWaitLockRelease(context->nnLock); } break; default: WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); } }
// 并行处理 VOID CY001Drv::DeviceIoControlParallel(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { NTSTATUS status = STATUS_SUCCESS; ULONG ulRetLen = 0; size_t size = 0; void* pBufferInput = NULL; void* pBufferOutput = NULL; KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlParallel] CtlCode:0x%0.8X", IoControlCode); // 取得输入缓冲区,判断其有效性 if(InputBufferLength){ status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size); if(status != STATUS_SUCCESS || pBufferInput == NULL || size < InputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // 取得输出缓冲区,判断其有效性 if(OutputBufferLength){ status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size); if(status != STATUS_SUCCESS || pBufferOutput == NULL || size < OutputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // // 下面是主处理过程。 // switch(IoControlCode) { // 取得驱动的版本信息 case IOCTL_GET_DRIVER_VERSION: { PDRIVER_VERSION pVersion = (PDRIVER_VERSION)pBufferOutput; ULONG length; char tcsBuffer[120]; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_GET_DRIVER_VERSION"); if(OutputBufferLength < sizeof(DRIVER_VERSION)){ status = STATUS_BUFFER_TOO_SMALL; break; } pVersion->DriverType = DR_WDF; pVersion->FirmwareType = FW_NOT_CY001; ulRetLen = sizeof(DRIVER_VERSION);// 告示返回长度 // 根据String描述符,判断Firmware代码是否已经被加载。 GetStringDes(2, 0, tcsBuffer, 120, &length); if(length){ WCHAR* pCyName = L"CY001 V"; size_t len; int nIndex; if(length < 8) break; RtlStringCchLengthW(pCyName, 7, &len); for(nIndex = 0; nIndex < len; nIndex++){ if(pCyName[nIndex] != ((WCHAR*)tcsBuffer)[nIndex]) break; } if(nIndex == len) pVersion->FirmwareType = FW_CY001; // 完全相符,说明新版Firmware已经加载到开发板。 } break; } // 收到App发送过来的一个同步Request,我们应该把它保存到同步Queue中,等到有同步事件发生的时候再从Queue中取出并完成。 case IOCTL_USB_SYNC: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); status = WdfRequestForwardToIoQueue(Request, m_hAppSyncManualQueue); // 直接返回,不调用WdfRequestComplete函数。 // 请求者将不会为此而等待;请求的完成在将来的某个时刻。 // 这就是所谓的异步处理之要义了。 if(NT_SUCCESS(status)) return; break; // 清空同步队列中的所有请求 case IOCTL_USB_SYNC_RELEASE: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); ClearSyncQueue(); break; // 应用程序退出,取消所有被阻塞的请求。 case IOCTL_APP_EXIT_CANCEL: // 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。 //WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo); break; // 取得当前的配置号.总是设置为0,因为在WDF框架中,0以外的配置是不被支持的。 case IOCTL_USB_GET_CURRENT_CONFIG: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CURRENT_CONFIG"); if(InputBufferLength < 4){ status = STATUS_INVALID_PARAMETER; break; } *(PULONG)pBufferInput = 0;// 直接赋值0,即总是选择0号配置。也可以发送URB到总线获取当前配置选项。 ulRetLen = sizeof(ULONG); break; } case IOCTL_USB_ABORTPIPE: { ULONG pipenum = *((PULONG) pBufferOutput); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_ABORTPIPE"); status = AbortPipe(pipenum); } break; // 获取Pipe信息 case IOCTL_USB_GET_PIPE_INFO: { // 遍历获取Pipe信息,复制到输出缓冲中。 BYTE byCurSettingIndex = 0; BYTE byPipeNum = 0; BYTE index; USB_INTERFACE_DESCRIPTOR interfaceDescriptor; WDF_USB_PIPE_INFORMATION pipeInfor; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_PIPE_INFO"); // 取得Pipe数。根据Pipe数计算缓冲区长度 byCurSettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); WdfUsbInterfaceGetDescriptor(m_hUsbInterface, byCurSettingIndex, &interfaceDescriptor); byPipeNum = WdfUsbInterfaceGetNumConfiguredPipes(m_hUsbInterface); if(OutputBufferLength < byPipeNum * sizeof(pipeInfor)){ status = STATUS_BUFFER_TOO_SMALL; // 缓冲区不足 }else{ ulRetLen = byPipeNum*sizeof(pipeInfor); // 遍历获取全部管道信息,拷贝到输出缓冲中。 // 应用程序得到输出缓冲的时候,也应该使用WDF_USB_PIPE_INFORMATION结构体解析缓冲区。 for(index = 0; index < byPipeNum; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfor); WdfUsbInterfaceGetEndpointInformation(m_hUsbInterface, byCurSettingIndex, index, &pipeInfor); RtlCopyMemory((PUCHAR)pBufferOutput + index*pipeInfor.Size, &pipeInfor, sizeof(pipeInfor)); } } } break; // 获取设备描述符 case IOCTL_USB_GET_DEVICE_DESCRIPTOR: { USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor; WdfUsbTargetDeviceGetDeviceDescriptor(m_hUsbDevice, &UsbDeviceDescriptor); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DEVICE_DESCRIPTOR"); // 判断输入缓冲区的长度是否足够长 if(OutputBufferLength < UsbDeviceDescriptor.bLength) status = STATUS_BUFFER_TOO_SMALL; else{ RtlCopyMemory(pBufferOutput, &UsbDeviceDescriptor, UsbDeviceDescriptor.bLength); ulRetLen = UsbDeviceDescriptor.bLength; } break; } // 获取字符串描述符 case IOCTL_USB_GET_STRING_DESCRIPTOR: { PGET_STRING_DESCRIPTOR Input = (PGET_STRING_DESCRIPTOR)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_STRING_DESCRIPTOR"); status = GetStringDes(Input->Index, Input->LanguageId, pBufferOutput, OutputBufferLength, &ulRetLen); // 由字符长度调整为字节长度 if(NT_SUCCESS(status) && ulRetLen > 0) ulRetLen *= (sizeof(WCHAR)/sizeof(char)); break; } // 获取配置描述信息。 case IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR"); // 首先获得配置描述符的长度。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, NULL, (USHORT*)&size); if(!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) break; // 输出缓冲区不够长 if(OutputBufferLength < size) break; // 正式取得配置描述符。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, pBufferOutput, (USHORT*)&size); if(!NT_SUCCESS(status)) break; ulRetLen = size; break; } // 根据可选值配置接口 case IOCTL_USB_SET_INTERFACE: { BYTE byAlterSetting = *(BYTE*)pBufferInput; BYTE byCurSetting = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); // 当前Alternate值 KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SETINTERFACE"); if(InputBufferLength < 1 || OutputBufferLength < 1) { status = STATUS_BUFFER_TOO_SMALL; break; } // 如果传入的可选值与当前的不同,则重新配置接口; // 否则直接返回。 if(byCurSetting != byAlterSetting) { WDF_USB_INTERFACE_SELECT_SETTING_PARAMS par; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&par, byAlterSetting); status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, NULL, &par); } *(BYTE*)pBufferOutput = byCurSetting; break; } // 固件Rest。自定义命令,与Port Rest是两码事。 case IOCTL_USB_FIRMWRAE_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_FIRMWRAE_RESET"); if(InputBufferLength < 1 || pBufferInput == NULL) status = STATUS_INVALID_PARAMETER; else status = FirmwareReset(*(char*)pBufferInput); break; } // 重置USB总线端口 case IOCTL_USB_PORT_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PORT_RESET"); WdfUsbTargetDeviceResetPortSynchronously(m_hUsbDevice); break; } // 管道重置 case IOCTL_USB_PIPE_RESET: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_RESET"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeResetSynchronously(pipe, NULL, NULL); break; } // 中断管道,放弃管道当前正在进行的操作 case IOCTL_USB_PIPE_ABORT: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_ABORT"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeAbortSynchronously(pipe, NULL, NULL); break; } // 取得驱动错误信息,驱动总是把最后一次发现的错误保存在设备对象的环境块中。 // 这个逻辑虽然实现了,但目前的版本中,应用程序并没有利用这个接口。 case IOCTL_USB_GET_LAST_ERROR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LAST_ERROR"); if (OutputBufferLength >= sizeof(ULONG)) *((PULONG)pBufferOutput) = m_ulLastUSBErrorStatusValue; else status = STATUS_BUFFER_TOO_SMALL; ulRetLen = sizeof(ULONG); break; } // Clear feature命令 case IOCTL_USB_SET_CLEAR_FEATURE: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_CLEAR_FEATURE"); status = UsbSetOrClearFeature(Request); break; } // 为USB设备加载固件程序。带有偏移量参数,用这个分支;不带偏移量,可用下一个分支。 // 带偏移量的情况下,固件代码是一段一段地加载; // 不带偏移量的情况,固件代码作为一整块一次性被加载。 case IOCTL_FIRMWARE_UPLOAD_OFFSET: { void* pData = pBufferOutput; WORD offset = 0; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD_OFFSET"); if(InputBufferLength < sizeof(WORD)){ status = STATUS_INVALID_PARAMETER; break; } offset = *(WORD*)pBufferInput; status = FirmwareUpload((PUCHAR)pData, OutputBufferLength, offset); break; } // 为USB设备加载固件程序。 case IOCTL_FIRMWARE_UPLOAD: { void* pData = pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD"); status = FirmwareUpload((PUCHAR)pData, InputBufferLength, 0); break; } // 读取开发板设备的RAM内容。RAM也就是内存。 // 每次从同一地址读取的内容可能不尽相同,开发板中固件程序在不断运行,RAM被用来储数据(包括临时数据)。 case IOCTL_FIRMWARE_READ_RAM: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_READ_RAM"); status = ReadRAM(Request, &ulRetLen);// inforVal中保存读取的长度 break; } // 其他的请求 default: { // 一律转发到SerialQueue中去。 WdfRequestForwardToIoQueue(Request, m_hIoCtlSerialQueue); // 命令转发之后,这里必须直接返回,千万不可调用WdfRequestComplete函数。 // 否则会导致一个Request被完成两次的错误。 return; } } // 完成请求 WdfRequestCompleteWithInformation(Request, status, ulRetLen); }
// 这里面的IO操作是经过序列化的。一个挨着一个,所以绝不会发生重入问题。 // VOID CY001Drv::DeviceIoControlSerial(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulRetLen = 0; size_t size; void* pBufferInput = NULL; void* pBufferOutput = NULL; KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlSerial]"); // 取得输入/输出缓冲区 if(InputBufferLength)WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size); if(OutputBufferLength)WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size); switch(IoControlCode) { // 设置数码管 case IOCTL_USB_SET_DIGITRON: { CHAR ch = *(CHAR*)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_DIGITRON"); SetDigitron(ch); break; } // 读数码管 case IOCTL_USB_GET_DIGITRON: { UCHAR* pCh = (UCHAR*)pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DIGITRON"); GetDigitron(pCh); ulRetLen = 1; break; } // 设置LED灯(共4盏) case IOCTL_USB_SET_LEDs: { CHAR ch = *(CHAR*)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_LEDs"); SetLEDs(ch); break; } // 读取LED灯(共4盏)的当前状态 case IOCTL_USB_GET_LEDs: { UCHAR* pCh = (UCHAR*)pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LEDs"); GetLEDs(pCh); ulRetLen = 1; break; } // 控制命令。 // 分为:USB协议预定义命令、Vendor自定义命令、特殊类(class)命令。 case IOCTL_USB_CTL_REQUEST: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_CTL_REQUEST"); ntStatus = UsbControlRequest(Request); if(NT_SUCCESS(ntStatus))return; break; } // 开启中断读 case IOCTL_START_INT_READ: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_START_INT_READ"); ntStatus = InterruptReadStart(); break; // 控制程序发送读请求。它们是被阻塞的,放至Queue中排队,所以不要即可完成他们。 case IOCTL_INT_READ_KEYs: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_INT_READ_KEYs"); ntStatus = WdfRequestForwardToIoQueue(Request, m_hInterruptManualQueue); if(NT_SUCCESS(ntStatus)) return;// 成功,直接返回;异步完成。 break; // 终止中断读 case IOCTL_STOP_INT_READ: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_STOP_INT_READ"); InterruptReadStop(); ntStatus = STATUS_SUCCESS; break; default: // 不应该到这里。 // 对于不能识别的IO控制命令,这里做错误处理。 KDBG(DPFLTR_INFO_LEVEL, "Unknown Request: %08x(%d)!!!", IoControlCode, IoControlCode); ntStatus = STATUS_INVALID_PARAMETER; break; } WdfRequestCompleteWithInformation(Request, ntStatus, ulRetLen); return; }
NTSTATUS CBCardTracking( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBCardTracking: callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was validated by the smclib (i.e. a card removal request will only be passed if a card is present). for a win95 build STATUS_PENDING will be returned without any other action. for NT the cancel routine for the irp will be set to the drivers cancel routine. Arguments: SmartcardExtension context of call Return Value: STATUS_PENDING --*/ { WDFREQUEST request; PDEVICE_EXTENSION DeviceExtension; NTSTATUS status; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBCardTracking: Enter\n" ) ); request = GET_WDFREQUEST_FROM_IRP(SmartcardExtension->OsData->NotificationIrp); DeviceExtension = GetDeviceExtension(WdfIoQueueGetDevice(WdfRequestGetIoQueue(request))); IoMarkIrpPending(SmartcardExtension->OsData->NotificationIrp); // // Move the stack pointer back to where it was when the IRP // was delivered to the driver. This compensates for the // IoSetNextIrpStackLocation that we did when we presented the IRP // to the smartcard libarary. // IoSkipCurrentIrpStackLocation(SmartcardExtension->OsData->NotificationIrp); status = WdfRequestForwardToIoQueue(request, DeviceExtension->NotificationQueue); if (!NT_SUCCESS(status)) { NT_ASSERT(NT_SUCCESS(status)); InterlockedExchangePointer( &(SmartcardExtension->OsData->NotificationIrp), NULL ); WdfRequestComplete(request, status); } status = STATUS_PENDING; SmartcardDebug( DEBUG_TRACE, ( "PSCR!CBCardTracking: Exit \n" ) ); return status; }
VOID SimSensorAddReadRequest ( _In_ WDFDEVICE Device, _In_ WDFREQUEST ReadRequest ) /*++ Routine Description: Handles IOCTL_THERMAL_READ_TEMPERATURE. If the request can be satisfied, it is completed immediately. Else, adds request to pending request queue. Arguments: Device - Supplies a handle to the device that received the request. ReadRequest - Supplies a handle to the request. --*/ { ULONG BytesReturned; PREAD_REQUEST_CONTEXT Context; WDF_OBJECT_ATTRIBUTES ContextAttributes; PFDO_DATA DevExt; LARGE_INTEGER ExpirationTime; size_t Length; BOOLEAN LockHeld; PULONG RequestTemperature; NTSTATUS Status; ULONG Temperature; WDFTIMER Timer; WDF_OBJECT_ATTRIBUTES TimerAttributes; WDF_TIMER_CONFIG TimerConfig; PTHERMAL_WAIT_READ ThermalWaitRead; DebugEnter(); PAGED_CODE(); DevExt = GetDeviceExtension(Device); BytesReturned = 0; LockHeld = FALSE; Status = WdfRequestRetrieveInputBuffer(ReadRequest, sizeof(THERMAL_WAIT_READ), &ThermalWaitRead, &Length); if (!NT_SUCCESS(Status) || Length != sizeof(THERMAL_WAIT_READ)) { // // This request is malformed, bail. // WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } if (ThermalWaitRead->Timeout != -1 /* INFINITE */ ) { // // Estimate the system time this request will expire at. // KeQuerySystemTime(&ExpirationTime); ExpirationTime.QuadPart += ThermalWaitRead->Timeout * 10000; } else { // // Value which indicates the request never expires. // ExpirationTime.QuadPart = -1LL /* INFINITE */; } // // Handle the immediate timeout case in the fast path. // Temperature = SimSensorReadVirtualTemperature(Device); if (SimSensorAreConstraintsSatisfied(Temperature, ThermalWaitRead->LowTemperature, ThermalWaitRead->HighTemperature, ExpirationTime)) { Status = WdfRequestRetrieveOutputBuffer(ReadRequest, sizeof(ULONG), &RequestTemperature, &Length); if(NT_SUCCESS(Status) && Length == sizeof(ULONG)) { *RequestTemperature = Temperature; BytesReturned = sizeof(ULONG); } else { Status = STATUS_INVALID_PARAMETER; DebugPrint(SIMSENSOR_ERROR, "WdfRequestRetrieveOutputBuffer() Failed. 0x%x", Status); } WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); } else { WdfWaitLockAcquire(DevExt->QueueLock, NULL); LockHeld = TRUE; // // Create a context to store request-specific information. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ContextAttributes, READ_REQUEST_CONTEXT); Status = WdfObjectAllocateContext(ReadRequest, &ContextAttributes, &Context); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfObjectAllocateContext() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } Context->ExpirationTime.QuadPart = ExpirationTime.QuadPart; Context->LowTemperature = ThermalWaitRead->LowTemperature; Context->HighTemperature = ThermalWaitRead->HighTemperature; if(Context->ExpirationTime.QuadPart != -1LL /* INFINITE */ ) { // // This request eventually expires, create a timer to complete it. // WDF_TIMER_CONFIG_INIT(&TimerConfig, SimSensorExpiredRequestTimer); WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; TimerAttributes.SynchronizationScope = WdfSynchronizationScopeNone; TimerAttributes.ParentObject = Device; Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &Timer); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfTimerCreate() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(ThermalWaitRead->Timeout)); } Status = WdfRequestForwardToIoQueue(ReadRequest, DevExt->PendingRequestQueue); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfRequestForwardToIoQueue() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } // // Force a rescan of the queue to update the interrupt thresholds. // SimSensorScanPendingQueue(Device); } AddReadRequestEnd: if(LockHeld == TRUE) { WdfWaitLockRelease(DevExt->QueueLock); } DebugExitStatus(Status); }