NTSTATUS LoopbackDeviceCreateIoQueue(_In_ WDFDEVICE device) { TraceEntry(); NTSTATUS status = STATUS_SUCCESS; WDF_IO_QUEUE_CONFIG config; // // Register I/O callbacks to tell the framework that you are interested // in handling read and write requests. // // A default queue is where requests are delivered by the framework // by default unless specific request handlers are configured using // WdfDeviceConfigureRequestDispatching. // // WdfIoQueueDispatchSequential means that the queue is setup to dispatch // no more than one WDFREQUEST at a time, so driver does not need to // protect data that could be accessed by the queue's callbacks concurrently // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&config, WdfIoQueueDispatchSequential); config.PowerManaged = WdfTrue; config.EvtIoWrite = LoopbackEvtIoWrite; config.EvtIoRead = LoopbackEvtIoRead; config.EvtIoDeviceControl = LoopbackEvtIoDeviceControl; status = WdfIoQueueCreate( device, &config, WDF_NO_OBJECT_ATTRIBUTES, nullptr); TraceStatusAndReturn(status); }
VOID DevicePerformSoftReset ( _In_ WDFDEVICE Device ) /*++ Routine Description: This functions performs soft reset of the controller and completes any initialization that needs to be done afterwards. Arguments: Device - Wdf FDO device object representing the controller --*/ { TraceEntry(); UNREFERENCED_PARAMETER(Device); // // #### TODO: Insert code that performs a controller soft reset #### // TraceExit(); }
VOID HandleUsbDisconnect ( WDFDEVICE WdfDevice ) /*++ Routine Description: Handles a disconnect event from the controller. Arguments: WdfDevice - WDFDEVICE object representing the controller. --*/ { TraceEntry(); UNREFERENCED_PARAMETER(WdfDevice); // // #### TODO: Add any code needed to configure controller after disconnect event #### // TraceExit(); }
VOID UfxDevice_EvtCleanupCallback ( _In_ WDFOBJECT UfxDevice ) /*++ Routine Description: EvtCleanupCallback handler for the UFXDEVICE object. Arguments: UfxDevice - Wdf object representing the UFXDEVICE --*/ { PUFXDEVICE_CONTEXT DeviceContext = NULL; PCONTROLLER_CONTEXT ControllerContext = NULL; TraceEntry(); DeviceContext = UfxDeviceGetContext(UfxDevice); ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); TraceExit(); }
VOID DefaultQueue_EvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: EvtIoDeviceControl handler for the default Queue Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. OutputBufferLength - Size of the output buffer in bytes InputBufferLength - Size of the input buffer in bytes IoControlCode - I/O control code. --*/ { WDFDEVICE WdfDevice; PCONTROLLER_CONTEXT ControllerContext; BOOLEAN HandledbyUfx; TraceEntry(); TraceVerbose("Queue 0x%p, Request 0x%p, OutputBufferLength %d, " "InputBufferLength %d, IoControlCode %d", Queue, Request, (int) OutputBufferLength, (int) InputBufferLength, IoControlCode); WdfDevice = WdfIoQueueGetDevice(Queue); ControllerContext = DeviceGetControllerContext(WdfDevice); HandledbyUfx = UfxDeviceIoControl( ControllerContext->UfxDevice, Request, OutputBufferLength, InputBufferLength, IoControlCode); if (!HandledbyUfx) { TraceError("Recieved an unsupported IOCTL"); WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST); } TraceExit(); }
BOOLEAN DeviceInterrupt_EvtAttachDetachInterruptIsr ( _In_ WDFINTERRUPT Interrupt, _In_ ULONG MessageID ) /*++ Routine Description: 'EvtInterruptIsr' handler for the attach/detach interrupt object. http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx Arguments: Interrupt - Associated interrupt object. MessageID - Message IDs for MSI Return Value: BOOLEAN --*/ { PCONTROLLER_CONTEXT ControllerContext; UNREFERENCED_PARAMETER(MessageID); TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfInterruptGetDevice(Interrupt)); WdfInterruptAcquireLock(ControllerContext->DeviceInterrupt); // // This is an ActiveBoth interrupt used for attach/detach. State is determined // by counting interrupts. Previous state was attached, so this is a detach. // if (!ControllerContext->Attached) { ControllerContext->Attached = TRUE; ControllerContext->GotAttachOrDetach = TRUE; (void) WdfInterruptQueueDpcForIsr(Interrupt); } else { ControllerContext->Attached = FALSE; ControllerContext->GotAttachOrDetach = TRUE; (void) WdfInterruptQueueDpcForIsr(Interrupt); } WdfInterruptReleaseLock(ControllerContext->DeviceInterrupt); TraceExit(); return TRUE; }
VOID LoopbackEvtIoRead( _In_ WDFQUEUE queue, _In_ WDFREQUEST request, _In_ size_t length ) { TraceEntry(); ForwardRequestToIoTarget(queue, request, length); }
VOID UfxDevice_EvtDeviceSuperSpeedPowerFeature ( _In_ UFXDEVICE Device, _In_ USHORT Feature, _In_ BOOLEAN Set ) /*++ Routine Description: EvtDeviceSuperSpeedPowerFeature handler for the UFXDEVICE object. Handles a set or clear U1/U2 request from the host. Arguments: UfxDevice - UFXDEVICE object representing the device. Feature - Indicates the feature being set or cleared. Either U1 or U2 enable. Set - Indicates if the feature should be set or cleared --*/ { TraceEntry(); if (Feature == USB_FEATURE_U1_ENABLE) { if (Set == TRUE) { // // #### TODO: Insert code to initiate U1 #### // } else { // // #### TODO: Insert code to exit U1 #### // } } else if (Feature == USB_FEATURE_U2_ENABLE) { if (Set == TRUE) { // // #### TODO: Insert code to initiate U2 #### // } else { // // #### TODO: Insert code to exit U2 #### // } } else { NT_ASSERT(FALSE); } UfxDeviceEventComplete(Device, STATUS_SUCCESS); TraceExit(); }
VOID HandleUsbConnect ( WDFDEVICE WdfDevice ) /*++ Routine Description: Handles a connect event from the controller. Arguments: WDfDevice - WDFDEVICE object representing the controller. --*/ { PCONTROLLER_CONTEXT ControllerContext; USB_DEVICE_SPEED DeviceSpeed; TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfDevice); // // Read the device speed. // // // #### TODO: Add code to read device speed from the controller #### // // Sample will assume SuperSpeed operation for illustration purposes DeviceSpeed = UsbSuperSpeed; // // #### TODO: Add any code needed to configure the controller after connect has occurred #### // ControllerContext->Speed = DeviceSpeed; TraceInformation("Connected Speed is %d!", DeviceSpeed); // // Notify UFX about reset, which will take care of updating // Max Packet Size for EP0 by calling descriptor update. // UfxDeviceNotifyReset(ControllerContext->UfxDevice, DeviceSpeed); ControllerContext->Connect = TRUE; TraceExit(); }
NTSTATUS DefaultQueueCreate( _In_ WDFDEVICE Device ) /*++ Routine Description: Creates and configures the default IO Queue for the device. Arguments: Device - Handle to a framework device object. Return Value: Appropriate NTSTATUS message --*/ { NTSTATUS Status; WDF_IO_QUEUE_CONFIG QueueConfig; TraceEntry(); PAGED_CODE(); // // Create the default queue // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &QueueConfig, WdfIoQueueDispatchParallel ); QueueConfig.PowerManaged = WdfTrue; QueueConfig.EvtIoDeviceControl = DefaultQueue_EvtIoDeviceControl; QueueConfig.EvtIoInternalDeviceControl = DefaultQueue_EvtIoInternalDeviceControl; Status = WdfIoQueueCreate( Device, &QueueConfig, WDF_NO_OBJECT_ATTRIBUTES, NULL); CHK_NT_MSG(Status, "WdfIoQueueCreate failed"); End: TraceExit(); return Status; }
VOID UfxDeviceSetRunStop ( _In_ UFXDEVICE UfxDevice, _In_ BOOLEAN Set ) /*++ Routine Description: Function that sets or clears the run/stop state on the controller. Setting the run state will initiate a connect to the host. Arguments: UfxDevice - Wdf object representing the UFXDEVICE Set - TRUE if setting the run state, FALSE if clearing the run state. --*/ { PCONTROLLER_CONTEXT ControllerContext; PUFXDEVICE_CONTEXT DeviceContext; BOOLEAN EventComplete; TraceEntry(); DeviceContext = UfxDeviceGetContext(UfxDevice); ControllerContext = DeviceGetControllerContext(DeviceContext->FdoWdfDevice); EventComplete = TRUE; WdfSpinLockAcquire(ControllerContext->DpcLock); if (Set) { // // #### TODO: Insert code to set the run state on the controller #### // } else { // // #### TODO: Insert code to clear the run state on the controller #### // } WdfSpinLockRelease(ControllerContext->DpcLock); if (EventComplete) { UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); } TraceExit(); }
VOID UfxDevice_EvtDeviceRemoteWakeupSignal ( _In_ UFXDEVICE UfxDevice ) /*++ Routine Description: Signals Remote Wakeup to the Host by issuing a link state change command. It acquires and releases the power reference to ensure a valid power state before accessing the device. Arguments: UfxDevice - UFXDEVICE object representing the device. --*/ { NTSTATUS Status; PUFXDEVICE_CONTEXT DeviceContext; PAGED_CODE(); TraceEntry(); DeviceContext = UfxDeviceGetContext(UfxDevice); // // Stop Idle to ensure the device is in working state // Status = WdfDeviceStopIdle(DeviceContext->FdoWdfDevice, TRUE); if (!NT_SUCCESS(Status)) { TraceError("Failed to stop idle %!STATUS!", Status); goto End; } // // Issue a Link State Change Request. // // // #### TODO: Insert code to issue a link state change on the controller #### // WdfDeviceResumeIdle(DeviceContext->FdoWdfDevice); End: UfxDeviceEventComplete(UfxDevice, Status); TraceExit(); }
NTSTATUS OnEvtDeviceReleaseHardware ( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDeviceReleaseHardware callback handler for the controller FDO. It expects Register memory and two interrupts - Device and Wake. Arguments: Device - WDFDEVICE object representing the controller. ResourcesTranslated - Translated resources available for the controller. Return Value: Appropriate NTSTATUS value --*/ { PREGISTERS_CONTEXT RegistersContext; PCONTROLLER_CONTEXT ControllerContext; TraceEntry(); PAGED_CODE(); UNREFERENCED_PARAMETER(ResourcesTranslated); ControllerContext = DeviceGetControllerContext(Device); ControllerContext->DeviceInterrupt = NULL; ControllerContext->AttachDetachInterrupt = NULL; RegistersContext = DeviceGetRegistersContext(Device); if ((RegistersContext == NULL) || (RegistersContext->RegisterBase == NULL)) { goto End; } MmUnmapIoSpace(RegistersContext->RegisterBase, RegistersContext->RegistersLength); RtlZeroMemory(RegistersContext, sizeof(*RegistersContext)); End: TraceExit(); return STATUS_SUCCESS; }
NTSTATUS OnEvtDeviceD0Entry ( _In_ WDFDEVICE Device, _In_ WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: Called by the framework after entering D0 state. Arguments: Device - WDFDEVICE framework handle to the bus FDO. PreviousState - The WDF_POWER_DEVICE_STATE from which the stack is making this transition. Return Value: Returns STATUS_SUCCESS or an appropriate NTSTATUS code otherwise. --*/ { PCONTROLLER_CONTEXT ControllerContext; TraceEntry(); ControllerContext = DeviceGetControllerContext(Device); if (PreviousState > WdfPowerDeviceD1) { DevicePerformSoftReset(Device); WdfWaitLockAcquire(ControllerContext->InitializeDefaultEndpointLock, NULL); ControllerContext->InitializeDefaultEndpoint = TRUE; WdfWaitLockRelease(ControllerContext->InitializeDefaultEndpointLock); } if (PreviousState == WdfPowerDeviceD3Final) { // // Notify UFX that HW is now ready // UfxDeviceNotifyHardwareReady(ControllerContext->UfxDevice); } TraceExit(); return STATUS_SUCCESS; }
VOID UfxDevice_Reset ( _In_ UFXDEVICE Device ) /*++ Routine Description: Cancels all transfers and disables non-zero endpoints in response to USB reset. Arguments: UfxDevice - UFXDEVICE object representing the device. --*/ { PUFXDEVICE_CONTEXT DeviceContext; PREGISTERS_CONTEXT RegistersContext; ULONG EpIndex; TraceEntry(); DeviceContext = UfxDeviceGetContext(Device); RegistersContext = DeviceGetRegistersContext(DeviceContext->FdoWdfDevice); // // Get EP0 back to setup stage. // TransferReset(WdfCollectionGetFirstItem(DeviceContext->Endpoints)); // // Disable all non-default endpoints // // // #### TODO: Insert code to disable non-default endpoints #### // // // End any transfers on non-default endpoints. // for (EpIndex = 1; EpIndex < WdfCollectionGetCount(DeviceContext->Endpoints); EpIndex++) { TransferReset(WdfCollectionGetItem(DeviceContext->Endpoints, EpIndex)); } TraceExit(); }
BOOLEAN DeviceInterrupt_EvtInterruptIsr( _In_ WDFINTERRUPT Interrupt, _In_ ULONG MessageID ) /*++ Routine Description: 'EvtInterruptIsr' handler for the device interrupt object. http://msdn.microsoft.com/en-us/library/windows/hardware/ff541735(v=vs.85).aspx Arguments: Interrupt - Associated interrupt object. MessageID - Message IDs for MSI Return Value: Appropriate NTSTATUS value --*/ { BOOLEAN PendingEvents; TraceEntry(); UNREFERENCED_PARAMETER(MessageID); // // #### TODO: Determine if controller has pending events. #### // // Sample will assume there is always a pending event for illustration purposes. PendingEvents = TRUE; if (PendingEvents) { // // Enqueue the DPC to handle the events. // WdfInterruptQueueDpcForIsr(Interrupt); } TraceExit(); return TRUE; }
VOID DeviceInitializeDefaultEndpoint ( _In_ WDFDEVICE Device ) /*++ Routine Description: This function initializes the default control endpoint Arguments: Device - Wdf FDO device object representing the controller --*/ { UFXENDPOINT Endpoint; PUFXDEVICE_CONTEXT DeviceContext; PCONTROLLER_CONTEXT ControllerContext; NTSTATUS Status; TraceEntry(); ControllerContext = DeviceGetControllerContext(Device); DeviceContext = UfxDeviceGetContext(ControllerContext->UfxDevice); if (DeviceContext->PhysicalEndpointToUfxEndpoint[0] != NULL) { Endpoint = DeviceContext->PhysicalEndpointToUfxEndpoint[0]; // // Re-initialize endpoint 0 // TransferDestroy(Endpoint); Status = TransferInitialize(Endpoint); LOG_NT_MSG(Status, "Failed to initialize default endpoint"); UfxEndpointConfigureHardware(Endpoint, FALSE); TransferStart(Endpoint); } else { NT_ASSERT(FALSE); } TraceExit(); }
VOID UfxDevice_EvtDeviceDefaultEndpointAdd ( _In_ UFXDEVICE UfxDevice, _In_ USHORT MaxPacketSize, _Inout_ PUFXENDPOINT_INIT EndpointInit ) /*++ Routine Description: EvtDeviceDefaultEndpointAdd handler for the UFXDEVICE object. Creates UFXENDPOINT object corresponding to the default endpoint of the device. Arguments: UfxDevice - UFXDEVICE object representing the device. MaxPacketSize - Max packet size of the device's default endpoint. EndpointInit - Pointer to the Opaque UFXENDPOINT_INIT object --*/ { NTSTATUS Status; USB_ENDPOINT_DESCRIPTOR Descriptor; PAGED_CODE(); TraceEntry(); Descriptor.bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE; Descriptor.bEndpointAddress = 0; Descriptor.bInterval = 0; Descriptor.bLength = sizeof(USB_ENDPOINT_DESCRIPTOR); Descriptor.bmAttributes = USB_ENDPOINT_TYPE_CONTROL; Descriptor.wMaxPacketSize = MaxPacketSize; Status = UfxEndpointAdd(UfxDevice, &Descriptor, EndpointInit); CHK_NT_MSG(Status, "Failed to create default endpoint!"); End: UfxDeviceEventComplete(UfxDevice, Status); TraceExit(); }
VOID HandleUSBLinkStateChange ( WDFDEVICE WdfDevice ) /*++ Routine Description: Handles a link change event from the controller. Arguments: WdfDevice - WDFDEVICE object representing the controller. --*/ { PCONTROLLER_CONTEXT ControllerContext; ULONG UsbLinkEvent; TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfDevice); // // #### TODO: Add code to read link state from controller #### // // For sample purposes use U0. UsbLinkEvent = USB_LINK_STATE_U0; if (UsbLinkEvent == USB_LINK_STATE_U0) { if(ControllerContext->Suspended) { ControllerContext->Suspended = FALSE; UfxDeviceNotifyResume(ControllerContext->UfxDevice); } ControllerContext->RemoteWakeupRequested = FALSE; } else { TraceVerbose("Ignoring link state change event: 0X%X", UsbLinkEvent); } TraceExit(); }
VOID ForwardRequestToIoTarget( _In_ WDFQUEUE queue, _In_ WDFREQUEST request, _In_ size_t length) { TraceEntry(); Trace(TRACE_LEVEL_INFORMATION, "%!FUNC! - Queue 0x%p, Request 0x%p Length %Iu", queue, request, length); auto device = WdfIoQueueGetDevice(queue); auto context = GetDeviceContext(device); if (length > context->MaxLengthInBytesForRWTransfers) { TraceError("%!FUNC! - Buffer Length to big %Iu, Max is %Iu. Status - %!STATUS!", length, context->MaxLengthInBytesForRWTransfers, STATUS_BUFFER_OVERFLOW); WdfRequestCompleteWithInformation(request, STATUS_BUFFER_OVERFLOW, NULL); return; } auto targetDevice = WdfDeviceGetIoTarget(device); WdfRequestFormatRequestUsingCurrentType(request); WDF_REQUEST_SEND_OPTIONS options; WDF_REQUEST_SEND_OPTIONS_INIT( &options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_ABS_TIMEOUT_IN_SEC(10)); auto sendSuccess = WdfRequestSend(request, targetDevice, &options); auto status = WdfRequestGetStatus(request); if (!sendSuccess || !NT_SUCCESS(status)) { TraceError("%!FUNC! - WdfRequestSend returned %d with status: %!STATUS!", sendSuccess, status); WdfRequestCompleteWithInformation(request, status, NULL); return; } WdfRequestComplete(request, status); }
NTSTATUS UfxDevice_EvtDeviceEndpointAdd ( _In_ UFXDEVICE UfxDevice, _In_ const PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, _Inout_ PUFXENDPOINT_INIT EndpointInit ) /*++ Routine Description: EvtDeviceEndpointAdd handler for the UFXDEVICE object. Creates UFXENDPOINT object corresponding to the newly reported endpoint. Arguments: UfxDevice - UFXDEVICE object representing the device. EndpointDescriptor - Cosntant Pointer to Endpoint descriptor for the newly reported endpoint. EndpointInit - Pointer to the Opaque UFXENDPOINT_INIT object Return Value: STATUS_SUCCESS on success, or an appropirate NTSTATUS message on failure. --*/ { NTSTATUS Status; TraceEntry(); Status = UfxEndpointAdd(UfxDevice, EndpointDescriptor, EndpointInit); CHK_NT_MSG(Status, "Failed to create endpoint"); End: TraceExit(); return Status; }
VOID LoopbackEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode) { UNREFERENCED_PARAMETER((OutputBufferLength, InputBufferLength)); TraceEntry(); NTSTATUS status = STATUS_SUCCESS; if (IoControlCode != LOOPBACK_IOCTL_ALTER_MAX_LENGTH || InputBufferLength != 4) { status = STATUS_UNSUCCESSFUL; goto Cleanup; } PUINT32 buffer; status = WdfRequestRetrieveInputBuffer(Request, 4, (PVOID*)&buffer, nullptr); if (!NT_SUCCESS(status)) { TraceError("%!FUNC! - Unable to read IOCTL input buffer. Status - %!STATUS!", status); goto Cleanup; } auto device = WdfIoQueueGetDevice(Queue); auto context = GetDeviceContext(device); context->MaxLengthInBytesForRWTransfers = *buffer; Cleanup: WdfRequestComplete(Request, status); }
VOID UfxDevice_EvtDevicePortChange ( _In_ UFXDEVICE UfxDevice, _In_ USBFN_PORT_TYPE NewPort ) /*++ Routine Description: EvtDevicePortChange handler for the UFXDEVICE object. Caches the new port type, and stops or resumes idle as needed. Arguments: UfxDevice - UFXDEVICE object representing the device. NewPort - New port type --*/ { NTSTATUS Status; PUFXDEVICE_CONTEXT Context; PAGED_CODE(); TraceEntry(); Context = UfxDeviceGetContext(UfxDevice); TraceInformation("New PORT: %d", NewPort); Status = UfxDeviceStopOrResumeIdle(UfxDevice, Context->UsbState, NewPort); LOG_NT_MSG(Status, "Failed to stop or resume idle"); UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); TraceExit(); }
VOID UfxDevice_EvtDeviceHostConnect ( _In_ UFXDEVICE UfxDevice ) /*++ Routine Description: EvtDeviceHostConnect callback handler for UFXDEVICE object. Arguments: UfxDevice - UFXDEVICE object representing the device. --*/ { TraceEntry(); UfxDeviceSetRunStop(UfxDevice, TRUE); TraceExit(); }
VOID UfxDevice_EvtDeviceTestModeSet ( _In_ UFXDEVICE UfxDevice, _In_ ULONG TestMode ) /*++ Routine Description: EvtDeviceTestModeSet handler for the UFXDEVICE object. Handles a set test mode request from the host. Places the controller into the specified test mode. Arguments: UfxDevice - UFXDEVICE object representing the device. TestMode - Test mode value. See Section 7.1.20 of the USB 2.0 specification for definitions of each test mode. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER(TestMode); TraceEntry(); // // #### TODO: Insert code to put the controller into the specified test mode #### // Status = STATUS_SUCCESS; UfxDeviceEventComplete(UfxDevice, Status); TraceExit(); }
VOID HandleUsbReset ( WDFDEVICE WdfDevice ) /*++ Routine Description: Handles a reset event notification from the controller. Arguments: WdfDevice - WDFDEVICE object representing the controller. --*/ { PCONTROLLER_CONTEXT ControllerContext; TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfDevice); UfxDevice_Reset(ControllerContext->UfxDevice); ControllerContext->RemoteWakeupRequested = FALSE; // // Update the controller to set device address to 0 // // // #### TODO: Add code to set the USB device address to 0 on the controller #### // TraceExit(); }
VOID UfxDevice_EvtDeviceAddressed ( _In_ UFXDEVICE UfxDevice, _In_ USHORT DeviceAddress ) /*++ Routine Description: EvtDeviceAddressed handler for the UFXDEVICE object. Sets the Address indicated by 'DeviceAddress' on the controller. Arguments: UfxDevice - UFXDEVICE object representing the device. DeviceAddress - USB Device Address, as determined by the UFX. --*/ { UNREFERENCED_PARAMETER(DeviceAddress); TraceEntry(); // // Set the device address on the controller // // // #### Insert code to set the device address on controller #### // UfxDeviceEventComplete(UfxDevice, STATUS_SUCCESS); TraceExit(); }
VOID HandleEndpointEvent ( WDFDEVICE WdfDevice, ENDPOINT_EVENT EndpointEvent ) /*++ Routine Description: Function to dispatch endpoint events. Arguments: WdfDevice - Wdf device object corresponding to the FDO EndpointEvent - Endpoint specific event. --*/ { UFXENDPOINT Endpoint; PCONTROLLER_CONTEXT ControllerContext; PUFXDEVICE_CONTEXT DeviceContext; TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfDevice); DeviceContext = UfxDeviceGetContext(ControllerContext->UfxDevice); // // #### TODO: Insert code to extract endpoint event and endpoint number #### // // Sample will assume a transfer complete event on endpoint 1 for illustration purposes EndpointEvent = EndpointEventTransferComplete; Endpoint = DeviceContext->PhysicalEndpointToUfxEndpoint[1]; switch (EndpointEvent) { case EndpointEventTransferComplete: TraceInformation("ENDPOINT EVENT: TransferComplete"); TransferComplete(Endpoint); break; case EndpointEventStartTransferComplete: TraceInformation("ENDPOINT EVENT: Complete Start Transfer"); TransferCommandStartComplete(Endpoint); break; case EndpointEventEndTransferComplete: TraceInformation("ENDPOINT EVENT: Complete End Transfer"); TransferCommandEndComplete(Endpoint); break; case EndpointEventSetStall: TraceInformation("ENDPOINT EVENT: Command Complete Stall Set"); TransferStallSetComplete(Endpoint); break; case EndpointEventClearStall: TraceInformation("ENDPOINT EVENT: Command Complete Stall Clear"); TransferStallClearComplete(Endpoint); break; default: TraceError("Unexpected endpoint event!"); NT_ASSERT(FALSE); } TraceExit(); }
VOID HandleDeviceEvent ( WDFDEVICE WdfDevice, DEVICE_EVENT DeviceEvent ) /*++ Routine Description: Function to dispatch device events from the controller. Arguments: WdfDevice - Wdf device object corresponding to the FDO DeviceEvent - Device specific event. --*/ { PCONTROLLER_CONTEXT ControllerContext; TraceEntry(); ControllerContext = DeviceGetControllerContext(WdfDevice); switch (DeviceEvent) { case DeviceEventDisconnect: ControllerContext->Suspended = FALSE; HandleUsbDisconnect(WdfDevice); break; case DeviceEventUSBReset: ControllerContext->Suspended = FALSE; HandleUsbReset(WdfDevice); break; case DeviceEventConnect: HandleUsbConnect(WdfDevice); break; case DeviceEventUSBLinkStateChange: HandleUSBLinkStateChange(WdfDevice); break; case DeviceEventWakeUp: if (ControllerContext->Suspended) { ControllerContext->Suspended = FALSE; UfxDeviceNotifyResume(ControllerContext->UfxDevice); } break; case DeviceEventSuspend: if (!ControllerContext->Suspended) { ControllerContext->Suspended = TRUE; UfxDeviceNotifySuspend(ControllerContext->UfxDevice); } break; default: TraceError("Unknown device event raised by controller"); NT_ASSERT(FALSE); break; } TraceExit(); }
NTSTATUS UfxClientDeviceCreate( _In_ WDFDRIVER Driver, _In_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: Worker routine called to create a device and its software resources. Arguments: Driver - WDF driver object DeviceInit - Pointer to an opaque init structure. Memory for this structure will be freed by the framework when the WdfDeviceCreate succeeds. So don't access the structure after that point. Return Value: Appropriate NTSTATUS value --*/ { WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE WdfDevice; NTSTATUS Status; WDF_PNPPOWER_EVENT_CALLBACKS PnpCallbacks; WDF_DMA_ENABLER_CONFIG DmaConfig; PCONTROLLER_CONTEXT ControllerContext; PAGED_CODE(); TraceEntry(); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, CONTROLLER_CONTEXT); // // Do UFX-specific initialization // Status = UfxFdoInit(Driver, DeviceInit, &DeviceAttributes); CHK_NT_MSG(Status, "Failed UFX initialization"); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpCallbacks); PnpCallbacks.EvtDevicePrepareHardware = OnEvtDevicePrepareHardware; PnpCallbacks.EvtDeviceReleaseHardware = OnEvtDeviceReleaseHardware; PnpCallbacks.EvtDeviceD0Entry = OnEvtDeviceD0Entry; PnpCallbacks.EvtDeviceD0Exit = OnEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpCallbacks); Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &WdfDevice); CHK_NT_MSG(Status, "Failed to create wdf device"); ControllerContext = DeviceGetControllerContext(WdfDevice); KeInitializeEvent(&ControllerContext->DetachEvent, NotificationEvent, FALSE); WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&ControllerContext->IdleSettings, IdleCanWakeFromS0); ControllerContext->IdleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; ControllerContext->IdleSettings.IdleTimeout = IDLE_TIMEOUT; ControllerContext->IdleSettings.DxState = PowerDeviceD3; Status = WdfDeviceAssignS0IdleSettings(WdfDevice, &ControllerContext->IdleSettings); LOG_NT_MSG(Status, "Failed to set S0 Idle Settings"); // // Create and initialize device's default queue // Status = DefaultQueueCreate(WdfDevice); CHK_NT_MSG(Status, "Failed to intialize default queue"); // // Set alignment required by controller // WdfDeviceSetAlignmentRequirement(WdfDevice, UFX_CLIENT_ALIGNMENT); // // Create and Initialize DMA Enabler object for the device. // WDF_DMA_ENABLER_CONFIG_INIT( &DmaConfig, WdfDmaProfileScatterGatherDuplex, MAX_DMA_LENGTH); // // Version 3 is required to perform multiple // simultaneous transfers. // DmaConfig.WdmDmaVersionOverride = 3; Status = WdfDmaEnablerCreate( WdfDevice, &DmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->DmaEnabler); CHK_NT_MSG(Status, "Failed to create DMA enabler object"); // // Create UFXDEVICE object // Status = UfxDevice_DeviceCreate(WdfDevice); CHK_NT_MSG(Status, "Failed to create UFX Device object"); // // Create DPC Lock // Status = WdfSpinLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->DpcLock); CHK_NT_MSG(Status, "Failed to create DPC lock"); Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &ControllerContext->InitializeDefaultEndpointLock); CHK_NT_MSG(Status, "Failed to create Ep0 init lock"); End: TraceExit(); return Status; }