1 /** @file
2 
3     Unified interface for RootHub and Hub.
4 
5 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UsbBus.h"
11 
12 //
13 // Array that maps the change bit to feature value which is
14 // used to clear these change bit. USB HUB API will clear
15 // these change bit automatically. For non-root hub, these
16 // bits determine whether hub will report the port in changed
17 // bit maps.
18 //
19 USB_CHANGE_FEATURE_MAP  mHubFeatureMap[] = {
20   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
21   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
22   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
23   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
24   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange}
25 };
26 
27 USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[] = {
28   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
29   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
30   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
31   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
32   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},
33 };
34 
35 //
36 // USB hub class specific requests. Although USB hub
37 // is related to an interface, these requests are sent
38 // to the control endpoint of the device.
39 //
40 /**
41   USB hub control transfer to set the hub depth.
42 
43   @param  HubDev                The device of the hub.
44   @param  Depth                 The depth to set.
45 
46   @retval EFI_SUCCESS           Depth of the hub is set.
47   @retval Others                Failed to set the depth.
48 
49 **/
50 EFI_STATUS
UsbHubCtrlSetHubDepth(IN USB_DEVICE * HubDev,IN UINT16 Depth)51 UsbHubCtrlSetHubDepth (
52   IN  USB_DEVICE          *HubDev,
53   IN  UINT16              Depth
54   )
55 {
56   EFI_STATUS              Status;
57 
58   Status = UsbCtrlRequest (
59              HubDev,
60              EfiUsbNoData,
61              USB_REQ_TYPE_CLASS,
62              USB_HUB_TARGET_HUB,
63              USB_HUB_REQ_SET_DEPTH,
64              Depth,
65              0,
66              NULL,
67              0
68              );
69 
70   return Status;
71 }
72 
73 /**
74   USB hub control transfer to clear the hub feature.
75 
76   @param  HubDev                The device of the hub.
77   @param  Feature               The feature to clear.
78 
79   @retval EFI_SUCCESS           Feature of the hub is cleared.
80   @retval Others                Failed to clear the feature.
81 
82 **/
83 EFI_STATUS
UsbHubCtrlClearHubFeature(IN USB_DEVICE * HubDev,IN UINT16 Feature)84 UsbHubCtrlClearHubFeature (
85   IN USB_DEVICE           *HubDev,
86   IN UINT16               Feature
87   )
88 {
89   EFI_STATUS              Status;
90 
91   Status = UsbCtrlRequest (
92              HubDev,
93              EfiUsbNoData,
94              USB_REQ_TYPE_CLASS,
95              USB_HUB_TARGET_HUB,
96              USB_HUB_REQ_CLEAR_FEATURE,
97              Feature,
98              0,
99              NULL,
100              0
101              );
102 
103   return Status;
104 }
105 
106 
107 /**
108   Clear the feature of the device's port.
109 
110   @param  HubDev                The hub device.
111   @param  Port                  The port to clear feature.
112   @param  Feature               The feature to clear.
113 
114   @retval EFI_SUCCESS           The feature of the port is cleared.
115   @retval Others                Failed to clear the feature.
116 
117 **/
118 EFI_STATUS
UsbHubCtrlClearPortFeature(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT16 Feature)119 UsbHubCtrlClearPortFeature (
120   IN USB_DEVICE           *HubDev,
121   IN UINT8                Port,
122   IN UINT16               Feature
123   )
124 {
125   EFI_STATUS              Status;
126 
127   //
128   // In USB bus, all the port index starts from 0. But HUB
129   // indexes its port from 1. So, port number is added one.
130   //
131   Status = UsbCtrlRequest (
132              HubDev,
133              EfiUsbNoData,
134              USB_REQ_TYPE_CLASS,
135              USB_HUB_TARGET_PORT,
136              USB_HUB_REQ_CLEAR_FEATURE,
137              Feature,
138              (UINT16) (Port + 1),
139              NULL,
140              0
141              );
142 
143   return Status;
144 }
145 
146 
147 /**
148   Clear the transaction translate buffer if full/low
149   speed control/bulk transfer failed and the transfer
150   uses this hub as translator.Remember to clear the TT
151   buffer of transaction translator, not that of the
152   parent.
153 
154   @param  HubDev                The hub device.
155   @param  Port                  The port of the hub.
156   @param  DevAddr               Address of the failed transaction.
157   @param  EpNum                 The endpoint number of the failed transaction.
158   @param  EpType                The type of failed transaction.
159 
160   @retval EFI_SUCCESS           The TT buffer is cleared.
161   @retval Others                Failed to clear the TT buffer.
162 
163 **/
164 EFI_STATUS
UsbHubCtrlClearTTBuffer(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT16 DevAddr,IN UINT16 EpNum,IN UINT16 EpType)165 UsbHubCtrlClearTTBuffer (
166   IN USB_DEVICE           *HubDev,
167   IN UINT8                Port,
168   IN UINT16               DevAddr,
169   IN UINT16               EpNum,
170   IN UINT16               EpType
171   )
172 {
173   EFI_STATUS              Status;
174   UINT16                  Value;
175 
176   //
177   // Check USB2.0 spec page 424 for wValue's encoding
178   //
179   Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |
180           ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
181 
182   Status = UsbCtrlRequest (
183              HubDev,
184              EfiUsbNoData,
185              USB_REQ_TYPE_CLASS,
186              USB_HUB_TARGET_PORT,
187              USB_HUB_REQ_CLEAR_TT,
188              Value,
189              (UINT16) (Port + 1),
190              NULL,
191              0
192              );
193 
194   return Status;
195 }
196 
197 /**
198   Usb hub control transfer to get the (super speed) hub descriptor.
199 
200   @param  HubDev                The hub device.
201   @param  Buf                   The buffer to hold the descriptor.
202   @param  Len                   The length to retrieve.
203 
204   @retval EFI_SUCCESS           The hub descriptor is retrieved.
205   @retval Others                Failed to retrieve the hub descriptor.
206 
207 **/
208 EFI_STATUS
UsbHubCtrlGetHubDesc(IN USB_DEVICE * HubDev,OUT VOID * Buf,IN UINTN Len)209 UsbHubCtrlGetHubDesc (
210   IN  USB_DEVICE          *HubDev,
211   OUT VOID                *Buf,
212   IN  UINTN               Len
213   )
214 {
215   EFI_STATUS              Status;
216   UINT8                   DescType;
217 
218   DescType = (HubDev->Speed == EFI_USB_SPEED_SUPER) ?
219              USB_DESC_TYPE_HUB_SUPER_SPEED :
220              USB_DESC_TYPE_HUB;
221 
222   Status = UsbCtrlRequest (
223              HubDev,
224              EfiUsbDataIn,
225              USB_REQ_TYPE_CLASS,
226              USB_HUB_TARGET_HUB,
227              USB_HUB_REQ_GET_DESC,
228              (UINT16) (DescType << 8),
229              0,
230              Buf,
231              Len
232              );
233 
234   return Status;
235 }
236 
237 
238 /**
239   Usb hub control transfer to get the hub status.
240 
241   @param  HubDev                The hub device.
242   @param  State                 The variable to return the status.
243 
244   @retval EFI_SUCCESS           The hub status is returned in State.
245   @retval Others                Failed to get the hub status.
246 
247 **/
248 EFI_STATUS
UsbHubCtrlGetHubStatus(IN USB_DEVICE * HubDev,OUT UINT32 * State)249 UsbHubCtrlGetHubStatus (
250   IN  USB_DEVICE          *HubDev,
251   OUT UINT32              *State
252   )
253 {
254   EFI_STATUS              Status;
255 
256   Status = UsbCtrlRequest (
257              HubDev,
258              EfiUsbDataIn,
259              USB_REQ_TYPE_CLASS,
260              USB_HUB_TARGET_HUB,
261              USB_HUB_REQ_GET_STATUS,
262              0,
263              0,
264              State,
265              4
266              );
267 
268   return Status;
269 }
270 
271 
272 /**
273   Usb hub control transfer to get the port status.
274 
275   @param  HubDev                The hub device.
276   @param  Port                  The port of the hub.
277   @param  State                 Variable to return the hub port state.
278 
279   @retval EFI_SUCCESS           The port state is returned in State.
280   @retval Others                Failed to retrieve the port state.
281 
282 **/
283 EFI_STATUS
UsbHubCtrlGetPortStatus(IN USB_DEVICE * HubDev,IN UINT8 Port,OUT VOID * State)284 UsbHubCtrlGetPortStatus (
285   IN  USB_DEVICE          *HubDev,
286   IN  UINT8               Port,
287   OUT VOID                *State
288   )
289 {
290   EFI_STATUS              Status;
291 
292   //
293   // In USB bus, all the port index starts from 0. But HUB
294   // indexes its port from 1. So, port number is added one.
295   // No need to convert the hub bit to UEFI definition, they
296   // are the same
297   //
298   Status = UsbCtrlRequest (
299              HubDev,
300              EfiUsbDataIn,
301              USB_REQ_TYPE_CLASS,
302              USB_HUB_TARGET_PORT,
303              USB_HUB_REQ_GET_STATUS,
304              0,
305              (UINT16) (Port + 1),
306              State,
307              4
308              );
309 
310   return Status;
311 }
312 
313 
314 /**
315   Usb hub control transfer to set the port feature.
316 
317   @param  HubDev                The Usb hub device.
318   @param  Port                  The Usb port to set feature for.
319   @param  Feature               The feature to set.
320 
321   @retval EFI_SUCCESS           The feature is set for the port.
322   @retval Others                Failed to set the feature.
323 
324 **/
325 EFI_STATUS
UsbHubCtrlSetPortFeature(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT8 Feature)326 UsbHubCtrlSetPortFeature (
327   IN USB_DEVICE           *HubDev,
328   IN UINT8                Port,
329   IN UINT8                Feature
330   )
331 {
332   EFI_STATUS              Status;
333 
334   //
335   // In USB bus, all the port index starts from 0. But HUB
336   // indexes its port from 1. So, port number is added one.
337   //
338   Status = UsbCtrlRequest (
339              HubDev,
340              EfiUsbNoData,
341              USB_REQ_TYPE_CLASS,
342              USB_HUB_TARGET_PORT,
343              USB_HUB_REQ_SET_FEATURE,
344              Feature,
345              (UINT16) (Port + 1),
346              NULL,
347              0
348              );
349 
350   return Status;
351 }
352 
353 
354 /**
355   Read the whole usb hub descriptor. It is necessary
356   to do it in two steps because hub descriptor is of
357   variable length.
358 
359   @param  HubDev                The hub device.
360   @param  HubDesc               The variable to return the descriptor.
361 
362   @retval EFI_SUCCESS           The hub descriptor is read.
363   @retval Others                Failed to read the hub descriptor.
364 
365 **/
366 EFI_STATUS
UsbHubReadDesc(IN USB_DEVICE * HubDev,OUT EFI_USB_HUB_DESCRIPTOR * HubDesc)367 UsbHubReadDesc (
368   IN  USB_DEVICE              *HubDev,
369   OUT EFI_USB_HUB_DESCRIPTOR  *HubDesc
370   )
371 {
372   EFI_STATUS              Status;
373 
374   //
375   // First get the hub descriptor length
376   //
377   Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
378 
379   if (EFI_ERROR (Status)) {
380     return Status;
381   }
382 
383   //
384   // Get the whole hub descriptor
385   //
386   return UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
387 }
388 
389 
390 
391 /**
392   Ack the hub change bits. If these bits are not ACKed, Hub will
393   always return changed bit map from its interrupt endpoint.
394 
395   @param  HubDev                The hub device.
396 
397   @retval EFI_SUCCESS           The hub change status is ACKed.
398   @retval Others                Failed to ACK the hub status.
399 
400 **/
401 EFI_STATUS
UsbHubAckHubStatus(IN USB_DEVICE * HubDev)402 UsbHubAckHubStatus (
403   IN  USB_DEVICE         *HubDev
404   )
405 {
406   EFI_USB_PORT_STATUS     HubState;
407   EFI_STATUS              Status;
408 
409   Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
410 
411   if (EFI_ERROR (Status)) {
412     return Status;
413   }
414 
415   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
416     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
417   }
418 
419   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
420     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
421   }
422 
423   return EFI_SUCCESS;
424 }
425 
426 
427 /**
428   Test whether the interface is a hub interface.
429 
430   @param  UsbIf                 The interface to test.
431 
432   @retval TRUE                  The interface is a hub interface.
433   @retval FALSE                 The interface isn't a hub interface.
434 
435 **/
436 BOOLEAN
UsbIsHubInterface(IN USB_INTERFACE * UsbIf)437 UsbIsHubInterface (
438   IN USB_INTERFACE        *UsbIf
439   )
440 {
441   EFI_USB_INTERFACE_DESCRIPTOR  *Setting;
442 
443   //
444   // If the hub is a high-speed hub with multiple TT,
445   // the hub will has a default setting of single TT.
446   //
447   Setting = &UsbIf->IfSetting->Desc;
448 
449   if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
450       (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
451 
452     return TRUE;
453   }
454 
455   return FALSE;
456 }
457 
458 
459 /**
460   The callback function to the USB hub status change
461   interrupt endpoint. It is called periodically by
462   the underlying host controller.
463 
464   @param  Data                  The data read.
465   @param  DataLength            The length of the data read.
466   @param  Context               The context.
467   @param  Result                The result of the last interrupt transfer.
468 
469   @retval EFI_SUCCESS           The process is OK.
470   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource.
471 
472 **/
473 EFI_STATUS
474 EFIAPI
UsbOnHubInterrupt(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)475 UsbOnHubInterrupt (
476   IN  VOID                *Data,
477   IN  UINTN               DataLength,
478   IN  VOID                *Context,
479   IN  UINT32              Result
480   )
481 {
482   USB_INTERFACE               *HubIf;
483   EFI_USB_IO_PROTOCOL         *UsbIo;
484   EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
485   EFI_STATUS                  Status;
486 
487   HubIf   = (USB_INTERFACE *) Context;
488   UsbIo   = &(HubIf->UsbIo);
489   EpDesc  = &(HubIf->HubEp->Desc);
490 
491   if (Result != EFI_USB_NOERROR) {
492     //
493     // If endpoint is stalled, clear the stall. Use UsbIo to access
494     // the control transfer so internal status are maintained.
495     //
496     if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
497       UsbIoClearFeature (
498         UsbIo,
499         USB_TARGET_ENDPOINT,
500         USB_FEATURE_ENDPOINT_HALT,
501         EpDesc->EndpointAddress
502         );
503     }
504 
505     //
506     // Delete and submit a new async interrupt
507     //
508     Status = UsbIo->UsbAsyncInterruptTransfer (
509                       UsbIo,
510                       EpDesc->EndpointAddress,
511                       FALSE,
512                       0,
513                       0,
514                       NULL,
515                       NULL
516                       );
517 
518     if (EFI_ERROR (Status)) {
519       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
520       return Status;
521     }
522 
523     Status = UsbIo->UsbAsyncInterruptTransfer (
524                       UsbIo,
525                       EpDesc->EndpointAddress,
526                       TRUE,
527                       USB_HUB_POLL_INTERVAL,
528                       HubIf->NumOfPort / 8 + 1,
529                       UsbOnHubInterrupt,
530                       HubIf
531                       );
532 
533     if (EFI_ERROR (Status)) {
534       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
535     }
536 
537     return Status;
538   }
539 
540   if ((DataLength == 0) || (Data == NULL)) {
541     return EFI_SUCCESS;
542   }
543 
544   //
545   // OK, actually something is changed, save the change map
546   // then signal the HUB to do enumeration. This is a good
547   // practise since UsbOnHubInterrupt is called in the context
548   // of host controller's AsyncInterrupt monitor.
549   //
550   HubIf->ChangeMap = AllocateZeroPool (DataLength);
551 
552   if (HubIf->ChangeMap == NULL) {
553     return EFI_OUT_OF_RESOURCES;
554   }
555 
556   CopyMem (HubIf->ChangeMap, Data, DataLength);
557   gBS->SignalEvent (HubIf->HubNotify);
558 
559   return EFI_SUCCESS;
560 }
561 
562 
563 
564 
565 /**
566   Initialize the device for a non-root hub.
567 
568   @param  HubIf                 The USB hub interface.
569 
570   @retval EFI_SUCCESS           The hub is initialized.
571   @retval EFI_DEVICE_ERROR      Failed to initialize the hub.
572 
573 **/
574 EFI_STATUS
UsbHubInit(IN USB_INTERFACE * HubIf)575 UsbHubInit (
576   IN USB_INTERFACE        *HubIf
577   )
578 {
579   UINT8                   HubDescBuffer[256];
580   EFI_USB_HUB_DESCRIPTOR  *HubDesc;
581   USB_ENDPOINT_DESC       *EpDesc;
582   USB_INTERFACE_SETTING   *Setting;
583   EFI_USB_IO_PROTOCOL     *UsbIo;
584   USB_DEVICE              *HubDev;
585   EFI_STATUS              Status;
586   UINT8                   Index;
587   UINT8                   NumEndpoints;
588   UINT16                  Depth;
589 
590   //
591   // Locate the interrupt endpoint for port change map
592   //
593   HubIf->IsHub  = FALSE;
594   Setting       = HubIf->IfSetting;
595   HubDev        = HubIf->Device;
596   EpDesc        = NULL;
597   NumEndpoints  = Setting->Desc.NumEndpoints;
598 
599   for (Index = 0; Index < NumEndpoints; Index++) {
600     ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
601 
602     EpDesc = Setting->Endpoints[Index];
603 
604     if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
605        (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
606       break;
607     }
608   }
609 
610   if (Index == NumEndpoints) {
611     DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
612     return EFI_DEVICE_ERROR;
613   }
614 
615   //
616   // The length field of descriptor is UINT8 type, so the buffer
617   // with 256 bytes is enough to hold the descriptor data.
618   //
619   HubDesc = (EFI_USB_HUB_DESCRIPTOR *) HubDescBuffer;
620   Status = UsbHubReadDesc (HubDev, HubDesc);
621 
622   if (EFI_ERROR (Status)) {
623     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));
624     return Status;
625   }
626 
627   HubIf->NumOfPort = HubDesc->NumPorts;
628 
629   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
630 
631   //
632   // OK, set IsHub to TRUE. Now usb bus can handle this device
633   // as a working HUB. If failed earlier, bus driver will not
634   // recognize it as a hub. Other parts of the bus should be able
635   // to work.
636   //
637   HubIf->IsHub  = TRUE;
638   HubIf->HubApi = &mUsbHubApi;
639   HubIf->HubEp  = EpDesc;
640 
641   if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
642     Depth = (UINT16)(HubIf->Device->Tier - 1);
643     DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
644     UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
645 
646     for (Index = 0; Index < HubDesc->NumPorts; Index++) {
647       UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
648     }
649   } else {
650     //
651     // Feed power to all the hub ports. It should be ok
652     // for both gang/individual powered hubs.
653     //
654     for (Index = 0; Index < HubDesc->NumPorts; Index++) {
655       UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);
656     }
657 
658     //
659     // Update for the usb hub has no power on delay requirement
660     //
661     if (HubDesc->PwrOn2PwrGood > 0) {
662       gBS->Stall (HubDesc->PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
663     }
664     UsbHubAckHubStatus (HubIf->Device);
665   }
666 
667   //
668   // Create an event to enumerate the hub's port. On
669   //
670   Status = gBS->CreateEvent (
671                   EVT_NOTIFY_SIGNAL,
672                   TPL_CALLBACK,
673                   UsbHubEnumeration,
674                   HubIf,
675                   &HubIf->HubNotify
676                   );
677 
678   if (EFI_ERROR (Status)) {
679     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",
680                 HubDev->Address, Status));
681 
682     return Status;
683   }
684 
685   //
686   // Create AsyncInterrupt to query hub port change endpoint
687   // periodically. If the hub ports are changed, hub will return
688   // changed port map from the interrupt endpoint. The port map
689   // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
690   // host change status).
691   //
692   UsbIo  = &HubIf->UsbIo;
693   Status = UsbIo->UsbAsyncInterruptTransfer (
694                     UsbIo,
695                     EpDesc->Desc.EndpointAddress,
696                     TRUE,
697                     USB_HUB_POLL_INTERVAL,
698                     HubIf->NumOfPort / 8 + 1,
699                     UsbOnHubInterrupt,
700                     HubIf
701                     );
702 
703   if (EFI_ERROR (Status)) {
704     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
705                 HubDev->Address, Status));
706 
707     gBS->CloseEvent (HubIf->HubNotify);
708     HubIf->HubNotify = NULL;
709 
710     return Status;
711   }
712 
713   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
714   return Status;
715 }
716 
717 
718 
719 /**
720   Get the port status. This function is required to
721   ACK the port change bits although it will return
722   the port changes in PortState. Bus enumeration code
723   doesn't need to ACK the port change bits.
724 
725   @param  HubIf                 The hub interface.
726   @param  Port                  The port of the hub to get state.
727   @param  PortState             Variable to return the port state.
728 
729   @retval EFI_SUCCESS           The port status is successfully returned.
730   @retval Others                Failed to return the status.
731 
732 **/
733 EFI_STATUS
UsbHubGetPortStatus(IN USB_INTERFACE * HubIf,IN UINT8 Port,OUT EFI_USB_PORT_STATUS * PortState)734 UsbHubGetPortStatus (
735   IN  USB_INTERFACE       *HubIf,
736   IN  UINT8               Port,
737   OUT EFI_USB_PORT_STATUS *PortState
738   )
739 {
740   EFI_STATUS              Status;
741 
742   Status  = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
743 
744   return Status;
745 }
746 
747 
748 
749 /**
750   Clear the port change status.
751 
752   @param  HubIf                 The hub interface.
753   @param  Port                  The hub port.
754 
755 **/
756 VOID
UsbHubClearPortChange(IN USB_INTERFACE * HubIf,IN UINT8 Port)757 UsbHubClearPortChange (
758   IN USB_INTERFACE        *HubIf,
759   IN UINT8                Port
760   )
761 {
762   EFI_USB_PORT_STATUS     PortState;
763   USB_CHANGE_FEATURE_MAP  *Map;
764   UINTN                   Index;
765   EFI_STATUS              Status;
766 
767   Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
768 
769   if (EFI_ERROR (Status)) {
770     return;
771   }
772 
773   //
774   // OK, get the usb port status, now ACK the change bits.
775   // Don't return error when failed to clear the change bits.
776   // It may lead to extra port state report. USB bus should
777   // be able to handle this.
778   //
779   for (Index = 0; Index < ARRAY_SIZE (mHubFeatureMap); Index++) {
780     Map = &mHubFeatureMap[Index];
781 
782     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
783       UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);
784     }
785   }
786 }
787 
788 
789 
790 /**
791   Function to set the port feature for non-root hub.
792 
793   @param  HubIf                 The hub interface.
794   @param  Port                  The port of the hub.
795   @param  Feature               The feature of the port to set.
796 
797   @retval EFI_SUCCESS           The hub port feature is set.
798   @retval Others                Failed to set the port feature.
799 
800 **/
801 EFI_STATUS
UsbHubSetPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)802 UsbHubSetPortFeature (
803   IN USB_INTERFACE        *HubIf,
804   IN UINT8                Port,
805   IN EFI_USB_PORT_FEATURE Feature
806   )
807 {
808   EFI_STATUS              Status;
809 
810   Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);
811 
812   return Status;
813 }
814 
815 
816 /**
817   Interface function to clear the port feature for non-root hub.
818 
819   @param  HubIf                 The hub interface.
820   @param  Port                  The port of the hub to clear feature for.
821   @param  Feature               The feature to clear.
822 
823   @retval EFI_SUCCESS           The port feature is cleared.
824   @retval Others                Failed to clear the port feature.
825 
826 **/
827 EFI_STATUS
UsbHubClearPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)828 UsbHubClearPortFeature (
829   IN USB_INTERFACE        *HubIf,
830   IN UINT8                Port,
831   IN EFI_USB_PORT_FEATURE Feature
832   )
833 {
834   EFI_STATUS              Status;
835 
836   Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);
837 
838   return Status;
839 }
840 
841 
842 /**
843   Interface function to reset the port.
844 
845   @param  HubIf                 The hub interface.
846   @param  Port                  The port to reset.
847 
848   @retval EFI_SUCCESS           The hub port is reset.
849   @retval EFI_TIMEOUT           Failed to reset the port in time.
850   @retval Others                Failed to reset the port.
851 
852 **/
853 EFI_STATUS
UsbHubResetPort(IN USB_INTERFACE * HubIf,IN UINT8 Port)854 UsbHubResetPort (
855   IN USB_INTERFACE        *HubIf,
856   IN UINT8                Port
857   )
858 {
859   EFI_USB_PORT_STATUS     PortState;
860   UINTN                   Index;
861   EFI_STATUS              Status;
862 
863   Status  = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
864 
865   if (EFI_ERROR (Status)) {
866     return Status;
867   }
868 
869   //
870   // Drive the reset signal for worst 20ms. Check USB 2.0 Spec
871   // section 7.1.7.5 for timing requirements.
872   //
873   gBS->Stall (USB_SET_PORT_RESET_STALL);
874 
875   //
876   // Check USB_PORT_STAT_C_RESET bit to see if the resetting state is done.
877   //
878   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
879 
880   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
881     Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
882 
883     if (EFI_ERROR (Status)) {
884       return Status;
885     }
886 
887     if (!EFI_ERROR (Status) &&
888         USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_RESET)) {
889       gBS->Stall (USB_SET_PORT_RECOVERY_STALL);
890       return EFI_SUCCESS;
891     }
892 
893     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
894   }
895 
896   return EFI_TIMEOUT;
897 }
898 
899 
900 /**
901   Release the hub's control of the interface.
902 
903   @param  HubIf                 The hub interface.
904 
905   @retval EFI_SUCCESS           The interface is release of hub control.
906 
907 **/
908 EFI_STATUS
UsbHubRelease(IN USB_INTERFACE * HubIf)909 UsbHubRelease (
910   IN USB_INTERFACE        *HubIf
911   )
912 {
913   EFI_USB_IO_PROTOCOL     *UsbIo;
914   EFI_STATUS              Status;
915 
916   UsbIo  = &HubIf->UsbIo;
917   Status = UsbIo->UsbAsyncInterruptTransfer (
918                     UsbIo,
919                     HubIf->HubEp->Desc.EndpointAddress,
920                     FALSE,
921                     USB_HUB_POLL_INTERVAL,
922                     0,
923                     NULL,
924                     0
925                     );
926 
927   if (EFI_ERROR (Status)) {
928     return Status;
929   }
930 
931   gBS->CloseEvent (HubIf->HubNotify);
932 
933   HubIf->IsHub      = FALSE;
934   HubIf->HubApi     = NULL;
935   HubIf->HubEp      = NULL;
936   HubIf->HubNotify  = NULL;
937 
938   DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
939   return EFI_SUCCESS;
940 }
941 
942 
943 
944 /**
945   Initialize the interface for root hub.
946 
947   @param  HubIf                 The root hub interface.
948 
949   @retval EFI_SUCCESS           The interface is initialized for root hub.
950   @retval Others                Failed to initialize the hub.
951 
952 **/
953 EFI_STATUS
UsbRootHubInit(IN USB_INTERFACE * HubIf)954 UsbRootHubInit (
955   IN USB_INTERFACE        *HubIf
956   )
957 {
958   EFI_STATUS              Status;
959   UINT8                   MaxSpeed;
960   UINT8                   NumOfPort;
961   UINT8                   Support64;
962 
963   Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
964 
965   if (EFI_ERROR (Status)) {
966     return Status;
967   }
968 
969   DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
970               HubIf, MaxSpeed, NumOfPort));
971 
972   HubIf->IsHub      = TRUE;
973   HubIf->HubApi     = &mUsbRootHubApi;
974   HubIf->HubEp      = NULL;
975   HubIf->MaxSpeed   = MaxSpeed;
976   HubIf->NumOfPort  = NumOfPort;
977   HubIf->HubNotify  = NULL;
978 
979   //
980   // Create a timer to poll root hub ports periodically
981   //
982   Status = gBS->CreateEvent (
983                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
984                   TPL_CALLBACK,
985                   UsbRootHubEnumeration,
986                   HubIf,
987                   &HubIf->HubNotify
988                   );
989 
990   if (EFI_ERROR (Status)) {
991     return Status;
992   }
993 
994   //
995   // It should signal the event immediately here, or device detection
996   // by bus enumeration might be delayed by the timer interval.
997   //
998   gBS->SignalEvent (HubIf->HubNotify);
999 
1000   Status = gBS->SetTimer (
1001                   HubIf->HubNotify,
1002                   TimerPeriodic,
1003                   USB_ROOTHUB_POLL_INTERVAL
1004                   );
1005 
1006   if (EFI_ERROR (Status)) {
1007     gBS->CloseEvent (HubIf->HubNotify);
1008   }
1009 
1010   return Status;
1011 }
1012 
1013 
1014 /**
1015   Get the port status. This function is required to
1016   ACK the port change bits although it will return
1017   the port changes in PortState. Bus enumeration code
1018   doesn't need to ACK the port change bits.
1019 
1020   @param  HubIf                 The root hub interface.
1021   @param  Port                  The root hub port to get the state.
1022   @param  PortState             Variable to return the port state.
1023 
1024   @retval EFI_SUCCESS           The port state is returned.
1025   @retval Others                Failed to retrieve the port state.
1026 
1027 **/
1028 EFI_STATUS
UsbRootHubGetPortStatus(IN USB_INTERFACE * HubIf,IN UINT8 Port,OUT EFI_USB_PORT_STATUS * PortState)1029 UsbRootHubGetPortStatus (
1030   IN  USB_INTERFACE       *HubIf,
1031   IN  UINT8               Port,
1032   OUT EFI_USB_PORT_STATUS *PortState
1033   )
1034 {
1035   USB_BUS                 *Bus;
1036   EFI_STATUS              Status;
1037 
1038   Bus     = HubIf->Device->Bus;
1039   Status  = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
1040 
1041   return Status;
1042 }
1043 
1044 
1045 /**
1046   Clear the port change status.
1047 
1048   @param  HubIf                 The root hub interface.
1049   @param  Port                  The root hub port.
1050 
1051 **/
1052 VOID
UsbRootHubClearPortChange(IN USB_INTERFACE * HubIf,IN UINT8 Port)1053 UsbRootHubClearPortChange (
1054   IN USB_INTERFACE        *HubIf,
1055   IN UINT8                Port
1056   )
1057 {
1058   EFI_USB_PORT_STATUS     PortState;
1059   USB_CHANGE_FEATURE_MAP  *Map;
1060   UINTN                   Index;
1061   EFI_STATUS              Status;
1062 
1063   Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
1064 
1065   if (EFI_ERROR (Status)) {
1066     return;
1067   }
1068 
1069   //
1070   // OK, get the usb port status, now ACK the change bits.
1071   // Don't return error when failed to clear the change bits.
1072   // It may lead to extra port state report. USB bus should
1073   // be able to handle this.
1074   //
1075   for (Index = 0; Index < ARRAY_SIZE (mRootHubFeatureMap); Index++) {
1076     Map = &mRootHubFeatureMap[Index];
1077 
1078     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
1079       UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);
1080     }
1081   }
1082 }
1083 
1084 
1085 /**
1086   Set the root hub port feature.
1087 
1088   @param  HubIf                 The Usb hub interface.
1089   @param  Port                  The hub port.
1090   @param  Feature               The feature to set.
1091 
1092   @retval EFI_SUCCESS           The root hub port is set with the feature.
1093   @retval Others                Failed to set the feature.
1094 
1095 **/
1096 EFI_STATUS
UsbRootHubSetPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)1097 UsbRootHubSetPortFeature (
1098   IN USB_INTERFACE        *HubIf,
1099   IN UINT8                Port,
1100   IN EFI_USB_PORT_FEATURE Feature
1101   )
1102 {
1103   EFI_STATUS              Status;
1104 
1105   Status  = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1106 
1107   return Status;
1108 }
1109 
1110 
1111 /**
1112   Clear the root hub port feature.
1113 
1114   @param  HubIf                 The root hub interface.
1115   @param  Port                  The root hub port.
1116   @param  Feature               The feature to clear.
1117 
1118   @retval EFI_SUCCESS           The root hub port is cleared of the feature.
1119   @retval Others                Failed to clear the feature.
1120 
1121 **/
1122 EFI_STATUS
UsbRootHubClearPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)1123 UsbRootHubClearPortFeature (
1124   IN USB_INTERFACE        *HubIf,
1125   IN UINT8                Port,
1126   IN EFI_USB_PORT_FEATURE Feature
1127   )
1128 {
1129   EFI_STATUS              Status;
1130 
1131   Status  = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
1132 
1133   return Status;
1134 }
1135 
1136 
1137 /**
1138   Interface function to reset the root hub port.
1139 
1140   @param  RootIf                The root hub interface.
1141   @param  Port                  The port to reset.
1142 
1143   @retval EFI_SUCCESS           The hub port is reset.
1144   @retval EFI_TIMEOUT           Failed to reset the port in time.
1145   @retval EFI_NOT_FOUND         The low/full speed device connected to high  speed.
1146                                 root hub is released to the companion UHCI.
1147   @retval Others                Failed to reset the port.
1148 
1149 **/
1150 EFI_STATUS
UsbRootHubResetPort(IN USB_INTERFACE * RootIf,IN UINT8 Port)1151 UsbRootHubResetPort (
1152   IN USB_INTERFACE        *RootIf,
1153   IN UINT8                Port
1154   )
1155 {
1156   USB_BUS                 *Bus;
1157   EFI_STATUS              Status;
1158   EFI_USB_PORT_STATUS     PortState;
1159   UINTN                   Index;
1160 
1161   //
1162   // Notice: although EHCI requires that ENABLED bit be cleared
1163   // when reset the port, we don't need to care that here. It
1164   // should be handled in the EHCI driver.
1165   //
1166   Bus     = RootIf->Device->Bus;
1167 
1168   Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1169 
1170   if (EFI_ERROR (Status)) {
1171     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
1172     return Status;
1173   }
1174 
1175   //
1176   // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
1177   // section 7.1.7.5 for timing requirements.
1178   //
1179   gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
1180 
1181   Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
1182 
1183   if (EFI_ERROR (Status)) {
1184     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
1185     return Status;
1186   }
1187 
1188   gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
1189 
1190   //
1191   // USB host controller won't clear the RESET bit until
1192   // reset is actually finished.
1193   //
1194   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
1195 
1196   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
1197     Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
1198 
1199     if (EFI_ERROR (Status)) {
1200       return Status;
1201     }
1202 
1203     if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
1204       break;
1205     }
1206 
1207     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
1208   }
1209 
1210   if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
1211     DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
1212     return EFI_TIMEOUT;
1213   }
1214 
1215   if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
1216     //
1217     // OK, the port is reset. If root hub is of high speed and
1218     // the device is of low/full speed, release the ownership to
1219     // companion UHCI. If root hub is of full speed, it won't
1220     // automatically enable the port, we need to enable it manually.
1221     //
1222     if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
1223       DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
1224 
1225       UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
1226       return EFI_NOT_FOUND;
1227 
1228     } else {
1229 
1230       Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
1231 
1232       if (EFI_ERROR (Status)) {
1233         DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
1234         return Status;
1235       }
1236 
1237       gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
1238     }
1239   }
1240 
1241   return EFI_SUCCESS;
1242 }
1243 
1244 
1245 /**
1246   Release the root hub's control of the interface.
1247 
1248   @param  HubIf                 The root hub interface.
1249 
1250   @retval EFI_SUCCESS           The root hub's control of the interface is
1251                                 released.
1252 
1253 **/
1254 EFI_STATUS
UsbRootHubRelease(IN USB_INTERFACE * HubIf)1255 UsbRootHubRelease (
1256   IN USB_INTERFACE        *HubIf
1257   )
1258 {
1259   DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
1260 
1261   gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
1262   gBS->CloseEvent (HubIf->HubNotify);
1263 
1264   return EFI_SUCCESS;
1265 }
1266 
1267 USB_HUB_API mUsbHubApi = {
1268   UsbHubInit,
1269   UsbHubGetPortStatus,
1270   UsbHubClearPortChange,
1271   UsbHubSetPortFeature,
1272   UsbHubClearPortFeature,
1273   UsbHubResetPort,
1274   UsbHubRelease
1275 };
1276 
1277 USB_HUB_API mUsbRootHubApi = {
1278   UsbRootHubInit,
1279   UsbRootHubGetPortStatus,
1280   UsbRootHubClearPortChange,
1281   UsbRootHubSetPortFeature,
1282   UsbRootHubClearPortFeature,
1283   UsbRootHubResetPort,
1284   UsbRootHubRelease
1285 };
1286