Newer
Older
AMI-Aptio-BIOS-Reversed / AmiModulePkg / Usb / Int13 / UsbInt13 / UsbInt13.c
@Ajax Dong Ajax Dong 2 days ago 25 KB Restructure the repo
/**
 * @file UsbInt13.c
 * @brief USB INT13 Legacy Driver - Full source reconstruction
 *
 * This module provides legacy INT13 BIOS support for USB mass storage devices
 * in Lenovo HR650X (and similar) platforms. It enables booting from USB floppy,
 * USB HDD, and USB CDROM devices when the system is in legacy BIOS / CSM mode.
 *
 * Source: e:\hs\AmiModulePkg\Usb\Int13\UsbInt13.c
 *
 * Key features:
 *  - Allocates and manages INT13 device parameter tables in legacy BIOS data areas
 *  - Handles USB hotplug events by installing/uninstalling INT13 handlers
 *  - Reorders boot priority at ReadyToBoot event to honor user boot selection
 *  - Manages three hotplug device types: FDD, HDD, CDROM
 *
 * All addresses are relative to image base 0x0.
 */

#include "UsbInt13.h"

// ============================================================================
// Globals
// ============================================================================

EFI_HANDLE             gImageHandle      = NULL;   // 0x1EF0
EFI_SYSTEM_TABLE       *gSystemTable     = NULL;   // 0x1EE0
EFI_BOOT_SERVICES      *gBootServices    = NULL;   // 0x1EE8
EFI_RUNTIME_SERVICES   *gRuntimeServices = NULL;   // 0x1EF8
EFI_SYSTEM_TABLE       *gSystemTable2    = NULL;   // 0x1F18
EFI_RUNTIME_SERVICES   *gRuntimeServices2= NULL;   // 0x1F10
VOID                   *gUsbHcDevice     = NULL;   // 0x1EC0
USB_INT13_DEVICE_ENTRY *gInt13DeviceTable= NULL;   // 0x1EC8
VOID                   *gBbsProtocol     = NULL;   // 0x1ED0
UINT8                  *gBbsDataBase     = NULL;   // 0x1EB0
UINT8                  *gBbsDeviceMap    = NULL;   // 0x1EA0
EFI_USB_HC_PROTOCOL    *gUsbHcProtocol   = NULL;   // 0x1ED8
VOID                   *gDebugProtocol   = NULL;   // 0x1F00
VOID                   *gHobList         = NULL;   // 0x1F08
UINT8                  gBootIndex        = 0;      // 0x1EB8
BOOLEAN                gBbsPortPatched   = FALSE;  // 0x1EA8
UINT8                  gSystemPowerState = 0;      // 0x1F20

USB_INT13_HOTPLUG_DEVICE gHotplugFdd   = { NULL, 0xFFFF, 3, 126, "USB Hotplug FDD", NULL };
USB_INT13_HOTPLUG_DEVICE gHotplugHdd   = { NULL, 0xFFFF, 1, 125, "USB Hotplug HDD", NULL };
USB_INT13_HOTPLUG_DEVICE gHotplugCdrom = { NULL, 0xFFFF, 2, 127, "USB Hotplug CDROM", NULL };

// ============================================================================
// Library helpers
// ============================================================================

void *SetMem(void *Buffer, UINTN Size, UINT8 Value)
{
  return memset(Buffer, Value, Size);
}

void *ZeroMem(void *Buffer, UINTN Size)
{
  return SetMem(Buffer, Size, 0);
}

UINT64 ReadUnaligned64(const VOID *Buffer)
{
  return *(const UINT64 *)Buffer;
}

BOOLEAN CompareGuid(const GUID *Guid1, const GUID *Guid2)
{
  return ReadUnaligned64(Guid1) == ReadUnaligned64(&Guid1->Data2)
      && ReadUnaligned64((VOID *)Guid2 + 8) == ReadUnaligned64((VOID *)Guid1 + 8);
}

// ============================================================================
// Debug support
// ============================================================================

