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