/** Enumerate all the changed hub ports. @param Event The event that is triggered. @param Context The context to the event. **/ VOID EFIAPI UsbRootHubEnumeration ( IN EFI_EVENT Event, IN VOID *Context ) { USB_INTERFACE *RootHub; UINT8 Index; USB_DEVICE *Child; RootHub = (USB_INTERFACE *) Context; if (!RootHub) { return; } DBG("USB event happen, NumOfPort=%d\n", RootHub->NumOfPort); for (Index = 0; Index < RootHub->NumOfPort; Index++) { Child = UsbFindChild (RootHub, Index); if ((Child != NULL) && (Child->DisconnectFail == TRUE)) { // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub)); DBG("UsbEnumeratePort: The device disconnect fails at port %d from root hub %p, try again\n", Index, RootHub); UsbRemoveDevice (Child); DBG("device removed\n"); } UsbEnumeratePort (RootHub, Index); } }
/** Enumerate all the changed hub ports. @param Event The event that is triggered. @param Context The context to the event. **/ VOID EFIAPI UsbHubEnumeration ( IN EFI_EVENT Event, IN VOID *Context ) { USB_INTERFACE *HubIf; UINT8 Byte; UINT8 Bit; UINT8 Index; USB_DEVICE *Child; // ASSERT (Context != NULL); if (!Context) { return; } HubIf = (USB_INTERFACE *) Context; for (Index = 0; Index < HubIf->NumOfPort; Index++) { Child = UsbFindChild (HubIf, Index); if ((Child != NULL) && (Child->DisconnectFail == TRUE)) { // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf)); DBG("UsbEnumeratePort: The device disconnect fails at port %d from hub %p, try again\n", Index, HubIf); UsbRemoveDevice (Child); } } if (HubIf->ChangeMap == NULL) { return ; } // // HUB starts its port index with 1. // Byte = 0; Bit = 1; DBG("Enumerate %d ports\n", HubIf->NumOfPort); for (Index = 0; Index < HubIf->NumOfPort; Index++) { if (USB_BIT_IS_SET (HubIf->ChangeMap[Byte], USB_BIT (Bit))) { UsbEnumeratePort (HubIf, Index); DBG("Port %d enumerated\n", Index); } USB_NEXT_BIT (Byte, Bit); } UsbHubAckHubStatus (HubIf->Device); gBS->FreePool (HubIf->ChangeMap); HubIf->ChangeMap = NULL; return ; }
/** Process the events on the port. @param HubIf The HUB that has the device connected. @param Port The port index of the hub (started with zero). @retval EFI_SUCCESS The device is enumerated (added or removed). @retval EFI_OUT_OF_RESOURCES Failed to allocate resource for the device. @retval Others Failed to enumerate the device. **/ EFI_STATUS UsbEnumeratePort ( IN USB_INTERFACE *HubIf, IN UINT8 Port ) { USB_HUB_API *HubApi; USB_DEVICE *Child; EFI_USB_PORT_STATUS PortState; EFI_STATUS Status; Child = NULL; HubApi = HubIf->HubApi; // // Host learns of the new device by polling the hub for port changes. // Status = HubApi->GetPortStatus (HubIf, Port, &PortState); if (EFI_ERROR (Status)) { // DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: failed to get state of port %d\n", Port)); DBG("UsbEnumeratePort: failed to get state of port %d\n", Port); return Status; } // // Only handle connection/enable/overcurrent/reset change. // Usb super speed hub may report other changes, such as warm reset change. Ignore them. // if ((PortState.PortChangeStatus & (USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_OVERCURRENT | USB_PORT_STAT_C_RESET)) == 0) { return EFI_SUCCESS; } // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n", //Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf)); DBG( "UsbEnumeratePort: port %d state - %02x, change - %02x on %p\n", Port, PortState.PortStatus, PortState.PortChangeStatus, HubIf); // // This driver only process two kinds of events now: over current and // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET. // ENABLE/RESET is used to reset port. SUSPEND isn't supported. // if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) { if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) { // // Case1: // Both OverCurrent and OverCurrentChange set, means over current occurs, // which probably is caused by short circuit. It has to wait system hardware // to perform recovery. // // DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: Critical Over Current\n", Port)); DBG("UsbEnumeratePort: Critical Over Current\n", Port); return EFI_DEVICE_ERROR; } // // Case2: // Only OverCurrentChange set, means system has been recoveried from // over current. As a result, all ports are nearly power-off, so // it's necessary to detach and enumerate all ports again. // // DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port)); DBG("UsbEnumeratePort: 2.0 device Recovery Over Current\n", Port); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) { // // Case3: // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart // on 2.0 roothub does. When over-current has influence on 1.1 device, the port // would be disabled, so it's also necessary to detach and enumerate again. // // DEBUG (( EFI_D_ERROR, "UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port)); DBG("UsbEnumeratePort: 1.1 device Recovery Over Current\n", Port); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) { // // Case4: // Device connected or disconnected normally. // // DEBUG ((EFI_D_ERROR, "UsbEnumeratePort: Device Connect/Discount Normally\n", Port)); DBG("UsbEnumeratePort: Device Connect/Discount Normally\n"); } // // Following as the above cases, it's safety to remove and create again. // Child = UsbFindChild (HubIf, Port); if (Child != NULL) { // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf)); DBG("UsbEnumeratePort: device at port %d removed from root hub %p\n", Port, HubIf); UsbRemoveDevice (Child); } if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) { // // Now, new device connected, enumerate and configure the device // // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: new device connected at port %d\n", Port)); DBG("UsbEnumeratePort: new device connected at port %d\n", Port); Status = UsbEnumerateNewDev (HubIf, Port); } else { // DEBUG (( EFI_D_INFO, "UsbEnumeratePort: device disconnected event on port %d\n", Port)); DBG("UsbEnumeratePort: device disconnected event on port %d status=0x%x\n", Port, PortState.PortStatus); } HubApi->ClearPortChange (HubIf, Port); DBG("ClearPortChange\n"); return Status; }
STATIC EFI_STATUS UsbEnumeratePort ( IN USB_INTERFACE *HubIf, IN UINT8 Port ) /*++ Routine Description: Process the events on the port. Arguments: HubIf - The HUB that has the device connected Port - The port index of the hub (started with zero) Returns: EFI_SUCCESS - The device is enumerated (added or removed) EFI_OUT_OF_RESOURCES - Failed to allocate resource for the device Others - Failed to enumerate the device --*/ { USB_HUB_API *HubApi; USB_DEVICE *Child; EFI_USB_PORT_STATUS PortState; EFI_STATUS Status; Child = NULL; HubApi = HubIf->HubApi; // // Host learns of the new device by polling the hub for port changes. // Status = HubApi->GetPortStatus (HubIf, Port, &PortState); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port)); return Status; } if (PortState.PortChangeStatus == 0) { return EFI_SUCCESS; } USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n", Port, PortState.PortStatus, PortState.PortChangeStatus)); // // This driver only process two kinds of events now: over current and // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET. // ENABLE/RESET is used to reset port. SUSPEND isn't supported. // if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) { if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) { // // Case1: // Both OverCurrent and OverCurrentChange set, means over current occurs, // which probably is caused by short circuit. It has to wait system hardware // to perform recovery. // USB_DEBUG (("UsbEnumeratePort: Critical Over Current\n", Port)); return EFI_DEVICE_ERROR; } // // Case2: // Only OverCurrentChange set, means system has been recoveried from // over current. As a result, all ports are nearly power-off, so // it's necessary to detach and enumerate all ports again. // USB_DEBUG (("UsbEnumeratePort: 2.0 Device Recovery Over Current\n", Port)); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) { // // Case3: // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart // on 2.0 roothub does. When over-current has influence on 1.1 device, the port // would be disabled, so it's also necessary to detach and enumerate again. // USB_DEBUG (("UsbEnumeratePort: 1.1 Device Recovery Over Current\n", Port)); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) { // // Case4: // Device connected or disconnected normally. // USB_DEBUG (("UsbEnumeratePort: Device Connect/Discount Normally\n", Port)); } // // Following as the above cases, it's safety to remove and create again. // Child = UsbFindChild (HubIf, Port); if (Child != NULL) { USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port)); UsbRemoveDevice (Child); } if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) { // // Now, new device connected, enumerate and configure the device // USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port)); Status = UsbEnumerateNewDev (HubIf, Port); } else { USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port)); } HubApi->ClearPortChange (HubIf, Port); return Status; }