• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3     Unified interface for RootHub and Hub.
4 
5 Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT 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 //
25 USB_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 
33 USB_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 **/
56 EFI_STATUS
UsbHubCtrlSetHubDepth(IN USB_DEVICE * HubDev,IN UINT16 Depth)57 UsbHubCtrlSetHubDepth (
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 **/
89 EFI_STATUS
UsbHubCtrlClearHubFeature(IN USB_DEVICE * HubDev,IN UINT16 Feature)90 UsbHubCtrlClearHubFeature (
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 **/
124 EFI_STATUS
UsbHubCtrlClearPortFeature(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT16 Feature)125 UsbHubCtrlClearPortFeature (
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 **/
170 EFI_STATUS
UsbHubCtrlClearTTBuffer(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT16 DevAddr,IN UINT16 EpNum,IN UINT16 EpType)171 UsbHubCtrlClearTTBuffer (
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 **/
213 EFI_STATUS
UsbHubCtrlGetSuperSpeedHubDesc(IN USB_DEVICE * HubDev,OUT VOID * Buf)214 UsbHubCtrlGetSuperSpeedHubDesc (
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 **/
249 EFI_STATUS
UsbHubCtrlGetHubDesc(IN USB_DEVICE * HubDev,OUT VOID * Buf,IN UINTN Len)250 UsbHubCtrlGetHubDesc (
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 **/
284 EFI_STATUS
UsbHubCtrlGetHubStatus(IN USB_DEVICE * HubDev,OUT UINT32 * State)285 UsbHubCtrlGetHubStatus (
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 **/
319 EFI_STATUS
UsbHubCtrlGetPortStatus(IN USB_DEVICE * HubDev,IN UINT8 Port,OUT VOID * State)320 UsbHubCtrlGetPortStatus (
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 **/
360 EFI_STATUS
UsbHubCtrlResetTT(IN USB_DEVICE * HubDev,IN UINT8 Port)361 UsbHubCtrlResetTT (
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 **/
394 EFI_STATUS
UsbHubCtrlSetHubFeature(IN USB_DEVICE * HubDev,IN UINT8 Feature)395 UsbHubCtrlSetHubFeature (
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 **/
429 EFI_STATUS
UsbHubCtrlSetPortFeature(IN USB_DEVICE * HubDev,IN UINT8 Port,IN UINT8 Feature)430 UsbHubCtrlSetPortFeature (
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 **/
470 EFI_STATUS
UsbHubReadDesc(IN USB_DEVICE * HubDev,OUT EFI_USB_HUB_DESCRIPTOR * HubDesc)471 UsbHubReadDesc (
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 **/
515 EFI_STATUS
UsbHubAckHubStatus(IN USB_DEVICE * HubDev)516 UsbHubAckHubStatus (
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 **/
550 BOOLEAN
UsbIsHubInterface(IN USB_INTERFACE * UsbIf)551 UsbIsHubInterface (
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 **/
587 EFI_STATUS
588 EFIAPI
UsbOnHubInterrupt(IN VOID * Data,IN UINTN DataLength,IN VOID * Context,IN UINT32 Result)589 UsbOnHubInterrupt (
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 **/
688 EFI_STATUS
UsbHubInit(IN USB_INTERFACE * HubIf)689 UsbHubInit (
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 **/
841 EFI_STATUS
UsbHubGetPortStatus(IN USB_INTERFACE * HubIf,IN UINT8 Port,OUT EFI_USB_PORT_STATUS * PortState)842 UsbHubGetPortStatus (
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 **/
864 VOID
UsbHubClearPortChange(IN USB_INTERFACE * HubIf,IN UINT8 Port)865 UsbHubClearPortChange (
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 **/
909 EFI_STATUS
UsbHubSetPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)910 UsbHubSetPortFeature (
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 **/
935 EFI_STATUS
UsbHubClearPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)936 UsbHubClearPortFeature (
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 **/
961 EFI_STATUS
UsbHubResetPort(IN USB_INTERFACE * HubIf,IN UINT8 Port)962 UsbHubResetPort (
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 **/
1016 EFI_STATUS
UsbHubRelease(IN USB_INTERFACE * HubIf)1017 UsbHubRelease (
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 **/
1061 EFI_STATUS
UsbRootHubInit(IN USB_INTERFACE * HubIf)1062 UsbRootHubInit (
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 **/
1136 EFI_STATUS
UsbRootHubGetPortStatus(IN USB_INTERFACE * HubIf,IN UINT8 Port,OUT EFI_USB_PORT_STATUS * PortState)1137 UsbRootHubGetPortStatus (
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 **/
1160 VOID
UsbRootHubClearPortChange(IN USB_INTERFACE * HubIf,IN UINT8 Port)1161 UsbRootHubClearPortChange (
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 **/
1204 EFI_STATUS
UsbRootHubSetPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)1205 UsbRootHubSetPortFeature (
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 **/
1230 EFI_STATUS
UsbRootHubClearPortFeature(IN USB_INTERFACE * HubIf,IN UINT8 Port,IN EFI_USB_PORT_FEATURE Feature)1231 UsbRootHubClearPortFeature (
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 **/
1258 EFI_STATUS
UsbRootHubResetPort(IN USB_INTERFACE * RootIf,IN UINT8 Port)1259 UsbRootHubResetPort (
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 **/
1362 EFI_STATUS
UsbRootHubRelease(IN USB_INTERFACE * HubIf)1363 UsbRootHubRelease (
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 
1375 USB_HUB_API mUsbHubApi = {
1376   UsbHubInit,
1377   UsbHubGetPortStatus,
1378   UsbHubClearPortChange,
1379   UsbHubSetPortFeature,
1380   UsbHubClearPortFeature,
1381   UsbHubResetPort,
1382   UsbHubRelease
1383 };
1384 
1385 USB_HUB_API mUsbRootHubApi = {
1386   UsbRootHubInit,
1387   UsbRootHubGetPortStatus,
1388   UsbRootHubClearPortChange,
1389   UsbRootHubSetPortFeature,
1390   UsbRootHubClearPortFeature,
1391   UsbRootHubResetPort,
1392   UsbRootHubRelease
1393 };
1394