xref: /reactos/drivers/usb/usbport/roothub.c (revision cdf90707)
1 /*
2  * PROJECT:     ReactOS USB Port Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBPort root hub implementation
5  * COPYRIGHT:   Copyright 2017 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbport.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define NDEBUG_USBPORT_CORE
14 #include "usbdebug.h"
15 
16 RHSTATUS
17 NTAPI
18 USBPORT_MPStatusToRHStatus(IN MPSTATUS MPStatus)
19 {
20     RHSTATUS RHStatus = RH_STATUS_SUCCESS;
21 
22     //DPRINT("USBPORT_MPStatusToRHStatus: MPStatus - %x\n", MPStatus);
23 
24     if (MPStatus)
25     {
26         RHStatus = (MPStatus != MP_STATUS_FAILURE);
27         ++RHStatus;
28     }
29 
30     return RHStatus;
31 }
32 
33 MPSTATUS
34 NTAPI
35 USBPORT_RH_SetFeatureUSB2PortPower(IN PDEVICE_OBJECT FdoDevice,
36                                    IN USHORT Port)
37 {
38     PUSBPORT_DEVICE_EXTENSION FdoExtension;
39     PUSBPORT_REGISTRATION_PACKET Packet;
40     PDEVICE_RELATIONS CompanionControllersList;
41     PUSBPORT_REGISTRATION_PACKET CompanionPacket;
42     PDEVICE_OBJECT CompanionFdoDevice;
43     PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension;
44     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
45     USHORT ix;
46     PDEVICE_OBJECT * Entry;
47     ULONG NumController = 0;
48 
49     DPRINT("USBPORT_RootHub_PowerUsb2Port: FdoDevice - %p, Port - %p\n",
50            FdoDevice,
51            Port);
52 
53     FdoExtension = FdoDevice->DeviceExtension;
54     Packet = &FdoExtension->MiniPortInterface->Packet;
55 
56     CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice,
57                                                                 FALSE,
58                                                                 TRUE);
59 
60     if (!CompanionControllersList)
61     {
62         Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
63         return MP_STATUS_SUCCESS;
64     }
65 
66     Entry = &CompanionControllersList->Objects[0];
67 
68     while (NumController < CompanionControllersList->Count)
69     {
70         CompanionFdoDevice = *Entry;
71 
72         CompanionFdoExtension = CompanionFdoDevice->DeviceExtension;
73         CompanionPacket = &CompanionFdoExtension->MiniPortInterface->Packet;
74 
75         PdoExtension = CompanionFdoExtension->RootHubPdo->DeviceExtension;
76 
77         for (ix = 0;
78              (PdoExtension->CommonExtension.PnpStateFlags & USBPORT_PNP_STATE_STARTED) &&
79               ix < PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts;
80              ++ix)
81         {
82             CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt,
83                                                     ix + 1);
84         }
85 
86         ++NumController;
87         ++Entry;
88     }
89 
90     Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
91 
92     if (CompanionControllersList)
93     {
94         ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG);
95     }
96 
97     return MP_STATUS_SUCCESS;
98 }
99 
100 RHSTATUS
101 NTAPI
102 USBPORT_RootHubClassCommand(IN PDEVICE_OBJECT FdoDevice,
103                             IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
104                             IN PVOID Buffer,
105                             IN PULONG BufferLength)
106 {
107     PUSBPORT_DEVICE_EXTENSION FdoExtension;
108     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
109     PUSBPORT_REGISTRATION_PACKET Packet;
110     USHORT Port;
111     USHORT Feature;
112     MPSTATUS MPStatus;
113     RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL;
114     KIRQL OldIrql;
115 
116     DPRINT("USBPORT_RootHubClassCommand: USB command - %x, *BufferLength - %x\n",
117            SetupPacket->bRequest,
118            *BufferLength);
119 
120     FdoExtension = FdoDevice->DeviceExtension;
121     PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
122     Packet = &FdoExtension->MiniPortInterface->Packet;
123 
124     Port = SetupPacket->wIndex.W;
125 
126     switch (SetupPacket->bRequest)
127     {
128         case USB_REQUEST_GET_STATUS:
129         {
130             if (!Buffer)
131             {
132                 return RHStatus;
133             }
134 
135             *(PULONG)Buffer = 0;
136 
137             if (SetupPacket->bmRequestType.Recipient == BMREQUEST_TO_OTHER)
138             {
139                 ASSERT(*BufferLength >= 4);
140 
141                 if (Port > PdoExtension->RootHubDescriptors->Descriptor.bNumberOfPorts ||
142                     Port <= 0  ||
143                     SetupPacket->wLength < 4)
144                 {
145                     return RHStatus;
146                 }
147 
148                 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
149 
150                 MPStatus = Packet->RH_GetPortStatus(FdoExtension->MiniPortExt,
151                                                     SetupPacket->wIndex.W,
152                                                     Buffer);
153 
154                 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
155             }
156             else
157             {
158                 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
159 
160                 MPStatus = Packet->RH_GetHubStatus(FdoExtension->MiniPortExt,
161                                                    Buffer);
162 
163                 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
164             }
165 
166             RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
167             break;
168         }
169 
170         case USB_REQUEST_CLEAR_FEATURE:
171             Feature = SetupPacket->wValue.W;
172 
173             if ((SetupPacket->bmRequestType.Recipient) != USBPORT_RECIPIENT_PORT)
174             {
175                 if (Feature == FEATURE_C_HUB_LOCAL_POWER)
176                 {
177                     RHStatus = RH_STATUS_SUCCESS;
178                     return RHStatus;
179                 }
180 
181                 if (Feature == FEATURE_C_HUB_OVER_CURRENT)
182                 {
183                     MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt,
184                                                                             0);
185                     RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
186                     return RHStatus;
187                 }
188 
189                 DbgBreakPoint();
190                 return RHStatus;
191             }
192 
193             switch (Feature)
194             {
195                 case FEATURE_PORT_ENABLE:
196                     MPStatus = Packet->RH_ClearFeaturePortEnable(FdoExtension->MiniPortExt,
197                                                                  Port);
198                     break;
199 
200                 case FEATURE_PORT_SUSPEND:
201                     MPStatus = Packet->RH_ClearFeaturePortSuspend(FdoExtension->MiniPortExt,
202                                                                   Port);
203                     break;
204 
205                 case FEATURE_PORT_POWER:
206                     MPStatus = Packet->RH_ClearFeaturePortPower(FdoExtension->MiniPortExt,
207                                                                 Port);
208                     break;
209 
210                 case FEATURE_C_PORT_CONNECTION:
211                     MPStatus = Packet->RH_ClearFeaturePortConnectChange(FdoExtension->MiniPortExt,
212                                                                         Port);
213                     break;
214 
215                 case FEATURE_C_PORT_ENABLE:
216                      MPStatus = Packet->RH_ClearFeaturePortEnableChange(FdoExtension->MiniPortExt,
217                                                                         Port);
218                     break;
219 
220                 case FEATURE_C_PORT_SUSPEND:
221                     MPStatus = Packet->RH_ClearFeaturePortSuspendChange(FdoExtension->MiniPortExt,
222                                                                         Port);
223                     break;
224 
225                 case FEATURE_C_PORT_OVER_CURRENT:
226                     MPStatus = Packet->RH_ClearFeaturePortOvercurrentChange(FdoExtension->MiniPortExt,
227                                                                             Port);
228                     break;
229 
230                 case FEATURE_C_PORT_RESET:
231                     MPStatus = Packet->RH_ClearFeaturePortResetChange(FdoExtension->MiniPortExt,
232                                                                       Port);
233                     break;
234 
235                 default:
236                     DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n",
237                             Feature);
238                     return RHStatus;
239             }
240 
241             RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
242             break;
243 
244         case USB_REQUEST_SET_FEATURE:
245             if (SetupPacket->bmRequestType.Recipient != USBPORT_RECIPIENT_PORT)
246             {
247                 return RHStatus;
248             }
249 
250             Feature = SetupPacket->wValue.W;
251 
252             switch (Feature)
253             {
254                 case FEATURE_PORT_ENABLE:
255                     MPStatus = Packet->RH_SetFeaturePortEnable(FdoExtension->MiniPortExt,
256                                                                Port);
257                     break;
258 
259                 case FEATURE_PORT_SUSPEND:
260                     MPStatus = Packet->RH_SetFeaturePortSuspend(FdoExtension->MiniPortExt,
261                                                                 Port);
262                     break;
263 
264                 case FEATURE_PORT_RESET:
265                     MPStatus = Packet->RH_SetFeaturePortReset(FdoExtension->MiniPortExt,
266                                                               Port);
267                     break;
268 
269                 case FEATURE_PORT_POWER:
270                     if (Packet->MiniPortFlags & USB_MINIPORT_FLAGS_USB2)
271                     {
272                         MPStatus = USBPORT_RH_SetFeatureUSB2PortPower(FdoDevice, Port);
273                     }
274                     else
275                     {
276                         MPStatus = Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt,
277                                                                   Port);
278                     }
279 
280                     break;
281 
282                 default:
283                     DPRINT1("USBPORT_RootHubClassCommand: Not supported feature - %x\n",
284                             Feature);
285                     return RHStatus;
286             }
287 
288             RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
289             break;
290 
291         case USB_REQUEST_GET_DESCRIPTOR:
292             if (Buffer &&
293                 SetupPacket->wValue.W == 0 &&
294                 SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST)
295             {
296                 SIZE_T DescriptorLength;
297 
298                 DescriptorLength = PdoExtension->RootHubDescriptors->Descriptor.bDescriptorLength;
299 
300                 if (*BufferLength < DescriptorLength)
301                     DescriptorLength = *BufferLength;
302 
303                 RtlCopyMemory(Buffer,
304                               &PdoExtension->RootHubDescriptors->Descriptor,
305                               DescriptorLength);
306 
307                 *BufferLength = DescriptorLength;
308                 RHStatus = RH_STATUS_SUCCESS;
309             }
310 
311             break;
312 
313         default:
314             DPRINT1("USBPORT_RootHubClassCommand: Not supported USB request - %x\n",
315                     SetupPacket->bRequest);
316             //USB_REQUEST_SET_ADDRESS                   0x05
317             //USB_REQUEST_SET_DESCRIPTOR                0x07
318             //USB_REQUEST_GET_CONFIGURATION             0x08
319             //USB_REQUEST_SET_CONFIGURATION             0x09
320             //USB_REQUEST_GET_INTERFACE                 0x0A
321             //USB_REQUEST_SET_INTERFACE                 0x0B
322             //USB_REQUEST_SYNC_FRAME                    0x0C
323             break;
324     }
325 
326     return RHStatus;
327 }
328 
329 RHSTATUS
330 NTAPI
331 USBPORT_RootHubStandardCommand(IN PDEVICE_OBJECT FdoDevice,
332                                IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
333                                IN PVOID Buffer,
334                                IN OUT PULONG TransferLength)
335 {
336     PUSBPORT_DEVICE_EXTENSION FdoExtension;
337     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
338     PUSBPORT_REGISTRATION_PACKET Packet;
339     SIZE_T Length;
340     PVOID Descriptor;
341     SIZE_T DescriptorLength;
342     MPSTATUS MPStatus;
343     RHSTATUS RHStatus = RH_STATUS_UNSUCCESSFUL;
344     KIRQL OldIrql;
345 
346     DPRINT("USBPORT_RootHubStandardCommand: USB command - %x, TransferLength - %p\n",
347            SetupPacket->bRequest,
348            TransferLength);
349 
350     FdoExtension = FdoDevice->DeviceExtension;
351     PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
352     Packet = &FdoExtension->MiniPortInterface->Packet;
353 
354     switch (SetupPacket->bRequest)
355     {
356         case USB_REQUEST_GET_DESCRIPTOR:
357             if (SetupPacket->wValue.LowByte ||
358                 !(SetupPacket->bmRequestType.Dir))
359             {
360                 return RHStatus;
361             }
362 
363             switch (SetupPacket->wValue.HiByte)
364             {
365                 case USB_DEVICE_DESCRIPTOR_TYPE:
366                     Descriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor;
367                     DescriptorLength = sizeof(USB_DEVICE_DESCRIPTOR);
368                     break;
369 
370                 case USB_CONFIGURATION_DESCRIPTOR_TYPE:
371                     Descriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor;
372                     DescriptorLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) +
373                                        sizeof(USB_INTERFACE_DESCRIPTOR) +
374                                        sizeof(USB_ENDPOINT_DESCRIPTOR);
375                     break;
376 
377                 default:
378                     DPRINT1("USBPORT_RootHubStandardCommand: Not supported Descriptor Type - %x\n",
379                             SetupPacket->wValue.HiByte);
380                     return RHStatus;
381             }
382 
383             if (!Descriptor)
384             {
385                 return RHStatus;
386             }
387 
388             if (*TransferLength >= DescriptorLength)
389                 Length = DescriptorLength;
390             else
391                 Length = *TransferLength;
392 
393             RtlCopyMemory(Buffer, Descriptor, Length);
394             *TransferLength = Length;
395 
396             RHStatus = RH_STATUS_SUCCESS;
397             break;
398 
399         case USB_REQUEST_GET_STATUS:
400             if (!SetupPacket->wValue.W &&
401                  SetupPacket->wLength == sizeof(USHORT) &&
402                  !SetupPacket->wIndex.W &&
403                  SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST)
404             {
405                 KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
406 
407                 MPStatus = Packet->RH_GetStatus(FdoExtension->MiniPortExt,
408                                                 Buffer);
409 
410                 KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
411 
412                 *TransferLength = sizeof(USHORT);
413                 RHStatus = USBPORT_MPStatusToRHStatus(MPStatus);
414             }
415 
416             break;
417 
418         case USB_REQUEST_GET_CONFIGURATION:
419             if (SetupPacket->wValue.W ||
420                 SetupPacket->wIndex.W ||
421                 SetupPacket->wLength != 1 ||
422                 SetupPacket->bmRequestType.Dir == BMREQUEST_HOST_TO_DEVICE)
423             {
424                 return RHStatus;
425             }
426 
427             Length = 0;
428 
429             if (*TransferLength >= 1)
430             {
431                 Length = 1;
432                 RtlCopyMemory(Buffer, &PdoExtension->ConfigurationValue, Length);
433             }
434 
435             *TransferLength = Length;
436 
437             RHStatus = RH_STATUS_SUCCESS;
438             break;
439 
440         case USB_REQUEST_SET_CONFIGURATION:
441             if (!SetupPacket->wIndex.W &&
442                 !SetupPacket->wLength &&
443                 !(SetupPacket->bmRequestType.Dir == BMREQUEST_DEVICE_TO_HOST))
444             {
445                 if (SetupPacket->wValue.W == 0 ||
446                     SetupPacket->wValue.W ==
447                         PdoExtension->RootHubDescriptors->ConfigDescriptor.bConfigurationValue)
448                 {
449                   PdoExtension->ConfigurationValue = SetupPacket->wValue.LowByte;
450                   RHStatus = RH_STATUS_SUCCESS;
451                 }
452             }
453 
454             break;
455 
456         case USB_REQUEST_SET_ADDRESS:
457             if (!SetupPacket->wIndex.W &&
458                 !SetupPacket->wLength &&
459                 !(SetupPacket->bmRequestType.Dir))
460             {
461                 PdoExtension->DeviceHandle.DeviceAddress = SetupPacket->wValue.LowByte;
462                 RHStatus = RH_STATUS_SUCCESS;
463                 break;
464             }
465 
466             break;
467 
468         default:
469             DPRINT1("USBPORT_RootHubStandardCommand: Not supported USB request - %x\n",
470                     SetupPacket->bRequest);
471             //USB_REQUEST_CLEAR_FEATURE                 0x01
472             //USB_REQUEST_SET_FEATURE                   0x03
473             //USB_REQUEST_SET_DESCRIPTOR                0x07
474             //USB_REQUEST_GET_INTERFACE                 0x0A
475             //USB_REQUEST_SET_INTERFACE                 0x0B
476             //USB_REQUEST_SYNC_FRAME                    0x0C
477             break;
478     }
479 
480     return RHStatus;
481 }
482 
483 RHSTATUS
484 NTAPI
485 USBPORT_RootHubEndpoint0(IN PUSBPORT_TRANSFER Transfer)
486 {
487     PDEVICE_OBJECT FdoDevice;
488     ULONG TransferLength;
489     PVOID Buffer;
490     PURB Urb;
491     PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket;
492     UCHAR Type;
493     RHSTATUS RHStatus;
494 
495     DPRINT("USBPORT_RootHubEndpoint0: Transfer - %p\n", Transfer);
496 
497     TransferLength = Transfer->TransferParameters.TransferBufferLength;
498     Urb = Transfer->Urb;
499     FdoDevice = Transfer->Endpoint->FdoDevice;
500 
501     if (TransferLength > 0)
502         Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa;
503     else
504         Buffer = NULL;
505 
506     SetupPacket = (PUSB_DEFAULT_PIPE_SETUP_PACKET)Urb->UrbControlTransfer.SetupPacket;
507 
508     Type = SetupPacket->bmRequestType.Type;
509 
510     if (Type == BMREQUEST_STANDARD)
511     {
512         RHStatus = USBPORT_RootHubStandardCommand(FdoDevice,
513                                                   SetupPacket,
514                                                   Buffer,
515                                                   &TransferLength);
516     }
517     else if (Type == BMREQUEST_CLASS)
518     {
519         RHStatus = USBPORT_RootHubClassCommand(FdoDevice,
520                                                SetupPacket,
521                                                Buffer,
522                                                &TransferLength);
523     }
524     else
525     {
526         return RH_STATUS_UNSUCCESSFUL;
527     }
528 
529     if (RHStatus == RH_STATUS_SUCCESS)
530         Transfer->CompletedTransferLen = TransferLength;
531 
532     return RHStatus;
533 }
534 
535 RHSTATUS
536 NTAPI
537 USBPORT_RootHubSCE(IN PUSBPORT_TRANSFER Transfer)
538 {
539     PUSBPORT_ENDPOINT Endpoint;
540     PUSBPORT_DEVICE_EXTENSION FdoExtension;
541     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
542     PUSBPORT_REGISTRATION_PACKET Packet;
543     ULONG TransferLength;
544     USB_PORT_STATUS_AND_CHANGE PortStatus;
545     USB_HUB_STATUS_AND_CHANGE HubStatus;
546     PVOID Buffer;
547     PULONG AddressBitMap;
548     ULONG Port;
549     PURB Urb;
550     RHSTATUS RHStatus = RH_STATUS_NO_CHANGES;
551     PUSB_HUB_DESCRIPTOR HubDescriptor;
552     UCHAR NumberOfPorts;
553 
554     DPRINT("USBPORT_RootHubSCE: Transfer - %p\n", Transfer);
555 
556     Endpoint = Transfer->Endpoint;
557 
558     FdoExtension = Endpoint->FdoDevice->DeviceExtension;
559     PdoExtension = FdoExtension->RootHubPdo->DeviceExtension;
560     Packet = &FdoExtension->MiniPortInterface->Packet;
561 
562     HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor;
563     NumberOfPorts = HubDescriptor->bNumberOfPorts;
564 
565     PortStatus.AsUlong32 = 0;
566     HubStatus.AsUlong32 = 0;
567 
568     Urb = Transfer->Urb;
569     TransferLength = Transfer->TransferParameters.TransferBufferLength;
570 
571     if (TransferLength)
572     {
573         Buffer = Urb->UrbControlTransfer.TransferBufferMDL->MappedSystemVa;
574     }
575     else
576     {
577         Buffer = NULL;
578     }
579 
580     /* Check parameters */
581 
582     if (!Buffer)
583     {
584         /* Not valid parameter */
585         DPRINT1("USBPORT_RootHubSCE: Error! Buffer is NULL\n");
586         return RH_STATUS_UNSUCCESSFUL;
587     }
588 
589     if ((TransferLength < (NumberOfPorts / 8 + 1)))
590     {
591         /* Not valid parameters */
592         DPRINT1("USBPORT_RootHubSCE: Error! TransferLength - %x, NumberOfPorts - %x\n",
593                 TransferLength,
594                 NumberOfPorts);
595 
596         return RH_STATUS_UNSUCCESSFUL;
597     }
598 
599     RtlZeroMemory(Buffer, TransferLength);
600 
601     AddressBitMap = Buffer;
602 
603     /* Scan all the ports for changes */
604     for (Port = 1; Port <= NumberOfPorts; Port++)
605     {
606         DPRINT_CORE("USBPORT_RootHubSCE: Port - %p\n", Port);
607 
608         /* Request the port status from miniport */
609         if (Packet->RH_GetPortStatus(FdoExtension->MiniPortExt,
610                                      Port,
611                                      &PortStatus))
612         {
613             /* Miniport returned an error */
614             DPRINT1("USBPORT_RootHubSCE: RH_GetPortStatus failed\n");
615             return RH_STATUS_UNSUCCESSFUL;
616         }
617 
618         if (PortStatus.PortChange.Usb20PortChange.ConnectStatusChange ||
619             PortStatus.PortChange.Usb20PortChange.PortEnableDisableChange ||
620             PortStatus.PortChange.Usb20PortChange.SuspendChange ||
621             PortStatus.PortChange.Usb20PortChange.OverCurrentIndicatorChange ||
622             PortStatus.PortChange.Usb20PortChange.ResetChange)
623         {
624             /* At the port status there is a change */
625             AddressBitMap[Port >> 5] |= 1 << (Port & 0x1F);
626             RHStatus = RH_STATUS_SUCCESS;
627         }
628     }
629 
630     /* Request the hub status from miniport */
631     if (!Packet->RH_GetHubStatus(FdoExtension->MiniPortExt, &HubStatus))
632     {
633         if (HubStatus.HubChange.LocalPowerChange == 1 ||
634             HubStatus.HubChange.OverCurrentChange == 1)
635         {
636             /* At the hub status there is a change */
637             AddressBitMap[0] |= 1;
638             RHStatus = RH_STATUS_SUCCESS;
639         }
640 
641         if (RHStatus == RH_STATUS_SUCCESS)
642         {
643             /* Done */
644             Urb->UrbControlTransfer.TransferBufferLength = TransferLength;
645             return RH_STATUS_SUCCESS;
646         }
647 
648         if (RHStatus == RH_STATUS_NO_CHANGES)
649         {
650             /* No changes. Enable IRQs for miniport root hub */
651             Packet->RH_EnableIrq(FdoExtension->MiniPortExt);
652         }
653 
654         return RHStatus;
655     }
656 
657     /* Miniport returned an error */
658     DPRINT1("USBPORT_RootHubSCE: RH_GetHubStatus failed\n");
659     return RH_STATUS_UNSUCCESSFUL;
660 }
661 
662 VOID
663 NTAPI
664 USBPORT_RootHubEndpointWorker(IN PUSBPORT_ENDPOINT Endpoint)
665 {
666     PDEVICE_OBJECT FdoDevice;
667     PUSBPORT_DEVICE_EXTENSION FdoExtension;
668     PUSBPORT_REGISTRATION_PACKET Packet;
669     PUSBPORT_TRANSFER Transfer;
670     RHSTATUS RHStatus;
671     USBD_STATUS USBDStatus;
672     KIRQL OldIrql;
673 
674     DPRINT_CORE("USBPORT_RootHubEndpointWorker: Endpoint - %p\n", Endpoint);
675 
676     FdoDevice = Endpoint->FdoDevice;
677     FdoExtension = FdoDevice->DeviceExtension;
678     Packet = &FdoExtension->MiniPortInterface->Packet;
679 
680     KeAcquireSpinLock(&FdoExtension->MiniportSpinLock, &OldIrql);
681     if (!(FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND))
682     {
683         Packet->CheckController(FdoExtension->MiniPortExt);
684     }
685     KeReleaseSpinLock(&FdoExtension->MiniportSpinLock, OldIrql);
686 
687     KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
688 
689     Transfer = CONTAINING_RECORD(Endpoint->TransferList.Flink,
690                                  USBPORT_TRANSFER,
691                                  TransferLink);
692 
693     if (IsListEmpty(&Endpoint->TransferList) ||
694         Endpoint->TransferList.Flink == NULL ||
695         !Transfer)
696     {
697         if (Endpoint->StateLast == USBPORT_ENDPOINT_REMOVE)
698         {
699             ExInterlockedInsertTailList(&FdoExtension->EndpointClosedList,
700                                         &Endpoint->CloseLink,
701                                         &FdoExtension->EndpointClosedSpinLock);
702        }
703 
704         KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
705 
706         USBPORT_FlushCancelList(Endpoint);
707         return;
708     }
709 
710     if (Transfer->Flags & (TRANSFER_FLAG_ABORTED | TRANSFER_FLAG_CANCELED))
711     {
712         RemoveEntryList(&Transfer->TransferLink);
713         InsertTailList(&Endpoint->CancelList, &Transfer->TransferLink);
714 
715         KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
716         USBPORT_FlushCancelList(Endpoint);
717         return;
718     }
719 
720     KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
721 
722     if (Endpoint->EndpointProperties.TransferType == USBPORT_TRANSFER_TYPE_CONTROL)
723         RHStatus = USBPORT_RootHubEndpoint0(Transfer);
724     else
725         RHStatus = USBPORT_RootHubSCE(Transfer);
726 
727     if (RHStatus != RH_STATUS_NO_CHANGES)
728     {
729         if (RHStatus == RH_STATUS_SUCCESS)
730             USBDStatus = USBD_STATUS_SUCCESS;
731         else
732             USBDStatus = USBD_STATUS_STALL_PID;
733 
734         KeAcquireSpinLock(&Endpoint->EndpointSpinLock, &Endpoint->EndpointOldIrql);
735         USBPORT_QueueDoneTransfer(Transfer, USBDStatus);
736         KeReleaseSpinLock(&Endpoint->EndpointSpinLock, Endpoint->EndpointOldIrql);
737 
738         USBPORT_FlushCancelList(Endpoint);
739         return;
740     }
741 
742     USBPORT_FlushCancelList(Endpoint);
743 }
744 
745 NTSTATUS
746 NTAPI
747 USBPORT_RootHubCreateDevice(IN PDEVICE_OBJECT FdoDevice,
748                             IN PDEVICE_OBJECT PdoDevice)
749 {
750     PUSBPORT_DEVICE_EXTENSION FdoExtension;
751     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
752     PUSBPORT_REGISTRATION_PACKET Packet;
753     PUSBPORT_DEVICE_HANDLE DeviceHandle;
754     USBPORT_ROOT_HUB_DATA RootHubData;
755     ULONG NumMaskByte;
756     ULONG DescriptorsLength;
757     PUSBPORT_RH_DESCRIPTORS Descriptors;
758     PUSB_DEVICE_DESCRIPTOR RH_DeviceDescriptor;
759     PUSB_CONFIGURATION_DESCRIPTOR RH_ConfigurationDescriptor;
760     PUSB_INTERFACE_DESCRIPTOR RH_InterfaceDescriptor;
761     PUSB_ENDPOINT_DESCRIPTOR RH_EndPointDescriptor;
762     PUSB_HUB_DESCRIPTOR RH_HubDescriptor;
763     ULONG ix;
764     PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
765     NTSTATUS Status;
766 
767     DPRINT("USBPORT_RootHubCreateDevice: FdoDevice - %p, PdoDevice - %p\n",
768            FdoDevice,
769            PdoDevice);
770 
771     FdoExtension = FdoDevice->DeviceExtension;
772     PdoExtension = PdoDevice->DeviceExtension;
773     Packet = &FdoExtension->MiniPortInterface->Packet;
774 
775     DeviceHandle = &PdoExtension->DeviceHandle;
776     USBPORT_AddDeviceHandle(FdoDevice, DeviceHandle);
777 
778     InitializeListHead(&DeviceHandle->PipeHandleList);
779 
780     DeviceHandle->IsRootHub = TRUE;
781     DeviceHandle->DeviceSpeed = UsbFullSpeed;
782     DeviceHandle->Flags = DEVICE_HANDLE_FLAG_ROOTHUB;
783 
784     RtlZeroMemory(&RootHubData, sizeof(RootHubData));
785 
786     Packet->RH_GetRootHubData(FdoExtension->MiniPortExt, &RootHubData);
787 
788     ASSERT(RootHubData.NumberOfPorts != 0);
789     NumMaskByte = (RootHubData.NumberOfPorts - 1) / 8 + 1;
790 
791     DescriptorsLength = sizeof(USB_DEVICE_DESCRIPTOR) +
792                         sizeof(USB_CONFIGURATION_DESCRIPTOR) +
793                         sizeof(USB_INTERFACE_DESCRIPTOR) +
794                         sizeof(USB_ENDPOINT_DESCRIPTOR) +
795                         (sizeof(USB_HUB_DESCRIPTOR) + 2 * NumMaskByte);
796 
797     Descriptors = ExAllocatePoolWithTag(NonPagedPool,
798                                         DescriptorsLength,
799                                         USB_PORT_TAG);
800 
801     if (Descriptors)
802     {
803         RtlZeroMemory(Descriptors, DescriptorsLength);
804 
805         PdoExtension->RootHubDescriptors = Descriptors;
806 
807         RH_DeviceDescriptor = &PdoExtension->RootHubDescriptors->DeviceDescriptor;
808 
809         RH_DeviceDescriptor->bLength = sizeof(USB_DEVICE_DESCRIPTOR);
810         RH_DeviceDescriptor->bDescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;
811         RH_DeviceDescriptor->bcdUSB = 0x100;
812         RH_DeviceDescriptor->bDeviceClass = USB_DEVICE_CLASS_HUB;
813         RH_DeviceDescriptor->bDeviceSubClass = 0x01;
814         RH_DeviceDescriptor->bDeviceProtocol = 0x00;
815         RH_DeviceDescriptor->bMaxPacketSize0 = 0x08;
816         RH_DeviceDescriptor->idVendor = FdoExtension->VendorID;
817         RH_DeviceDescriptor->idProduct = FdoExtension->DeviceID;
818         RH_DeviceDescriptor->bcdDevice = FdoExtension->RevisionID;
819         RH_DeviceDescriptor->iManufacturer = 0x00;
820         RH_DeviceDescriptor->iProduct = 0x00;
821         RH_DeviceDescriptor->iSerialNumber = 0x00;
822         RH_DeviceDescriptor->bNumConfigurations = 0x01;
823 
824         RH_ConfigurationDescriptor = &PdoExtension->RootHubDescriptors->ConfigDescriptor;
825 
826         RH_ConfigurationDescriptor->bLength = sizeof(USB_CONFIGURATION_DESCRIPTOR);
827         RH_ConfigurationDescriptor->bDescriptorType = USB_CONFIGURATION_DESCRIPTOR_TYPE;
828 
829         RH_ConfigurationDescriptor->wTotalLength = sizeof(USB_CONFIGURATION_DESCRIPTOR) +
830                                                    sizeof(USB_INTERFACE_DESCRIPTOR) +
831                                                    sizeof(USB_ENDPOINT_DESCRIPTOR);
832 
833         RH_ConfigurationDescriptor->bNumInterfaces = 0x01;
834         RH_ConfigurationDescriptor->bConfigurationValue = 0x01;
835         RH_ConfigurationDescriptor->iConfiguration = 0x00;
836         RH_ConfigurationDescriptor->bmAttributes = USB_CONFIG_SELF_POWERED;
837         RH_ConfigurationDescriptor->MaxPower = 0x00;
838 
839         RH_InterfaceDescriptor = &PdoExtension->RootHubDescriptors->InterfaceDescriptor;
840 
841         RH_InterfaceDescriptor->bLength = sizeof(USB_INTERFACE_DESCRIPTOR);
842         RH_InterfaceDescriptor->bDescriptorType = USB_INTERFACE_DESCRIPTOR_TYPE;
843         RH_InterfaceDescriptor->bInterfaceNumber = 0x00;
844         RH_InterfaceDescriptor->bAlternateSetting = 0x00;
845         RH_InterfaceDescriptor->bNumEndpoints = 0x01;
846         RH_InterfaceDescriptor->bInterfaceClass = USB_DEVICE_CLASS_HUB;
847         RH_InterfaceDescriptor->bInterfaceSubClass = 0x01;
848         RH_InterfaceDescriptor->bInterfaceProtocol = 0x00;
849         RH_InterfaceDescriptor->iInterface = 0x00;
850 
851         RH_EndPointDescriptor = &PdoExtension->RootHubDescriptors->EndPointDescriptor;
852 
853         RH_EndPointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR);
854         RH_EndPointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
855         RH_EndPointDescriptor->bEndpointAddress = 0x81;
856         RH_EndPointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_INTERRUPT; // SCE endpoint
857         RH_EndPointDescriptor->wMaxPacketSize = 0x0008;
858         RH_EndPointDescriptor->bInterval = 0x0C; // 12 msec
859 
860         RH_HubDescriptor = &PdoExtension->RootHubDescriptors->Descriptor;
861 
862         RH_HubDescriptor->bDescriptorLength = FIELD_OFFSET(USB_HUB_DESCRIPTOR, bRemoveAndPowerMask) + 2 * NumMaskByte;
863 
864         if (Packet->MiniPortVersion == USB_MINIPORT_VERSION_OHCI ||
865             Packet->MiniPortVersion == USB_MINIPORT_VERSION_UHCI ||
866             Packet->MiniPortVersion == USB_MINIPORT_VERSION_EHCI)
867         {
868             RH_HubDescriptor->bDescriptorType = USB_20_HUB_DESCRIPTOR_TYPE;
869         }
870         else if (Packet->MiniPortVersion == USB_MINIPORT_VERSION_XHCI)
871         {
872             RH_HubDescriptor->bDescriptorType = USB_30_HUB_DESCRIPTOR_TYPE;
873         }
874         else
875         {
876             DPRINT1("USBPORT_RootHubCreateDevice: Unknown MiniPortVersion - %x\n",
877                     Packet->MiniPortVersion);
878 
879             DbgBreakPoint();
880         }
881 
882         RH_HubDescriptor->bNumberOfPorts = RootHubData.NumberOfPorts;
883         RH_HubDescriptor->wHubCharacteristics = RootHubData.HubCharacteristics.AsUSHORT;
884         RH_HubDescriptor->bPowerOnToPowerGood = RootHubData.PowerOnToPowerGood;
885         RH_HubDescriptor->bHubControlCurrent = RootHubData.HubControlCurrent;
886 
887         for (ix = 0; ix < NumMaskByte; ix += 2)
888         {
889             RH_HubDescriptor->bRemoveAndPowerMask[ix] = 0;
890             RH_HubDescriptor->bRemoveAndPowerMask[ix + 1] = -1;
891         }
892 
893         EndpointDescriptor = &DeviceHandle->PipeHandle.EndpointDescriptor;
894 
895         EndpointDescriptor->bLength = sizeof(USB_ENDPOINT_DESCRIPTOR);
896         EndpointDescriptor->bDescriptorType = USB_ENDPOINT_DESCRIPTOR_TYPE;
897         EndpointDescriptor->bEndpointAddress = 0x00;
898         EndpointDescriptor->bmAttributes = USB_ENDPOINT_TYPE_CONTROL;
899         EndpointDescriptor->wMaxPacketSize = 0x0040;
900         EndpointDescriptor->bInterval = 0x00;
901 
902         Status = USBPORT_OpenPipe(FdoDevice,
903                                   DeviceHandle,
904                                   &DeviceHandle->PipeHandle,
905                                   NULL);
906     }
907     else
908     {
909         Status = STATUS_INSUFFICIENT_RESOURCES;
910     }
911 
912     return Status;
913 }
914 
915 ULONG
916 NTAPI
917 USBPORT_InvalidateRootHub(PVOID MiniPortExtension)
918 {
919     PUSBPORT_DEVICE_EXTENSION FdoExtension;
920     PDEVICE_OBJECT FdoDevice;
921     PDEVICE_OBJECT PdoDevice;
922     PUSBPORT_RHDEVICE_EXTENSION PdoExtension;
923     PUSBPORT_ENDPOINT Endpoint = NULL;
924 
925     DPRINT("USBPORT_InvalidateRootHub ... \n");
926 
927     FdoExtension = (PUSBPORT_DEVICE_EXTENSION)((ULONG_PTR)MiniPortExtension -
928                                                sizeof(USBPORT_DEVICE_EXTENSION));
929 
930     FdoDevice = FdoExtension->CommonExtension.SelfDevice;
931 
932     if (FdoExtension->Flags & USBPORT_FLAG_HC_SUSPEND &&
933         FdoExtension->Flags & USBPORT_FLAG_HC_WAKE_SUPPORT &&
934         FdoExtension->MiniPortFlags & USBPORT_MPFLAG_SUSPENDED &&
935         FdoExtension->TimerFlags & USBPORT_TMFLAG_WAKE)
936     {
937         USBPORT_HcQueueWakeDpc(FdoDevice);
938         return 0;
939     }
940 
941     FdoExtension->MiniPortInterface->Packet.RH_DisableIrq(FdoExtension->MiniPortExt);
942 
943     PdoDevice = FdoExtension->RootHubPdo;
944 
945     if (PdoDevice)
946     {
947         PdoExtension = PdoDevice->DeviceExtension;
948         Endpoint = PdoExtension->Endpoint;
949 
950         if (Endpoint)
951         {
952             USBPORT_InvalidateEndpointHandler(FdoDevice,
953                                               PdoExtension->Endpoint,
954                                               INVALIDATE_ENDPOINT_WORKER_THREAD);
955         }
956     }
957 
958     return 0;
959 }
960 
961 VOID
962 NTAPI
963 USBPORT_RootHubPowerAndChirpAllCcPorts(IN PDEVICE_OBJECT FdoDevice)
964 {
965     PUSBPORT_DEVICE_EXTENSION FdoExtension;
966     PUSBPORT_REGISTRATION_PACKET Packet;
967     USBPORT_ROOT_HUB_DATA RootHubData;
968     ULONG Port;
969     PDEVICE_RELATIONS CompanionControllersList;
970     PUSBPORT_DEVICE_EXTENSION CompanionFdoExtension;
971     PUSBPORT_REGISTRATION_PACKET CompanionPacket;
972     ULONG CompanionPorts;
973     ULONG NumController;
974     PDEVICE_OBJECT * Entry;
975     ULONG NumPorts;
976 
977     DPRINT("USBPORT_RootHub_PowerAndChirpAllCcPorts: FdoDevice - %p\n",
978            FdoDevice);
979 
980     FdoExtension = FdoDevice->DeviceExtension;
981 
982     Packet = &FdoExtension->MiniPortInterface->Packet;
983 
984     RtlZeroMemory(&RootHubData, sizeof(RootHubData));
985 
986     Packet->RH_GetRootHubData(FdoExtension->MiniPortExt,
987                               &RootHubData);
988 
989     NumPorts = RootHubData.NumberOfPorts;
990 
991     for (Port = 1; Port <= NumPorts; ++Port)
992     {
993         Packet->RH_SetFeaturePortPower(FdoExtension->MiniPortExt, Port);
994     }
995 
996     USBPORT_Wait(FdoDevice, 10);
997 
998     CompanionControllersList = USBPORT_FindCompanionControllers(FdoDevice,
999                                                                 FALSE,
1000                                                                 TRUE);
1001 
1002     if (CompanionControllersList)
1003     {
1004         Entry = &CompanionControllersList->Objects[0];
1005 
1006         for (NumController = 0;
1007              NumController < CompanionControllersList->Count;
1008              NumController++)
1009         {
1010             CompanionPacket = &FdoExtension->MiniPortInterface->Packet;
1011 
1012             CompanionFdoExtension = (*Entry)->DeviceExtension;
1013 
1014             CompanionPacket->RH_GetRootHubData(CompanionFdoExtension->MiniPortExt,
1015                                                &RootHubData);
1016 
1017             CompanionPorts = RootHubData.NumberOfPorts;
1018 
1019             for (Port = 1; Port <= CompanionPorts; ++Port)
1020             {
1021                 CompanionPacket->RH_SetFeaturePortPower(CompanionFdoExtension->MiniPortExt,
1022                                                         Port);
1023             }
1024 
1025             ++Entry;
1026         }
1027 
1028         ExFreePoolWithTag(CompanionControllersList, USB_PORT_TAG);
1029     }
1030 
1031     USBPORT_Wait(FdoDevice, 100);
1032 
1033     for (Port = 1; Port <= NumPorts; ++Port)
1034     {
1035         if (FdoExtension->MiniPortInterface->Version < 200)
1036         {
1037             break;
1038         }
1039 
1040         InterlockedIncrement((PLONG)&FdoExtension->ChirpRootPortLock);
1041         Packet->RH_ChirpRootPort(FdoExtension->MiniPortExt, Port);
1042         InterlockedDecrement((PLONG)&FdoExtension->ChirpRootPortLock);
1043     }
1044 }
1045