EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

MdeModulePkg/Bus/Usb/UsbBusDxe/UsbHub.c

Go to the documentation of this file.
00001 
00016 #include "UsbBus.h"
00017 
00018 //
00019 // Array that maps the change bit to feature value which is
00020 // used to clear these change bit. USB HUB API will clear
00021 // these change bit automatically. For non-root hub, these
00022 // bits determine whether hub will report the port in changed
00023 // bit maps.
00024 //
00025 USB_CHANGE_FEATURE_MAP  mHubFeatureMap[] = {
00026   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
00027   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
00028   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
00029   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
00030   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange}
00031 };
00032 
00033 USB_CHANGE_FEATURE_MAP  mRootHubFeatureMap[] = {
00034   {USB_PORT_STAT_C_CONNECTION,  EfiUsbPortConnectChange},
00035   {USB_PORT_STAT_C_ENABLE,      EfiUsbPortEnableChange},
00036   {USB_PORT_STAT_C_SUSPEND,     EfiUsbPortSuspendChange},
00037   {USB_PORT_STAT_C_OVERCURRENT, EfiUsbPortOverCurrentChange},
00038   {USB_PORT_STAT_C_RESET,       EfiUsbPortResetChange},
00039 };
00040 
00041 //
00042 // USB hub class specific requests. Although USB hub
00043 // is related to an interface, these requests are sent
00044 // to the control endpoint of the device.
00045 //
00056 EFI_STATUS
00057 UsbHubCtrlSetHubDepth (
00058   IN  USB_DEVICE          *HubDev,
00059   IN  UINT16              Depth
00060   )
00061 {
00062   EFI_STATUS              Status;
00063 
00064   Status = UsbCtrlRequest (
00065              HubDev,
00066              EfiUsbNoData,
00067              USB_REQ_TYPE_CLASS,
00068              USB_HUB_TARGET_HUB,
00069              USB_HUB_REQ_SET_DEPTH,
00070              Depth,
00071              0,
00072              NULL,
00073              0
00074              );
00075 
00076   return Status;
00077 }
00078 
00089 EFI_STATUS
00090 UsbHubCtrlClearHubFeature (
00091   IN USB_DEVICE           *HubDev,
00092   IN UINT16               Feature
00093   )
00094 {
00095   EFI_STATUS              Status;
00096 
00097   Status = UsbCtrlRequest (
00098              HubDev,
00099              EfiUsbNoData,
00100              USB_REQ_TYPE_CLASS,
00101              USB_HUB_TARGET_HUB,
00102              USB_HUB_REQ_CLEAR_FEATURE,
00103              Feature,
00104              0,
00105              NULL,
00106              0
00107              );
00108 
00109   return Status;
00110 }
00111 
00112 
00124 EFI_STATUS
00125 UsbHubCtrlClearPortFeature (
00126   IN USB_DEVICE           *HubDev,
00127   IN UINT8                Port,
00128   IN UINT16               Feature
00129   )
00130 {
00131   EFI_STATUS              Status;
00132 
00133   //
00134   // In USB bus, all the port index starts from 0. But HUB
00135   // indexes its port from 1. So, port number is added one.
00136   //
00137   Status = UsbCtrlRequest (
00138              HubDev,
00139              EfiUsbNoData,
00140              USB_REQ_TYPE_CLASS,
00141              USB_HUB_TARGET_PORT,
00142              USB_HUB_REQ_CLEAR_FEATURE,
00143              Feature,
00144              (UINT16) (Port + 1),
00145              NULL,
00146              0
00147              );
00148 
00149   return Status;
00150 }
00151 
00152 
00170 EFI_STATUS
00171 UsbHubCtrlClearTTBuffer (
00172   IN USB_DEVICE           *HubDev,
00173   IN UINT8                Port,
00174   IN UINT16               DevAddr,
00175   IN UINT16               EpNum,
00176   IN UINT16               EpType
00177   )
00178 {
00179   EFI_STATUS              Status;
00180   UINT16                  Value;
00181 
00182   //
00183   // Check USB2.0 spec page 424 for wValue's encoding
00184   //
00185   Value = (UINT16) ((EpNum & 0x0F) | (DevAddr << 4) |
00186           ((EpType & 0x03) << 11) | ((EpNum & 0x80) << 15));
00187 
00188   Status = UsbCtrlRequest (
00189              HubDev,
00190              EfiUsbNoData,
00191              USB_REQ_TYPE_CLASS,
00192              USB_HUB_TARGET_PORT,
00193              USB_HUB_REQ_CLEAR_TT,
00194              Value,
00195              (UINT16) (Port + 1),
00196              NULL,
00197              0
00198              );
00199 
00200   return Status;
00201 }
00202 
00213 EFI_STATUS
00214 UsbHubCtrlGetSuperSpeedHubDesc (
00215   IN  USB_DEVICE          *HubDev,
00216   OUT VOID                *Buf
00217   )
00218 {
00219   EFI_STATUS              Status;
00220   
00221   Status = EFI_INVALID_PARAMETER;
00222   
00223   Status = UsbCtrlRequest (
00224              HubDev,
00225              EfiUsbDataIn,
00226              USB_REQ_TYPE_CLASS,
00227              USB_HUB_TARGET_HUB,
00228              USB_HUB_REQ_GET_DESC,
00229              (UINT16) (USB_DESC_TYPE_HUB_SUPER_SPEED << 8),
00230              0,
00231              Buf,
00232              32
00233              );
00234 
00235   return Status;
00236 }
00237 
00249 EFI_STATUS
00250 UsbHubCtrlGetHubDesc (
00251   IN  USB_DEVICE          *HubDev,
00252   OUT VOID                *Buf,
00253   IN  UINTN               Len
00254   )
00255 {
00256   EFI_STATUS              Status;
00257 
00258   Status = UsbCtrlRequest (
00259              HubDev,
00260              EfiUsbDataIn,
00261              USB_REQ_TYPE_CLASS,
00262              USB_HUB_TARGET_HUB,
00263              USB_HUB_REQ_GET_DESC,
00264              (UINT16) (USB_DESC_TYPE_HUB << 8),
00265              0,
00266              Buf,
00267              Len
00268              );
00269 
00270   return Status;
00271 }
00272 
00273 
00284 EFI_STATUS
00285 UsbHubCtrlGetHubStatus (
00286   IN  USB_DEVICE          *HubDev,
00287   OUT UINT32              *State
00288   )
00289 {
00290   EFI_STATUS              Status;
00291 
00292   Status = UsbCtrlRequest (
00293              HubDev,
00294              EfiUsbDataIn,
00295              USB_REQ_TYPE_CLASS,
00296              USB_HUB_TARGET_HUB,
00297              USB_HUB_REQ_GET_STATUS,
00298              0,
00299              0,
00300              State,
00301              4
00302              );
00303 
00304   return Status;
00305 }
00306 
00307 
00319 EFI_STATUS
00320 UsbHubCtrlGetPortStatus (
00321   IN  USB_DEVICE          *HubDev,
00322   IN  UINT8               Port,
00323   OUT VOID                *State
00324   )
00325 {
00326   EFI_STATUS              Status;
00327 
00328   //
00329   // In USB bus, all the port index starts from 0. But HUB
00330   // indexes its port from 1. So, port number is added one.
00331   // No need to convert the hub bit to UEFI definition, they
00332   // are the same
00333   //
00334   Status = UsbCtrlRequest (
00335              HubDev,
00336              EfiUsbDataIn,
00337              USB_REQ_TYPE_CLASS,
00338              USB_HUB_TARGET_PORT,
00339              USB_HUB_REQ_GET_STATUS,
00340              0,
00341              (UINT16) (Port + 1),
00342              State,
00343              4
00344              );
00345 
00346   return Status;
00347 }
00348 
00349 
00360 EFI_STATUS
00361 UsbHubCtrlResetTT (
00362   IN  USB_DEVICE          *HubDev,
00363   IN  UINT8               Port
00364   )
00365 {
00366   EFI_STATUS              Status;
00367 
00368   Status = UsbCtrlRequest (
00369              HubDev,
00370              EfiUsbNoData,
00371              USB_REQ_TYPE_CLASS,
00372              USB_HUB_TARGET_HUB,
00373              USB_HUB_REQ_RESET_TT,
00374              0,
00375              (UINT16) (Port + 1),
00376              NULL,
00377              0
00378              );
00379 
00380   return Status;
00381 }
00382 
00383 
00394 EFI_STATUS
00395 UsbHubCtrlSetHubFeature (
00396   IN  USB_DEVICE          *HubDev,
00397   IN  UINT8               Feature
00398   )
00399 {
00400   EFI_STATUS              Status;
00401 
00402   Status = UsbCtrlRequest (
00403              HubDev,
00404              EfiUsbNoData,
00405              USB_REQ_TYPE_CLASS,
00406              USB_HUB_TARGET_HUB,
00407              USB_HUB_REQ_SET_FEATURE,
00408              Feature,
00409              0,
00410              NULL,
00411              0
00412              );
00413 
00414   return Status;
00415 }
00416 
00417 
00429 EFI_STATUS
00430 UsbHubCtrlSetPortFeature (
00431   IN USB_DEVICE           *HubDev,
00432   IN UINT8                Port,
00433   IN UINT8                Feature
00434   )
00435 {
00436   EFI_STATUS              Status;
00437 
00438   //
00439   // In USB bus, all the port index starts from 0. But HUB
00440   // indexes its port from 1. So, port number is added one.
00441   //
00442   Status = UsbCtrlRequest (
00443              HubDev,
00444              EfiUsbNoData,
00445              USB_REQ_TYPE_CLASS,
00446              USB_HUB_TARGET_PORT,
00447              USB_HUB_REQ_SET_FEATURE,
00448              Feature,
00449              (UINT16) (Port + 1),
00450              NULL,
00451              0
00452              );
00453 
00454   return Status;
00455 }
00456 
00457 
00470 EFI_STATUS
00471 UsbHubReadDesc (
00472   IN  USB_DEVICE              *HubDev,
00473   OUT EFI_USB_HUB_DESCRIPTOR  *HubDesc
00474   )
00475 {
00476   EFI_STATUS              Status;
00477 
00478   if (HubDev->Speed == EFI_USB_SPEED_SUPER) {
00479     //
00480     // Get the super speed hub descriptor
00481     //
00482     Status = UsbHubCtrlGetSuperSpeedHubDesc (HubDev, HubDesc);
00483   } else {
00484 
00485     //
00486     // First get the hub descriptor length
00487     //
00488     Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, 2);
00489 
00490     if (EFI_ERROR (Status)) {
00491       return Status;
00492     }
00493 
00494     //
00495     // Get the whole hub descriptor
00496     //
00497     Status = UsbHubCtrlGetHubDesc (HubDev, HubDesc, HubDesc->Length);
00498   }
00499 
00500   return Status;
00501 }
00502 
00503 
00504 
00515 EFI_STATUS
00516 UsbHubAckHubStatus (
00517   IN  USB_DEVICE         *HubDev
00518   )
00519 {
00520   EFI_USB_PORT_STATUS     HubState;
00521   EFI_STATUS              Status;
00522 
00523   Status = UsbHubCtrlGetHubStatus (HubDev, (UINT32 *) &HubState);
00524 
00525   if (EFI_ERROR (Status)) {
00526     return Status;
00527   }
00528 
00529   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_LOCAL_POWER)) {
00530     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_LOCAL_POWER);
00531   }
00532 
00533   if (USB_BIT_IS_SET (HubState.PortChangeStatus, USB_HUB_STAT_C_OVER_CURRENT)) {
00534     UsbHubCtrlClearHubFeature (HubDev, USB_HUB_C_HUB_OVER_CURRENT);
00535   }
00536 
00537   return EFI_SUCCESS;
00538 }
00539 
00540 
00550 BOOLEAN
00551 UsbIsHubInterface (
00552   IN USB_INTERFACE        *UsbIf
00553   )
00554 {
00555   EFI_USB_INTERFACE_DESCRIPTOR  *Setting;
00556 
00557   //
00558   // If the hub is a high-speed hub with multiple TT,
00559   // the hub will has a default setting of single TT.
00560   //
00561   Setting = &UsbIf->IfSetting->Desc;
00562 
00563   if ((Setting->InterfaceClass == USB_HUB_CLASS_CODE) &&
00564       (Setting->InterfaceSubClass == USB_HUB_SUBCLASS_CODE)) {
00565 
00566     return TRUE;
00567   }
00568 
00569   return FALSE;
00570 }
00571 
00572 
00587 EFI_STATUS
00588 EFIAPI
00589 UsbOnHubInterrupt (
00590   IN  VOID                *Data,
00591   IN  UINTN               DataLength,
00592   IN  VOID                *Context,
00593   IN  UINT32              Result
00594   )
00595 {
00596   USB_INTERFACE               *HubIf;
00597   EFI_USB_IO_PROTOCOL         *UsbIo;
00598   EFI_USB_ENDPOINT_DESCRIPTOR *EpDesc;
00599   EFI_STATUS                  Status;
00600 
00601   HubIf   = (USB_INTERFACE *) Context;
00602   UsbIo   = &(HubIf->UsbIo);
00603   EpDesc  = &(HubIf->HubEp->Desc);
00604 
00605   if (Result != EFI_USB_NOERROR) {
00606     //
00607     // If endpoint is stalled, clear the stall. Use UsbIo to access
00608     // the control transfer so internal status are maintained.
00609     //
00610     if (USB_BIT_IS_SET (Result, EFI_USB_ERR_STALL)) {
00611       UsbIoClearFeature (
00612         UsbIo,
00613         USB_TARGET_ENDPOINT,
00614         USB_FEATURE_ENDPOINT_HALT,
00615         EpDesc->EndpointAddress
00616         );
00617     }
00618 
00619     //
00620     // Delete and submit a new async interrupt
00621     //
00622     Status = UsbIo->UsbAsyncInterruptTransfer (
00623                       UsbIo,
00624                       EpDesc->EndpointAddress,
00625                       FALSE,
00626                       0,
00627                       0,
00628                       NULL,
00629                       NULL
00630                       );
00631 
00632     if (EFI_ERROR (Status)) {
00633       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to remove async transfer - %r\n", Status));
00634       return Status;
00635     }
00636 
00637     Status = UsbIo->UsbAsyncInterruptTransfer (
00638                       UsbIo,
00639                       EpDesc->EndpointAddress,
00640                       TRUE,
00641                       USB_HUB_POLL_INTERVAL,
00642                       HubIf->NumOfPort / 8 + 1,
00643                       UsbOnHubInterrupt,
00644                       HubIf
00645                       );
00646 
00647     if (EFI_ERROR (Status)) {
00648       DEBUG (( EFI_D_ERROR, "UsbOnHubInterrupt: failed to submit new async transfer - %r\n", Status));
00649     }
00650 
00651     return Status;
00652   }
00653 
00654   if ((DataLength == 0) || (Data == NULL)) {
00655     return EFI_SUCCESS;
00656   }
00657 
00658   //
00659   // OK, actually something is changed, save the change map
00660   // then signal the HUB to do enumeration. This is a good
00661   // practise since UsbOnHubInterrupt is called in the context
00662   // of host contrller's AsyncInterrupt monitor.
00663   //
00664   HubIf->ChangeMap = AllocateZeroPool (DataLength);
00665 
00666   if (HubIf->ChangeMap == NULL) {
00667     return EFI_OUT_OF_RESOURCES;
00668   }
00669 
00670   CopyMem (HubIf->ChangeMap, Data, DataLength);
00671   gBS->SignalEvent (HubIf->HubNotify);
00672 
00673   return EFI_SUCCESS;
00674 }
00675 
00676 
00677 
00678 
00688 EFI_STATUS
00689 UsbHubInit (
00690   IN USB_INTERFACE        *HubIf
00691   )
00692 {
00693   EFI_USB_HUB_DESCRIPTOR  HubDesc;
00694   USB_ENDPOINT_DESC       *EpDesc;
00695   USB_INTERFACE_SETTING   *Setting;
00696   EFI_USB_IO_PROTOCOL     *UsbIo;
00697   USB_DEVICE              *HubDev;
00698   EFI_STATUS              Status;
00699   UINT8                   Index;
00700   UINT8                   NumEndpoints;
00701   UINT16                  Depth;
00702 
00703   //
00704   // Locate the interrupt endpoint for port change map
00705   //
00706   HubIf->IsHub  = FALSE;
00707   Setting       = HubIf->IfSetting;
00708   HubDev        = HubIf->Device;
00709   EpDesc        = NULL;
00710   NumEndpoints  = Setting->Desc.NumEndpoints;
00711 
00712   for (Index = 0; Index < NumEndpoints; Index++) {
00713     ASSERT ((Setting->Endpoints != NULL) && (Setting->Endpoints[Index] != NULL));
00714 
00715     EpDesc = Setting->Endpoints[Index];
00716 
00717     if (USB_BIT_IS_SET (EpDesc->Desc.EndpointAddress, USB_ENDPOINT_DIR_IN) &&
00718        (USB_ENDPOINT_TYPE (&EpDesc->Desc) == USB_ENDPOINT_INTERRUPT)) {
00719       break;
00720     }
00721   }
00722 
00723   if (Index == NumEndpoints) {
00724     DEBUG (( EFI_D_ERROR, "UsbHubInit: no interrupt endpoint found for hub %d\n", HubDev->Address));
00725     return EFI_DEVICE_ERROR;
00726   }
00727 
00728   Status = UsbHubReadDesc (HubDev, &HubDesc);
00729 
00730   if (EFI_ERROR (Status)) {
00731     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to read HUB descriptor %r\n", Status));
00732     return Status;
00733   }
00734 
00735   HubIf->NumOfPort = HubDesc.NumPorts;
00736 
00737   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d has %d ports\n", HubDev->Address,HubIf->NumOfPort));
00738 
00739   //
00740   // OK, set IsHub to TRUE. Now usb bus can handle this device
00741   // as a working HUB. If failed eariler, bus driver will not
00742   // recognize it as a hub. Other parts of the bus should be able
00743   // to work.
00744   //
00745   HubIf->IsHub  = TRUE;
00746   HubIf->HubApi = &mUsbHubApi;
00747   HubIf->HubEp  = EpDesc;
00748 
00749   if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
00750     Depth = (UINT16)(HubIf->Device->Tier - 1);
00751     DEBUG ((EFI_D_INFO, "UsbHubInit: Set Hub Depth as 0x%x\n", Depth));
00752     UsbHubCtrlSetHubDepth (HubIf->Device, Depth);
00753     
00754     for (Index = 0; Index < HubDesc.NumPorts; Index++) {
00755       UsbHubCtrlSetPortFeature (HubIf->Device, Index, USB_HUB_PORT_REMOTE_WAKE_MASK);
00756     }    
00757   } else {
00758     //
00759     // Feed power to all the hub ports. It should be ok
00760     // for both gang/individual powered hubs.
00761     //
00762     for (Index = 0; Index < HubDesc.NumPorts; Index++) {
00763       UsbHubCtrlSetPortFeature (HubIf->Device, Index, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_POWER);
00764     }
00765 
00766     gBS->Stall (HubDesc.PwrOn2PwrGood * USB_SET_PORT_POWER_STALL);
00767     UsbHubAckHubStatus (HubIf->Device);
00768   }
00769 
00770   //
00771   // Create an event to enumerate the hub's port. On
00772   //
00773   Status = gBS->CreateEvent (
00774                   EVT_NOTIFY_SIGNAL,
00775                   TPL_CALLBACK,
00776                   UsbHubEnumeration,
00777                   HubIf,
00778                   &HubIf->HubNotify
00779                   );
00780 
00781   if (EFI_ERROR (Status)) {
00782     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to create signal for hub %d - %r\n",
00783                 HubDev->Address, Status));
00784 
00785     return Status;
00786   }
00787 
00788   //
00789   // Create AsyncInterrupt to query hub port change endpoint
00790   // periodically. If the hub ports are changed, hub will return
00791   // changed port map from the interrupt endpoint. The port map
00792   // must be able to hold (HubIf->NumOfPort + 1) bits (one bit for
00793   // host change status).
00794   //
00795   UsbIo  = &HubIf->UsbIo;
00796   Status = UsbIo->UsbAsyncInterruptTransfer (
00797                     UsbIo,
00798                     EpDesc->Desc.EndpointAddress,
00799                     TRUE,
00800                     USB_HUB_POLL_INTERVAL,
00801                     HubIf->NumOfPort / 8 + 1,
00802                     UsbOnHubInterrupt,
00803                     HubIf
00804                     );
00805 
00806   if (EFI_ERROR (Status)) {
00807     DEBUG (( EFI_D_ERROR, "UsbHubInit: failed to queue interrupt transfer for hub %d - %r\n",
00808                 HubDev->Address, Status));
00809 
00810     gBS->CloseEvent (HubIf->HubNotify);
00811     HubIf->HubNotify = NULL;
00812 
00813     return Status;
00814   }
00815 
00816   DEBUG (( EFI_D_INFO, "UsbHubInit: hub %d initialized\n", HubDev->Address));
00817   return Status;
00818 }
00819 
00820 
00821 
00836 EFI_STATUS
00837 UsbHubGetPortStatus (
00838   IN  USB_INTERFACE       *HubIf,
00839   IN  UINT8               Port,
00840   OUT EFI_USB_PORT_STATUS *PortState
00841   )
00842 {
00843   EFI_STATUS              Status;
00844 
00845   Status  = UsbHubCtrlGetPortStatus (HubIf->Device, Port, PortState);
00846 
00847   //
00848   // Mark the USB_PORT_STAT_SUPER_SPEED bit if SuperSpeed
00849   //
00850   if (HubIf->Device->Speed == EFI_USB_SPEED_SUPER) {
00851     PortState->PortStatus |= USB_PORT_STAT_SUPER_SPEED;
00852   } 
00853   return Status;
00854 }
00855 
00856 
00857 
00865 VOID
00866 UsbHubClearPortChange (
00867   IN USB_INTERFACE        *HubIf,
00868   IN UINT8                Port
00869   )
00870 {
00871   EFI_USB_PORT_STATUS     PortState;
00872   USB_CHANGE_FEATURE_MAP  *Map;
00873   UINTN                   Index;
00874   EFI_STATUS              Status;
00875 
00876   Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
00877 
00878   if (EFI_ERROR (Status)) {
00879     return;
00880   }
00881 
00882   //
00883   // OK, get the usb port status, now ACK the change bits.
00884   // Don't return error when failed to clear the change bits.
00885   // It may lead to extra port state report. USB bus should
00886   // be able to handle this.
00887   //
00888   for (Index = 0; Index < sizeof (mHubFeatureMap) / sizeof (mHubFeatureMap[0]); Index++) {
00889     Map = &mHubFeatureMap[Index];
00890 
00891     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
00892       UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT16) Map->Feature);
00893     }
00894   }
00895 }
00896 
00897 
00898 
00910 EFI_STATUS
00911 UsbHubSetPortFeature (
00912   IN USB_INTERFACE        *HubIf,
00913   IN UINT8                Port,
00914   IN EFI_USB_PORT_FEATURE Feature
00915   )
00916 {
00917   EFI_STATUS              Status;
00918 
00919   Status = UsbHubCtrlSetPortFeature (HubIf->Device, Port, (UINT8) Feature);
00920 
00921   return Status;
00922 }
00923 
00924 
00936 EFI_STATUS
00937 UsbHubClearPortFeature (
00938   IN USB_INTERFACE        *HubIf,
00939   IN UINT8                Port,
00940   IN EFI_USB_PORT_FEATURE Feature
00941   )
00942 {
00943   EFI_STATUS              Status;
00944 
00945   Status = UsbHubCtrlClearPortFeature (HubIf->Device, Port, (UINT8) Feature);
00946 
00947   return Status;
00948 }
00949 
00950 
00962 EFI_STATUS
00963 UsbHubResetPort (
00964   IN USB_INTERFACE        *HubIf,
00965   IN UINT8                Port
00966   )
00967 {
00968   EFI_USB_PORT_STATUS     PortState;
00969   UINTN                   Index;
00970   EFI_STATUS              Status;
00971 
00972   Status  = UsbHubSetPortFeature (HubIf, Port, (EFI_USB_PORT_FEATURE) USB_HUB_PORT_RESET);
00973 
00974   if (EFI_ERROR (Status)) {
00975     return Status;
00976   }
00977 
00978   //
00979   // Drive the reset signal for at least 10ms. Check USB 2.0 Spec
00980   // section 7.1.7.5 for timing requirements.
00981   //
00982   gBS->Stall (USB_SET_PORT_RESET_STALL);
00983 
00984   //
00985   // USB hub will clear RESET bit if reset is actually finished.
00986   //
00987   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
00988 
00989   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
00990     Status = UsbHubGetPortStatus (HubIf, Port, &PortState);
00991 
00992     if (!EFI_ERROR (Status) &&
00993         !USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
00994 
00995       return EFI_SUCCESS;
00996     }
00997 
00998     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
00999   }
01000 
01001   return EFI_TIMEOUT;
01002 }
01003 
01004 
01013 EFI_STATUS
01014 UsbHubRelease (
01015   IN USB_INTERFACE        *HubIf
01016   )
01017 {
01018   EFI_USB_IO_PROTOCOL     *UsbIo;
01019   EFI_STATUS              Status;
01020 
01021   UsbIo  = &HubIf->UsbIo;
01022   Status = UsbIo->UsbAsyncInterruptTransfer (
01023                     UsbIo,
01024                     HubIf->HubEp->Desc.EndpointAddress,
01025                     FALSE,
01026                     USB_HUB_POLL_INTERVAL,
01027                     0,
01028                     NULL,
01029                     0
01030                     );
01031 
01032   if (EFI_ERROR (Status)) {
01033     return Status;
01034   }
01035 
01036   gBS->CloseEvent (HubIf->HubNotify);
01037 
01038   HubIf->IsHub      = FALSE;
01039   HubIf->HubApi     = NULL;
01040   HubIf->HubEp      = NULL;
01041   HubIf->HubNotify  = NULL;
01042 
01043   DEBUG (( EFI_D_INFO, "UsbHubRelease: hub device %d released\n", HubIf->Device->Address));
01044   return EFI_SUCCESS;
01045 }
01046 
01047 
01048 
01058 EFI_STATUS
01059 UsbRootHubInit (
01060   IN USB_INTERFACE        *HubIf
01061   )
01062 {
01063   EFI_STATUS              Status;
01064   UINT8                   MaxSpeed;
01065   UINT8                   NumOfPort;
01066   UINT8                   Support64;
01067 
01068   Status = UsbHcGetCapability (HubIf->Device->Bus, &MaxSpeed, &NumOfPort, &Support64);
01069 
01070   if (EFI_ERROR (Status)) {
01071     return Status;
01072   }
01073 
01074   DEBUG (( EFI_D_INFO, "UsbRootHubInit: root hub %p - max speed %d, %d ports\n",
01075               HubIf, MaxSpeed, NumOfPort));
01076 
01077   HubIf->IsHub      = TRUE;
01078   HubIf->HubApi     = &mUsbRootHubApi;
01079   HubIf->HubEp      = NULL;
01080   HubIf->MaxSpeed   = MaxSpeed;
01081   HubIf->NumOfPort  = NumOfPort;
01082   HubIf->HubNotify  = NULL;
01083 
01084   //
01085   // Create a timer to poll root hub ports periodically
01086   //
01087   Status = gBS->CreateEvent (
01088                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
01089                   TPL_CALLBACK,
01090                   UsbRootHubEnumeration,
01091                   HubIf,
01092                   &HubIf->HubNotify
01093                   );
01094 
01095   if (EFI_ERROR (Status)) {
01096     return Status;
01097   }
01098 
01099   //
01100   // It should signal the event immediately here, or device detection
01101   // by bus enumeration might be delayed by the timer interval.
01102   //
01103   gBS->SignalEvent (HubIf->HubNotify);
01104 
01105   Status = gBS->SetTimer (
01106                   HubIf->HubNotify,
01107                   TimerPeriodic,
01108                   USB_ROOTHUB_POLL_INTERVAL
01109                   );
01110 
01111   if (EFI_ERROR (Status)) {
01112     gBS->CloseEvent (HubIf->HubNotify);
01113   }
01114 
01115   return Status;
01116 }
01117 
01118 
01133 EFI_STATUS
01134 UsbRootHubGetPortStatus (
01135   IN  USB_INTERFACE       *HubIf,
01136   IN  UINT8               Port,
01137   OUT EFI_USB_PORT_STATUS *PortState
01138   )
01139 {
01140   USB_BUS                 *Bus;
01141   EFI_STATUS              Status;
01142 
01143   Bus     = HubIf->Device->Bus;
01144   Status  = UsbHcGetRootHubPortStatus (Bus, Port, PortState);
01145 
01146   return Status;
01147 }
01148 
01149 
01157 VOID
01158 UsbRootHubClearPortChange (
01159   IN USB_INTERFACE        *HubIf,
01160   IN UINT8                Port
01161   )
01162 {
01163   EFI_USB_PORT_STATUS     PortState;
01164   USB_CHANGE_FEATURE_MAP  *Map;
01165   UINTN                   Index;
01166   EFI_STATUS              Status;
01167 
01168   Status = UsbRootHubGetPortStatus (HubIf, Port, &PortState);
01169 
01170   if (EFI_ERROR (Status)) {
01171     return;
01172   }
01173 
01174   //
01175   // OK, get the usb port status, now ACK the change bits.
01176   // Don't return error when failed to clear the change bits.
01177   // It may lead to extra port state report. USB bus should
01178   // be able to handle this.
01179   //
01180   for (Index = 0; Index < sizeof (mRootHubFeatureMap) / sizeof (mRootHubFeatureMap[0]); Index++) {
01181     Map = &mRootHubFeatureMap[Index];
01182 
01183     if (USB_BIT_IS_SET (PortState.PortChangeStatus, Map->ChangedBit)) {
01184       UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, (EFI_USB_PORT_FEATURE) Map->Feature);
01185     }
01186   }
01187 }
01188 
01189 
01201 EFI_STATUS
01202 UsbRootHubSetPortFeature (
01203   IN USB_INTERFACE        *HubIf,
01204   IN UINT8                Port,
01205   IN EFI_USB_PORT_FEATURE Feature
01206   )
01207 {
01208   EFI_STATUS              Status;
01209 
01210   Status  = UsbHcSetRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
01211 
01212   return Status;
01213 }
01214 
01215 
01227 EFI_STATUS
01228 UsbRootHubClearPortFeature (
01229   IN USB_INTERFACE        *HubIf,
01230   IN UINT8                Port,
01231   IN EFI_USB_PORT_FEATURE Feature
01232   )
01233 {
01234   EFI_STATUS              Status;
01235 
01236   Status  = UsbHcClearRootHubPortFeature (HubIf->Device->Bus, Port, Feature);
01237 
01238   return Status;
01239 }
01240 
01241 
01255 EFI_STATUS
01256 UsbRootHubResetPort (
01257   IN USB_INTERFACE        *RootIf,
01258   IN UINT8                Port
01259   )
01260 {
01261   USB_BUS                 *Bus;
01262   EFI_STATUS              Status;
01263   EFI_USB_PORT_STATUS     PortState;
01264   UINTN                   Index;
01265 
01266   //
01267   // Notice: although EHCI requires that ENABLED bit be cleared
01268   // when reset the port, we don't need to care that here. It
01269   // should be handled in the EHCI driver.
01270   //
01271   Bus     = RootIf->Device->Bus;
01272   Status  = UsbHcSetRootHubPortFeature (Bus, Port, EfiUsbPortReset);
01273 
01274   if (EFI_ERROR (Status)) {
01275     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to start reset on port %d\n", Port));
01276     return Status;
01277   }
01278 
01279   //
01280   // Drive the reset signal for at least 50ms. Check USB 2.0 Spec
01281   // section 7.1.7.5 for timing requirements.
01282   //
01283   gBS->Stall (USB_SET_ROOT_PORT_RESET_STALL);
01284 
01285   Status = UsbHcClearRootHubPortFeature (Bus, Port, EfiUsbPortReset);
01286 
01287   if (EFI_ERROR (Status)) {
01288     DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to clear reset on port %d\n", Port));
01289     return Status;
01290   }
01291 
01292   gBS->Stall (USB_CLR_ROOT_PORT_RESET_STALL);
01293 
01294   //
01295   // USB host controller won't clear the RESET bit until
01296   // reset is actually finished.
01297   //
01298   ZeroMem (&PortState, sizeof (EFI_USB_PORT_STATUS));
01299 
01300   for (Index = 0; Index < USB_WAIT_PORT_STS_CHANGE_LOOP; Index++) {
01301     Status = UsbHcGetRootHubPortStatus (Bus, Port, &PortState);
01302 
01303     if (EFI_ERROR (Status)) {
01304       return Status;
01305     }
01306 
01307     if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_RESET)) {
01308       break;
01309     }
01310 
01311     gBS->Stall (USB_WAIT_PORT_STS_CHANGE_STALL);
01312   }
01313 
01314   if (Index == USB_WAIT_PORT_STS_CHANGE_LOOP) {
01315     DEBUG ((EFI_D_ERROR, "UsbRootHubResetPort: reset not finished in time on port %d\n", Port));
01316     return EFI_TIMEOUT;
01317   }
01318 
01319   if (!USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_ENABLE)) {
01320     //
01321     // OK, the port is reset. If root hub is of high speed and
01322     // the device is of low/full speed, release the ownership to
01323     // companion UHCI. If root hub is of full speed, it won't
01324     // automatically enable the port, we need to enable it manually.
01325     //
01326     if (RootIf->MaxSpeed == EFI_USB_SPEED_HIGH) {
01327       DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: release low/full speed device (%d) to UHCI\n", Port));
01328 
01329       UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortOwner);
01330       return EFI_NOT_FOUND;
01331 
01332     } else {
01333 
01334       Status = UsbRootHubSetPortFeature (RootIf, Port, EfiUsbPortEnable);
01335 
01336       if (EFI_ERROR (Status)) {
01337         DEBUG (( EFI_D_ERROR, "UsbRootHubResetPort: failed to enable port %d for UHCI\n", Port));
01338         return Status;
01339       }
01340 
01341       gBS->Stall (USB_SET_ROOT_PORT_ENABLE_STALL);
01342     }
01343   }
01344 
01345   return EFI_SUCCESS;
01346 }
01347 
01348 
01358 EFI_STATUS
01359 UsbRootHubRelease (
01360   IN USB_INTERFACE        *HubIf
01361   )
01362 {
01363   DEBUG (( EFI_D_INFO, "UsbRootHubRelease: root hub released for hub %p\n", HubIf));
01364 
01365   gBS->SetTimer (HubIf->HubNotify, TimerCancel, USB_ROOTHUB_POLL_INTERVAL);
01366   gBS->CloseEvent (HubIf->HubNotify);
01367 
01368   return EFI_SUCCESS;
01369 }
01370 
01371 USB_HUB_API mUsbHubApi = {
01372   UsbHubInit,
01373   UsbHubGetPortStatus,
01374   UsbHubClearPortChange,
01375   UsbHubSetPortFeature,
01376   UsbHubClearPortFeature,
01377   UsbHubResetPort,
01378   UsbHubRelease
01379 };
01380 
01381 USB_HUB_API mUsbRootHubApi = {
01382   UsbRootHubInit,
01383   UsbRootHubGetPortStatus,
01384   UsbRootHubClearPortChange,
01385   UsbRootHubSetPortFeature,
01386   UsbRootHubClearPortFeature,
01387   UsbRootHubResetPort,
01388   UsbRootHubRelease
01389 };
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines