usb.c

来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 822 行 · 第 1/2 页

C
822
字号
/*++

Copyright (c) 2004, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             

  Module Name:

    Usb.c

  Abstract:

    Parse usb device configurations.

  Revision History

--*/

#include "usbbus.h"

//
// Here are some internal helper functions
//
STATIC
EFI_STATUS
GetExpectedDescriptor (
  IN  UINT8     *Buffer,
  IN  UINTN     Length,
  IN  UINT8     DescType,
  IN  UINT8     DescLength,
  OUT UINTN     *ParsedBytes
  );

STATIC
EFI_STATUS
ParseThisEndpoint (
  IN  ENDPOINT_DESC_LIST_ENTRY     *EndpointEntry,
  IN  UINT8                        *Buffer,
  IN  UINTN                        BufferLength,
  OUT UINTN                        *ParsedBytes
  );

STATIC
EFI_STATUS
ParseThisInterface (
  IN  INTERFACE_DESC_LIST_ENTRY      *InterfaceEntry,
  IN  UINT8                          *Buffer,
  IN  UINTN                          *BufferLen,
  OUT UINTN                          *ParsedBytes
  );

STATIC
EFI_STATUS
ParseThisConfig (
  IN CONFIG_DESC_LIST_ENTRY     *ConfigDescEntry,
  IN UINT8                      *Buffer,
  IN UINTN                      Length
  );

//
// Implementations
//
BOOLEAN
IsHub (
  IN USB_IO_CONTROLLER_DEVICE     *Dev
  )
/*++
  
  Routine Description:
    Tell if a usb controller is a hub controller.
    
  Arguments:
    Dev - UsbIoController device structure.
    
  Returns:
    TRUE/FALSE
--*/
{
  EFI_USB_INTERFACE_DESCRIPTOR  Interface;
  EFI_USB_IO_PROTOCOL           *UsbIo;
  EFI_USB_ENDPOINT_DESCRIPTOR   EndpointDescriptor;
  UINT8                         Index;

  if (Dev == NULL) {
    return FALSE;
  }

  UsbIo = &Dev->UsbIo;

  UsbIo->UsbGetInterfaceDescriptor (
          UsbIo,
          &Interface
          );

  //
  // Check classcode
  //
  if (Interface.InterfaceClass != 0x09) {
    return FALSE;
  }
  
  //
  // Check protocol
  //
  if (Interface.InterfaceProtocol != 0x0) {
    return FALSE;
  }

  for (Index = 0; Index < Interface.NumEndpoints; Index++) {
    UsbIo->UsbGetEndpointDescriptor (
            UsbIo,
            Index,
            &EndpointDescriptor
            );

    if ((EndpointDescriptor.EndpointAddress & 0x80) == 0) {
      continue;
    }

    if (EndpointDescriptor.Attributes != 0x03) {
      continue;
    }

    Dev->HubEndpointAddress = EndpointDescriptor.EndpointAddress;
    return TRUE;
  }

  return FALSE;
}

EFI_STATUS
UsbGetStringtable (
  IN USB_IO_DEVICE     *Dev
  )