VOID *EfiGetDebugProtocol(VOID)
{
  UINTN Pages;
  EFI_STATUS Status;

  if (gDebugProtocol != NULL)
    return gDebugProtocol;

  Pages = gBootServices->GetMemoryMap(&Pages, NULL, NULL, NULL, NULL);
  gBootServices->GetMemoryMap(&Pages, NULL, NULL, NULL, NULL);

  if (Pages <= 16) {
    Status = gBootServices->LocateProtocol(&gEfiDebugProtocolGuid, NULL, &gDebugProtocol);
    if (EFI_ERROR(Status))
      gDebugProtocol = NULL;
  }

  return gDebugProtocol;
}

UINTN EFIAPI DebugPrint(UINTN ErrorLevel, CONST CHAR8 *Format, ...)
{
  VA_LIST Marker;
  UINTN Result;

  if (!EfiGetDebugProtocol())
    return 0;

  Result = GetSystemPowerState();
  if ((Result & ErrorLevel) != 0) {
    VA_START(Marker, Format);
    VA_END(Marker);
  }

  return Result;
}

VOID EFIAPI AssertHandler(CONST CHAR8 *FileName, UINTN LineNumber, CONST CHAR8 *Description)
{
  VOID *DebugProtocol;

  DebugProtocol = EfiGetDebugProtocol();
  if (DebugProtocol != NULL) {
    ((EFI_DEBUG_PROTOCOL *)DebugProtocol)->Assert(FileName, LineNumber, Description);
  }
}

// ============================================================================
// HOB list retrieval
// ============================================================================

VOID *EfiGetHobList(VOID)
{
  UINTN Index;

  if (gHobList != NULL)
    return gHobList;

  gHobList = NULL;

  for (Index = 0; Index < gSystemTable->NumberOfTableEntries; Index++) {
    if (CompareGuid(
          (GUID *)&gSystemTable->ConfigurationTable[Index].VendorGuid,
          &gEfiHobListGuid))
    {
      gHobList = gSystemTable->ConfigurationTable[Index].VendorTable;
      break;
    }
  }

  if (gHobList == NULL)
    AssertHandler("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 54, "!EFI_ERROR (Status)");

  if (gHobList == NULL)
    AssertHandler("e:\\hs\\MdePkg\\Library\\DxeHobLib\\HobLib.c", 55, "mHobList != ((void *) 0)");

  return gHobList;
}

// ============================================================================
// System power state
// ============================================================================

UINTN GetSystemPowerState(VOID)
{
  UINT8 Index;
  UINT8 CmosValue;
  UINT8 PowerState;

  Index = __inbyte(CMOS_REG_ADDRESS);
  __outbyte(CMOS_REG_ADDRESS, (Index & 0x80) | CMOS_STATUS_REGISTER);
  CmosValue = __inbyte(CMOS_REG_DATA);
  PowerState = CmosValue;

  if (PowerState > 3) {
    if (gSystemPowerState) {
      PowerState = gSystemPowerState;
    } else {
      PowerState = (MEMORY[0xFDAF0490] & 2) | 1;
    }
  }

  if (PowerState - 1 > 0xFD)
    return 0;

  return (PowerState == SYSTEM_POWER_STATE_S5) ? 0x80000004 : 0x80000005;
}

// ============================================================================
// Entry point
// ============================================================================

EFI_STATUS EFIAPI _ModuleEntryPoint(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable)
{
  gImageHandle = ImageHandle;
  if (!ImageHandle)
    AssertHandler("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c", 51, "gImageHandle != ((void *) 0)");

  gSystemTable = SystemTable;
  if (!SystemTable)
    AssertHandler("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c", 57, "gST != ((void *) 0)");

  gBootServices = SystemTable->BootServices;
  if (!gBootServices)
    AssertHandler("e:\\hs\\MdePkg\\Library\\UefiBootServicesTableLib\\UefiBootServicesTableLib.c", 63, "gBS != ((void *) 0)");

  gRuntimeServices = SystemTable->RuntimeServices;
  if (!gRuntimeServices)
    AssertHandler("e:\\hs\\MdePkg\\Library\\UefiRuntimeServicesTableLib\\UefiRuntimeServicesTableLib.c", 47, "gRT != ((void *) 0)");

  EfiGetHobList();
  return UsbInt13DriverEntry(ImageHandle, SystemTable);
}

// ============================================================================
// Main driver entry
// ============================================================================

EFI_STATUS EFIAPI UsbInt13DriverEntry(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable)
{
  EFI_STATUS Status;
  EFI_EVENT  ReadyToBootEvent;

  if (gSystemTable2 == NULL) {
    gSystemTable2 = SystemTable;
    gRuntimeServices2 = SystemTable->RuntimeServices;
  }

  Status = gBootServices->LocateProtocol(&gEfiUsbHcProtocolGuid, NULL, &gUsbHcProtocol);
  if (EFI_ERROR(Status)) {
    AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 81, "!EFI_ERROR (Status)");
    return Status;
  }

  gUsbHcDevice = *(VOID **)gUsbHcProtocol;

  Status = UsbInt13AllocateLegacyStructs();
  if (EFI_ERROR(Status)) {
    AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 89, "!EFI_ERROR (Status)");
    return Status;
  }

  *(UINT64 *)(gUsbHcProtocol + 40) = (UINT64)UsbInt13EnumerateUsbDevices;
  *(UINT64 *)(gUsbHcProtocol + 48) = (UINT64)UsbInt13InstallDevice;
  *(UINT64 *)(gUsbHcProtocol + 56) = (UINT64)UsbInt13UninstallDevice;

  Status = RegisterReadyToBootEvent(&ReadyToBootEvent);
  if (EFI_ERROR(Status)) {
    AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 99, "!EFI_ERROR (Status)");
    return Status;
  }

  return EFI_SUCCESS;
}

