ReactOS 0.4.17-dev-1281-g065abb3
upstream.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS SuperSpeed USB Hub Driver
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Requests a hub sends to its parent: configuration, resets, hub info
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8#include "usbhub3.h"
9
10#define NDEBUG
11#include <debug.h>
12
13/* Hub class interface and its protocols */
14#define HUB_CLASS_CODE 9
15#define HUB_PROTOCOL_SINGLE_TT 1
16#define HUB_PROTOCOL_MULTI_TT 2
17#define HUB_PROTOCOL_ANY (-1)
18
19/* A SuperSpeed hub status change endpoint carries at most two bytes */
20#define HUB_30_MAX_STATUS_PACKET 2
21
22static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubConfigurationComplete;
23static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubPipeResetComplete;
24static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubResetComplete;
25static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubParentInfoComplete;
26
28static
33 _In_ WDFREQUEST Request,
35 _In_ PVOID Payload,
38{
41
42 RtlZeroMemory(&Stack, sizeof(Stack));
44 Stack.Parameters.DeviceIoControl.IoControlCode = IoControlCode;
45 Stack.Parameters.Others.Argument1 = Payload;
46 WdfRequestWdmFormatUsingStackLocation(Request, &Stack);
47
48 WdfRequestSetCompletionRoutine(Request, Completion, Context);
49
50 if (WdfRequestSend(Request, WdfDeviceGetIoTarget(Hub->m_Device), WDF_NO_SEND_OPTIONS))
51 return TRUE;
52
53 /* A refusal with a success status leaves nothing to report */
54 Status = WdfRequestGetStatus(Request);
55 if (!NT_SUCCESS(Status))
56 DPRINT1("Hub %p parent request 0x%lx not sent 0x%lx\n", Hub, IoControlCode, Status);
57
58 return NT_SUCCESS(Status);
59}
60
61static
66 _Out_ WDFREQUEST* Request)
67{
70
72 Attributes.ParentObject = Hub->m_Device;
73
74 *Request = NULL;
75 Status = WdfRequestCreate(&Attributes, WdfDeviceGetIoTarget(Hub->m_Device), Request);
76 if (!NT_SUCCESS(Status))
77 DPRINT1("Hub %p parent request create failed 0x%lx\n", Hub, Status);
78
79 return Status;
80}
81
82/* Configuration */
83
84/* High speed hubs prefer their multi TT interface */
85static
90{
91 static const LONG HighSpeedOrder[] = { HUB_PROTOCOL_MULTI_TT, HUB_PROTOCOL_SINGLE_TT, 0, HUB_PROTOCOL_ANY };
92 static const LONG OtherOrder[] = { HUB_PROTOCOL_SINGLE_TT, 0, HUB_PROTOCOL_ANY };
95 const LONG* Order;
98
99 switch (Hub->m_Parent.HubSpeed)
100 {
101 case UsbHighSpeed:
102 Order = HighSpeedOrder;
103 Count = RTL_NUMBER_OF(HighSpeedOrder);
104 break;
105
106 case UsbFullSpeed:
107 case UsbSuperSpeed:
108 Order = OtherOrder;
109 Count = RTL_NUMBER_OF(OtherOrder);
110 break;
111
112 default:
113 return NULL;
114 }
115
116 for (Index = 0; Index < Count; Index++)
117 {
119 if (Interface != NULL)
120 return Interface;
121 }
122
123 return NULL;
124}
125
126/* ConfigurationFailed is posted when the URB cannot be built */
127VOID
129{
132 WDFREQUEST Request = NULL;
133 PURB Urb = NULL;
134
136 if (Interface == NULL ||
137 Interface->bInterfaceClass != HUB_CLASS_CODE ||
138 Interface->bNumEndpoints == 0)
139 {
140 DPRINT1("Hub %p has no usable hub interface\n", m_Hub);
141 goto Failed;
142 }
143
144 RtlZeroMemory(List, sizeof(List));
145 List[0].InterfaceDescriptor = Interface;
146
148 if (Urb == NULL)
149 {
150 DPRINT1("Hub %p select configuration URB not built\n", m_Hub);
151 goto Failed;
152 }
153
154 DPRINT("Hub %p selecting interface %u protocol %u\n",
155 m_Hub, Interface->bInterfaceNumber, Interface->bInterfaceProtocol);
156
158 goto Failed;
159
161 return;
162
163Failed:
164 if (Request != NULL)
166 if (Urb != NULL)
168
169 m_Hub->Post(HubEvent::ConfigurationFailed);
170}
171
172/* Pipe 0 is the status change endpoint; a SuperSpeed hub may use at most two bytes, zero and one included */
173static
174VOID
175NTAPI
177 _In_ WDFREQUEST Request,
178 _In_ WDFIOTARGET Target,
181{
182 PURB Urb = (PURB)Context;
183 HubFdo* Hub = HubFdo::FromDevice(WdfIoTargetGetDevice(Target));
184 NTSTATUS Status = Params->IoStatus.Status;
186
187 if (NT_SUCCESS(Status))
188 {
189 Pipe = &Urb->UrbSelectConfiguration.Interface.Pipes[0];
190
191 Hub->m_Interrupt.Pipe = Pipe->PipeHandle;
192 Hub->m_ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
193 Hub->m_InterruptMaxPacket = Pipe->MaximumPacketSize;
194
195 if (Hub->m_ParentInfo.DeviceDescriptor.bcdUSB >= 0x0300 &&
196 Pipe->MaximumPacketSize != HUB_30_MAX_STATUS_PACKET)
197 {
198 DPRINT1("Hub %p SuperSpeed status endpoint packet size %u\n", Hub, Pipe->MaximumPacketSize);
199 }
200
201 if (Hub->m_ParentInfo.DeviceDescriptor.bcdUSB >= 0x0300 &&
202 Pipe->MaximumPacketSize > HUB_30_MAX_STATUS_PACKET)
203 {
205 }
206 }
207
208 if (!NT_SUCCESS(Status))
209 {
210 DPRINT1("Hub %p set configuration failed 0x%lx, URB status 0x%lx\n",
211 Hub, Status, Urb->UrbHeader.Status);
212 }
213
216
218}
219
220/* Status change pipe reset, on the hub's own control request */
221
222static
223VOID
224NTAPI
226 _In_ WDFREQUEST Request,
227 _In_ WDFIOTARGET Target,
230{
232
235
236 if (!NT_SUCCESS(Params->IoStatus.Status))
237 {
238 DPRINT1("Hub %p status change pipe reset failed 0x%lx, URB status 0x%lx\n",
239 Hub, Params->IoStatus.Status, Hub->m_PipeUrb.Hdr.Status);
240 }
241
244}
245
246VOID
248{
250
251 RtlZeroMemory(Urb, sizeof(*Urb));
252 Urb->Hdr.Length = sizeof(*Urb);
254 Urb->Hdr.UsbdDeviceHandle = m_Hub->UsbDevice();
255 Urb->PipeHandle = m_Hub->m_Interrupt.Pipe;
256
258 {
260 m_Hub->Post(HubEvent::PipeResetFailed);
261 }
262}
263
264/* Hub reset through the parent port */
265
266static
267VOID
268NTAPI
270 _In_ WDFREQUEST Request,
271 _In_ WDFIOTARGET Target,
274{
276 NTSTATUS Status = Params->IoStatus.Status;
278
280
281 if (NT_SUCCESS(Status))
282 DPRINT("Hub %p reset by parent, flags 0x%lx\n", Hub, Hub->m_ResetFlags);
283 else
284 DPRINT1("Hub %p reset by parent failed 0x%lx\n", Hub, Status);
285
286 Flags.AsUlong = Hub->m_ResetFlags;
287 if (NT_SUCCESS(Status) && Flags.HostContextLost)
289
291
292 if (NT_SUCCESS(Status))
294 else if (Status == STATUS_NO_SUCH_DEVICE)
296 else
298}
299
300VOID
302{
303 WDFREQUEST Request;
304
306 {
307 m_Hub->Post(HubEvent::ResetFailed);
308 return;
309 }
310
311 m_Hub->m_ResetFlags = 0;
312 DPRINT("Hub %p asking parent for a reset\n", m_Hub);
313
315 {
317 m_Hub->Post(HubEvent::ResetFailed);
318 }
319}
320
321/* Hub info from the parent hub, external hubs only */
322
323/* Control transfers go straight to the root hub PDO; the previous target is closed on each start */
324static
325VOID
326NTAPI
328 _In_ WDFREQUEST Request,
329 _In_ WDFIOTARGET Target,
332{
334 NTSTATUS Status = Params->IoStatus.Status;
336 WDFIOTARGET RootTarget;
337
339
340 if (!NT_SUCCESS(Status))
341 {
342 DPRINT1("Hub %p parent hub info failed 0x%lx\n", Hub, Status);
343 }
344 else
345 {
346 Status = WdfIoTargetCreate(Hub->m_Device, WDF_NO_OBJECT_ATTRIBUTES, &RootTarget);
347 if (!NT_SUCCESS(Status))
348 DPRINT1("Hub %p root hub target create failed 0x%lx\n", Hub, Status);
349 }
350
351 if (NT_SUCCESS(Status))
352 {
354
355 Status = WdfIoTargetOpen(RootTarget, &Open);
356 if (!NT_SUCCESS(Status))
357 {
358 DPRINT1("Hub %p root hub target open on %p failed 0x%lx\n",
360 WdfObjectDelete(RootTarget);
361 }
362 else
363 {
364 if (Hub->m_RootHubTarget != NULL)
366 Hub->m_RootHubTarget = RootTarget;
367 }
368 }
369
372
375}
376
377VOID
379{
380 WDFREQUEST Request;
381
383 {
384 m_Hub->Post(HubEvent::IoctlFailed);
385 return;
386 }
387
389 {
391 m_Hub->Post(HubEvent::IoctlFailed);
392 }
393}
394
395/*
396 * Both parent callbacks clear what they report, so this is called even when
397 * the hub machine ignores the answer.
398 */
401{
403
405 return FALSE;
406
408 {
409 DPRINT("Hub %p lost controller programming on resume\n", m_Hub);
411 }
412
413 return TRUE;
414}
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
HubFdo * Hub
Definition: bootdev.cpp:261
Definition: fdo.h:132
PUSB_CONFIGURATION_DESCRIPTOR m_ConfigDescriptor
Definition: fdo.h:425
WDFDEVICE m_Device
Definition: fdo.h:349
VOID SetFlag(_In_ HubFlag Flag)
Definition: fdo.h:160
WDFIOTARGET m_RootHubTarget
Definition: fdo.h:368
VOID Post(_In_ HubEvent Event)
Definition: fdo.h:194
HubControlRequest m_Control
Definition: fdo.h:413
HubInterruptRequest m_Interrupt
Definition: fdo.h:414
struct _URB_PIPE_REQUEST m_PipeUrb
Definition: fdo.h:365
static HubFdo * FromDevice(_In_ WDFDEVICE Device)
Definition: fdo.cpp:37
UCXUSBDEVICE UsbDevice() const
Definition: fdo.h:180
USHORT m_InterruptMaxPacket
Definition: fdo.h:429
USBD_CONFIGURATION_HANDLE m_ConfigurationHandle
Definition: fdo.h:430
HubParentInfo m_ParentInfo
Definition: fdo.h:360
UCXHUB_PARENT_INTERFACE m_Parent
Definition: fdo.h:355
VOID MarkDevicesProgrammingLost()
Definition: fanout.cpp:840
ULONG m_ResetFlags
Definition: fdo.h:364
BOOLEAN WasResetByParent()
Definition: upstream.cpp:400
VOID ResetHub()
Definition: upstream.cpp:301
VOID SelectHubConfiguration()
Definition: upstream.cpp:128
HubFdo * m_Hub
Definition: hubsm.h:574
VOID GetParentInfo()
Definition: upstream.cpp:378
VOID ResetStatusChangePipe()
Definition: upstream.cpp:247
_In_ ULONG Attributes
Definition: dispmprt.h:1077
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
Status
Definition: gdiplustypes.h:24
@ ConfigurationSet
@ ResetFailedOnRemoval
@ PipeResetFailed
@ ConfigurationFailed
#define IOCTL_UCXHUB_RESET_PORT_ASYNC
Definition: hubucx.h:78
#define IOCTL_UCXHUB_GET_HUB_INFO
Definition: hubucx.h:64
_In_ PIRP _In_ PIO_COMPLETION_ROUTINE _In_ PVOID Context
Definition: kse.h:81
#define Open
Definition: syshdrs.h:62
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define STATUS_INVALID_HW_PROFILE
Definition: ntstatus.h:855
long LONG
Definition: pedump.c:60
@ Failed
Definition: arc.h:88
#define DPRINT
Definition: sndvol32.h:73
WDFREQUEST Request
Definition: hubreq.h:19
USBD_PIPE_HANDLE Pipe
Definition: hubreq.h:72
PDEVICE_OBJECT RootHubPdo
Definition: fdo.h:88
USB_DEVICE_DESCRIPTOR DeviceDescriptor
Definition: fdo.h:89
ULONG Flags
Definition: fdo.h:100
PVOID Context
Definition: miniport.h:123
PFN_UCXHUB_WAS_HUB_RESET ParentResetDuringResume
Definition: hubucx.h:507
PFN_UCXHUB_WAS_PROGRAMMING_LOST ParentLostStateDuringResume
Definition: hubucx.h:508
USB_DEVICE_SPEED HubSpeed
Definition: hubucx.h:504
Definition: usb.h:565
Definition: usbdlib.h:7
#define NTAPI
Definition: typedefs.h:36
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST _In_ size_t _In_ size_t _In_ ULONG IoControlCode
_Must_inspect_result_ _In_ WDFDEVICE _In_ PUCX_CONTROLLER_CONFIG Config
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFREQUEST Request
_In_ UCXUSBDEVICE _In_ ULONG Interface
Definition: ucxusbdevice.h:428
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
static BOOLEAN NTAPI HubSendToParent(_In_ HubFdo *Hub, _In_ WDFREQUEST Request, _In_ ULONG IoControlCode, _In_ PVOID Payload, _In_ PFN_WDF_REQUEST_COMPLETION_ROUTINE Completion, _In_ WDFCONTEXT Context)
Definition: upstream.cpp:31
static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubResetComplete
Definition: upstream.cpp:24
#define HUB_CLASS_CODE
Definition: upstream.cpp:14
#define HUB_PROTOCOL_ANY
Definition: upstream.cpp:17
#define HUB_PROTOCOL_MULTI_TT
Definition: upstream.cpp:16
#define HUB_PROTOCOL_SINGLE_TT
Definition: upstream.cpp:15
static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubParentInfoComplete
Definition: upstream.cpp:25
static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubConfigurationComplete
Definition: upstream.cpp:22
#define HUB_30_MAX_STATUS_PACKET
Definition: upstream.cpp:20
static EVT_WDF_REQUEST_COMPLETION_ROUTINE HubPipeResetComplete
Definition: upstream.cpp:23
static PUSB_INTERFACE_DESCRIPTOR NTAPI HubFindHubInterface(_In_ HubFdo *Hub)
Definition: upstream.cpp:88
static NTSTATUS NTAPI HubCreateParentRequest(_In_ HubFdo *Hub, _Out_ WDFREQUEST *Request)
Definition: upstream.cpp:64
@ UsbSuperSpeed
Definition: usb200.h:45
@ UsbHighSpeed
Definition: usb200.h:44
@ UsbFullSpeed
Definition: usb200.h:43
#define HUB_PARENT_DISABLE_LPM
Definition: fdo.h:106
struct _URB * PURB
#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL
Definition: usb.h:116
PURB NTAPI USBD_CreateConfigurationRequestEx(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PUSBD_INTERFACE_LIST_ENTRY InterfaceList)
Definition: usbd.c:311
PUSB_INTERFACE_DESCRIPTOR NTAPI USBD_ParseConfigurationDescriptorEx(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PVOID StartPosition, LONG InterfaceNumber, LONG AlternateSetting, LONG InterfaceClass, LONG InterfaceSubClass, LONG InterfaceProtocol)
Definition: usbd.c:478
_In_opt_ PUSB_CONFIGURATION_DESCRIPTOR _Inout_ PUSBD_INTERFACE_LIST_ENTRY _Outptr_ PURB * Urb
Definition: usbdlib.h:333
#define IOCTL_INTERNAL_USB_SUBMIT_URB
Definition: usbioctl.h:32
USHORT Count
Definition: userreq.cpp:200
WdfObjectDelete(String)
_In_ WDFCOLLECTION _In_ ULONG Index
FORCEINLINE VOID WDF_IO_TARGET_OPEN_PARAMS_INIT_EXISTING_DEVICE(_Out_ PWDF_IO_TARGET_OPEN_PARAMS Params, _In_ PDEVICE_OBJECT DeviceObject)
Definition: wdfiotarget.h:287
FORCEINLINE VOID WDF_OBJECT_ATTRIBUTES_INIT(_Out_ PWDF_OBJECT_ATTRIBUTES Attributes)
Definition: wdfobject.h:147
_Must_inspect_result_ FORCEINLINE BOOLEAN WdfRequestSend(_In_ WDFREQUEST Request, _In_ WDFIOTARGET Target, _In_opt_ PWDF_REQUEST_SEND_OPTIONS Options)
Definition: wdfrequest.h:677
_In_ WDFIOTARGET Target
Definition: wdfrequest.h:306
_In_ WDFIOTARGET _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
Definition: wdfrequest.h:308
EVT_WDF_REQUEST_COMPLETION_ROUTINE * PFN_WDF_REQUEST_COMPLETION_ROUTINE
Definition: wdfrequest.h:313
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
#define WDF_NO_SEND_OPTIONS
Definition: wdftypes.h:109
#define WDF_NO_OBJECT_ATTRIBUTES
Definition: wdftypes.h:105
_In_ WDFUSBPIPE Pipe
Definition: wdfusb.h:1741
#define IRP_MJ_INTERNAL_DEVICE_CONTROL