/*++
  
  Routine Description:
    Get the string table stored in a usb device.
    
  Arguments:
    Dev     -     UsbIoController device structure.
    
  Returns:
    EFI_SUCCESS
    EFI_UNSUPPORTED
    EFI_OUT_OF_RESOURCES
    
--*/
{
  EFI_STATUS                  Result;
  UINT32                      Status;
  EFI_USB_SUPPORTED_LANGUAGES *LanguageTable;
  UINT8                       *Buffer;
  UINT8                       *ptr;
  UINTN                       Index;
  UINTN                       LangTableSize;
  EFI_USB_IO_PROTOCOL         *UsbIo;
  UINT16                      TempBuffer;

  UsbIo = &(Dev->UsbController[0]->UsbIo);

  //
  // We get first 2 byte of langID table,
  // so we can have the whole table length
  //
  Result = UsbGetString (
            UsbIo,
            0,
            0,
            &TempBuffer,
            2,
            &Status
            );
  if (EFI_ERROR (Result)) {
    return EFI_UNSUPPORTED;
  }

  LanguageTable = (EFI_USB_SUPPORTED_LANGUAGES *) &TempBuffer;

  if (LanguageTable->Length == 0) {
    return EFI_UNSUPPORTED;
  }
  //
  // If length is 2, then there is no string table
  //
  if (LanguageTable->Length == 2) {
    return EFI_UNSUPPORTED;
  }

  Buffer = EfiLibAllocateZeroPool (LanguageTable->Length);
  if (Buffer == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
  
  //
  // Now we get the whole LangID table
  //
  Result = UsbGetString (
            UsbIo,
            0,
            0,
            Buffer,
            LanguageTable->Length,
            &Status
            );
  if (EFI_ERROR (Result)) {
    gBS->FreePool (Buffer);
    return EFI_UNSUPPORTED;
  }

  LanguageTable = (EFI_USB_SUPPORTED_LANGUAGES *) Buffer;

  //
  // ptr point to the LangID table
  //
  ptr           = Buffer + 2;
  LangTableSize = (LanguageTable->Length - 2) / 2;

  for (Index = 0; Index < LangTableSize && Index < USB_MAXLANID; Index++) {
    Dev->LangID[Index] = *((UINT16 *) ptr);
    ptr += 2;
  }

  gBS->FreePool (Buffer);
  LanguageTable = NULL;

  return EFI_SUCCESS;
}


EFI_STATUS
UsbGetAllConfigurations (
  IN USB_IO_DEVICE     *UsbIoDevice
  )
/*++

  Routine Description:
    This function is to parse all the configuration descriptor.
    
  Arguments:
    UsbIoDevice  -  USB_IO_DEVICE device structure.
    
  Returns:
    EFI_SUCCESS
    EFI_DEVICE_ERROR
    EFI_OUT_OF_RESOURCES  

--*/
{
  EFI_STATUS              Result;
  UINT32                  Status;
  UINTN                   Index;
  UINTN                   TotalLength;
  UINT8                   *Buffer;
  CONFIG_DESC_LIST_ENTRY  *ConfigDescEntry;
  EFI_USB_IO_PROTOCOL     *UsbIo;

  InitializeListHead (&UsbIoDevice->ConfigDescListHead);
  UsbIo = &(UsbIoDevice->UsbController[0]->UsbIo);

  for (Index = 0; Index < UsbIoDevice->DeviceDescriptor.NumConfigurations; Index++) {
    ConfigDescEntry = NULL;

    ConfigDescEntry = EfiLibAllocateZeroPool (sizeof (CONFIG_DESC_LIST_ENTRY));
    if (ConfigDescEntry == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }
    //
    // 1st only get 1st 4 bytes config descriptor,
    // so we can know the whole length
    //
    Result = UsbGetDescriptor (
              UsbIo,
              (UINT16) ((USB_DT_CONFIG << 8) | Index),
              0,
              4,
              &ConfigDescEntry->CongfigDescriptor,
              &Status
              );
    if (EFI_ERROR (Result)) {
      DEBUG ((gUSBErrorLevel, "First get config descriptor error\n"));
      gBS->FreePool (ConfigDescEntry);
      return EFI_DEVICE_ERROR;
    }

    TotalLength = ConfigDescEntry->CongfigDescriptor.TotalLength;

    Buffer      = EfiLibAllocateZeroPool (TotalLength);
    if (Buffer == NULL) {
      gBS->FreePool (ConfigDescEntry);
      return EFI_OUT_OF_RESOURCES;
    }
    //
    // Then we get the total descriptors for this configuration
    //
    Result = UsbGetDescriptor (
              UsbIo,
              (UINT16) ((USB_DT_CONFIG << 8) | Index),
              0,
              (UINT16) TotalLength,
              Buffer,
              &Status
              );
    if (EFI_ERROR (Result)) {
      DEBUG ((gUSBErrorLevel, "Get whole config descriptor error\n"));
      gBS->FreePool (ConfigDescEntry);
      gBS->FreePool (Buffer);
      return EFI_DEVICE_ERROR;
    }

    InitializeListHead (&ConfigDescEntry->InterfaceDescListHead);

    //
    // Parse this whole configuration
    //
    Result = ParseThisConfig (ConfigDescEntry, Buffer, TotalLength);

    if (EFI_ERROR (Result)) {
      //
      // Ignore this configuration, parse next one
      //
      gBS->FreePool (ConfigDescEntry);
      gBS->FreePool (Buffer);
      continue;
    }

    InsertTailList (&UsbIoDevice->ConfigDescListHead, &ConfigDescEntry->Link);

    gBS->FreePool (Buffer);

  }

  return EFI_SUCCESS;
}

STATIC
EFI_STATUS
GetExpectedDescriptor (
  IN  UINT8     *Buffer,
  IN  UINTN     Length,
  IN  UINT8     DescType,
  IN  UINT8     DescLength,
  OUT UINTN     *ParsedBytes
  )
/*++
  
  Routine Description:
    Get the start position of next wanted descriptor.
    
  Arguments:
    Buffer      - Buffer to parse
    Length      - Buffer length 
    DescType    - Descriptor type 
    DescLength  - Descriptor length
    ParsedBytes - Parsed Bytes to return
  Returns:
    EFI_SUCCESS
    EFI_DEVICE_ERROR

--*/
{
  UINT16  DescriptorHeader;
  UINT8   Len;
  UINT8   *ptr;
  UINTN   Parsed;

  Parsed  = 0;
  ptr     = Buffer;

  while (TRUE) {
    //
    // Buffer length should not less than Desc length
    //
    if (Length < DescLength) {
      return EFI_DEVICE_ERROR;
    }
    //
    // DescriptorHeader = *((UINT16 *)ptr), compatible with IPF
    //
    DescriptorHeader  = (UINT16) ((*(ptr + 1) << 8) | *ptr);

    Len               = ptr[0];

    //
    // Check to see if it is a start of expected descriptor
    //
    if (DescriptorHeader == ((DescType << 8) | DescLength)) {
      break;
    }

    if ((UINT8) (DescriptorHeader >> 8) == DescType) {
      if (Len > DescLength) {
        return EFI_DEVICE_ERROR;
      }
    }
    //
    // Descriptor length should be at least 2
    // and should not exceed the buffer length
    //
    if (Len < 2) {
      return EFI_DEVICE_ERROR;
    }

    if (Len > Length) {
      return EFI_DEVICE_ERROR;
    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?