// ============================================================================
// Legacy struct allocation
// ============================================================================

EFI_STATUS UsbInt13AllocateLegacyStructs(VOID)
{
  EFI_STATUS   Status;
  UINT16       BbsConfigSize;
  UINT16       BbsDeviceMapOffset;
  UINT8        *BbsDataArea;

  BbsConfigSize = 0;

  if (MEMORY[0xF0018] < 8 && MEMORY[0xF0019] < 0x55)
    return EFI_UNSUPPORTED;

  gBbsDataBase = (UINT8 *)(MEMORY[0xFFF4C] + 0xF0000);

  Status = gBootServices->LocateProtocol(&gEfiBbsTableProtocolGuid, NULL, &gBbsProtocol);
  if (EFI_ERROR(Status))
    return Status;

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->GetConfig(1, 0, 2, &BbsConfigSize, &BbsDeviceMapOffset);
  if (EFI_ERROR(Status))
    return Status;

  BbsDataArea = (UINT8 *)(BbsDeviceMapOffset + gBbsDataBase[BbsConfigSize * 2 + 0x5A0]);
  *(UINT64 *)BbsDataArea = 0x31000000B2000001ULL;
  *(UINT16 *)(BbsDataArea + 8) = 0;
  *(UINT8 *)(BbsDataArea + 10) = 0;

  gInt13DeviceTable = (USB_INT13_DEVICE_ENTRY *)(
    ((BBS_PROTOCOL *)gBbsProtocol)->Allocate(BbsDeviceMapOffset, BbsConfigSize, 16));

  if (gInt13DeviceTable == NULL)
    return EFI_OUT_OF_RESOURCES;

  gBbsDeviceMap = (UINT8 *)gInt13DeviceTable + *(UINT16 *)((UINT8 *)gInt13DeviceTable + 1442);

  return EFI_SUCCESS;
}

// ============================================================================
// Hotplug init
// ============================================================================

EFI_STATUS UsbInt13InitHotplugStructs(VOID)
{
  UINT8 *HcDeviceBase;

  HcDeviceBase = (UINT8 *)gUsbHcDevice;

  gHotplugFdd.Handle         = NULL;
  gHotplugFdd.Int13DriveNum  = 0xFFFF;
  gHotplugFdd.DeviceType     = USB_INT13_DEVICE_TYPE_FLOPPY;
  gHotplugFdd.LegacyInt13Num = 126;
  gHotplugFdd.Buffer         = HcDeviceBase + 27712;
  gHotplugFdd.NameString     = "USB Hotplug FDD";

  gHotplugHdd.Handle         = NULL;
  gHotplugHdd.Int13DriveNum  = 0xFFFF;
  gHotplugHdd.DeviceType     = USB_INT13_DEVICE_TYPE_HDD;
  gHotplugHdd.LegacyInt13Num = 125;
  gHotplugHdd.Buffer         = HcDeviceBase + 28160;
  gHotplugHdd.NameString     = "USB Hotplug HDD";

  gHotplugCdrom.Handle         = NULL;
  gHotplugCdrom.Int13DriveNum  = 0xFFFF;
  gHotplugCdrom.DeviceType     = USB_INT13_DEVICE_TYPE_CDROM;
  gHotplugCdrom.LegacyInt13Num = 127;
  gHotplugCdrom.Buffer         = HcDeviceBase + 28608;
  gHotplugCdrom.NameString     = "USB Hotplug CDROM";

  if (((HcDeviceBase[30497] - 1) & 0xFD) == 0)
    UsbInt13InstallDevice((VOID *)&gHotplugFdd);

  if (((HcDeviceBase[30498] - 1) & 0xFD) == 0)
    UsbInt13InstallDevice((VOID *)&gHotplugHdd);

  if (((HcDeviceBase[30499] - 1) & 0xFD) == 0)
    UsbInt13InstallDevice((VOID *)&gHotplugCdrom);

  return EFI_SUCCESS;
}

// ============================================================================
// ReadyToBoot callback
// ============================================================================

VOID EFIAPI UsbInt13ReadyToBootCallback(
  IN EFI_EVENT  Event,
  IN VOID       *Context)
{
  EFI_STATUS         Status;
  UINTN              HandleCount;
  VOID               *BbsProtocol;
  BBS_TABLE          *BbsTable;
  UINT16             BbsEntryCount;
  UINT16             EntryIndex;
  UINT16             BestBbsIndex;

  HandleCount = 0;

  Status = gBootServices->LocateProtocol(&gEfiBbsTableProtocolGuid, NULL, &HandleCount);
  ASSERT(!EFI_ERROR(Status));

  if (EFI_ERROR(Status))
    return;

  BbsProtocol = (VOID *)HandleCount;
  HandleCount = 0;
  BbsTable = NULL;

  Status = ((BBS_PROTOCOL *)BbsProtocol)->GetTable(
             (VOID *)&Event, (UINT8 *)&BbsTable, &BbsEntryCount, &HandleCount);
  ASSERT(!EFI_ERROR(Status));

  if (EFI_ERROR(Status))
    return;

  for (EntryIndex = 0; EntryIndex < BbsEntryCount; EntryIndex++) {
    BBS_ENTRY *Entry = &BbsTable->Entries[EntryIndex];

    if (Entry->DeviceType == BBS_TYPE_ATAPI) {
      switch (Entry->InterfaceType & 0x0F) {
      case 2:
        Entry->DeviceType = BBS_TYPE_ATA;
        break;
      case 3:
        Entry->DeviceType = 3;
        break;
      case 4:
        Entry->DeviceType = BBS_TYPE_ATA;
        break;
      default:
        Entry->DeviceType = 0xFF;
        break;
      }
    }
  }

  if (gBootIndex != 0) {
    BestBbsIndex = 256;
    UINT8 BootDeviceIndex = gBootIndex;
    UINT16 BootDeviceEntryCount = BbsTable->Entries[BootDeviceIndex].Priority;

    for (EntryIndex = 0; EntryIndex < 256; EntryIndex++) {
      if (EntryIndex != BootDeviceIndex) {
        if (BbsTable->Entries[EntryIndex].Priority < BootDeviceEntryCount) {
          BootDeviceEntryCount = BbsTable->Entries[EntryIndex].Priority;
          BestBbsIndex = EntryIndex;
        }
      }
    }

    if (BestBbsIndex < 256) {
      UINT16 Temp = BbsTable->Entries[BootDeviceIndex].Priority;
      BbsTable->Entries[BootDeviceIndex].Priority = BbsTable->Entries[BestBbsIndex].Priority;
      BbsTable->Entries[BestBbsIndex].Priority = Temp;
    }
  }
}

// ============================================================================
// Build INT13 param table
// ============================================================================

EFI_STATUS UsbInt13BuildInt13ParamTable(
  IN  UINT8             DevIndex,
  IN  VOID              *UsbDevice,
  OUT INT13_PARAM_TABLE *ParamTable)
{
  UINT8       DeviceType;
  UINT8       *ProductName;
  UINT8       *ProductNameDest;
  CHAR8       NameChar;
  UINT8       *PatchedEntry;
  UINTN       EbbOffset;
  UINT8       MediaType;

  if (DevIndex >= USB_INT13_MAX_DEVICES)
    AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 412, "DevIndex < 16");

  if (gBbsProtocol == NULL)
    return EFI_NOT_FOUND;

  ZeroMem(ParamTable, USB_INT13_DEVICE_ENTRY_SIZE);

  ParamTable->Heads          = *(UINT8 *)(UsbDevice + 137);
  ParamTable->SectorsPerTrack= (*(UINT16 *)(UsbDevice + 136) >> 3) & 0x1F;
  ParamTable->Cylinders      = *(UINT16 *)(UsbDevice + 136) & 7;
  ParamTable->BytesPerSector = INT13_SECTOR_SIZE;
  ParamTable->Int13Flags     = INT13_DISK_SIZE_HEAD_MULT;

  ProductName = *(UINT8 **)(UsbDevice + 144);
  ParamTable->NameStrLen = (UINT8)((UINTN)gInt13DeviceTable + 25 + DevIndex * 89) & 0xFF;
  ProductNameDest = (UINT8 *)((UINTN)gInt13DeviceTable + 25 + DevIndex * 89);

  for (UINTN i = 0; i < 63; i++) {
    NameChar = *ProductName;
    if (NameChar == 0)
      break;
    if (NameChar != ' ' || *(ProductName - 1) != ' ')
      *ProductNameDest++ = NameChar;
    ProductName++;
  }
  *ProductNameDest = 0;

  ParamTable->NameStrOff  = (UINT16)(UINTN)ProductNameDest;
  ParamTable->NameStrSeg  = (UINT16)((UINTN)ProductNameDest >> 4) & 0xF000;
  ParamTable->DevPathSegment = ((UINTN)gInt13DeviceTable + 1424) >> 4 & 0xF000;
  ParamTable->DevPathOffset  = (UINT16)(UINTN)((UINTN)gInt13DeviceTable + 1424);

  DeviceType = *(UINT8 *)(UsbDevice + 152);
  MediaType  = *(UINT8 *)(UsbDevice + 120);

  switch (DeviceType) {
  case USB_INT13_DEVICE_TYPE_FLOPPY:
    MediaType |= 0x80;
    ParamTable->Int13DevType = INT13_DEVICE_TYPE_HDD;
    ParamTable->ControllerIndex = 2;
    break;

  case USB_INT13_DEVICE_TYPE_CDROM:
    ParamTable->Int13DevType = INT13_DEVICE_TYPE_HDD;
    ParamTable->ControllerIndex = 4;
    break;

  case USB_INT13_DEVICE_TYPE_HDD:
    ParamTable->Int13DevType = INT13_DEVICE_TYPE_FLOPPY;
    ParamTable->EbbTableSegment = 0xF000;
    ParamTable->EbbTableOffset = *(UINT16 *)(gBbsDataBase + 12);

    if (!gBbsPortPatched) {
      EbbOffset = ((UINTN)gInt13DeviceTable << 12) + *(UINT16 *)((UINT8 *)gInt13DeviceTable + 1438);
      gBbsPortPatched = TRUE;
      PatchedEntry = (UINT8 *)(*(UINT16 *)(gBbsDataBase + 14) + 0xF0005);
      *PatchedEntry = BBS_PORT_PATCH_OPCODE;
      *(UINT32 *)(PatchedEntry + 1) = EbbOffset;
    }
    break;

  default:
    ParamTable->Int13DevType = INT13_DEVICE_TYPE_UNKNOWN;
    ParamTable->ControllerIndex = 0;
    break;
  }

  ParamTable->Int13Flags = ((MediaType + (ControllerIndex << 16)) << 8) + 17;
  ParamTable->DeviceSectors = *(UINT64 *)(UsbDevice + 128);

  return EFI_SUCCESS;
}

// ============================================================================
// Device enumeration
// ============================================================================

EFI_STATUS UsbInt13EnumerateUsbDevices(VOID)
{
  EFI_STATUS           Status;
  EFI_HANDLE           *HandleBuffer;
  UINTN                HandleCount;
  UINTN                HandleIndex;
  VOID                 *UsbIoProtocol;
  USB_DEVICE_DESCRIPTOR DevDesc;
  VOID                 *BbsProtocol;
  UINT8                *UsbHcDevice;
  UINT8                *UsbDevice;
  UINT8                DeviceProtocol;

  if (*(UINT8 *)((UINT8 *)gUsbHcDevice + 4) & 4)
    return EFI_UNSUPPORTED;

  UsbInt13InitHotplugStructs();

  Status = gBootServices->LocateHandleBuffer(
             ByProtocol, &gEfiUsbIoProtocolGuid, NULL, &HandleCount, &HandleBuffer);
  if (EFI_ERROR(Status))
    return Status;

  for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
    if (EFI_ERROR(gBootServices->OpenProtocol(
           HandleBuffer[HandleIndex], &gEfiUsbHcProtocolGuid, &BbsProtocol,
           gImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)))
      continue;

    if (EFI_ERROR(((USB_IO_PROTOCOL *)BbsProtocol)->GetDeviceDescriptor(
            (USB_DEVICE_DESCRIPTOR *)&DevDesc)))
      continue;

    if (DevDesc.DeviceClass != USB_CLASS_MASS_STORAGE)
      continue;

    if (EFI_ERROR(gBootServices->OpenProtocol(
           HandleBuffer[HandleIndex], &gEfiUsbIoProtocolGuid, &UsbIoProtocol,
           gImageHandle, NULL, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)))
      continue;

    UsbHcDevice = (UINT8 *)UsbIoProtocol - 8;
    if (*(UINT32 *)UsbHcDevice != 0x73657255)
      AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 568, "CR has Bad Signature");

    UsbDevice = *(UINT8 **)(UsbHcDevice + 112);
    DeviceProtocol = *(UINT8 *)(UsbDevice + 101);

    if (DeviceProtocol &&
        (DeviceProtocol == 2 || (UINT16)(*(UINT16 *)(UsbDevice + 78) - 513) > 0xFDFD))
    {
      UsbInt13InstallDevice((VOID *)UsbHcDevice);
    }
  }

  if (HandleBuffer != NULL)
    gBootServices->FreePool(HandleBuffer);

  return EFI_SUCCESS;
}

// ============================================================================
// Install device
// ============================================================================

EFI_STATUS UsbInt13InstallDevice(VOID *UsbDevice)
{
  EFI_STATUS         Status;
  UINT8              UsbPort;
  UINT8              DevIndex;
  INT13_PARAM_TABLE  ParamTable;
  UINT8              BbsEntryIndex;
  UINT8              *HcDataArea;
  USB_INT13_DEVICE_ENTRY *Entry;
  UINTN              TableOffset;
  UINT8              HcNumber;
  UINT8              PortNumber;

  UsbPort = *(UINT8 *)(UsbDevice + 120);
  BbsEntryIndex = 0xFF;

  for (DevIndex = 0; DevIndex < USB_INT13_MAX_DEVICES; DevIndex++) {
    if (gInt13DeviceTable[DevIndex].UsbPort == UsbPort) {
      AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 608, "((BOOLEAN)(0==1))");
      return EFI_INVALID_PARAMETER;
    }
  }

  for (DevIndex = 0; DevIndex < USB_INT13_MAX_DEVICES; DevIndex++) {
    if (gInt13DeviceTable[DevIndex].UsbPort == 0)
      break;
  }

  if (DevIndex >= USB_INT13_MAX_DEVICES) {
    AssertHandler("e:\\hs\\AmiModulePkg\\Usb\\Int13\\UsbInt13.c", 620, "Index<16");
    if (DevIndex == 16)
      return EFI_OUT_OF_RESOURCES;
  }

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->Reset(0, 0, 0, 0);
  ASSERT(!EFI_ERROR(Status));

  Status = UsbInt13BuildInt13ParamTable(DevIndex, UsbDevice, &ParamTable);
  ASSERT(!EFI_ERROR(Status));

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->AddEntry(gBbsProtocol, &ParamTable, &BbsEntryIndex);
  if (EFI_ERROR(Status)) {
    ((BBS_PROTOCOL *)gBbsProtocol)->EndConfig(0, 0);
    return Status;
  }

  Entry = &gInt13DeviceTable[DevIndex];
  Entry->UsbPort         = UsbPort;
  Entry->BbsIndex        = BbsEntryIndex;
  Entry->DeviceType      = *(UINT16 *)(*(UINT8 **)(UsbDevice + 112) + 94);
  Entry->VendorId        = *(UINT16 *)(*(UINT8 **)(UsbDevice + 112) + 88);
  Entry->ProductId       = *(UINT16 *)(*(UINT8 **)(UsbDevice + 112) + 98);
  Entry->BcdRevision     = *(UINT16 *)(*(UINT8 **)(UsbDevice + 112) + 92);
  Entry->ConfigValue     = *(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 96);
  Entry->InterfaceNumber = *(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 90);
  Entry->RemovableMedia  = *(UINT16 *)(*(UINT8 **)(UsbDevice + 112) + 78);
  Entry->Reserved3       = *(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 102);
  Entry->UsbDevPathPtr   = *(UINT64 *)(*(UINT8 **)(UsbDevice + 112) + 80);

  TableOffset = (UINTN)gBbsDeviceMap + 2 * DevIndex;
  *(UINT8 *)(DevIndex + (UINTN)gBbsDeviceMap) = UsbPort;
  *(UINT16 *)(DevIndex + (UINTN)gBbsDeviceMap + 1) = *(UINT16 *)(UsbDevice + 136);

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->EndConfig(0, 0);
  ASSERT(!EFI_ERROR(Status));

  *(UINT32 *)(*(UINT8 **)(UsbDevice + 112)) |= 4;

  if ((*(CHAR8 *)(*(UINT8 **)(UsbDevice + 112) + 12) < 0) &&
      (gUsbHcProtocol->GetPortStatus(&BbsEntryIndex, &(UINT8){0}) >= 0) &&
      !gBootIndex)
  {
    gUsbHcProtocol->GetPortStatus(&HcNumber, &PortNumber);
    DebugPrint(DEBUG_INIT,
      "OemUsbGetAssignBootPort: HC %d, Port %d; current HC %d, Port %d\n",
      HcNumber, PortNumber,
      *(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 11),
      *(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 13));

    if ((*(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 11) == HcNumber) &&
        (*(UINT8 *)(*(UINT8 **)(UsbDevice + 112) + 13) == PortNumber))
    {
      DebugPrint(DEBUG_INIT, "---OemUsbGetAssignBootPort: BBS Entry# %d\n", BbsEntryIndex);
      gBootIndex = BbsEntryIndex;
    }
  }

  if ((UsbDevice != (VOID *)&gHotplugFdd) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_FLOPPY) &&
      (*(UINT8 *)((UINT8 *)gUsbHcDevice + 30497) == 3))
  {
    DebugPrint(DEBUG_INIT, "Uninstalling Hotplug Floppy (Setup 'Auto' option)\n");
    UsbInt13UninstallDevice((VOID *)&gHotplugFdd);
  }

  if ((UsbDevice != (VOID *)&gHotplugHdd) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_HDD) &&
      (*(UINT8 *)((UINT8 *)gUsbHcDevice + 30498) == 3))
  {
    DebugPrint(DEBUG_INIT, "Uninstalling Hotplug HDD (Setup 'Auto' option)\n");
    UsbInt13UninstallDevice((VOID *)&gHotplugHdd);
  }

  if ((UsbDevice != (VOID *)&gHotplugCdrom) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_CDROM) &&
      (*(UINT8 *)((UINT8 *)gUsbHcDevice + 30499) == 3))
  {
    DebugPrint(DEBUG_INIT, "Uninstalling Hotplug CDROM (Setup 'Auto' option)\n");
    UsbInt13UninstallDevice((VOID *)&gHotplugCdrom);
  }

  return EFI_SUCCESS;
}

// ============================================================================
// Uninstall device
// ============================================================================

EFI_STATUS UsbInt13UninstallDevice(VOID *UsbDevice)
{
  EFI_STATUS Status;
  UINT8      DevIndex;
  UINT8      BbsEntryIndex;
  UINT8      *HcDeviceBase;

  DebugPrint(DEBUG_INIT, "Uninstalling INT13 device %x\n", UsbDevice);

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->Reset(0, 0, 0, 0);
  ASSERT(!EFI_ERROR(Status));

  for (DevIndex = 0; DevIndex < USB_INT13_MAX_DEVICES; DevIndex++) {
    if (gInt13DeviceTable[DevIndex].UsbPort == *(UINT8 *)(UsbDevice + 120))
      break;
  }

  if (DevIndex >= USB_INT13_MAX_DEVICES)
    goto End;

  BbsEntryIndex = gInt13DeviceTable[DevIndex].BbsIndex;
  gInt13DeviceTable[DevIndex].UsbPort = 0;

  Status = ((BBS_PROTOCOL *)gBbsProtocol)->RemoveEntry(gBbsProtocol, BbsEntryIndex);
  ASSERT(!EFI_ERROR(Status));

  if (gBootIndex == BbsEntryIndex)
    gBootIndex = 0;

  *(UINT8 *)((UINTN)gBbsDeviceMap + 2 * DevIndex) = 0;

End:
  ((BBS_PROTOCOL *)gBbsProtocol)->EndConfig(0, 0);

  if (EFI_ERROR(Status))
    return Status;

  *(UINT32 *)(*(UINT8 **)(UsbDevice + 112)) &= 0xFFFFFFFA;

  HcDeviceBase = (UINT8 *)gUsbHcDevice;

  if ((UsbDevice != (VOID *)&gHotplugFdd) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_FLOPPY) &&
      (HcDeviceBase[30497] == 3) &&
      !(HcDeviceBase[30507]))
  {
    DebugPrint(DEBUG_INIT, "Installing Hotplug Floppy (Setup 'Auto' option)\n");
    UsbInt13InstallDevice((VOID *)&gHotplugFdd);
  }

  if ((UsbDevice != (VOID *)&gHotplugHdd) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_HDD) &&
      (HcDeviceBase[30498] == 3) &&
      !(HcDeviceBase[30508]))
  {
    DebugPrint(DEBUG_INIT, "Installing Hotplug HDD (Setup 'Auto' option)\n");
    UsbInt13InstallDevice((VOID *)&gHotplugHdd);
  }

  if ((UsbDevice != (VOID *)&gHotplugCdrom) &&
      (*(UINT8 *)(UsbDevice + 152) == USB_INT13_DEVICE_TYPE_CDROM) &&
      (HcDeviceBase[30499] == 3) &&
      !(HcDeviceBase[30509]))
  {
    DebugPrint(DEBUG_INIT, "Installing Hotplug CDROM (Setup 'Auto' option)\n");
    UsbInt13InstallDevice((VOID *)&gHotplugCdrom);
  }

  return Status;
}

// ============================================================================
// Register ReadyToBoot event
// ============================================================================

EFI_STATUS RegisterReadyToBootEvent(OUT EFI_EVENT *ReadyToBootEvent)
{
  if (ReadyToBootEvent == NULL) {
    AssertHandler("e:\\hs\\MdePkg\\Library\\UefiLib\\UefiNotTiano.c", 181,
                  "ReadyToBootEvent != ((void *) 0)");
    return EFI_INVALID_PARAMETER;
  }

  if (gSystemTable->Hdr.Revision >= 0x20000) {
    return gBootServices->CreateEventEx(
             EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
             UsbInt13ReadyToBootCallback, NULL,
             &gEfiEventReadyToBootGuid,
             ReadyToBootEvent);
  }

  DebugPrint(DEBUG_ERROR, "EFI1.1 can't support ReadyToBootEvent!");
  AssertHandler("e:\\hs\\MdePkg\\Library\\UefiLib\\UefiNotTiano.c", 185,
                "((BOOLEAN)(0==1))");
  return EFI_UNSUPPORTED;
}