From 878ddf1fc3540a715f63594ed22b6929e881afb4 Mon Sep 17 00:00:00 2001 From: bbahnsen Date: Fri, 21 Apr 2006 22:54:32 +0000 Subject: Initial import. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524 --- EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c | 190 ++ EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd | 43 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa | 69 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c | 1088 +++++++++ EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h | 78 + EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c | 154 ++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd | 44 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa | 76 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c | 507 +++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h | 138 ++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c | 825 +++++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c | 2305 ++++++++++++++++++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h | 261 +++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c | 1176 ++++++++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c | 556 +++++ EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h | 94 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c | 1042 +++++++++ .../Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c | 192 ++ EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd | 43 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa | 68 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd | 43 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa | 66 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c | 854 ++++++++ EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h | 70 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c | 215 ++ EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd | 44 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa | 77 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c | 772 +++++++ EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h | 118 + EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c | 1150 ++++++++++ EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h | 106 + .../Bus/Usb/UsbMassStorage/Dxe/ComponentName.c | 154 ++ .../Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c | 727 ++++++ .../Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h | 59 + .../Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd | 43 + .../Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa | 70 + .../Usb/UsbMassStorage/Dxe/UsbMassStorageData.h | 394 ++++ .../Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c | 1653 ++++++++++++++ .../Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h | 111 + EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c | 216 ++ EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd | 43 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa | 71 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml | 47 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c | 395 ++++ EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h | 84 + EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c | 1028 +++++++++ EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h | 85 + 53 files changed, 17926 insertions(+) create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c create mode 100644 EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c create mode 100644 EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c create mode 100644 EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c create mode 100644 EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h (limited to 'EdkModulePkg/Bus/Usb') diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c new file mode 100644 index 0000000000..6a9cf13456 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/ComponentName.c @@ -0,0 +1,190 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "bot.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbBotComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbBotComponentName = { + UsbBotComponentNameGetDriverName, + UsbBotComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbBotDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Bot Mass Storage Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbBotComponentName.SupportedLanguages, + mUsbBotDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbBotComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_BOT_DEVICE *UsbBotDev; + EFI_USB_ATAPI_PROTOCOL *UsbAtapi; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &UsbAtapi, + gUsbBotDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (UsbAtapi); + + return LookupUnicodeString ( + Language, + gUsbBotComponentName.SupportedLanguages, + UsbBotDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd new file mode 100644 index 0000000000..1d18c75266 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.mbd @@ -0,0 +1,43 @@ + + + + + UsbBot + B40612B9-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa new file mode 100644 index 0000000000..c00bebdce5 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/UsbBot.msa @@ -0,0 +1,69 @@ + + + + + UsbBot + DXE_DRIVER + BS_DRIVER + B40612B9-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbBot module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + bot.h + bot.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gUsbBotDriverBinding + gUsbBotComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c new file mode 100644 index 0000000000..0aa0507c2a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.c @@ -0,0 +1,1088 @@ +/*++ + +Copyright (c) 2006, 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: + + BOT.c + +Abstract: + +--*/ + +#include "bot.h" + +// +// Function prototypes +// +EFI_STATUS +EFIAPI +UsbBotDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// Bot Driver Binding Protocol +// +EFI_STATUS +EFIAPI +BotDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +BotDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +BotDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbBotDriverBinding = { + BotDriverBindingSupported, + BotDriverBindingStart, + BotDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// Bot Protocol +// +STATIC +EFI_STATUS +BotCommandPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT32 DataTransferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +BotDataPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +BotStatusPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + OUT UINT8 *TransferStatus, + IN UINT16 Timeout + ); + +// +// USB Atapi protocol prototype +// +STATIC +EFI_STATUS +EFIAPI +BotAtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +BotMassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +VOID +BotReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +STATIC EFI_USB_ATAPI_PROTOCOL BotAtapiProtocol = { + BotAtapiCommand, + BotMassStorageReset, + 0 +}; + +EFI_STATUS +EFIAPI +BotDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Default interface descriptor, now we only + // suppose interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + // + // Check if it is a BOT type Mass Storage Device + // + if ((InterfaceDescriptor.InterfaceClass != 0x08) || + (InterfaceDescriptor.InterfaceProtocol != BOT)) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + +Exit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; +} + +EFI_STATUS +EFIAPI +BotDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle by opening a Block IO and Disk IO + protocol, reading Device Path, and creating a child handle with a + Disk IO and device path protocol. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + EFI_OUT_OF_RESOURCES- Can't allocate the memory resource + other - This driver does not support this device + +--*/ +{ + USB_BOT_DEVICE *UsbBotDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Check if the Controller supports USB IO protocol + // + UsbBotDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + InterfaceDescriptor = AllocateZeroPool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (InterfaceDescriptor == NULL) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + // + // Get the controller interface descriptor, + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (InterfaceDescriptor); + goto ErrorExit; + } + + BotAtapiProtocol.CommandProtocol = InterfaceDescriptor->InterfaceSubClass; + + UsbBotDev = AllocateZeroPool (sizeof (USB_BOT_DEVICE)); + if (UsbBotDev == NULL) { + Status = EFI_OUT_OF_RESOURCES; + gBS->FreePool (InterfaceDescriptor); + goto ErrorExit; + } + + UsbBotDev->Signature = USB_BOT_DEVICE_SIGNATURE; + UsbBotDev->UsbIo = UsbIo; + UsbBotDev->InterfaceDescriptor = InterfaceDescriptor; + CopyMem (&UsbBotDev->UsbAtapiProtocol, &BotAtapiProtocol, sizeof (BotAtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbBotDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + for (Index = 0; Index < InterfaceDescriptor->NumEndpoints; Index++) { + EndpointDescriptor = AllocatePool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (EndpointDescriptor == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if ((EndpointDescriptor->Attributes & 0x03) == 0x02) { + if ((EndpointDescriptor->EndpointAddress & 0x80) != 0) { + UsbBotDev->BulkInEndpointDescriptor = EndpointDescriptor; + } else { + UsbBotDev->BulkOutEndpointDescriptor = EndpointDescriptor; + } + + continue; + } + + gBS->FreePool (EndpointDescriptor); + } + // + // Double check we have these endpoint descriptors + // + if (!(UsbBotDev->BulkInEndpointDescriptor && + UsbBotDev->BulkOutEndpointDescriptor)) { + Status = EFI_DEVICE_ERROR; + goto ErrorExit; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + // + // Install Usb-Atapi Protocol onto the handle + // + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbBotDev->UsbAtapiProtocol + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + UsbBotDev->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbBotComponentName.SupportedLanguages, + &UsbBotDev->ControllerNameTable, + (CHAR16 *) L"Usb Bot Mass Storage" + ); + + return EFI_SUCCESS; + +ErrorExit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + if (UsbBotDev != NULL) { + if (UsbBotDev->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbBotDev->InterfaceDescriptor); + } + + if (UsbBotDev->BulkInEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); + } + + if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); + } + + gBS->FreePool (UsbBotDev); + } + + return Status; +} + +EFI_STATUS +EFIAPI +BotDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - Can't open the gEfiUsbAtapiProtocolGuid protocl + other - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *BotAtapiProtocol; + USB_BOT_DEVICE *UsbBotDev; + + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &BotAtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (BotAtapiProtocol); + + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + UsbIo = UsbBotDev->UsbIo; + + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + // + // Uninstall protocol + // + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbBotDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Free all allocated resources + // + if (UsbBotDev->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbBotDev->InterfaceDescriptor); + } + + if (UsbBotDev->BulkInEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkInEndpointDescriptor); + } + + if (UsbBotDev->BulkOutEndpointDescriptor != NULL) { + gBS->FreePool (UsbBotDev->BulkOutEndpointDescriptor); + } + + if (UsbBotDev->ControllerNameTable) { + FreeUnicodeStringTable (UsbBotDev->ControllerNameTable); + } + + gBS->FreePool (UsbBotDev); + + return Status; +} + +STATIC +EFI_STATUS +BotRecoveryReset ( + IN USB_BOT_DEVICE *UsbBotDev + ) +/*++ + +Routine Description: + + Bot reset routine + +Arguments: + + UsbBotDev - USB_BOT_DEVICE pointer + +Returns: + EFI_SUCCESS - Success the operation + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_DEVICE_REQUEST Request; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + + UsbIo = UsbBotDev->UsbIo; + + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // See BOT specification + // + Request.RequestType = 0x21; + Request.Request = 0xFF; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + &Result + ); + + gBS->Stall (100 * 1000); + + if (!EFI_ERROR (Status)) { + // + // clear bulk in endpoint stall feature + // + EndpointAddr = UsbBotDev->BulkInEndpointDescriptor->EndpointAddress; + + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + // + // clear bulk out endpoint stall feature + // + EndpointAddr = UsbBotDev->BulkOutEndpointDescriptor->EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + return Status; +} +// +// Bot Protocol Implementation +// +STATIC +EFI_STATUS +BotCommandPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT32 DataTransferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Send ATAPI command through BOT interface. + + Parameters: + UsbBotDev - USB_BOT_DEVICE + Command - command packet + CommandSize - Command size + DataTransferLength - Data Transfer Length + Direction - Data IN/OUT/NODATA + Timeout - Time out value in milliseconds + Return Values: + EFI_SUCCESS + Others + +--*/ +{ + CBW cbw; + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINTN DataSize; + + UsbIo = UsbBotDev->UsbIo; + + ZeroMem (&cbw, sizeof (CBW)); + + // + // Fill the command block, detailed see BOT spec + // + cbw.dCBWSignature = CBWSIG; + cbw.dCBWTag = 0x01; + cbw.dCBWDataTransferLength = DataTransferLength; + cbw.bmCBWFlags = (UINT8) (Direction << 7); + cbw.bCBWCBLength = CommandSize; + + CopyMem (cbw.CBWCB, Command, CommandSize); + + DataSize = sizeof (CBW); + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + (UsbBotDev->BulkOutEndpointDescriptor)->EndpointAddress, + &cbw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + // + // Command phase fail, we need to recovery reset this device + // + BotRecoveryReset (UsbBotDev); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +BotDataPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get/Send Data through BOT interface + + Parameters: + UsbBotDev - USB_BOT_DEVICE pointer + DataSize - Data size + DataBuffer - Data buffer pointer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Return Value: + EFI_SUCCESS + Others + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLen; + UINT8 *BufferPtr; + UINTN TransferredSize; + UINTN RetryTimes; + UINTN MaxRetry; + UINTN BlockSize; + UINTN PackageNum; + + UsbIo = UsbBotDev->UsbIo; + Remain = *DataSize; + BufferPtr = (UINT8 *) DataBuffer; + TransferredSize = 0; + MaxRetry = 10; + PackageNum = 15; + + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLen = (UsbBotDev->BulkInEndpointDescriptor)->MaxPacketSize; + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + } else { + MaxPacketLen = (UsbBotDev->BulkOutEndpointDescriptor)->MaxPacketSize; + EndpointAddr = (UsbBotDev->BulkOutEndpointDescriptor)->EndpointAddress; + } + + RetryTimes = MaxRetry; + BlockSize = PackageNum * MaxPacketLen; + while (Remain > 0) { + // + // Using 15 packets to aVOID Bitstuff error + // + if (Remain > PackageNum * MaxPacketLen) { + Increment = BlockSize; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + BufferPtr, + &Increment, + Timeout, + &Result + ); + + TransferredSize += Increment; + + if (EFI_ERROR (Status)) { + RetryTimes--; + if ((RetryTimes == 0) || ((Result & EFI_USB_ERR_TIMEOUT) == 0)) { + goto ErrorExit; + } + + TransferredSize -= Increment; + continue; + } else { + // + // we try MaxTetry times for every bulk transfer + // + RetryTimes = MaxRetry; + } + + BufferPtr += Increment; + Remain -= Increment; + if (Increment < BlockSize && TransferredSize <= *DataSize) { + // + // we get to the end of transter and transter size is + // less than requriedsize + // + break; + } + } + + *DataSize = (UINT32) TransferredSize; + + return EFI_SUCCESS; + +ErrorExit: + if (Direction == EfiUsbDataIn) { + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + BotReportStatusCode ( + UsbBotDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + *DataSize = (UINT32) TransferredSize; + + return Status; + +} + +STATIC +EFI_STATUS +BotStatusPhase ( + IN USB_BOT_DEVICE *UsbBotDev, + OUT UINT8 *TransferStatus, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get transfer status through BOT interface + + Parameters: + UsbBotDev - USB_BOT_DEVICE pointer + TransferStatus - TransferStatus + Timeout - Time out value in milliseconds + Return Value: + EFI_SUCCESS + Others + +--*/ +{ + CSW csw; + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN DataSize; + + UsbIo = UsbBotDev->UsbIo; + + ZeroMem (&csw, sizeof (CSW)); + + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + + DataSize = sizeof (CSW); + + // + // Get the status field from bulk transfer + // + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + &csw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + ZeroMem (&csw, sizeof (CSW)); + + EndpointAddr = (UsbBotDev->BulkInEndpointDescriptor)->EndpointAddress; + + DataSize = sizeof (CSW); + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + &csw, + &DataSize, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + } + + return Status; + } + } + + if (csw.dCSWSignature == CSWSIG) { + *TransferStatus = csw.bCSWStatus; + } else { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} +// +// Usb Atapi Protocol implementation +// +EFI_STATUS +EFIAPI +BotAtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using BOT protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeoutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS BotDataStatus; + UINT8 TransferStatus; + USB_BOT_DEVICE *UsbBotDev; + UINT32 BufferSize; + + BotDataStatus = EFI_SUCCESS; + TransferStatus = 0; + + // + // Get the context + // + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); + + // + // First send ATAPI command through Bot + // + Status = BotCommandPhase ( + UsbBotDev, + Command, + CommandSize, + BufferLength, + Direction, + TimeOutInMilliSeconds + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Send/Get Data if there is a Data Stage + // + switch (Direction) { + + case EfiUsbDataIn: + case EfiUsbDataOut: + BufferSize = BufferLength; + + BotDataStatus = BotDataPhase ( + UsbBotDev, + &BufferSize, + DataBuffer, + Direction, + (UINT16) (TimeOutInMilliSeconds) + ); + + break; + + case EfiUsbNoData: + break; + } + + // + // Status Phase + // + Status = BotStatusPhase ( + UsbBotDev, + &TransferStatus, + TimeOutInMilliSeconds + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (TransferStatus == 0x02) { + // + // Phase error + // + BotRecoveryReset (UsbBotDev); + return EFI_DEVICE_ERROR; + } + + if (TransferStatus == 0x01) { + return EFI_DEVICE_ERROR; + } + + return BotDataStatus; +} + +EFI_STATUS +EFIAPI +BotMassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset Bot Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + USB_BOT_DEVICE *UsbBotDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbBotDev = USB_BOT_DEVICE_FROM_THIS (This); + UsbIo = UsbBotDev->UsbIo; + + if (ExtendedVerification) { + // + // If we need to do strictly reset, reset its parent hub port + // + Status = UsbIo->UsbPortReset (UsbIo); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Status = BotRecoveryReset (UsbBotDev); + + return Status; +} + +VOID +BotReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h new file mode 100644 index 0000000000..575dfbea05 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/bot.h @@ -0,0 +1,78 @@ +/*++ + +Copyright (c) 2006, 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: + + BOT.h + +Abstract: + +--*/ + +#ifndef _BOT_H +#define _BOT_H + + +#include + +#pragma pack(1) +// +// Bulk Only device protocol +// +typedef struct { + UINT32 dCBWSignature; + UINT32 dCBWTag; + UINT32 dCBWDataTransferLength; + UINT8 bmCBWFlags; + UINT8 bCBWLUN; + UINT8 bCBWCBLength; + UINT8 CBWCB[16]; +} CBW; + +typedef struct { + UINT32 dCSWSignature; + UINT32 dCSWTag; + UINT32 dCSWDataResidue; + UINT8 bCSWStatus; +} CSW; + +#pragma pack() + +#define USB_BOT_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'b', 'o', 't') + +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_USB_ATAPI_PROTOCOL UsbAtapiProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpointDescriptor; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_BOT_DEVICE; + +#define USB_BOT_DEVICE_FROM_THIS(a) \ + CR(a, USB_BOT_DEVICE, UsbAtapiProtocol, USB_BOT_DEVICE_SIGNATURE) + +// +// Status code, see Usb Bot device spec +// +#define CSWSIG 0x53425355 +#define CBWSIG 0x43425355 + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbBotDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbBotComponentName; +extern EFI_GUID gUsbBotDriverGuid; + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml new file mode 100644 index 0000000000..aab054b222 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBot/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c new file mode 100644 index 0000000000..347a0003f4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/ComponentName.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "UsbBus.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbBusComponentName = { + UsbBusComponentNameGetDriverName, + UsbBusComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbBusDriverNameTable[] = { + { "eng", (CHAR16 *) L"USB Bus Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +UsbBusComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbBusComponentName.SupportedLanguages, + mUsbBusDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbBusComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle, OPTIONAL + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd new file mode 100644 index 0000000000..4e46c13f97 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.mbd @@ -0,0 +1,44 @@ + + + + + UsbBus + 240612B7-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + UefiDevicePathLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa new file mode 100644 index 0000000000..f035473c61 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/UsbBus.msa @@ -0,0 +1,76 @@ + + + + + UsbBus + DXE_DRIVER + BS_DRIVER + 240612B7-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbBus module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + DevicePathLib + + + UsbBus.h + usbutil.h + hub.h + UsbBus.c + UsbIo.c + usb.c + usbutil.c + Hub.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + UsbIo + UsbHc + DevicePath + + + + + + + gUsbBusDriverBinding + gUsbBusComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml new file mode 100644 index 0000000000..508c7582b3 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c new file mode 100644 index 0000000000..fd9e673b6c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.c @@ -0,0 +1,507 @@ +/*++ + +Copyright (c) 2006, 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: + + Hub.c + + Abstract: + + Usb Hub Request + + Revision History + +--*/ + +#include "usbbus.h" + +EFI_STATUS +HubGetPortStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + OUT UINT32 *PortStatus + ) +/*++ + + Routine Description: + Get a given hub port status + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + PortStatus - Current Hub port status and change status. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_GET_PORT_STATUS_REQ_TYPE; + DevReq.Request = HUB_GET_PORT_STATUS; + DevReq.Value = 0; + DevReq.Index = Port; + DevReq.Length = sizeof (UINT32); + + Timeout = 3000; + + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + PortStatus, + sizeof (UINT32), + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubSetPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set specified feature to a give hub port + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + Value - New feature value. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_SET_PORT_FEATURE_REQ_TYPE; + DevReq.Request = HUB_SET_PORT_FEATURE; + DevReq.Value = Value; + DevReq.Index = Port; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubClearPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ) +/*++ + + Routine Description: + Clear a specified feature of a given hub port + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Port - Usb hub port number (starting from 1). + Value - Feature value that will be cleared from + that hub port. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + EFI_INVALID_PARAMETER + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_CLEAR_FEATURE_PORT_REQ_TYPE; + DevReq.Request = HUB_CLEAR_FEATURE_PORT; + DevReq.Value = Value; + DevReq.Index = Port; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubGetHubStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT32 *HubStatus + ) +/*++ + + Routine Description: + Get Hub Status + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + HubStatus - Current Hub status and change status. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_GET_HUB_STATUS_REQ_TYPE; + DevReq.Request = HUB_GET_HUB_STATUS; + DevReq.Value = 0; + DevReq.Index = 0; + DevReq.Length = sizeof (UINT32); + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + HubStatus, + sizeof (UINT32), + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubSetHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set a specified feature to the hub + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Value - Feature value that will be set to the hub. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_SET_HUB_FEATURE_REQ_TYPE; + DevReq.Request = HUB_SET_HUB_FEATURE; + DevReq.Value = Value; + DevReq.Index = 0; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; +} + +EFI_STATUS +HubClearHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ) +/*++ + + Routine Description: + Set a specified feature to the hub + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + Value - Feature value that will be cleared from the hub. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = HUB_CLEAR_FEATURE_REQ_TYPE; + DevReq.Request = HUB_CLEAR_FEATURE; + DevReq.Value = Value; + DevReq.Index = 0; + DevReq.Length = 0; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + Timeout, + NULL, + 0, + &UsbStatus + ); + + return EfiStatus; + +} + +EFI_STATUS +GetHubDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ) +/*++ + + Routine Description: + Get the hub descriptor + + Arguments: + UsbIo - EFI_USB_IO_PROTOCOL instance + DescriptorSize - The length of Hub Descriptor buffer. + HubDescriptor - Caller allocated buffer to store the hub descriptor + if successfully returned. + + Returns: + EFI_SUCCESS + EFI_DEVICE + EFI_TIME_OUT + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + EFI_STATUS EfiStatus; + UINT32 UsbStatus; + UINT32 Timeout; + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Fill Device request packet + // + DevReq.RequestType = USB_RT_HUB | 0x80; + DevReq.Request = HUB_GET_DESCRIPTOR; + DevReq.Value = USB_DT_HUB << 8; + DevReq.Index = 0; + DevReq.Length = (UINT16) DescriptorSize; + + Timeout = 3000; + EfiStatus = UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbDataIn, + Timeout, + HubDescriptor, + (UINT16) DescriptorSize, + &UsbStatus + ); + + return EfiStatus; + +} + +EFI_STATUS +DoHubConfig ( + IN USB_IO_CONTROLLER_DEVICE *HubController + ) +/*++ + + Routine Description: + Configure the hub + + Arguments: + HubController - Indicating the hub controller device that + will be configured + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_HUB_DESCRIPTOR HubDescriptor; + EFI_STATUS Status; + EFI_USB_HUB_STATUS HubStatus; + UINTN Index; + UINT32 PortStatus; + + UsbIo = &HubController->UsbIo; + + ZeroMem (&HubDescriptor, sizeof (HubDescriptor)); + + // + // First get the hub descriptor length + // + Status = GetHubDescriptor (UsbIo, 2, &HubDescriptor); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // First get the whole descriptor, then + // get the number of hub ports + // + Status = GetHubDescriptor ( + UsbIo, + HubDescriptor.Length, + &HubDescriptor + ); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub descriptor fail\n")); + return EFI_DEVICE_ERROR; + } + + HubController->DownstreamPorts = HubDescriptor.NbrPorts; + + Status = HubGetHubStatus (UsbIo, (UINT32 *) &HubStatus); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub status fail when configure\n")); + return EFI_DEVICE_ERROR; + } + + // + // Get all hub ports status + // + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + + Status = HubGetPortStatus (UsbIo, (UINT8) (Index + 1), &PortStatus); + if (EFI_ERROR (Status)) { + continue; + } + } + // + // Power all the hub ports + // + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + Status = HubSetPortFeature ( + UsbIo, + (UINT8) (Index + 1), + EfiUsbPortPower + ); + if (EFI_ERROR (Status)) { + continue; + } + } + + // + // Clear Hub Status Change + // + Status = HubGetHubStatus (UsbIo, (UINT32 *) &HubStatus); + if (EFI_ERROR (Status)) { + DEBUG ((gUSBErrorLevel, "Get hub status fail\n")); + return EFI_DEVICE_ERROR; + } else { + // + // Hub power supply change happens + // + if (HubStatus.HubChange & HUB_CHANGE_LOCAL_POWER) { + HubClearHubFeature (UsbIo, C_HUB_LOCAL_POWER); + } + // + // Hub change overcurrent happens + // + if (HubStatus.HubChange & HUB_CHANGE_OVERCURRENT) { + HubClearHubFeature (UsbIo, C_HUB_OVER_CURRENT); + } + } + + return EFI_SUCCESS; + +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h new file mode 100644 index 0000000000..4545d71c6a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/hub.h @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) 2006, 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: + + Hub.h + + Abstract: + + Constants definitions for Usb Hub + + Revision History + +--*/ + +#ifndef _HUB_H +#define _HUB_H + +// +// Hub feature numbers +// +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +// +// Hub class code & sub class code +// +#define CLASS_CODE_HUB 0x09 +#define SUB_CLASS_CODE_HUB 0 + +// +// Hub Status & Hub Change bit masks +// +#define HUB_STATUS_LOCAL_POWER 0x0001 +#define HUB_STATUS_OVERCURRENT 0x0002 + +#define HUB_CHANGE_LOCAL_POWER 0x0001 +#define HUB_CHANGE_OVERCURRENT 0x0002 + +// +// Hub Characteristics +// +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 + +// +// Hub specific request +// +#define HUB_CLEAR_FEATURE 0x01 +#define HUB_CLEAR_FEATURE_REQ_TYPE 0x20 + +#define HUB_CLEAR_FEATURE_PORT 0x01 +#define HUB_CLEAR_FEATURE_PORT_REQ_TYPE 0x23 + +#define HUB_GET_BUS_STATE 0x02 +#define HUB_GET_BUS_STATE_REQ_TYPE 0xA3 + +#define HUB_GET_DESCRIPTOR 0x06 +#define HUB_GET_DESCRIPTOR_REQ_TYPE 0xA0 + +#define HUB_GET_HUB_STATUS 0x00 +#define HUB_GET_HUB_STATUS_REQ_TYPE 0xA0 + +#define HUB_GET_PORT_STATUS 0x00 +#define HUB_GET_PORT_STATUS_REQ_TYPE 0xA3 + +#define HUB_SET_DESCRIPTOR 0x07 +#define HUB_SET_DESCRIPTOR_REQ_TYPE 0x20 + +#define HUB_SET_HUB_FEATURE 0x03 +#define HUB_SET_HUB_FEATURE_REQ_TYPE 0x20 + +#define HUB_SET_PORT_FEATURE 0x03 +#define HUB_SET_PORT_FEATURE_REQ_TYPE 0x23 + +#pragma pack(1) +typedef struct usb_hub_status { + UINT16 HubStatus; + UINT16 HubChange; +} EFI_USB_HUB_STATUS; +#pragma pack() + +EFI_STATUS +HubGetPortStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + OUT UINT32 *PortStatus + ); + +EFI_STATUS +HubSetPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ); + +EFI_STATUS +HubSetHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ); + +EFI_STATUS +HubGetHubStatus ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT UINT32 *HubStatus + ); + +EFI_STATUS +HubClearPortFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Port, + IN UINT8 Value + ); + +EFI_STATUS +HubClearHubFeature ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 Value + ); + +EFI_STATUS +GetHubDescriptor ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINTN DescriptorSize, + OUT EFI_USB_HUB_DESCRIPTOR *HubDescriptor + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c new file mode 100644 index 0000000000..474e38829e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usb.c @@ -0,0 +1,825 @@ +/*++ + +Copyright (c) 2006, 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 = AllocateZeroPool (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 = AllocateZeroPool (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 = AllocateZeroPool (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; + } + // + // Skip this mismatch descriptor + // + Length -= Len; + ptr += Len; + Parsed += Len; + } + + *ParsedBytes = Parsed; + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +ParseThisEndpoint ( + IN ENDPOINT_DESC_LIST_ENTRY *EndpointEntry, + IN UINT8 *Buffer, + IN UINTN BufferLength, + OUT UINTN *ParsedBytes + ) +/*++ + + Routine Description: + Get the start position of next wanted endpoint descriptor. + + Arguments: + EndpointEntry - ENDPOINT_DESC_LIST_ENTRY + Buffer - Buffer to parse + BufferLength - Buffer Length + ParsedBytes - Parsed Bytes to return + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + EFI_STATUS Status; + UINTN SkipBytes; + + // + // Skip some data for this interface + // + Status = GetExpectedDescriptor ( + Buffer, + BufferLength, + USB_DT_ENDPOINT, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + *ParsedBytes = SkipBytes; + + CopyMem ( + &EndpointEntry->EndpointDescriptor, + ptr, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) + ); + + *ParsedBytes += sizeof (EFI_USB_ENDPOINT_DESCRIPTOR); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseThisInterface ( + IN INTERFACE_DESC_LIST_ENTRY *InterfaceEntry, + IN UINT8 *Buffer, + IN UINTN *BufferLen, + OUT UINTN *ParsedBytes + ) +/*++ + + Routine Description: + Get the start position of next wanted interface descriptor. + + Arguments: + InterfaceEntry - INTERFACE_DESC_LIST_ENTRY + Buffer - Buffer to parse + BufferLength - Buffer Length + ParsedBytes - Parsed Bytes to return + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + UINTN SkipBytes; + UINTN Index; + UINTN Length; + UINTN Parsed; + ENDPOINT_DESC_LIST_ENTRY *EndpointEntry; + EFI_STATUS Status; + + Parsed = 0; + + // + // Skip some data for this interface + // + Status = GetExpectedDescriptor ( + Buffer, + *BufferLen, + USB_DT_INTERFACE, + sizeof (EFI_USB_INTERFACE_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + *ParsedBytes = SkipBytes; + + // + // Copy the interface descriptor + // + CopyMem ( + &InterfaceEntry->InterfaceDescriptor, + ptr, + sizeof (EFI_USB_INTERFACE_DESCRIPTOR) + ); + + ptr = Buffer + sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + *ParsedBytes += sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + InitializeListHead (&InterfaceEntry->EndpointDescListHead); + + Length = *BufferLen - SkipBytes - sizeof (EFI_USB_INTERFACE_DESCRIPTOR); + + for (Index = 0; Index < InterfaceEntry->InterfaceDescriptor.NumEndpoints; Index++) { + EndpointEntry = AllocateZeroPool (sizeof (ENDPOINT_DESC_LIST_ENTRY)); + if (EndpointEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Parses all the endpoint descriptors within this interface. + // + Status = ParseThisEndpoint (EndpointEntry, ptr, Length, &Parsed); + + if (EFI_ERROR (Status)) { + gBS->FreePool (EndpointEntry); + return Status; + } + + InsertTailList ( + &InterfaceEntry->EndpointDescListHead, + &EndpointEntry->Link + ); + + Length -= Parsed; + ptr += Parsed; + *ParsedBytes += Parsed; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ParseThisConfig ( + IN CONFIG_DESC_LIST_ENTRY *ConfigDescEntry, + IN UINT8 *Buffer, + IN UINTN Length + ) +/*++ + + Routine Description: + Parse the current configuration descriptior. + + Arguments: + ConfigDescEntry - CONFIG_DESC_LIST_ENTRY + Buffer - Buffer to parse + Length - Buffer Length + + Returns + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + UINT8 *ptr; + UINT8 NumInterface; + UINTN Index; + INTERFACE_DESC_LIST_ENTRY *InterfaceEntry; + UINTN SkipBytes; + UINTN Parsed; + EFI_STATUS Status; + UINTN LengthLeft; + + Parsed = 0; + + // + // First skip the current config descriptor; + // + Status = GetExpectedDescriptor ( + Buffer, + Length, + USB_DT_CONFIG, + sizeof (EFI_USB_CONFIG_DESCRIPTOR), + &SkipBytes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + ptr = Buffer + SkipBytes; + + CopyMem ( + &ConfigDescEntry->CongfigDescriptor, + ptr, + sizeof (EFI_USB_CONFIG_DESCRIPTOR) + ); + + NumInterface = ConfigDescEntry->CongfigDescriptor.NumInterfaces; + + // + // Skip size of Configuration Descriptor + // + ptr += sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + LengthLeft = Length - SkipBytes - sizeof (EFI_USB_CONFIG_DESCRIPTOR); + + for (Index = 0; Index < NumInterface; Index++) { + // + // Parse all Interface + // + InterfaceEntry = AllocateZeroPool (sizeof (INTERFACE_DESC_LIST_ENTRY)); + if (InterfaceEntry == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = ParseThisInterface (InterfaceEntry, ptr, &LengthLeft, &Parsed); + if (EFI_ERROR (Status)) { + gBS->FreePool (InterfaceEntry); + return Status; + } + + InsertTailList ( + &ConfigDescEntry->InterfaceDescListHead, + &InterfaceEntry->Link + ); + + // + // Parsed for next interface + // + LengthLeft -= Parsed; + ptr += Parsed; + } + // + // Parse for additional alt setting; + // + return EFI_SUCCESS; +} + +EFI_STATUS +UsbSetConfiguration ( + IN USB_IO_DEVICE *UsbIoDev, + IN UINTN ConfigurationValue + ) +/*++ + + Routine Description: + Set the device to a configuration value. + + Arguments: + UsbIoDev - USB_IO_DEVICE to be set configuration + ConfigrationValue - The configuration value to be set to that device + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + LIST_ENTRY *NextEntry; + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + UINT32 Status; + EFI_STATUS Result; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbIo = &(UsbIoDev->UsbController[0]->UsbIo); + NextEntry = UsbIoDev->ConfigDescListHead.ForwardLink; + + while (NextEntry != &UsbIoDev->ConfigDescListHead) { + // + // Get one entry + // + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + if (ConfigEntry->CongfigDescriptor.ConfigurationValue == ConfigurationValue) { + // + // Find one, set to the active configuration + // + UsbIoDev->ActiveConfig = ConfigEntry; + break; + } + + NextEntry = NextEntry->ForwardLink; + } + // + // Next Entry should not be null + // + Result = UsbSetDeviceConfiguration ( + UsbIo, + (UINT16) ConfigurationValue, + &Status + ); + + return Result; +} + +EFI_STATUS +UsbSetDefaultConfiguration ( + IN USB_IO_DEVICE *UsbIoDev + ) +/*++ + + Routine Description: + Set the device to a default configuration value. + + Arguments: + UsbIoDev - USB_IO_DEVICE to be set configuration + + Returns + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + UINT16 ConfigValue; + LIST_ENTRY *NextEntry; + + if (IsListEmpty (&UsbIoDev->ConfigDescListHead)) { + return EFI_DEVICE_ERROR; + } + + NextEntry = UsbIoDev->ConfigDescListHead.ForwardLink; + + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + ConfigValue = ConfigEntry->CongfigDescriptor.ConfigurationValue; + + return UsbSetConfiguration (UsbIoDev, ConfigValue); +} + +VOID +UsbDestroyAllConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Delete all configuration data when device is not used. + + Arguments: + UsbIoDevice - USB_IO_DEVICE to be set configuration + + Returns: + N/A + +--*/ +{ + CONFIG_DESC_LIST_ENTRY *ConfigEntry; + INTERFACE_DESC_LIST_ENTRY *InterfaceEntry; + ENDPOINT_DESC_LIST_ENTRY *EndpointEntry; + LIST_ENTRY *NextEntry; + + // + // Delete all configuration descriptor data + // + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) UsbIoDevice->ConfigDescListHead.ForwardLink; + + while (ConfigEntry != (CONFIG_DESC_LIST_ENTRY *) &UsbIoDevice->ConfigDescListHead) { + // + // Delete all its interface descriptors + // + InterfaceEntry = (INTERFACE_DESC_LIST_ENTRY *) ConfigEntry->InterfaceDescListHead.ForwardLink; + + while (InterfaceEntry != (INTERFACE_DESC_LIST_ENTRY *) &ConfigEntry->InterfaceDescListHead) { + // + // Delete all its endpoint descriptors + // + EndpointEntry = (ENDPOINT_DESC_LIST_ENTRY *) InterfaceEntry->EndpointDescListHead.ForwardLink; + while (EndpointEntry != (ENDPOINT_DESC_LIST_ENTRY *) &InterfaceEntry->EndpointDescListHead) { + NextEntry = ((LIST_ENTRY *) EndpointEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) EndpointEntry); + gBS->FreePool (EndpointEntry); + EndpointEntry = (ENDPOINT_DESC_LIST_ENTRY *) NextEntry; + } + + NextEntry = ((LIST_ENTRY *) InterfaceEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) InterfaceEntry); + gBS->FreePool (InterfaceEntry); + InterfaceEntry = (INTERFACE_DESC_LIST_ENTRY *) NextEntry; + } + + NextEntry = ((LIST_ENTRY *) ConfigEntry)->ForwardLink; + RemoveEntryList ((LIST_ENTRY *) ConfigEntry); + gBS->FreePool (ConfigEntry); + ConfigEntry = (CONFIG_DESC_LIST_ENTRY *) NextEntry; + } +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c new file mode 100644 index 0000000000..f4ac69e13f --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.c @@ -0,0 +1,2305 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbBus.c + + Abstract: + + USB Bus Driver + + Revision History + +--*/ + +#include "usbbus.h" + +//#ifdef EFI_DEBUG +UINTN gUSBDebugLevel = EFI_D_ERROR; +UINTN gUSBErrorLevel = EFI_D_ERROR; +//#endif +// +// The UsbBusProtocol is just used to locate USB_BUS_CONTROLLER +// structure in the UsbBusDriverControllerDriverStop(). Then we can +// Close all opened protocols and release this structure. +// +STATIC EFI_GUID mUsbBusProtocolGuid = EFI_USB_BUS_PROTOCOL_GUID; + + + +// +// EFI_DRIVER_BINDING_PROTOCOL Protocol Interface +// +EFI_STATUS +EFIAPI +UsbBusControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +EFI_DRIVER_BINDING_PROTOCOL gUsbBusDriverBinding = { + UsbBusControllerDriverSupported, + UsbBusControllerDriverStart, + UsbBusControllerDriverStop, + 0x10, + NULL, + NULL +}; + +// +// Internal use only +// +STATIC +EFI_STATUS +ReportUsbStatusCode ( + IN USB_BUS_CONTROLLER_DEVICE *UsbBusController, + IN EFI_STATUS_CODE_TYPE Type, + IN EFI_STATUS_CODE_VALUE Code + ); + +// +// Supported function +// +VOID +InitializeUsbIoInstance ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ); + +STATIC +USB_IO_CONTROLLER_DEVICE * +CreateUsbIoControllerDevice ( + VOID + ); + +STATIC +EFI_STATUS +InitUsbIoController ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ); + +// +// USB Device Configuration / Deconfiguration +// +STATIC +EFI_STATUS +UsbDeviceConfiguration ( + IN USB_IO_CONTROLLER_DEVICE *ParentHubController, + IN EFI_HANDLE HostController, + IN UINT8 ParentPort, + IN USB_IO_DEVICE *UsbIoDevice + ); + +// +// Usb Bus enumeration function +// +STATIC +VOID +EFIAPI +UsbEnumeration ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +ResetRootPort ( + IN EFI_USB_HC_PROTOCOL *UsbHCInterface, + IN UINT8 PortNum, + IN UINT8 RetryTimes + ); + +EFI_STATUS +ResetHubPort ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN UINT8 PortIndex + ); + +EFI_STATUS +ClearRootPortConnectionChangeStatus ( + IN UINT8 PortNum, + IN EFI_USB_HC_PROTOCOL *UsbHCInterface + ); + +STATIC +EFI_STATUS +ParentPortReset ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN BOOLEAN ReConfigure, + IN UINT8 RetryTimes + ); + +// +// Following are address allocate and free functions +// +STATIC +UINT8 +UsbAllocateAddress ( + IN UINT8 *AddressPool + ) +{ + UINT8 ByteIndex; + UINT8 BitIndex; + + for (ByteIndex = 0; ByteIndex < 16; ByteIndex++) { + for (BitIndex = 0; BitIndex < 8; BitIndex++) { + if ((AddressPool[ByteIndex] & (1 << BitIndex)) == 0) { + // + // Found one, covert to address, and mark it use + // + AddressPool[ByteIndex] |= (1 << BitIndex); + return (UINT8) (ByteIndex * 8 + BitIndex); + } + } + } + + return 0; + +} + +STATIC +VOID +UsbFreeAddress ( + IN UINT8 DevAddress, + IN UINT8 *AddressPool + ) +{ + UINT8 WhichByte; + UINT8 WhichBit; + // + // Locate the position + // + WhichByte = (UINT8) (DevAddress / 8); + WhichBit = (UINT8) (DevAddress & 0x7); + + AddressPool[WhichByte] &= (~(1 << WhichBit)); +} + +EFI_STATUS +EFIAPI +UsbBusControllerDriverSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + + // + // Check whether USB Host Controller Protocol is already + // installed on this handle. If it is installed, we can start + // USB Bus Driver now. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + NULL, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + return OpenStatus; +} + + +EFI_STATUS +EFIAPI +UsbBusControllerDriverStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + + Starting the Usb Bus Driver + + Arguments: + + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - This driver has been started + +--*/ +{ + EFI_STATUS Status; + EFI_STATUS OpenStatus; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + USB_IO_DEVICE *RootHub; + USB_IO_CONTROLLER_DEVICE *RootHubController; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + + // + // Allocate USB_BUS_CONTROLLER_DEVICE structure + // + UsbBusDev = NULL; + UsbBusDev = AllocateZeroPool (sizeof (USB_BUS_CONTROLLER_DEVICE)); + if (UsbBusDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UsbBusDev->Signature = USB_BUS_DEVICE_SIGNATURE; + UsbBusDev->AddressPool[0] = 1; + + // + // Get the Device Path Protocol on Controller's handle + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbBusDev->DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus)) { + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + // + // Locate the Host Controller Interface + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHCInterface, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + + // + // Report Status Code here since we will reset the host controller + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_CONTROLLER_ERROR, + UsbBusDev->DevicePath + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + if (OpenStatus == EFI_ALREADY_STARTED) { + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_ALREADY_STARTED; + } + + UsbBusDev->UsbHCInterface = UsbHCInterface; + + // + // Attach EFI_USB_BUS_PROTOCOL to controller handle, + // for locate UsbBusDev later + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &mUsbBusProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbBusDev->BusIdentify + ); + + if (EFI_ERROR (Status)) { + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return Status; + } + // + // Add root hub to the tree + // + RootHub = NULL; + RootHub = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (RootHub == NULL) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + return EFI_OUT_OF_RESOURCES; + } + + RootHub->BusController = UsbBusDev; + RootHub->DeviceAddress = UsbAllocateAddress (UsbBusDev->AddressPool); + + UsbBusDev->Root = RootHub; + + // + // Allocate Root Hub Controller + // + RootHubController = CreateUsbIoControllerDevice (); + if (RootHubController == NULL) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + gBS->FreePool (UsbBusDev); + gBS->FreePool (RootHub); + return EFI_OUT_OF_RESOURCES; + } + + UsbHCInterface->GetRootHubPortNumber ( + UsbHCInterface, + &RootHubController->DownstreamPorts + ); + RootHubController->UsbDevice = RootHub; + RootHubController->IsUsbHub = TRUE; + RootHubController->DevicePath = UsbBusDev->DevicePath; + RootHubController->HostController = Controller; + + RootHub->NumOfControllers = 1; + RootHub->UsbController[0] = RootHubController; + + // + // Report Status Code here since we will reset the host controller + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_RESET, + UsbBusDev->DevicePath + ); + + // + // Reset USB Host Controller + // + UsbHCInterface->Reset ( + UsbHCInterface, + EFI_USB_HC_RESET_GLOBAL + ); + + // + // Report Status Code while we are going to bring up the Host Controller + // and start bus enumeration + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_ENABLE, + UsbBusDev->DevicePath + ); + + // + // Start USB Host Controller + // + UsbHCInterface->SetState ( + UsbHCInterface, + EfiUsbHcStateOperational + ); + + // + // Create a timer to query root ports periodically + // + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + RootHubController, + &RootHubController->HubNotify + ); + if (EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (RootHubController); + gBS->FreePool (RootHub); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + // + // Before depending on the timer to check root ports periodically, + // here we should check them immediately for the first time, or + // there will be an interval between bus start and devices start. + // + gBS->SignalEvent (RootHubController->HubNotify); + + Status = gBS->SetTimer ( + RootHubController->HubNotify, + TimerPeriodic, + BUSPOLLING_PERIOD + ); + if (EFI_ERROR (Status)) { + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusDev->BusIdentify + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseEvent (RootHubController->HubNotify); + gBS->FreePool (RootHubController); + gBS->FreePool (RootHub); + gBS->FreePool (UsbBusDev); + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} +// +// Stop the bus controller +// +EFI_STATUS +EFIAPI +UsbBusControllerDriverStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_IO_DEVICE *Root; + USB_IO_CONTROLLER_DEVICE *RootHubController; + USB_BUS_CONTROLLER_DEVICE *UsbBusController; + EFI_USB_BUS_PROTOCOL *UsbIdentifier; + UINT8 Index2; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbController; + USB_IO_DEVICE *UsbIoDevice; + USB_IO_CONTROLLER_DEVICE *HubController; + UINTN Index; + EFI_USB_IO_PROTOCOL *UsbIo; + + if (NumberOfChildren > 0) { + + for (Index = 0; Index < NumberOfChildren; Index++) { + Status = gBS->OpenProtocol ( + ChildHandleBuffer[Index], + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // We are here since the handle passed in does not support + // UsbIo protocol. There are several reasons that will cause + // this. + // For combo device such as keyboard, it may have 2 devices + // in one, namely, keyboard and mouse. If we deconfigure one + // of them, the other will be freed at the same time. This will + // cause the status error. But this is the correct behavior. + // For hub device, if we deconfigure hub first, the other chile + // device will be disconnected also, this will also provide us + // a status error. Now we will only report EFI_SUCCESS since Uhc + // driver will be disconnected at the second time.(pls see + // CoreDisconnectController for details) + // + continue; + } + + UsbController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (UsbIo); + UsbIoDevice = UsbController->UsbDevice; + HubController = UsbController->Parent; + UsbDeviceDeConfiguration (UsbIoDevice); + for (Index2 = 0; Index2 < HubController->DownstreamPorts; Index2++) { + if (HubController->Children[Index2] == UsbIoDevice) { + HubController->Children[Index2] = NULL; + } + } + } + + return EFI_SUCCESS; + } + // + // Get the USB_BUS_CONTROLLER_DEVICE + // + Status = gBS->OpenProtocol ( + Controller, + &mUsbBusProtocolGuid, + (VOID **) &UsbIdentifier, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbBusController = USB_BUS_CONTROLLER_DEVICE_FROM_THIS (UsbIdentifier); + + // + // Stop USB Host Controller + // + UsbHCInterface = UsbBusController->UsbHCInterface; + + // + // Report Status Code here since we will reset the host controller + // + ReportUsbStatusCode ( + UsbBusController, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_RESET + ); + + UsbHCInterface->SetState ( + UsbHCInterface, + EfiUsbHcStateHalt + ); + + // + // Deconfiguration all its devices + // + Root = UsbBusController->Root; + RootHubController = Root->UsbController[0]; + + gBS->CloseEvent (RootHubController->HubNotify); + + for (Index2 = 0; Index2 < RootHubController->DownstreamPorts; Index2++) { + if (RootHubController->Children[Index2]) { + UsbDeviceDeConfiguration (RootHubController->Children[Index2]); + RootHubController->Children[Index2] = NULL; + } + } + + gBS->FreePool (RootHubController); + gBS->FreePool (Root); + + // + // Uninstall USB Bus Protocol + // + gBS->UninstallProtocolInterface ( + Controller, + &mUsbBusProtocolGuid, + &UsbBusController->BusIdentify + ); + + // + // Close USB_HC_PROTOCOL & DEVICE_PATH_PROTOCOL + // Opened by this Controller + // + gBS->CloseProtocol ( + Controller, + &gEfiUsbHcProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->CloseProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (UsbBusController); + + return EFI_SUCCESS; +} +// +// USB Device Configuration +// +STATIC +EFI_STATUS +UsbDeviceConfiguration ( + IN USB_IO_CONTROLLER_DEVICE *ParentHubController, + IN EFI_HANDLE HostController, + IN UINT8 ParentPort, + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Configurate a new device attached to the usb bus + + Arguments: + ParentHubController - Parent Hub which this device is connected. + HostController - Host Controller handle + ParentPort - Parent Hub port which this device is connected. + UsbIoDevice - The device to be configured. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINT8 DevAddress; + UINT8 Index; + EFI_STATUS Result; + UINT32 Status; + CHAR16 *StrManufacturer; + CHAR16 *StrProduct; + CHAR16 *StrSerialNumber; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 NumOfInterface; + USB_IO_CONTROLLER_DEVICE *FirstController; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + UsbBusDev = UsbIoDevice->BusController; + // + // Since a USB device must have at least on interface, + // so create this instance first + // + FirstController = CreateUsbIoControllerDevice (); + FirstController->UsbDevice = UsbIoDevice; + UsbIoDevice->UsbController[0] = FirstController; + FirstController->InterfaceNumber = 0; + FirstController->ParentPort = ParentPort; + FirstController->Parent = ParentHubController; + FirstController->HostController = HostController; + + InitializeUsbIoInstance (FirstController); + + DEBUG ((gUSBDebugLevel, "Configuration Usb Device at 0x%x...\n", ParentPort)); + + // + // Ensure we used the correctly USB I/O instance + // + UsbIo = &FirstController->UsbIo; + + // + // First retrieve the 1st 8 bytes of + // in order to get the MaxPacketSize for Endpoint 0 + // + for (Index = 0; Index < 3; Index++) { + + UsbIoDevice->DeviceDescriptor.MaxPacketSize0 = 8; + + ParentPortReset (FirstController, FALSE, Index); + + Result = UsbGetDescriptor ( + UsbIo, + (USB_DT_DEVICE << 8), + 0, + 8, + &UsbIoDevice->DeviceDescriptor, + &Status + ); + if (!EFI_ERROR (Result)) { + DEBUG ((gUSBDebugLevel, + "Get Device Descriptor Success, MaxPacketSize0 = 0x%x\n", + UsbIoDevice->DeviceDescriptor.MaxPacketSize0) + ); + break; + } + + } + + if (Index == 3) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + DEBUG ((gUSBErrorLevel, "Get Device Descriptor Fail when configing\n")); + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + DevAddress = UsbAllocateAddress (UsbIoDevice->BusController->AddressPool); + if (DevAddress == 0) { + DEBUG ((gUSBErrorLevel, "Cannot allocate address\n")); + gBS->FreePool (FirstController); + return EFI_OUT_OF_RESOURCES; + } + + Result = UsbSetDeviceAddress (UsbIo, DevAddress, &Status); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Set address error\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR + ); + + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + UsbIoDevice->DeviceAddress = DevAddress; + + // + // Get the whole device descriptor + // + Result = UsbGetDescriptor ( + UsbIo, + (USB_DT_DEVICE << 8), + 0, + sizeof (EFI_USB_DEVICE_DESCRIPTOR), + &UsbIoDevice->DeviceDescriptor, + &Status + ); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Get whole Device Descriptor error\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + // + // Get & parse all configurations for this device, including + // all configuration descriptors, all interface descriptors, all + // endpoint descriptors + // + Result = UsbGetAllConfigurations (UsbIoDevice); + + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Failed to get device configuration\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_READ_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + // + // Set the 1st configuration value + // + Result = UsbSetDefaultConfiguration (UsbIoDevice); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBErrorLevel, "Failed to set device configuration\n")); + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_WRITE_ERROR + ); + UsbFreeAddress ( + DevAddress, + UsbIoDevice->BusController->AddressPool + ); + + gBS->FreePool (FirstController); + return EFI_DEVICE_ERROR; + } + + UsbIoDevice->IsConfigured = TRUE; + + // + // Get all string table if applicable + // + Result = UsbGetStringtable (UsbIoDevice); + if (EFI_ERROR (Result)) { + DEBUG ((gUSBDebugLevel, "Device doesn't support string table\n")); + } else { + + StrManufacturer = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrManufacturer, + &StrManufacturer + ); + + StrProduct = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrProduct, + &StrProduct + ); + + StrSerialNumber = NULL; + UsbIo->UsbGetStringDescriptor ( + UsbIo, + UsbIoDevice->LangID[0], + (UsbIoDevice->DeviceDescriptor).StrSerialNumber, + &StrSerialNumber + ); + + if (StrManufacturer) { + gBS->FreePool (StrManufacturer); + } + + if (StrProduct) { + gBS->FreePool (StrProduct); + } + + if (StrSerialNumber) { + gBS->FreePool (StrSerialNumber); + } + } + // + // Create USB_IO_CONTROLLER_DEVICE for + // each detected interface + // + FirstController->CurrentConfigValue = + UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue; + + NumOfInterface = + UsbIoDevice->ActiveConfig->CongfigDescriptor.NumInterfaces; + UsbIoDevice->NumOfControllers = NumOfInterface; + + Result = InitUsbIoController (FirstController); + if (EFI_ERROR (Result)) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR + ); + gBS->FreePool (FirstController); + UsbIoDevice->UsbController[0] = NULL; + return EFI_DEVICE_ERROR; + } + + for (Index = 1; Index < NumOfInterface; Index++) { + UsbIoController = CreateUsbIoControllerDevice (); + UsbIoController->UsbDevice = UsbIoDevice; + UsbIoController->CurrentConfigValue = + UsbIoDevice->ActiveConfig->CongfigDescriptor.ConfigurationValue; + UsbIoController->InterfaceNumber = Index; + UsbIoDevice->UsbController[Index] = UsbIoController; + UsbIoController->ParentPort = ParentPort; + UsbIoController->Parent = ParentHubController; + UsbIoController->HostController = HostController; + + // + // First copy the USB_IO Protocol instance + // + CopyMem ( + &UsbIoController->UsbIo, + UsbIo, + sizeof (EFI_USB_IO_PROTOCOL) + ); + + Result = InitUsbIoController (UsbIoController); + if (EFI_ERROR (Result)) { + ReportUsbStatusCode ( + UsbBusDev, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + EFI_IO_BUS_USB | EFI_IOB_EC_INTERFACE_ERROR + ); + gBS->FreePool (UsbIoController); + UsbIoDevice->UsbController[Index] = NULL; + } + } + + return EFI_SUCCESS; +} +// +// USB Device DeConfiguration +// + +EFI_STATUS +UsbDeviceDeConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ) +/*++ + + Routine Description: + Remove Device, Device Handles, Uninstall Protocols. + + Arguments: + UsbIoDevice - The device to be deconfigured. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbController; + UINT8 index; + USB_IO_DEVICE *ChildDevice; + UINT8 Index; + EFI_USB_IO_PROTOCOL *UsbIo; + + DEBUG ((gUSBDebugLevel, "Enter Usb Device Deconfiguration\n")); + + // + // Double check UsbIoDevice exists + // + if (UsbIoDevice == NULL) { + return EFI_SUCCESS; + } + + for (index = 0; index < UsbIoDevice->NumOfControllers; index++) { + // + // Check if it is a hub, if so, de configuration all its + // downstream ports + // + UsbController = UsbIoDevice->UsbController[index]; + + // + // Check the controller pointer + // + if (UsbController == NULL) { + continue; + } + + if (UsbController->IsUsbHub) { + + DEBUG ((gUSBDebugLevel, "Hub Deconfig, First Deconfig its downstream ports\n")); + + // + // First Remove interrupt transfer request for the status + // change port + // + UsbIo = &UsbController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbController->HubEndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + if (NULL != UsbController->HubNotify) { + gBS->CloseEvent (UsbController->HubNotify); + } + + for (Index = 0; Index < UsbController->DownstreamPorts; Index++) { + if (UsbController->Children[Index]) { + ChildDevice = UsbController->Children[Index]; + UsbDeviceDeConfiguration (ChildDevice); + UsbController->Children[Index] = NULL; + } + } + } + // + // If the controller is managed by a device driver, we need to + // disconnect them + // + if (UsbController->IsManagedByDriver) { + gBS->DisconnectController ( + UsbController->Handle, + NULL, + NULL + ); + } + + // + // remove child handle reference to the USB_HC_PROTOCOL + // + gBS->CloseProtocol ( + UsbController->HostController, + &gEfiUsbHcProtocolGuid, + gUsbBusDriverBinding.DriverBindingHandle, + UsbController->Handle + ); + + // + // Uninstall EFI_USB_IO_PROTOCOL & DEVICE_PATH_PROTOCOL + // installed on this handle + // + gBS->UninstallMultipleProtocolInterfaces ( + UsbController->Handle, + &gEfiDevicePathProtocolGuid, + UsbController->DevicePath, + &gEfiUsbIoProtocolGuid, + &UsbController->UsbIo, + NULL + ); + + if (UsbController->DevicePath != NULL) { + gBS->FreePool (UsbController->DevicePath); + } + + gBS->FreePool (UsbController); + UsbIoDevice->UsbController[index] = NULL; + } + // + // Free address for later use + // + UsbFreeAddress ( + UsbIoDevice->DeviceAddress, + UsbIoDevice->BusController->AddressPool + ); + + // + // Free all resouces allocated for all its configurations + // + UsbDestroyAllConfiguration (UsbIoDevice); + + if (UsbIoDevice) { + gBS->FreePool (UsbIoDevice); + UsbIoDevice = NULL; + } + + return EFI_SUCCESS; +} +// +// After interrupt complete, this function will be called, +// This function need to be well-defined later +// +STATIC +EFI_STATUS +EFIAPI +OnHubInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + Whenever hub interrupt occurs, this routine will be called to check + which event happens. + + Arguments: + Data - Hub interrupt transfer data. + DataLength - The length of the Data. + Context - Hub Controller Device. + Result - Hub interrupt transfer status. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *HubController; + UINT8 Index; + UINT8 *ptr; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT32 UsbResult; + BOOLEAN Disconnected; + EFI_STATUS Status; + + HubController = (USB_IO_CONTROLLER_DEVICE *) Context; + UsbIo = &HubController->UsbIo; + + // + // If something error in this interrupt transfer, + // + if (Result != EFI_USB_NOERROR) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + UsbClearEndpointHalt ( + UsbIo, + HubController->HubEndpointAddress, + &UsbResult + ); + } + + // + // Delete & Submit this interrupt again + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + HubController->HubEndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + // + // try to detect if the hub itself was disconnected or not + // + Status = IsDeviceDisconnected ( + HubController, + &Disconnected + ); + + if (!EFI_ERROR (Status) && Disconnected == TRUE) { + DEBUG ((gUSBErrorLevel, "Hub is disconnected\n")); + return EFI_DEVICE_ERROR; + } + // + // Hub ports < 7 + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + HubController->HubEndpointAddress, + TRUE, + 100, + 1, + OnHubInterruptComplete, + HubController + ); + + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + // + // Scan which port has status change + // Bit 0 stands for hub itself, other bit stands for + // the corresponding port + // + for (Index = 0; Index < DataLength * 8; Index++) { + ptr = (UINT8 *) Data + Index / 8; + if ((*ptr) & (1 << (Index & 0x7))) { + HubController->StatusChangePort = Index; + break; + } + } + // + // Signal hub notify event + // + gBS->SignalEvent (HubController->HubNotify); + + return EFI_SUCCESS; +} +// +// USB Root Hub Enumerator +// +STATIC +VOID +EFIAPI +UsbEnumeration ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + This is USB enumerator + + Arguments: + Event - Indicating which event is signaled + Context - actually it is a USB_IO_DEVICE + + Returns: + EFI_SUCCESS + Others + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *HubController; + EFI_USB_PORT_STATUS HubPortStatus; + EFI_STATUS Status; + UINT8 Index; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_DEVICE *UsbIoDev; + USB_BUS_CONTROLLER_DEVICE *UsbBusDev; + EFI_HANDLE HostController; + USB_IO_DEVICE *OldUsbIoDevice; + USB_IO_DEVICE *NewDevice; + USB_IO_CONTROLLER_DEVICE *NewController; + UINT8 Index2; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 StatusChangePort; + + HubController = (USB_IO_CONTROLLER_DEVICE *) Context; + HostController = HubController->HostController; + UsbBusDev = HubController->UsbDevice->BusController; + + if (HubController->UsbDevice->DeviceAddress == 1) { + // + // Root hub has the address 1 + // + UsbIoDev = HubController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + for (Index = 0; Index < HubController->DownstreamPorts; Index++) { + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + if (!IsPortConnectChange (HubPortStatus.PortChangeStatus)) { + continue; + } + // + // Clear root hub status change status + // + ClearRootPortConnectionChangeStatus ( + Index, + UsbHCInterface + ); + + gBS->Stall (100 * 1000); + + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + if (IsPortConnect (HubPortStatus.PortStatus)) { + + // + // There is something connected to this port + // + DEBUG ((gUSBDebugLevel, "Something attached from Root Hub in 0x%x\n", Index)); + + ReportUsbStatusCode ( + UsbBusDev, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG + ); + // + // if there is something physically detached, but still logically + // attached... + // + OldUsbIoDevice = HubController->Children[Index]; + + if (NULL != OldUsbIoDevice) { + UsbDeviceDeConfiguration (OldUsbIoDevice); + HubController->Children[Index] = NULL; + } + + NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (NewDevice == NULL) { + return ; + } + // + // Initialize some fields by copying data from + // its parents + // + NewDevice->IsSlowDevice = IsPortLowSpeedDeviceAttached (HubPortStatus.PortStatus); + + DEBUG ((gUSBDebugLevel, "DeviceSpeed 0x%x\n", NewDevice->IsSlowDevice)); + + NewDevice->BusController = UsbIoDev->BusController; + + // + // Configure that device + // + Status = UsbDeviceConfiguration ( + HubController, + HostController, + Index, + NewDevice + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDevice); + return ; + } + // + // Add this device to the usb bus tree + // + HubController->Children[Index] = NewDevice; + + for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) { + // + // If this device is hub, add to the hub index + // + NewController = NewDevice->UsbController[Index2]; + + Status = gBS->ConnectController ( + NewController->Handle, + NULL, + NULL, + TRUE + ); + // + // If connect success, we need to disconnect when + // stop the controller, otherwise we need not call + // gBS->DisconnectController () + // This is used by those usb devices we don't plan + // to support. We can allocate + // controller handles for them, but we don't have + // device drivers to manage them. + // + NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status)); + + if (IsHub (NewController)) { + + NewController->IsUsbHub = TRUE; + + // + // Configure Hub Controller + // + Status = DoHubConfig (NewController); + if (EFI_ERROR (Status)) { + continue; + } + // + // Create an event to do hub enumeration + // + gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + NewController, + &NewController->HubNotify + ); + + // + // Add request to do query hub status + // change endpoint + // Hub ports < 7 + // + UsbIo = &NewController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + NewController->HubEndpointAddress, + TRUE, + 100, + 1, + OnHubInterruptComplete, + NewController + ); + + } + } + } else { + // + // Something disconnected from USB root hub + // + DEBUG ((gUSBDebugLevel, "Something deteached from Root Hub\n")); + + OldUsbIoDevice = HubController->Children[Index]; + + UsbDeviceDeConfiguration (OldUsbIoDevice); + + HubController->Children[Index] = NULL; + + UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + Index, + EfiUsbPortEnableChange + ); + + UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + Index, + (EFI_USB_PORT_STATUS *) &HubPortStatus + ); + + } + } + + return ; + } else { + // + // Event from Hub, Get the hub controller handle + // + // + // Get the status change endpoint + // + StatusChangePort = HubController->StatusChangePort; + + // + // Clear HubController Status Change Bit + // + HubController->StatusChangePort = 0; + + if (StatusChangePort == 0) { + // + // Hub changes, we don't handle here + // + return ; + } + // + // Check which event took place at that port + // + UsbIo = &HubController->UsbIo; + Status = HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + if (EFI_ERROR (Status)) { + return ; + } + // + // Clear some change status + // + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) { + // + // Clear Hub port enable change + // + DEBUG ((gUSBDebugLevel, "Port Enable Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortEnableChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) { + // + // Clear Hub reset change + // + DEBUG ((gUSBDebugLevel, "Port Reset Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortResetChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_OVERCURRENT) { + // + // Clear Hub overcurrent change + // + DEBUG ((gUSBDebugLevel, "Port Overcurrent Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortOverCurrentChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + } + + if (IsPortConnectChange (HubPortStatus.PortChangeStatus)) { + // + // First clear port connection change + // + DEBUG ((gUSBDebugLevel, "Port Connection Change\n")); + HubClearPortFeature ( + UsbIo, + StatusChangePort, + EfiUsbPortConnectChange + ); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + if (IsPortConnect (HubPortStatus.PortStatus)) { + + DEBUG ((gUSBDebugLevel, "New Device Connect on Hub port \n")); + + ReportUsbStatusCode ( + UsbBusDev, + EFI_PROGRESS_CODE, + EFI_IO_BUS_USB | EFI_IOB_PC_HOTPLUG + ); + + // + // if there is something physically detached, but still logically + // attached... + // + OldUsbIoDevice = HubController->Children[StatusChangePort - 1]; + + if (NULL != OldUsbIoDevice) { + UsbDeviceDeConfiguration (OldUsbIoDevice); + HubController->Children[StatusChangePort - 1] = NULL; + } + + NewDevice = AllocateZeroPool (sizeof (USB_IO_DEVICE)); + if (NewDevice == NULL) { + return ; + } + + ResetHubPort (HubController, StatusChangePort); + + HubGetPortStatus ( + UsbIo, + StatusChangePort, + (UINT32 *) &HubPortStatus + ); + + // + // Initialize some fields + // + NewDevice->IsSlowDevice = IsPortLowSpeedDeviceAttached (HubPortStatus.PortStatus); + + NewDevice->BusController = HubController->UsbDevice->BusController; + + // + // Configure that device + // + Status = UsbDeviceConfiguration ( + HubController, + HostController, + (UINT8) (StatusChangePort - 1), + NewDevice + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (NewDevice); + return ; + } + // + // Add this device to the usb bus tree + // StatusChangePort is begin from 1, + // + HubController->Children[StatusChangePort - 1] = NewDevice; + + for (Index2 = 0; Index2 < NewDevice->NumOfControllers; Index2++) { + // + // If this device is hub, add to the hub index + // + NewController = NewDevice->UsbController[Index2]; + + // + // Connect the controller to the driver image + // + Status = gBS->ConnectController ( + NewController->Handle, + NULL, + NULL, + TRUE + ); + // + // If connect success, we need to disconnect when + // stop the controller, otherwise we need not call + // gBS->DisconnectController () + // This is used by those usb devices we don't plan + // to support. We can allocate + // controller handles for them, but we don't have + // device drivers to manage them. + // + NewController->IsManagedByDriver = (BOOLEAN) (!EFI_ERROR (Status)); + + // + // If this device is hub, add to the hub index + // + if (IsHub (NewController)) { + + NewController->IsUsbHub = TRUE; + + // + // Configure Hub + // + Status = DoHubConfig (NewController); + + if (EFI_ERROR (Status)) { + continue; + } + // + // Create an event to do hub enumeration + // + gBS->CreateEvent ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + UsbEnumeration, + NewController, + &NewController->HubNotify + ); + + // + // Add request to do query hub status + // change endpoint + // + UsbIo = &NewController->UsbIo; + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + NewController->HubEndpointAddress, // Hub endpoint address + TRUE, + 100, + 1, // Hub ports < 7 + OnHubInterruptComplete, + NewController + ); + } + } + } else { + // + // Something disconnected from USB hub + // + DEBUG ((gUSBDebugLevel, "Something Device Detached on Hub port\n")); + + OldUsbIoDevice = HubController->Children[StatusChangePort - 1]; + + UsbDeviceDeConfiguration (OldUsbIoDevice); + + HubController->Children[StatusChangePort - 1] = NULL; + + } + + return ; + } + + return ; + } +} +// +// Clear port connection change status over a given root hub port +// +EFI_STATUS +ClearRootPortConnectionChangeStatus ( + UINT8 PortNum, + EFI_USB_HC_PROTOCOL *UsbHCInterface + ) +/*++ + + Routine Description: + Clear port connection change status over a given root hub port + + Arguments: + PortNum - The given port. + UsbHCInterface - The EFI_USB_HC_PROTOCOL instance. + + Returns: + EFI_SUCCESS + +--*/ +{ + EFI_STATUS Status; + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortConnectChange + ); + return Status; +} + +STATIC +USB_IO_CONTROLLER_DEVICE * +CreateUsbIoControllerDevice ( + VOID + ) +/*++ + + Routine Description: + Allocate a structure for USB_IO_CONTROLLER_DEVICE + + Arguments: + N/A + + Returns: + A pointer to a USB_IO_CONTROLLER_DEVICE structure, + Or NULL. + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoControllerDev; + + // + // Allocate USB_IO_CONTROLLER_DEVICE structure + // + UsbIoControllerDev = NULL; + UsbIoControllerDev = AllocateZeroPool (sizeof (USB_IO_CONTROLLER_DEVICE)); + + if (UsbIoControllerDev == NULL) { + return NULL; + } + + UsbIoControllerDev->Signature = USB_IO_CONTROLLER_SIGNATURE; + + return UsbIoControllerDev; +} + +STATIC +EFI_STATUS +InitUsbIoController ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ) +/*++ + + Routine Description: + Init and install EFI_USB_IO_PROTOCOL onto that controller. + + Arguments: + UsbIoController - The Controller to be operated. + + Returns: + EFI_SUCCESS + Others + +--*/ +{ + USB_DEVICE_PATH UsbNode; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath; + EFI_USB_HC_PROTOCOL *UsbHcProtocol; + + // + // Build the child device path for each new USB_IO device + // + ZeroMem (&UsbNode, sizeof (UsbNode)); + UsbNode.Header.Type = MESSAGING_DEVICE_PATH; + UsbNode.Header.SubType = MSG_USB_DP; + SetDevicePathNodeLength (&UsbNode.Header, sizeof (UsbNode)); + UsbNode.InterfaceNumber = UsbIoController->InterfaceNumber; + UsbNode.ParentPortNumber = UsbIoController->ParentPort; + ParentDevicePath = UsbIoController->Parent->DevicePath; + + UsbIoController->DevicePath = + AppendDevicePathNode (ParentDevicePath, &UsbNode.Header); + if (UsbIoController->DevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = gBS->InstallMultipleProtocolInterfaces ( + &UsbIoController->Handle, + &gEfiDevicePathProtocolGuid, + UsbIoController->DevicePath, + &gEfiUsbIoProtocolGuid, + &UsbIoController->UsbIo, + NULL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->OpenProtocol ( + UsbIoController->HostController, + &gEfiUsbHcProtocolGuid, + (VOID **) &UsbHcProtocol, + gUsbBusDriverBinding.DriverBindingHandle, + UsbIoController->Handle, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + + return Status; +} + +STATIC +EFI_STATUS +ParentPortReset ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN BOOLEAN ReConfigure, + IN UINT8 RetryTimes + ) +/*++ + + Routine Description: + Reset parent hub port to which this device is connected. + + Arguments: + UsbIoController - Indicating the Usb Controller Device. + Reconfigure - Do we need to reconfigure it. + RetryTimes - Retry Times when failed + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *ParentIoDev; + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *ParentController; + UINT8 HubPort; + UINT32 Status; + EFI_STATUS Result; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 Address; + + ParentController = UsbIoController->Parent; + ParentIoDev = ParentController->UsbDevice; + UsbIoDev = UsbIoController->UsbDevice; + HubPort = UsbIoController->ParentPort; + + gBS->Stall (100 * 1000); + + if (ParentIoDev->DeviceAddress == 1) { + DEBUG ((gUSBDebugLevel, "Reset from Root Hub 0x%x\n", HubPort)); + ResetRootPort (ParentIoDev->BusController->UsbHCInterface, HubPort, RetryTimes); + } else { + DEBUG ((gUSBDebugLevel, "Reset from Hub, Addr 0x%x\n", ParentIoDev->DeviceAddress)); + ResetHubPort (ParentController, HubPort + 1); + } + // + // If we only need port reset, just return + // + if (!ReConfigure) { + return EFI_SUCCESS; + } + // + // Re-config that USB device + // + UsbIo = &UsbIoController->UsbIo; + + // + // Assign a unique address to this device + // + Address = UsbIoDev->DeviceAddress; + UsbIoDev->DeviceAddress = 0; + + Result = UsbSetDeviceAddress (UsbIo, Address, &Status); + UsbIoDev->DeviceAddress = Address; + + if (EFI_ERROR (Result)) { + return EFI_DEVICE_ERROR; + } + // + // Set the device to the default configuration + // + Result = UsbSetDefaultConfiguration (UsbIoDev); + if (EFI_ERROR (Result)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +UsbPortReset ( + IN EFI_USB_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Resets and reconfigures the USB controller. This function will + work for all USB devices except USB Hub Controllers. + + Arguments: + This - Indicates the calling context. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + EFI_STATUS Status; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + + // + // Since at this time, this device has already been configured, + // it needs to be re-configured. + // + Status = ParentPortReset (UsbIoController, TRUE, 0); + + return Status; +} + +EFI_STATUS +ResetRootPort ( + IN EFI_USB_HC_PROTOCOL *UsbHCInterface, + IN UINT8 PortNum, + IN UINT8 RetryTimes + ) +/*++ + + Routine Description: + Reset Root Hub port. + + Arguments: + UsbHCInterface - The EFI_USB_HC_PROTOCOL instance. + PortNum - The given port to be reset. + RetryTimes - RetryTimes when failed + Returns: + N/A + +--*/ +{ + EFI_STATUS Status; + + // + // reset root port + // + Status = UsbHCInterface->SetRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->Stall (50 * 1000); + + // + // clear reset root port + // + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortReset + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + gBS->Stall (1000); + + Status = ClearRootPortConnectionChangeStatus (PortNum, UsbHCInterface); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Set port enable + // + Status = UsbHCInterface->SetRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortEnable + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + Status = UsbHCInterface->ClearRootHubPortFeature ( + UsbHCInterface, + PortNum, + EfiUsbPortEnableChange + ); + gBS->Stall ((1 + RetryTimes) * 50 * 1000); + + return EFI_SUCCESS; +} + + +EFI_STATUS +ResetHubPort ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN UINT8 PortIndex + ) +/*++ + + Routine Description: + Reset Hub port. + + Arguments: + UsbIoController - The USB_IO_CONTROLLER_DEVICE instance. + PortIndex - The given port to be reset. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_PORT_STATUS HubPortStatus; + UINT8 Number; + + ASSERT (UsbIoController->IsUsbHub == TRUE); + + UsbIo = &UsbIoController->UsbIo; + + HubSetPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortReset + ); + + gBS->Stall (10 * 1000); + + // + // Wait for port reset complete + // + Number = 10; + do { + HubGetPortStatus ( + UsbIo, + PortIndex, + (UINT32 *) &HubPortStatus + ); + gBS->Stall (10 * 100); + Number -= 1; + } while ((HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) == 0 && Number > 0); + + if (Number == 0) { + // + // Cannot reset port, return error + // + return EFI_DEVICE_ERROR; + } + + gBS->Stall (1000); + + HubGetPortStatus ( + UsbIo, + PortIndex, + (UINT32 *) &HubPortStatus + ); + // + // reset port will cause some bits change, clear them + // + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_ENABLE) { + DEBUG ((gUSBDebugLevel, "Port Enable Change\n")); + HubClearPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortEnableChange + ); + } + + if (HubPortStatus.PortChangeStatus & USB_PORT_STAT_C_RESET) { + DEBUG ((gUSBDebugLevel, "Port Reset Change\n")); + HubClearPortFeature ( + UsbIo, + PortIndex, + EfiUsbPortResetChange + ); + } + + return EFI_SUCCESS; +} + + + + + +STATIC +EFI_STATUS +ReportUsbStatusCode ( + IN USB_BUS_CONTROLLER_DEVICE *UsbBusController, + IN EFI_STATUS_CODE_TYPE Type, + IN EFI_STATUS_CODE_VALUE Code + ) +/*++ + +Routine Description: + + report a error Status code of USB bus driver controller + + Arguments: + UsbBusController - USB_BUS_CONTROLLER_DEVICE + Type - EFI_STATUS_CODE_TYPE + Code - EFI_STATUS_CODE_VALUE + Returns: + + None + +--*/ +{ + return REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + Type, + Code, + UsbBusController->DevicePath + ); +} + + +EFI_STATUS +IsDeviceDisconnected ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN OUT BOOLEAN *Disconnected + ) +/*++ + + Routine Description: + Reset if the device is disconencted or not + + Arguments: + UsbIoController - Indicating the Usb Controller Device. + Disconnected - Indicate whether the device is disconencted or not + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *ParentIoDev; + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *ParentController; + UINT8 HubPort; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_PORT_STATUS PortStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + + ParentController = UsbIoController->Parent; + ParentIoDev = ParentController->UsbDevice; + UsbIoDev = UsbIoController->UsbDevice; + HubPort = UsbIoController->ParentPort; + + if (ParentIoDev->DeviceAddress == 1) { + // + // Connected to the root hub + // + UsbHCInterface = ParentIoDev->BusController->UsbHCInterface; + Status = UsbHCInterface->GetRootHubPortStatus ( + UsbHCInterface, + HubPort, + &PortStatus + ); + + } else { + UsbIo = &UsbIoController->UsbIo; + Status = HubGetPortStatus ( + &ParentController->UsbIo, + HubPort + 1, + (UINT32 *) &PortStatus + ); + + if (EFI_ERROR (Status)) { + return IsDeviceDisconnected (ParentController, Disconnected); + } + } + + *Disconnected = FALSE; + + if (!IsPortConnect (PortStatus.PortStatus)) { + *Disconnected = TRUE; + } + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h new file mode 100644 index 0000000000..b32620342c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbbus.h @@ -0,0 +1,261 @@ +/*++ +Copyright (c) 2006, 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: + + usbbus.h + + Abstract: + + Header file for USB bus driver Interface + + Revision History + + + +--*/ + +#ifndef _EFI_USB_BUS_H +#define _EFI_USB_BUS_H + + +#include +#include "Hub.h" +#include "Usbutil.h" + +//#ifdef EFI_DEBUG +extern UINTN gUSBDebugLevel; +extern UINTN gUSBErrorLevel; +//#endif + +#define MICROSECOND 10000 +#define ONESECOND (1000 * MICROSECOND) +#define BUSPOLLING_PERIOD ONESECOND +// +// We define some maximun value here +// +#define USB_MAXCONFIG 8 +#define USB_MAXALTSETTING 4 +#define USB_MAXINTERFACES 32 +#define USB_MAXENDPOINTS 16 +#define USB_MAXSTRINGS 16 +#define USB_MAXLANID 16 +#define USB_MAXCHILDREN 8 +#define USB_MAXCONTROLLERS 4 + +#define USB_IO_CONTROLLER_SIGNATURE EFI_SIGNATURE_32 ('u', 's', 'b', 'd') + +typedef struct { + LIST_ENTRY Link; + UINT16 StringIndex; + CHAR16 *String; +} STR_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + UINT16 Toggle; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; +} ENDPOINT_DESC_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + LIST_ENTRY EndpointDescListHead; +} INTERFACE_DESC_LIST_ENTRY; + +typedef struct { + LIST_ENTRY Link; + EFI_USB_CONFIG_DESCRIPTOR CongfigDescriptor; + LIST_ENTRY InterfaceDescListHead; + UINTN ActiveInterface; +} CONFIG_DESC_LIST_ENTRY; + +// +// Forward declaring +// +struct usb_io_device; + +// +// This is used to form the USB Controller Handle +// +typedef struct usb_io_controller_device { + UINTN Signature; + EFI_HANDLE Handle; + EFI_USB_IO_PROTOCOL UsbIo; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE HostController; + UINT8 CurrentConfigValue; + UINT8 InterfaceNumber; + struct usb_io_device *UsbDevice; + + BOOLEAN IsUsbHub; + BOOLEAN IsManagedByDriver; + + // + // Fields specified for USB Hub + // + EFI_EVENT HubNotify; + UINT8 HubEndpointAddress; + UINT8 StatusChangePort; + UINT8 DownstreamPorts; + + UINT8 ParentPort; + struct usb_io_controller_device *Parent; + struct usb_io_device *Children[USB_MAXCHILDREN]; +} USB_IO_CONTROLLER_DEVICE; + +#define USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS(a) \ + CR(a, USB_IO_CONTROLLER_DEVICE, UsbIo, USB_IO_CONTROLLER_SIGNATURE) + +// +// This is used to keep the topology of USB bus +// +struct _usb_bus_controller_device; + +typedef struct usb_io_device { + UINT8 DeviceAddress; + BOOLEAN IsConfigured; + BOOLEAN IsSlowDevice; + EFI_USB_DEVICE_DESCRIPTOR DeviceDescriptor; + LIST_ENTRY ConfigDescListHead; + CONFIG_DESC_LIST_ENTRY *ActiveConfig; + UINT16 LangID[USB_MAXLANID]; + + struct _usb_bus_controller_device *BusController; + + // + // Track the controller handle + // + UINT8 NumOfControllers; + USB_IO_CONTROLLER_DEVICE *UsbController[USB_MAXCONTROLLERS]; + +} USB_IO_DEVICE; + +// +// Usb Bus Controller device strcuture +// +#define EFI_USB_BUS_PROTOCOL_GUID \ + { 0x2B2F68CC, 0x0CD2, 0x44cf, { 0x8E, 0x8B, 0xBB, 0xA2, 0x0B, 0x1B, 0x5B, 0x75 } } + +typedef struct _EFI_USB_BUS_PROTOCOL { + UINT64 Reserved; +} EFI_USB_BUS_PROTOCOL; + +#define USB_BUS_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'b', 'u', 's') + +typedef struct _usb_bus_controller_device { + UINTN Signature; + + EFI_USB_BUS_PROTOCOL BusIdentify; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINT8 AddressPool[16]; + USB_IO_DEVICE *Root; +} USB_BUS_CONTROLLER_DEVICE; + +#define USB_BUS_CONTROLLER_DEVICE_FROM_THIS(a) \ + CR(a, USB_BUS_CONTROLLER_DEVICE, BusIdentify, USB_BUS_DEVICE_SIGNATURE) + + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbBusDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbBusComponentName; +extern EFI_GUID gUSBBusDriverGuid; + +// +// Usb Device Configuration functions +// +BOOLEAN +IsHub ( + IN USB_IO_CONTROLLER_DEVICE *Dev + ); + +EFI_STATUS +UsbGetStringtable ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +UsbGetAllConfigurations ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +UsbSetConfiguration ( + IN USB_IO_DEVICE *Dev, + IN UINTN ConfigurationValue + ); + +EFI_STATUS +UsbSetDefaultConfiguration ( + IN USB_IO_DEVICE *Dev + ); + +// +// Device Deconfiguration functions +// +VOID +UsbDestroyAllConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ); + +EFI_STATUS +DoHubConfig ( + IN USB_IO_CONTROLLER_DEVICE *HubIoDevice + ); + +VOID +GetDeviceEndPointMaxPacketLength ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *MaxPacketLength + ); + +VOID +GetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *DataToggle + ); + +VOID +SetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + IN UINT8 DataToggle + ); + +INTERFACE_DESC_LIST_ENTRY * +FindInterfaceListEntry ( + IN EFI_USB_IO_PROTOCOL *This + ); + +ENDPOINT_DESC_LIST_ENTRY * +FindEndPointListEntry ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndPointAddress + ); + + +EFI_STATUS +IsDeviceDisconnected ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController, + IN OUT BOOLEAN *Disconnected + ); + +EFI_STATUS +UsbDeviceDeConfiguration ( + IN USB_IO_DEVICE *UsbIoDevice + ); + + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c new file mode 100644 index 0000000000..bd87c5ca2e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbio.c @@ -0,0 +1,1176 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbIo.c + + Abstract: + + USB I/O Abstraction Driver + + Revision History + +--*/ + +#include "usbbus.h" + +// +// USB I/O Support Function Prototypes +// +STATIC +EFI_STATUS +EFIAPI +UsbControlTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT32 Timeout, + IN OUT VOID *Data, OPTIONAL + IN UINTN DataLength, OPTIONAL + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbBulkTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL * This, + IN UINT8 DeviceEndpoint, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack, OPTIONAL + IN VOID *Context OPTIONAL + ); + +STATIC +EFI_STATUS +EFIAPI +UsbSyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *Status + ); + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL * This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ); + +extern +EFI_STATUS +EFIAPI +UsbPortReset ( + IN EFI_USB_IO_PROTOCOL *This + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetDeviceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_DEVICE_DESCRIPTOR *DeviceDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetActiveConfigDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_CONFIG_DESCRIPTOR *ConfigurationDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetStringDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 LangID, + IN UINT8 StringIndex, + OUT CHAR16 **String + ); + +STATIC +EFI_STATUS +EFIAPI +UsbGetSupportedLanguages ( + IN EFI_USB_IO_PROTOCOL *This, + OUT UINT16 **LangIDTable, + OUT UINT16 *TableSize + ); + +// +// USB I/O Interface structure +// +STATIC EFI_USB_IO_PROTOCOL UsbIoInterface = { + UsbControlTransfer, + UsbBulkTransfer, + UsbAsyncInterruptTransfer, + UsbSyncInterruptTransfer, + UsbIsochronousTransfer, + UsbAsyncIsochronousTransfer, + UsbGetDeviceDescriptor, + UsbGetActiveConfigDescriptor, + UsbGetInterfaceDescriptor, + UsbGetEndpointDescriptor, + UsbGetStringDescriptor, + UsbGetSupportedLanguages, + UsbPortReset +}; + +VOID +InitializeUsbIoInstance ( + IN USB_IO_CONTROLLER_DEVICE *UsbIoController + ) +{ + // + // Copy EFI_USB_IO protocol instance + // + CopyMem ( + &UsbIoController->UsbIo, + &UsbIoInterface, + sizeof (EFI_USB_IO_PROTOCOL) + ); +} +// +// Implementation +// +STATIC +EFI_STATUS +EFIAPI +UsbControlTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN EFI_USB_DEVICE_REQUEST *Request, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT32 Timeout, + IN OUT VOID *Data, OPTIONAL + IN UINTN DataLength, OPTIONAL + OUT UINT32 *Status + ) +/*++ + + Routine Description: + This function is used to manage a USB device with a control transfer pipe. + + Arguments: + This - Indicates calling context. + Request - A pointer to the USB device request that will be sent to + the USB device. + Direction - Indicates the data direction. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + Timeout - Indicates the transfer should be completed within this time + frame. + DataLength - The size, in bytes, of the data buffer specified by Data. + Status - A pointer to the result of the USB transfer. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_STATUS RetStatus; + USB_IO_DEVICE *UsbIoDevice; + UINT8 MaxPacketLength; + UINT32 TransferResult; + BOOLEAN Disconnected; + // + // Parameters Checking + // + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's ControlTransfer + // to perform other parameters checking + // + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDevice = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDevice->BusController->UsbHCInterface; + MaxPacketLength = UsbIoDevice->DeviceDescriptor.MaxPacketSize0; + + + if (Request->Request == USB_DEV_CLEAR_FEATURE && + Request->RequestType == 0x02 && + Request->Value == EfiUsbEndpointHalt) { + // + //Reduce the remove delay time for system response + // + IsDeviceDisconnected (UsbIoController, &Disconnected); + if (!EFI_ERROR (Status) && Disconnected == TRUE) { + DEBUG ((gUSBErrorLevel, "Device is disconnected when trying reset\n")); + return EFI_DEVICE_ERROR; + } + } + + + + // + // using HostController's ControlTransfer to complete the request + // + RetStatus = UsbHCInterface->ControlTransfer ( + UsbHCInterface, + UsbIoDevice->DeviceAddress, + UsbIoDevice->IsSlowDevice, + MaxPacketLength, + Request, + Direction, + Data, + &DataLength, + (UINTN) Timeout, + &TransferResult + ); + *Status = TransferResult; + + if (Request->Request == USB_DEV_CLEAR_FEATURE && + Request->RequestType == 0x02 && + Request->Value == EfiUsbEndpointHalt) { + // + // This is a UsbClearEndpointHalt request + // Need to clear data toggle + // Request.Index == EndpointAddress + // + if (!EFI_ERROR (RetStatus) && TransferResult == EFI_USB_NOERROR) { + SetDataToggleBit ( + This, + (UINT8) Request->Index, + 0 + ); + } + } + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbBulkTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + This function is used to manage a USB device with the bulk transfer pipe. + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the device + request is being sent. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength - On input, the size, in bytes, of the data buffer + specified by Data. On output, the number of bytes that + were actually transferred. + Timeout - Indicates the transfer should be completed within this + time frame. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_STATUS RetStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + UINT32 TransferResult; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + // + // Parameters Checking + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + EndPointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndPointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndPointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x02) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's BulkTransfer + // to perform other parameters checking + // + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + OldToggle = DataToggle; + + // + // using HostController's BulkTransfer to complete the request + // + RetStatus = UsbHCInterface->BulkTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + &TransferResult + ); + + if (OldToggle != DataToggle) { + // + // Write the toggle back + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + } + + *Status = TransferResult; + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbSyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN OUT UINTN *DataLength, + IN UINTN Timeout, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + Usb Sync Interrupt Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the device + request is being sent. + Data - A pointer to the buffer of data that will be transmitted + to USB device or received from USB device. + DataLength - On input, the size, in bytes, of the data buffer + specified by Data. On output, the number of bytes that + were actually transferred. + Timeout - Indicates the transfer should be completed within this + time frame. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + UINT8 OldToggle; + EFI_STATUS RetStatus; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + + // + // Parameters Checking + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + if (Status == NULL) { + return EFI_INVALID_PARAMETER; + } + + EndPointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndPointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndPointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x03) { + return EFI_INVALID_PARAMETER; + } + + // + // leave the HostController's SyncInterruptTransfer + // to perform other parameters checking + // + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + OldToggle = DataToggle; + // + // using HostController's SyncInterruptTransfer to complete the request + // + RetStatus = UsbHCInterface->SyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + MaxPacketLength, + Data, + DataLength, + &DataToggle, + Timeout, + Status + ); + + if (OldToggle != DataToggle) { + // + // Write the toggle back + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + } + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncInterruptTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN BOOLEAN IsNewTransfer, + IN UINTN PollingInterval, OPTIONAL + IN UINTN DataLength, OPTIONAL + IN EFI_ASYNC_USB_TRANSFER_CALLBACK InterruptCallBack, OPTIONAL + IN VOID *Context OPTIONAL + ) +/*++ + + Routine Description: + Usb Async Interrput Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the + device request is being sent. + IsNewTransfer - If TRUE, a new transfer will be submitted to USB + controller. If FALSE, the interrupt transfer is + deleted from the device's interrupt transfer queue. + PollingInterval - Indicates the periodic rate, in milliseconds, that + the transfer is to be executed. + DataLength - Specifies the length, in bytes, of the data to be + received from the USB device. + InterruptCallback - The Callback function. This function is called if + the asynchronous interrupt transfer is completed. + Context - Passed to InterruptCallback + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + UINT8 MaxPacketLength; + UINT8 DataToggle; + EFI_USB_HC_PROTOCOL *UsbHCInterface; + EFI_STATUS RetStatus; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + // + // Check endpoint + // + if ((DeviceEndpoint & 0x7F) == 0) { + return EFI_INVALID_PARAMETER; + } + + if ((DeviceEndpoint & 0x7F) > 15) { + return EFI_INVALID_PARAMETER; + } + + EndpointListEntry = FindEndPointListEntry ( + This, + DeviceEndpoint + ); + + if (EndpointListEntry == NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((EndpointListEntry->EndpointDescriptor.Attributes & 0x03) != 0x03) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + UsbHCInterface = UsbIoDev->BusController->UsbHCInterface; + + if (!IsNewTransfer) { + // + // Delete this transfer + // + UsbHCInterface->AsyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + 0, + FALSE, + &DataToggle, + PollingInterval, + DataLength, + NULL, + NULL + ); + + // + // We need to store the toggle value + // + SetDataToggleBit ( + This, + DeviceEndpoint, + DataToggle + ); + + return EFI_SUCCESS; + } + + GetDeviceEndPointMaxPacketLength ( + This, + DeviceEndpoint, + &MaxPacketLength + ); + + GetDataToggleBit ( + This, + DeviceEndpoint, + &DataToggle + ); + + RetStatus = UsbHCInterface->AsyncInterruptTransfer ( + UsbHCInterface, + UsbIoDev->DeviceAddress, + DeviceEndpoint, + UsbIoDev->IsSlowDevice, + MaxPacketLength, + TRUE, + &DataToggle, + PollingInterval, + DataLength, + InterruptCallBack, + Context + ); + + return RetStatus; +} + +STATIC +EFI_STATUS +EFIAPI +UsbIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + OUT UINT32 *Status + ) +/*++ + + Routine Description: + Usb Isochronous Transfer + + Arguments: + This - Indicates calling context. + DeviceEndpoint - The destination USB device endpoint to which the + device request is being sent. + Data - A pointer to the buffer of data that will be + transmitted to USB device or received from USB device. + DataLength - The size, in bytes, of the data buffer specified by + Data. + Status - This parameter indicates the USB transfer status. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_OUT_OF_RESOURCES + EFI_TIMEOUT + EFI_DEVICE_ERROR + EFI_UNSUPPORTED +--*/ +{ + // + // Currently we don't support this transfer + // + return EFI_UNSUPPORTED; +} + +STATIC +EFI_STATUS +EFIAPI +UsbAsyncIsochronousTransfer ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 DeviceEndpoint, + IN OUT VOID *Data, + IN UINTN DataLength, + IN EFI_ASYNC_USB_TRANSFER_CALLBACK IsochronousCallBack, + IN VOID *Context OPTIONAL + ) +/*++ + +Routine Description: + + Usb Async Isochronous Transfer + +Arguments: + + This - EFI_USB_IO_PROTOCOL + DeviceEndpoint - DeviceEndpoint number + Data - Data to transfer + DataLength - DataLength + IsochronousCallBack - Isochronous CallBack function + Context - Passed to IsochronousCallBack function +Returns: + + EFI_UNSUPPORTED - Unsupported now + +--*/ +{ + // + // Currently we don't support this transfer + // + return EFI_UNSUPPORTED; +} +// +// Here is new definitions +// +STATIC +EFI_STATUS +EFIAPI +UsbGetDeviceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_DEVICE_DESCRIPTOR *DeviceDescriptor + ) +/*++ + + Routine Description: + Retrieves the USB Device Descriptor. + + Arguments: + This - Indicates the calling context. + DeviceDescriptor - A pointer to the caller allocated USB Device + Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + USB_IO_DEVICE *UsbIoDev; + + // + // This function just wrapps UsbGetDeviceDescriptor. + // + + if (DeviceDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return EFI_NOT_FOUND; + } + + CopyMem ( + DeviceDescriptor, + &UsbIoDev->DeviceDescriptor, + sizeof (EFI_USB_DEVICE_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetActiveConfigDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_CONFIG_DESCRIPTOR *ConfigurationDescriptor + ) +/*++ + + Routine Description: + Retrieves the current USB configuration Descriptor. + + Arguments: + This - Indicates the calling context. + ConfigurationDescriptor - A pointer to the caller allocated USB active + Configuration Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + // + // This function just wrapps UsbGetActiveConfigDescriptor. + // + if (ConfigurationDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return EFI_NOT_FOUND; + } + + CopyMem ( + ConfigurationDescriptor, + &(UsbIoDev->ActiveConfig->CongfigDescriptor), + sizeof (EFI_USB_CONFIG_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetInterfaceDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + OUT EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor + ) +/*++ + + Routine Description: + Retrieves the interface Descriptor for that controller. + + Arguments: + This - Indicates the calling context. + InterfaceDescriptor - A pointer to the caller allocated USB interface + Descriptor. + + Returns: + EFI_SUCCESS + EFI_INVALID_PARAMETER + EFI_NOT_FOUND + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + + if (InterfaceDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + InterfaceListEntry = FindInterfaceListEntry (This); + + if (InterfaceListEntry == NULL) { + return EFI_NOT_FOUND; + } + + CopyMem ( + InterfaceDescriptor, + &(InterfaceListEntry->InterfaceDescriptor), + sizeof (EFI_USB_INTERFACE_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetEndpointDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndpointIndex, + OUT EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor + ) +/*++ + + Routine Description: + Retrieves the endpoint Descriptor for a given endpoint. + + Arguments: + This - Indicates the calling context. + EndpointIndex - Indicates which endpoint descriptor to retrieve. + The valid range is 0..15. + EndpointDescriptor - A pointer to the caller allocated USB Endpoint + Descriptor of a USB controller. + + Returns: + EFI_SUCCESS - The endpoint descriptor was retrieved successfully. + EFI_INVALID_PARAMETER - EndpointIndex is not valid. + - EndpointDescriptor is NULL. + EFI_NOT_FOUND - The endpoint descriptor cannot be found. + The device may not be correctly configured. + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + LIST_ENTRY *EndpointListHead; + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + if (EndpointDescriptor == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (EndpointIndex > 15) { + return EFI_INVALID_PARAMETER; + } + + InterfaceListEntry = FindInterfaceListEntry (This); + + if (InterfaceListEntry == NULL) { + return EFI_NOT_FOUND; + } + + EndpointListHead = (LIST_ENTRY *) (&InterfaceListEntry->EndpointDescListHead); + EndpointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointListHead->ForwardLink); + + if (EndpointIndex >= InterfaceListEntry->InterfaceDescriptor.NumEndpoints) { + return EFI_NOT_FOUND; + } + // + // Loop all endpoint descriptor to get match one. + // + while (EndpointIndex != 0) { + EndpointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointListEntry->Link.ForwardLink); + EndpointIndex--; + } + + CopyMem ( + EndpointDescriptor, + &EndpointListEntry->EndpointDescriptor, + sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetSupportedLanguages ( + IN EFI_USB_IO_PROTOCOL *This, + OUT UINT16 **LangIDTable, + OUT UINT16 *TableSize + ) +/*++ + + Routine Description: + Get all the languages that the USB device supports + + Arguments: + This - Indicates the calling context. + LangIDTable - Language ID for the string the caller wants to get. + TableSize - The size, in bytes, of the table LangIDTable. + + Returns: + EFI_SUCCESS + EFI_NOT_FOUND + +--*/ +{ + USB_IO_DEVICE *UsbIoDev; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + UINTN Index; + BOOLEAN Found; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + Found = FALSE; + Index = 0; + // + // Loop language table + // + while (UsbIoDev->LangID[Index]) { + Found = TRUE; + Index++; + } + + if (!Found) { + return EFI_NOT_FOUND; + } + + *LangIDTable = UsbIoDev->LangID; + *TableSize = (UINT16) Index; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbGetStringDescriptor ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT16 LangID, + IN UINT8 StringIndex, + OUT CHAR16 **String + ) +/*++ + + Routine Description: + Get a given string descriptor + + Arguments: + This - Indicates the calling context. + LangID - The Language ID for the string being retrieved. + StringIndex - The ID of the string being retrieved. + String - A pointer to a buffer allocated by this function + with AllocatePool() to store the string. If this + function returns EFI_SUCCESS, it stores the string + the caller wants to get. The caller should release + the string buffer with FreePool() after the string + is not used any more. + Returns: + EFI_SUCCESS + EFI_NOT_FOUND + EFI_OUT_OF_RESOURCES + +--*/ +{ + UINT32 Status; + EFI_STATUS Result; + EFI_USB_STRING_DESCRIPTOR *StrDescriptor; + UINT8 *Buffer; + CHAR16 *UsbString; + UINT16 TempBuffer; + USB_IO_DEVICE *UsbIoDev; + UINT8 Index; + BOOLEAN Found; + USB_IO_CONTROLLER_DEVICE *UsbIoController; + + if (StringIndex == 0) { + return EFI_NOT_FOUND; + } + // + // Search LanguageID, check if it is supported by this device + // + if (LangID == 0) { + return EFI_NOT_FOUND; + } + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + Found = FALSE; + Index = 0; + while (UsbIoDev->LangID[Index]) { + if (UsbIoDev->LangID[Index] == LangID) { + Found = TRUE; + break; + } + + Index++; + } + + if (!Found) { + return EFI_NOT_FOUND; + } + // + // Get String Length + // + Result = UsbGetString ( + This, + LangID, + StringIndex, + &TempBuffer, + 2, + &Status + ); + if (EFI_ERROR (Result)) { + return EFI_NOT_FOUND; + } + + StrDescriptor = (EFI_USB_STRING_DESCRIPTOR *) &TempBuffer; + + if (StrDescriptor->Length == 0) { + return EFI_UNSUPPORTED; + } + + Buffer = AllocateZeroPool (StrDescriptor->Length); + if (Buffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Result = UsbGetString ( + This, + LangID, + StringIndex, + Buffer, + StrDescriptor->Length, + &Status + ); + + if (EFI_ERROR (Result)) { + gBS->FreePool (Buffer); + return EFI_NOT_FOUND; + } + + StrDescriptor = (EFI_USB_STRING_DESCRIPTOR *) Buffer; + + // + // UsbString is a UNICODE string + // + UsbString = AllocateZeroPool (StrDescriptor->Length); + if (UsbString == NULL) { + gBS->FreePool (Buffer); + return EFI_OUT_OF_RESOURCES; + } + + CopyMem ( + (VOID *) UsbString, + Buffer + 2, + StrDescriptor->Length - 2 + ); + + *String = UsbString; + + gBS->FreePool (Buffer); + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c new file mode 100644 index 0000000000..07eb5805e9 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.c @@ -0,0 +1,556 @@ +/*++ + +Copyright (c) 2006, 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: + usbutil.c + + Abstract: + + Helper functions for USB + + Revision History + +--*/ + +#include "usbbus.h" + +// +// Following APIs are used to query Port Status +// +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if there is a device connected to that port according to + the Port Status. + + Parameters: + PortStatus - The status value of that port. + + Return Value: + TRUE + FALSE + +--*/ +{ + // + // return the bit 0 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortEnable ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if Port is enabled. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE - Port is enable + FALSE - Port is disable + +--*/ +{ + // + // return the bit 1 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_ENABLE) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortInReset ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the port is being reset. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 4 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_RESET) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortPowerApplied ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if there is power applied to that port. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 8 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_POWER) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the connected device is a low device. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 9 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_LOW_SPEED) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortSuspend ( + IN UINT16 PortStatus + ) +/*++ + + Routine Description: + Tell if the port is suspend. + + Arguments: + PortStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 2 value of PortStatus + // + if ((PortStatus & USB_PORT_STAT_SUSPEND) != 0) { + return TRUE; + } else { + return FALSE; + } +} +// +// Following APIs are used to query Port Change Status +// +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Connect Change status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 0 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_CONNECTION) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortEnableDisableChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Enable/Disable change in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 1 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_ENABLE) != 0) { + return TRUE; + } else { + return FALSE; + } +} + +BOOLEAN +IsPortResetChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Port Reset Change status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 4 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_RESET) != 0) { + return TRUE; + } else { + return FALSE; + } +} + + +BOOLEAN +IsPortSuspendChange ( + IN UINT16 PortChangeStatus + ) +/*++ + + Routine Description: + Tell if there is a Suspend Change Status in that port. + + Arguments: + PortChangeStatus - The status value of that port. + + Returns: + TRUE + FALSE + +--*/ +{ + // + // return the bit 2 value of PortChangeStatus + // + if ((PortChangeStatus & USB_PORT_STAT_C_SUSPEND) != 0) { + return TRUE; + } else { + return FALSE; + } +} + + +INTERFACE_DESC_LIST_ENTRY* +FindInterfaceListEntry ( + IN EFI_USB_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Find Interface ListEntry. + + Arguments: + This - EFI_USB_IO_PROTOCOL + + Returns: + INTERFACE_DESC_LIST_ENTRY pointer + +--*/ +{ + USB_IO_CONTROLLER_DEVICE *UsbIoController; + USB_IO_DEVICE *UsbIoDev; + LIST_ENTRY *InterfaceListHead; + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + + UsbIoController = USB_IO_CONTROLLER_DEVICE_FROM_USB_IO_THIS (This); + UsbIoDev = UsbIoController->UsbDevice; + + if (!UsbIoDev->IsConfigured) { + return NULL; + } + + InterfaceListHead = &UsbIoDev->ActiveConfig->InterfaceDescListHead; + InterfaceListEntry = (INTERFACE_DESC_LIST_ENTRY *) (InterfaceListHead->ForwardLink); + + // + // Loop all interface descriptor to get match one. + // + while (InterfaceListEntry != (INTERFACE_DESC_LIST_ENTRY *) InterfaceListHead) { + if (InterfaceListEntry->InterfaceDescriptor.InterfaceNumber == UsbIoController->InterfaceNumber) { + return InterfaceListEntry; + } + + InterfaceListEntry = (INTERFACE_DESC_LIST_ENTRY *) InterfaceListEntry->Link.ForwardLink; + } + + return NULL; +} + +ENDPOINT_DESC_LIST_ENTRY* +FindEndPointListEntry ( + IN EFI_USB_IO_PROTOCOL *This, + IN UINT8 EndPointAddress + ) +/*++ + + Routine Description: + Find EndPoint ListEntry. + + Arguments: + This - EFI_USB_IO_PROTOCOL + EndpointAddr - Endpoint address. + + Returns: + ENDPOINT_DESC_LIST_ENTRY pointer + +--*/ +{ + INTERFACE_DESC_LIST_ENTRY *InterfaceListEntry; + LIST_ENTRY *EndpointDescListHead; + ENDPOINT_DESC_LIST_ENTRY *EndPointListEntry; + + InterfaceListEntry = FindInterfaceListEntry (This); + if (InterfaceListEntry != NULL) { + EndpointDescListHead = &InterfaceListEntry->EndpointDescListHead; + EndPointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) (EndpointDescListHead->ForwardLink); + + // + // Loop all interface descriptor to get match one. + // + while (EndPointListEntry != (ENDPOINT_DESC_LIST_ENTRY *) EndpointDescListHead) { + if (EndPointListEntry->EndpointDescriptor.EndpointAddress == EndPointAddress) { + return EndPointListEntry; + } + + EndPointListEntry = (ENDPOINT_DESC_LIST_ENTRY *) EndPointListEntry->Link.ForwardLink; + } + } + + return NULL; +} + +VOID +GetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *DataToggle + ) +/*++ + + Routine Description: + Get the datatoggle of a specified endpoint. + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + DataToggle - The current data toggle of that endpoint + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + *DataToggle = 0; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + *DataToggle = (UINT8) (EndpointListEntry->Toggle); + return ; +} + +VOID +SetDataToggleBit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + IN UINT8 DataToggle + ) +/*++ + + Routine Description: + Set the datatoggle of a specified endpoint + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + DataToggle - The current data toggle of that endpoint to be set + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + EndpointListEntry->Toggle = DataToggle; + return ; +} + +VOID +GetDeviceEndPointMaxPacketLength ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT8 EndpointAddr, + OUT UINT8 *MaxPacketLength + ) +/*++ + + Routine Description: + Get the Max Packet Length of the speified Endpoint. + + Arguments: + UsbIo - Given Usb Controller device. + EndpointAddr - Given Endpoint address. + MaxPacketLength - The max packet length of that endpoint + + Returns: + N/A + +--*/ +{ + + ENDPOINT_DESC_LIST_ENTRY *EndpointListEntry; + + *MaxPacketLength = 0; + + EndpointListEntry = FindEndPointListEntry (UsbIo, EndpointAddr); + if (EndpointListEntry == NULL) { + return ; + } + + *MaxPacketLength = (UINT8) (EndpointListEntry->EndpointDescriptor.MaxPacketSize); + + return ; +} + + +EFI_STATUS +UsbSetDeviceAddress ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 AddressValue, + OUT UINT32 *Status + ) +/*++ + +Routine Description: + + Usb Set Device Address + +Arguments: + + UsbIo - EFI_USB_IO_PROTOCOL + AddressValue - Device address + Status - Transfer status + +Returns: + + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_TIMEOUT - Device has no response + + +--*/ +{ + EFI_USB_DEVICE_REQUEST DevReq; + + if (UsbIo == NULL) { + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST)); + + DevReq.RequestType = USB_DEV_SET_ADDRESS_REQ_TYPE; + DevReq.Request = USB_DEV_SET_ADDRESS; + DevReq.Value = AddressValue; + + return UsbIo->UsbControlTransfer ( + UsbIo, + &DevReq, + EfiUsbNoData, + TIMEOUT_VALUE, + NULL, + 0, + Status + ); +} + diff --git a/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h new file mode 100644 index 0000000000..259276cbaf --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbBus/Dxe/usbutil.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 2006, 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: + usbutil.h + + Abstract: + + Helper functions for USB + + Revision History + + +--*/ + +#ifndef _USB_UTIL_H +#define _USB_UTIL_H + +// +// Following APIs are used to query Port Status +// +BOOLEAN +IsPortConnect ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortEnable ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortInReset ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortPowerApplied ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortLowSpeedDeviceAttached ( + IN UINT16 PortStatus + ); + +BOOLEAN +IsPortSuspend ( + IN UINT16 PortStatus + ); + +// +// Following APIs are used to query Port Change Status +// +BOOLEAN +IsPortConnectChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortEnableDisableChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortResetChange ( + IN UINT16 PortChangeStatus + ); + +BOOLEAN +IsPortSuspendChange ( + IN UINT16 PortChangeStatus + ); + +// +// Set device address; +// +EFI_STATUS +UsbSetDeviceAddress ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + IN UINT16 AddressValue, + OUT UINT32 *Status + ); + + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c new file mode 100644 index 0000000000..5bd8728fcf --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/Cbi0.c @@ -0,0 +1,1042 @@ +/*++ + +Copyright (c) 2006, 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: + + Cbi0.c + +Abstract: + +--*/ + +#include "../cbi.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gUsbCbi0ComponentName; +// +// Function prototypes +// +EFI_STATUS +EFIAPI +UsbCbi0DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// Bot Driver Binding Protocol +// +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +Cbi0ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbCbi0DriverBinding = { + Cbi0DriverBindingSupported, + Cbi0DriverBindingStart, + Cbi0DriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC +EFI_STATUS +Cbi0RecoveryReset ( + IN USB_CBI_DEVICE *UsbCbiDev + ); + +STATIC +EFI_STATUS +Cbi0CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +Cbi0DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ); + +STATIC +EFI_STATUS +Cbi0StatusPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + OUT INTERRUPT_DATA_BLOCK *InterruptDataBlock, + IN UINT16 Timeout + ); + +// +// USB Atapi protocol prototype +// +STATIC +EFI_STATUS +EFIAPI +Cbi0AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +Cbi0MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC EFI_USB_ATAPI_PROTOCOL Cbi0AtapiProtocol = { + Cbi0AtapiCommand, + Cbi0MassStorageReset, + 0 +}; + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Default interface descriptor, now we only + // suppose interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + // + // Check if it is a Cbi0 Type Mass Storage Device + // + if((InterfaceDescriptor.InterfaceClass != MASS_STORAGE_CLASS) || + (InterfaceDescriptor.InterfaceProtocol != CBI0_INTERFACE_PROTOCOL)) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_SUCCESS; + } + + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle by opening a Block IO and Disk IO + protocol, reading Device Path, and creating a child handle with a + Disk IO and device path protocol. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + other - This driver does not support this device + EFI_OUT_OF_RESOURCES- Can't allocate memory + EFI_UNSUPPORTED - Endpoint is not as expected +--*/ +{ + USB_CBI_DEVICE *UsbCbiDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointExistMask; + + // + // Check if the Controller supports USB IO protocol + // + UsbCbiDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + } + + Cbi0AtapiProtocol.CommandProtocol = InterfaceDescriptor.InterfaceSubClass; + + UsbCbiDev = AllocateZeroPool (sizeof (USB_CBI_DEVICE)); + if (UsbCbiDev == NULL) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return EFI_OUT_OF_RESOURCES; + } + + UsbCbiDev->Signature = USB_CBI_DEVICE_SIGNATURE; + UsbCbiDev->UsbIo = UsbIo; + CopyMem (&UsbCbiDev->InterfaceDescriptor, &InterfaceDescriptor, sizeof (InterfaceDescriptor)); + CopyMem (&UsbCbiDev->UsbAtapiProtocol, &Cbi0AtapiProtocol, sizeof (Cbi0AtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbCbiDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + } + // + // Mask used to see whether all three kinds of endpoints exist, + // Mask value: + // bit0: bulk in endpoint; + // bit1: bulk out endpoint; + // bit2: interrupt in endpoint; + // + EndpointExistMask = 0; + for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if (EndpointDescriptor.Attributes == 0x02) { + if (EndpointDescriptor.EndpointAddress & 0x80) { + CopyMem (&UsbCbiDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->BulkInEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (0); + } else { + CopyMem (&UsbCbiDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->BulkOutEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (1); + } + } + // + // We parse interrupt endpoint + // + if (EndpointDescriptor.Attributes == 0x03) { + CopyMem (&UsbCbiDev->InterruptEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + // UsbCbiDev->InterruptEndpointDescriptor = EndpointDescriptor; + EndpointExistMask |= bit (2); + } + + } + // + // Double check we have all endpoints needed + // + if (EndpointExistMask != (bit (0) | bit (1) | bit (2))) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return EFI_UNSUPPORTED; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + } + + UsbCbiDev->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbCbi0ComponentName.SupportedLanguages, + &UsbCbiDev->ControllerNameTable, + (CHAR16 *) L"Usb Cbi0 Mass Storage" + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *Cbi0AtapiProtocol; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &Cbi0AtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (Cbi0AtapiProtocol); + + UsbIo = UsbCbiDev->UsbIo; + + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + // + // Uninstall protocol + // + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + // + // Free all allocated resources + // + if (UsbCbiDev->ControllerNameTable) { + FreeUnicodeStringTable (UsbCbiDev->ControllerNameTable); + } + + gBS->FreePool (UsbCbiDev); + + return Status; +} + + +STATIC +EFI_STATUS +Cbi0RecoveryReset ( + IN USB_CBI_DEVICE *UsbCbiDev + ) +/*++ + +Routine Description: + + Cbi0 Recovery Reset routine + +Arguments: + + UsbCbiDev - Cbi0RecoveryReset + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + UINT8 ResetCommand[12]; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddress; + UINT32 Result; + UINT16 Timeout; + + UsbIo = UsbCbiDev->UsbIo; + + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + // + // CBI reset command protocol + // + SetMem (ResetCommand, sizeof (ResetCommand), 0xff); + ResetCommand[0] = 0x1d; + ResetCommand[1] = 0x04; + + // + // (in millisecond unit) + // + Timeout = STALL_1_SECOND; + + Status = Cbi0AtapiCommand ( + &UsbCbiDev->UsbAtapiProtocol, + ResetCommand, + 12, + NULL, + 0, + EfiUsbNoData, + Timeout + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->Stall (100 * 1000); + // + // clear bulk in endpoint stall feature + // + EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddress, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // clear bulk out endpoint stall feature + // + EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + Status = UsbClearEndpointHalt ( + UsbIo, + EndpointAddress, + &Result + ); + // + // according to CBI spec, no need to clear interrupt endpoint feature. + // + return Status; +} + +STATIC +EFI_STATUS +Cbi0CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Send ATAPI command through CBI0 interface. + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + Command - Command to send + CommandSize - Command size + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Fail + Others + +--*/ +{ + EFI_STATUS Status; + UINT32 Result; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_DEVICE_REQUEST Request; + + UsbIo = UsbCbiDev->UsbIo; + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Device request see CBI specification + // + Request.RequestType = 0x21; + Request.Request = 0x00; + Request.Value = 0; + Request.Index = 0; + Request.Length = CommandSize; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataOut, + Timeout, + Command, + CommandSize, + &Result + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +Cbi0DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 *DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get/Send Data through CBI0 interface + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + DataSize - Data size + DataBuffer - Data buffer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS + Others + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddress; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLength; + UINT8 *BufferPtr; + UINT32 Result; + UINTN TransferredSize; + + UsbIo = UsbCbiDev->UsbIo; + + Remain = *DataSize; + BufferPtr = (UINT8 *) DataBuffer; + TransferredSize = 0; + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLength = UsbCbiDev->BulkInEndpointDescriptor.MaxPacketSize; + EndpointAddress = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + } else { + MaxPacketLength = UsbCbiDev->BulkOutEndpointDescriptor.MaxPacketSize; + EndpointAddress = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + } + + while (Remain > 0) { + + if (Remain > 16 * MaxPacketLength) { + Increment = 16 * MaxPacketLength; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddress, + BufferPtr, + &Increment, + Timeout, + &Result + ); + TransferredSize += Increment; + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + BufferPtr += Increment; + Remain -= Increment; + } + + return EFI_SUCCESS; + +ErrorExit: + + if (Direction == EfiUsbDataIn) { + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + Cbi0ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + Status = Cbi0RecoveryReset (UsbCbiDev); + } + + *DataSize = (UINT32) TransferredSize; + return Status; +} + +STATIC +EFI_STATUS +Cbi0StatusPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + OUT INTERRUPT_DATA_BLOCK *InterruptDataBlock, + IN UINT16 Timeout + ) +/*++ + + Routine Description: + Get transfer status through BOT interface + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + InterruptDataBlock - Interrupt Data Block for interrupt transfer + Timeout - Time out value in milliseconds + Returns: + EFI_SUCCESS + Others + +--*/ +{ + UINT8 EndpointAddress; + UINTN InterruptDataBlockLength; + UINT32 Result; + EFI_STATUS Status; + + ZeroMem (InterruptDataBlock, sizeof (INTERRUPT_DATA_BLOCK)); + + EndpointAddress = UsbCbiDev->InterruptEndpointDescriptor.EndpointAddress; + InterruptDataBlockLength = sizeof (INTERRUPT_DATA_BLOCK); + + Status = UsbCbiDev->UsbIo->UsbSyncInterruptTransfer ( + UsbCbiDev->UsbIo, + EndpointAddress, + InterruptDataBlock, + &InterruptDataBlockLength, + Timeout, + &Result + ); + if (EFI_ERROR (Status)) { + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbCbiDev->UsbIo, + EndpointAddress, + &Result + ); + gBS->Stall (100 * 1000); + } + + return Status; + } + + return EFI_SUCCESS; +} +// +// Cbi0 Atapi Protocol Implementation +// +STATIC +EFI_STATUS +EFIAPI +Cbi0MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset CBI Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_CBI_DEVICE *UsbCbiDev; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + UsbIo = UsbCbiDev->UsbIo; + + if (ExtendedVerification) { + // + // UsbIo->UsbPortReset (UsbIo); + // + } + + Status = Cbi0RecoveryReset (UsbCbiDev); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +Cbi0AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using BOT protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeOutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + EFI_INVALID_PARAMETER - Invalidate parameter +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + UINT32 BufferSize; + INTERRUPT_DATA_BLOCK InterruptDataBlock; + EFI_STATUS DataPhaseStatus; + + if (Direction != EfiUsbNoData) { + if (DataBuffer == NULL || BufferLength == 0) { + return EFI_INVALID_PARAMETER; + } + } + + DataPhaseStatus = EFI_SUCCESS; + // + // Get the context + // + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + + // + // First send ATAPI command through Cbi + // + Status = Cbi0CommandPhase ( + UsbCbiDev, + Command, + CommandSize, + TimeOutInMilliSeconds + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + // + // Send/Get Data if there is a Data Stage + // + switch (Direction) { + + case EfiUsbDataIn: + case EfiUsbDataOut: + BufferSize = BufferLength; + + DataPhaseStatus = Cbi0DataPhase ( + UsbCbiDev, + &BufferSize, + DataBuffer, + Direction, + TimeOutInMilliSeconds + ); + break; + + case EfiUsbNoData: + break; + } + + if (EFI_ERROR (DataPhaseStatus)) { + return EFI_DEVICE_ERROR; + } + + // + // Status Phase + // + Status = Cbi0StatusPhase ( + UsbCbiDev, + &InterruptDataBlock, + TimeOutInMilliSeconds + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (This->CommandProtocol != EFI_USB_SUBCLASS_UFI) { + + if (InterruptDataBlock.bType == 0) { + // + // indicates command completion + // + switch (InterruptDataBlock.bValue & 0x03) { + + case 0: + Status = EFI_SUCCESS; + break; + + case 1: + Status = EFI_DEVICE_ERROR; + break; + + case 2: + Status = Cbi0RecoveryReset (UsbCbiDev); + if (EFI_ERROR (Status)) { + UsbCbiDev->UsbIo->UsbPortReset (UsbCbiDev->UsbIo); + } + + Status = EFI_DEVICE_ERROR; + break; + + case 3: + Status = EFI_DEVICE_ERROR; + } + } else { + Status = DataPhaseStatus; + } + + } else { + // + // UFI device, InterruptDataBlock.bType: ASC (Additional Sense Code) + // InterruptDataBlock.bValue: ASCQ (Additional Snese Code Qualifier) + // + Status = DataPhaseStatus; + } + + return Status; +} + +VOID +Cbi0ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Cbi0 Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c new file mode 100644 index 0000000000..0692c7fee5 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/ComponentName.c @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "../cbi.h" + +extern EFI_DRIVER_BINDING_PROTOCOL gUsbCbi0DriverBinding; + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbCbi0ComponentName = { + UsbCbi0ComponentNameGetDriverName, + UsbCbi0ComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbCbi0DriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Cbi0 Mass Storage Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbCbi0ComponentName.SupportedLanguages, + mUsbCbi0DriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbCbi0ComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_ATAPI_PROTOCOL *UsbAtapi; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &UsbAtapi, + gUsbCbi0DriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (UsbAtapi); + + return LookupUnicodeString ( + Language, + gUsbCbi0ComponentName.SupportedLanguages, + UsbCbiDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd new file mode 100644 index 0000000000..17a63f9b21 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.mbd @@ -0,0 +1,43 @@ + + + + + UsbCbi0 + A3527D16-E6CC-42f5-BADB-BF3DE177742B + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa new file mode 100644 index 0000000000..a128159e12 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/UsbCbi0.msa @@ -0,0 +1,68 @@ + + + + + UsbCbi0 + DXE_DRIVER + BS_DRIVER + A3527D16-E6CC-42f5-BADB-BF3DE177742B + 0 + Component description file for UsbCbi1 module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + cbi0.c + componentname.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gUsbCbi0DriverBinding + gUsbCbi0ComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml new file mode 100644 index 0000000000..e406abee8b --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi0/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd new file mode 100644 index 0000000000..e48251eb07 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.mbd @@ -0,0 +1,43 @@ + + + + + UsbCbi1 + B40612B2-A063-11d4-9A3A-0090273FC14D + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa new file mode 100644 index 0000000000..057585689e --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/UsbCbi1.msa @@ -0,0 +1,66 @@ + + + + + UsbCbi1 + DXE_DRIVER + BS_DRIVER + B40612B2-A063-11d4-9A3A-0090273FC14D + 0 + Component description file for UsbCbi1 module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + cbi1.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + UsbAtapi + + + + + + + gCBI1DriverBinding + + + diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml new file mode 100644 index 0000000000..132e52237c --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c new file mode 100644 index 0000000000..71644acef8 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/Cbi1/cbi1.c @@ -0,0 +1,854 @@ +/*++ + +Copyright (c) 2006, 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: + + cbi1.c + +Abstract: + cbi1 transportation protocol implementation files + +--*/ + +#include "../cbi.h" + +EFI_STATUS +EFIAPI +UsbCBI1DriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +// +// CBI Function prototypes +// +STATIC +EFI_STATUS +CBI1CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + OUT UINT32 *Result + ); + +STATIC +EFI_STATUS +CBI1DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout, + OUT UINT32 *Result + ); + +// +// USB Atapi implementation +// +STATIC +EFI_STATUS +EFIAPI +CBI1AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +// +// CBI1 Driver Binding Protocol +// +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +VOID +Cbi1ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + + +EFI_DRIVER_BINDING_PROTOCOL gCBI1DriverBinding = { + CBI1DriverBindingSupported, + CBI1DriverBindingStart, + CBI1DriverBindingStop, + 0x10, + NULL, + NULL +}; + +STATIC EFI_USB_ATAPI_PROTOCOL CBI1AtapiProtocol = { + CBI1AtapiCommand, + CBI1MassStorageReset, + 0 +}; + +// +// CBI1 Driver Binding implementation +// +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + than contains a BlockIo and DiskIo protocol can be supported. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device + EFI_ALREADY_STARTED - This driver is already running on this device + other - This driver does not support this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Check if the Controller supports USB IO protocol + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the Controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto Exit; + } + // + // Bug here: just let Vendor specific CBI protocol get supported + // + if (!((InterfaceDescriptor.InterfaceClass == 0xFF) && + (InterfaceDescriptor.InterfaceProtocol == 0))) { + Status = EFI_UNSUPPORTED; + goto Exit; + } + +Exit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + return Status; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start this driver on ControllerHandle by opening a Block IO and Disk IO + protocol, reading Device Path, and creating a child handle with a + Disk IO and device path protocol. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to bind driver to + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver is added to DeviceHandle + EFI_ALREADY_STARTED - This driver is already running on DeviceHandle + other - This driver does not support this device + +--*/ +{ + USB_CBI_DEVICE *UsbCbiDev; + UINT8 Index; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + BOOLEAN Found; + + Found = FALSE; + // + // Check if the Controller supports USB IO protocol + // + UsbCbiDev = NULL; + + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Get the controller interface descriptor + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + CBI1AtapiProtocol.CommandProtocol = InterfaceDescriptor.InterfaceSubClass; + + UsbCbiDev = AllocateZeroPool (sizeof (USB_CBI_DEVICE)); + if (UsbCbiDev == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbCbiDev->Signature = USB_CBI_DEVICE_SIGNATURE; + UsbCbiDev->UsbIo = UsbIo; + CopyMem (&UsbCbiDev->InterfaceDescriptor, &InterfaceDescriptor, sizeof (InterfaceDescriptor)); + CopyMem (&UsbCbiDev->UsbAtapiProtocol , &CBI1AtapiProtocol, sizeof (CBI1AtapiProtocol)); + + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbCbiDev->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + for (Index = 0; Index < InterfaceDescriptor.NumEndpoints; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + // + // We parse bulk endpoint + // + if (EndpointDescriptor.Attributes == 0x02) { + if (EndpointDescriptor.EndpointAddress & 0x80) { + CopyMem (&UsbCbiDev->BulkInEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->BulkInEndpointDescriptor = EndpointDescriptor; + } else { + CopyMem (&UsbCbiDev->BulkOutEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->BulkOutEndpointDescriptor = EndpointDescriptor; + } + + Found = TRUE; + } + // + // We parse interrupt endpoint + // + if (EndpointDescriptor.Attributes == 0x03) { + CopyMem (&UsbCbiDev->InterruptEndpointDescriptor, &EndpointDescriptor, sizeof(EndpointDescriptor)); + //UsbCbiDev->InterruptEndpointDescriptor = EndpointDescriptor; + Found = TRUE; + } + + } + // + // Double check we have these + // + if (!Found) { + goto ErrorExit; + } + // + // After installing Usb-Atapi protocol onto this handle + // it will be called by upper layer drivers such as Fat + // + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE) + ); + + Status = gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbCbiDev->UsbAtapiProtocol + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + if (UsbCbiDev != NULL) { + gBS->FreePool (UsbCbiDev); + } + + return Status; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + ControllerHandle - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + EFI_UNSUPPORTED - Can't open the gEfiUsbAtapiProtocolGuid protocol + other - This driver was not removed from this device + +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *CBI1AtapiProtocol; + USB_CBI_DEVICE *UsbCbiDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &CBI1AtapiProtocol, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (CBI1AtapiProtocol); + + UsbIo = UsbCbiDev->UsbIo; + + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE) + ); + + Status = gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiUsbAtapiProtocolGuid, + &UsbCbiDev->UsbAtapiProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + ControllerHandle + ); + gBS->FreePool (UsbCbiDev); + + return Status; + +} +// +// CBI1 command +// +STATIC +EFI_STATUS +CBI1CommandPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN VOID *Command, + IN UINT8 CommandSize, + OUT UINT32 *Result + ) +/*++ + + Routine Description: + In order to make consistence, CBI transportation protocol does only use + the first 3 parameters. Other parameters are not used here. + + Arguments: + UsbCbiDev - USB_CBI_DEVICE + Command - Command to send + CommandSize - Command Size + Result - Result to return + + Returns: + EFI_SUCCESS - This driver is removed DeviceHandle + other - This driver was not removed from this device +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_DEVICE_REQUEST Request; + UINT32 TimeOutInMilliSeconds; + + UsbIo = UsbCbiDev->UsbIo; + + ZeroMem (&Request, sizeof (EFI_USB_DEVICE_REQUEST)); + + // + // Device request see CBI specification + // + Request.RequestType = 0x21; + Request.Length = CommandSize; + + TimeOutInMilliSeconds = 1000; + + Status = UsbIo->UsbControlTransfer ( + UsbIo, + &Request, + EfiUsbDataOut, + TimeOutInMilliSeconds, + Command, + CommandSize, + Result + ); + + return Status; +} + +STATIC +EFI_STATUS +CBI1DataPhase ( + IN USB_CBI_DEVICE *UsbCbiDev, + IN UINT32 DataSize, + IN OUT VOID *DataBuffer, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 Timeout, + OUT UINT32 *Result + ) +/*++ + +Routine Description: + + CBI1 Data Phase + +Arguments: + + UsbCbiDev - USB_CBI_DEVICE + DataSize - Data Size + DataBuffer - Data Buffer + Direction - IN/OUT/NODATA + Timeout - Time out value in milliseconds + Result - Transfer result + +Returns: + + EFI_SUCCESS - Success + +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINTN Remain; + UINTN Increment; + UINT32 MaxPacketLen; + UINT8 *BufferPtr; + + UsbIo = UsbCbiDev->UsbIo; + + Remain = DataSize; + BufferPtr = (UINT8 *) DataBuffer; + + // + // retrieve the the max packet length of the given endpoint + // + if (Direction == EfiUsbDataIn) { + MaxPacketLen = (UsbCbiDev->BulkInEndpointDescriptor).MaxPacketSize; + EndpointAddr = (UsbCbiDev->BulkInEndpointDescriptor).EndpointAddress; + } else { + MaxPacketLen = (UsbCbiDev->BulkOutEndpointDescriptor).MaxPacketSize; + EndpointAddr = (UsbCbiDev->BulkOutEndpointDescriptor).EndpointAddress; + } + + while (Remain > 0) { + // + // Using 15 packets to aVOID Bitstuff error + // + if (Remain > 15 * MaxPacketLen) { + Increment = 15 * MaxPacketLen; + } else { + Increment = Remain; + } + + Status = UsbIo->UsbBulkTransfer ( + UsbIo, + EndpointAddr, + BufferPtr, + &Increment, + Timeout, + Result + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + BufferPtr += Increment; + Remain -= Increment; + } + + return EFI_SUCCESS; + +ErrorExit: + + if (Direction == EfiUsbDataIn) { + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_INPUT_ERROR) + ); + } else { + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_OUTPUT_ERROR) + ); + } + + if (((*Result) & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + // + // just endpoint stall happens + // + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + Result + ); + } + + return Status; +} +// +// CBI1 USB ATAPI Protocol +// +STATIC +EFI_STATUS +EFIAPI +CBI1MassStorageReset ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset CBI Devices + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - TRUE if we need to do strictly reset. + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + UINT8 ResetCommand[12]; + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_CBI_DEVICE *UsbCbiDev; + UINT8 EndpointAddr; + UINT32 Result; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + UsbIo = UsbCbiDev->UsbIo; + + Cbi1ReportStatusCode ( + UsbCbiDev->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET) + ); + + if (ExtendedVerification) { + UsbIo->UsbPortReset (UsbIo); + } + // + // CBI reset command protocol + // + SetMem (ResetCommand, sizeof (ResetCommand), 0xff); + ResetCommand[0] = 0x1d; + ResetCommand[1] = 0x04; + + Status = CBI1CommandPhase ( + UsbCbiDev, + ResetCommand, + 12, + &Result + ); + + // + // clear bulk in endpoint stall feature + // + EndpointAddr = UsbCbiDev->BulkInEndpointDescriptor.EndpointAddress; + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + // + // clear bulk out endpoint stall feature + // + EndpointAddr = UsbCbiDev->BulkOutEndpointDescriptor.EndpointAddress; + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &Result + ); + + return EFI_SUCCESS; + +} + +STATIC +EFI_STATUS +EFIAPI +CBI1AtapiCommand ( + IN EFI_USB_ATAPI_PROTOCOL *This, + IN VOID *Command, + IN UINT8 CommandSize, + IN VOID *DataBuffer, + IN UINT32 BufferLength, + IN EFI_USB_DATA_DIRECTION Direction, + IN UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Send ATAPI command using CBI1 protocol. + + Arguments: + This - Protocol instance pointer. + Command - Command buffer + CommandSize - Size of Command Buffer + DataBuffer - Data buffer + BufferLength - Length of Data buffer + Direction - Data direction of this command + TimeOutInMilliSeconds - Timeout value in ms + + Returns: + EFI_SUCCESS - Command succeeded. + EFI_DEVICE_ERROR - Command failed. + +--*/ +{ + EFI_STATUS Status; + USB_CBI_DEVICE *UsbCbiDev; + UINT32 Result; + UINT8 Index; + UINT8 MaxRetryNum; + + UsbCbiDev = USB_CBI_DEVICE_FROM_THIS (This); + + MaxRetryNum = 3; + + for (Index = 0; Index < MaxRetryNum; Index++) { + + // + // First send ATAPI command through CBI1 + // + Status = CBI1CommandPhase ( + UsbCbiDev, + Command, + CommandSize, + &Result + ); + if (EFI_ERROR (Status)) { + + switch (Result) { + + case EFI_USB_NOERROR: + case EFI_USB_ERR_STALL: + case EFI_USB_ERR_SYSTEM: + return EFI_DEVICE_ERROR; + + default: + continue; + break; + } + } else { + break; + } + } + + if (Index == MaxRetryNum) { + return EFI_DEVICE_ERROR; + } + + for (Index = 0; Index < MaxRetryNum; Index++) { + // + // Send/Get Data if there is a Data Stage + // + switch (Direction) { + + case EfiUsbDataIn: + case EfiUsbDataOut: + Status = CBI1DataPhase ( + UsbCbiDev, + BufferLength, + DataBuffer, + Direction, + TimeOutInMilliSeconds, + &Result + ); + + if (EFI_ERROR (Status)) { + switch (Result) { + + case EFI_USB_NOERROR: + case EFI_USB_ERR_STALL: + case EFI_USB_ERR_SYSTEM: + return EFI_DEVICE_ERROR; + + default: + continue; + break; + } + + } else { + + return EFI_SUCCESS; + } + break; + + case EfiUsbNoData: + return EFI_SUCCESS; + } + } + // + // If goes here, means met error. + // + return EFI_DEVICE_ERROR; +} + +VOID +Cbi1ReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Cbi1 Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h new file mode 100644 index 0000000000..dfbe4d9886 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbCbi/Dxe/cbi.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (c) 2006, 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: + + cbi.h + +Abstract: + + USB CBI transportation protocol definitions. +--*/ + +#ifndef _CBI_H +#define _CBI_H + + +#include + +#define bit(a) (1 << (a)) + +#define MASS_STORAGE_CLASS 0x08 +#define CBI0_INTERFACE_PROTOCOL 0x00 +#define CBI1_INTERFACE_PROTOCOL 0x01 + +// +// in millisecond unit +// +#define STALL_1_SECOND 1000 + +#pragma pack(1) +// +// Data block definition for transportation through interrupt endpoint +// +typedef struct { + UINT8 bType; + UINT8 bValue; +} INTERRUPT_DATA_BLOCK; + +#pragma pack() + +#define USB_CBI_DEVICE_SIGNATURE EFI_SIGNATURE_32 ('u', 'c', 'b', 'i') + +// +// Device structure for CBI, interrupt endpoint may be not used in +// CBI1 Protocol +// +typedef struct { + UINT32 Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_USB_ATAPI_PROTOCOL UsbAtapiProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR BulkInEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR BulkOutEndpointDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR InterruptEndpointDescriptor; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_CBI_DEVICE; + +#define USB_CBI_DEVICE_FROM_THIS(a) \ + CR(a, USB_CBI_DEVICE, UsbAtapiProtocol, USB_CBI_DEVICE_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c new file mode 100644 index 0000000000..3e139f9d9a --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/ComponentName.c @@ -0,0 +1,215 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "keyboard.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName = { + UsbKeyboardComponentNameGetDriverName, + UsbKeyboardComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbKeyboardDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Keyboard Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbKeyboardComponentName.SupportedLanguages, + mUsbKeyboardDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbKeyboardComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_KB_DEV *UsbKbDev; + EFI_SIMPLE_TEXT_IN_PROTOCOL *SimpleTxtIn; + EFI_USB_IO_PROTOCOL *UsbIoProtocol; + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Check Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIoProtocol, + gUsbKeyboardDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + gUsbKeyboardDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &SimpleTxtIn, + gUsbKeyboardDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbKbDev = USB_KB_DEV_FROM_THIS (SimpleTxtIn); + + return LookupUnicodeString ( + Language, + gUsbKeyboardComponentName.SupportedLanguages, + UsbKbDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd new file mode 100644 index 0000000000..ecb6af6c96 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.mbd @@ -0,0 +1,44 @@ + + + + + UsbKb + 2D2E62CF-9ECF-43b7-8219-94E7FC713DFE + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa new file mode 100644 index 0000000000..0ff6464825 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/UsbKb.msa @@ -0,0 +1,77 @@ + + + + + UsbKb + DXE_DRIVER + BS_DRIVER + 2D2E62CF-9ECF-43b7-8219-94E7FC713DFE + 0 + Component description file for UsbKb module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + + + efikey.h + keyboard.h + efikey.c + keyboard.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + SimpleTextIn + + + + HotPlugDevice + + + + + + + + gUsbKeyboardDriverBinding + gUsbKeyboardComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml new file mode 100644 index 0000000000..2608381d96 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c new file mode 100644 index 0000000000..a9cdbc8760 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.c @@ -0,0 +1,772 @@ +/*++ + +Copyright (c) 2006, 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: + + EfiKey.c + +Abstract: + + USB Keyboard Driver + +Revision History + +--*/ + +#include "efikey.h" +#include "keyboard.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Simple Text In Protocol Interface +// +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ); + +STATIC +VOID +EFIAPI +USBKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Helper functions +// +STATIC +EFI_STATUS +USBKeyboardCheckForKey ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +// +// USB Keyboard Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding = { + USBKeyboardDriverBindingSupported, + USBKeyboardDriverBindingStart, + USBKeyboardDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Supported. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL + Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_STATUS Status; + + // + // Check if USB_IO protocol is attached on the controller handle. + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus)) { + return OpenStatus; + } + + // + // Use the USB I/O protocol interface to check whether the Controller is + // the Keyboard controller that can be managed by this driver. + // + Status = EFI_SUCCESS; + + if (!IsUSBKeyboard (UsbIo)) { + Status = EFI_UNSUPPORTED; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return Status; +} + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Start. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + RemainingDevicePath - EFI_DEVICE_PATH_PROTOCOL + Returns: + EFI_SUCCESS - Success + EFI_OUT_OF_RESOURCES - Can't allocate memory + EFI_UNSUPPORTED - The Start routine fail +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + USB_KB_DEV *UsbKeyboardDevice; + UINT8 EndpointNumber; + EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor; + UINT8 Index; + UINT8 EndpointAddr; + UINT8 PollingInterval; + UINT8 PacketSize; + BOOLEAN Found; + + UsbKeyboardDevice = NULL; + Found = FALSE; + + // + // Open USB_IO Protocol + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + UsbKeyboardDevice = AllocateZeroPool (sizeof (USB_KB_DEV)); + if (UsbKeyboardDevice == NULL) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_OUT_OF_RESOURCES; + } + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbKeyboardDevice->DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // Report that the usb keyboard is being enabled + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE) + ); + + // + // This is pretty close to keyboard detection, so log progress + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT) + ); + + // + // Initialize UsbKeyboardDevice + // + UsbKeyboardDevice->UsbIo = UsbIo; + + // + // Get interface & endpoint descriptor + // + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &UsbKeyboardDevice->InterfaceDescriptor + ); + + EndpointNumber = UsbKeyboardDevice->InterfaceDescriptor.NumEndpoints; + + for (Index = 0; Index < EndpointNumber; Index++) { + + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + &EndpointDescriptor + ); + + if ((EndpointDescriptor.Attributes & 0x03) == 0x03) { + // + // We only care interrupt endpoint here + // + CopyMem (&UsbKeyboardDevice->IntEndpointDescriptor, &EndpointDescriptor, sizeof (EndpointDescriptor)); + //UsbKeyboardDevice->IntEndpointDescriptor = EndpointDescriptor; + Found = TRUE; + } + } + + if (!Found) { + // + // No interrupt endpoint found, then return unsupported. + // + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return EFI_UNSUPPORTED; + } + + UsbKeyboardDevice->Signature = USB_KB_DEV_SIGNATURE; + UsbKeyboardDevice->SimpleInput.Reset = USBKeyboardReset; + UsbKeyboardDevice->SimpleInput.ReadKeyStroke = USBKeyboardReadKeyStroke; + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + USBKeyboardWaitForKey, + UsbKeyboardDevice, + &(UsbKeyboardDevice->SimpleInput.WaitForKey) + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // Install simple txt in protocol interface + // for the usb keyboard device. + // Usb keyboard is a hot plug device, and expected to work immediately + // when plugging into system, so a HotPlugDeviceGuid is installed onto + // the usb keyboard device handle, to distinguish it from other conventional + // console devices. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + // + // Reset USB Keyboard Device + // + Status = UsbKeyboardDevice->SimpleInput.Reset ( + &UsbKeyboardDevice->SimpleInput, + TRUE + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // submit async interrupt transfer + // + EndpointAddr = UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress; + PollingInterval = UsbKeyboardDevice->IntEndpointDescriptor.Interval; + PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); + + Status = UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + EndpointAddr, + TRUE, + PollingInterval, + PacketSize, + KeyboardHandler, + UsbKeyboardDevice + ); + + if (EFI_ERROR (Status)) { + + gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + gBS->CloseEvent (UsbKeyboardDevice->SimpleInput.WaitForKey); + gBS->FreePool (UsbKeyboardDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + UsbKeyboardDevice->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbKeyboardComponentName.SupportedLanguages, + &UsbKeyboardDevice->ControllerNameTable, + (CHAR16 *) L"Generic Usb Keyboard" + ); + + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +USBKeyboardDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop. + + Arguments: + This - EFI_DRIVER_BINDING_PROTOCOL + Controller - Controller handle + NumberOfChildren - Child handle number + ChildHandleBuffer - Child handle buffer + Returns: + EFI_SUCCESS - Success + EFI_UNSUPPORTED - Can't support +--*/ +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_IN_PROTOCOL *SimpleInput; + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimpleTextInProtocolGuid, + (VOID **) &SimpleInput, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + // + // Get USB_KB_DEV instance. + // + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (SimpleInput); + + gBS->CloseProtocol ( + Controller, + &gEfiSimpleTextInProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + UsbIo = UsbKeyboardDevice->UsbIo; + // + // Uninstall the Asyn Interrupt Transfer from this device + // will disable the key data input from this device + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE) + ); + + // + // Destroy asynchronous interrupt transfer + // + UsbKeyboardDevice->UsbIo->UsbAsyncInterruptTransfer ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + FALSE, + UsbKeyboardDevice->IntEndpointDescriptor.Interval, + 0, + NULL, + NULL + ); + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + Controller, + &gEfiSimpleTextInProtocolGuid, + &UsbKeyboardDevice->SimpleInput, + &gEfiHotPlugDeviceGuid, + NULL, + NULL + ); + // + // free all the resources. + // + gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); + gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); + gBS->CloseEvent ((UsbKeyboardDevice->SimpleInput).WaitForKey); + + if (UsbKeyboardDevice->ControllerNameTable != NULL) { + FreeUnicodeStringTable (UsbKeyboardDevice->ControllerNameTable); + } + + gBS->FreePool (UsbKeyboardDevice); + + return Status; + +} + + +EFI_STATUS +EFIAPI +USBKeyboardReset ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.Reset() function. + + Arguments: + This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance. + ExtendedVerification + Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + EFI_STATUS Status; + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); + + UsbIo = UsbKeyboardDevice->UsbIo; + + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET) + ); + + // + // Non Exhaustive reset: + // only reset private data structures. + // + if (!ExtendedVerification) { + // + // Clear the key buffer of this Usb keyboard + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER) + ); + + InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer)); + UsbKeyboardDevice->CurKeyChar = 0; + return EFI_SUCCESS; + } + + // + // Exhaustive reset + // + Status = InitUSBKeyboard (UsbKeyboardDevice); + UsbKeyboardDevice->CurKeyChar = 0; + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +USBKeyboardReadKeyStroke ( + IN EFI_SIMPLE_TEXT_IN_PROTOCOL *This, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Implements EFI_SIMPLE_TEXT_IN_PROTOCOL.ReadKeyStroke() function. + + Arguments: + This The EFI_SIMPLE_TEXT_IN_PROTOCOL instance. + Key A pointer to a buffer that is filled in with the keystroke + information for the key that was pressed. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_STATUS Status; + UINT8 KeyChar; + + UsbKeyboardDevice = USB_KB_DEV_FROM_THIS (This); + + // + // if there is no saved ASCII byte, fetch it + // by calling USBKeyboardCheckForKey(). + // + if (UsbKeyboardDevice->CurKeyChar == 0) { + Status = USBKeyboardCheckForKey (UsbKeyboardDevice); + if (EFI_ERROR (Status)) { + return Status; + } + } + + Key->UnicodeChar = 0; + Key->ScanCode = SCAN_NULL; + + KeyChar = UsbKeyboardDevice->CurKeyChar; + + UsbKeyboardDevice->CurKeyChar = 0; + + // + // Translate saved ASCII byte into EFI_INPUT_KEY + // + Status = USBKeyCodeToEFIScanCode (UsbKeyboardDevice, KeyChar, Key); + + return Status; + +} + +STATIC +VOID +EFIAPI +USBKeyboardWaitForKey ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Handler function for WaitForKey event. + + Arguments: + Event Event to be signaled when a key is pressed. + Context Points to USB_KB_DEV instance. + + Returns: + VOID +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + if (UsbKeyboardDevice->CurKeyChar == 0) { + + if (EFI_ERROR (USBKeyboardCheckForKey (UsbKeyboardDevice))) { + return ; + } + } + // + // If has key pending, signal the event. + // + gBS->SignalEvent (Event); +} + + +STATIC +EFI_STATUS +USBKeyboardCheckForKey ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Check whether there is key pending. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + UINT8 KeyChar; + + // + // Fetch raw data from the USB keyboard input, + // and translate it into ASCII data. + // + Status = USBParseKey (UsbKeyboardDevice, &KeyChar); + if (EFI_ERROR (Status)) { + return Status; + } + + UsbKeyboardDevice->CurKeyChar = KeyChar; + return EFI_SUCCESS; +} + +VOID +KbdReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h new file mode 100644 index 0000000000..bf9f47732d --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/efikey.h @@ -0,0 +1,118 @@ +/*++ +Copyright (c) 2006, 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: + + EfiKey.h + +Abstract: + + Header file for USB Keyboard Driver's Data Structures + +Revision History +--*/ +#ifndef _USB_KB_H +#define _USB_KB_H + + +#include + +#define MAX_KEY_ALLOWED 32 + +#define HZ 1000 * 1000 * 10 +#define USBKBD_REPEAT_DELAY ((HZ) / 2) +#define USBKBD_REPEAT_RATE ((HZ) / 50) + +#define CLASS_HID 3 +#define SUBCLASS_BOOT 1 +#define PROTOCOL_KEYBOARD 1 + +#define BOOT_PROTOCOL 0 +#define REPORT_PROTOCOL 1 + +typedef struct { + UINT8 Down; + UINT8 KeyCode; +} USB_KEY; + +typedef struct { + USB_KEY buffer[MAX_KEY_ALLOWED + 1]; + UINT8 bHead; + UINT8 bTail; +} USB_KB_BUFFER; + +#define USB_KB_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'k', 'b', 'd') +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_EVENT DelayedRecoveryEvent; + EFI_SIMPLE_TEXT_IN_PROTOCOL SimpleInput; + EFI_USB_IO_PROTOCOL *UsbIo; + + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR IntEndpointDescriptor; + + USB_KB_BUFFER KeyboardBuffer; + UINT8 CtrlOn; + UINT8 AltOn; + UINT8 ShiftOn; + UINT8 NumLockOn; + UINT8 CapsOn; + UINT8 LastKeyCodeArray[8]; + UINT8 CurKeyChar; + + UINT8 RepeatKey; + EFI_EVENT RepeatTimer; + + EFI_UNICODE_STRING_TABLE *ControllerNameTable; + +} USB_KB_DEV; + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbKeyboardDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbKeyboardComponentName; +extern EFI_GUID gEfiUsbKeyboardDriverGuid; + +VOID +KbdReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +#define USB_KB_DEV_FROM_THIS(a) \ + CR(a, USB_KB_DEV, SimpleInput, USB_KB_DEV_SIGNATURE) + +#define MOD_CONTROL_L 0x01 +#define MOD_CONTROL_R 0x10 +#define MOD_SHIFT_L 0x02 +#define MOD_SHIFT_R 0x20 +#define MOD_ALT_L 0x04 +#define MOD_ALT_R 0x40 +#define MOD_WIN_L 0x08 +#define MOD_WIN_R 0x80 + +typedef struct { + UINT8 Mask; + UINT8 Key; +} KB_MODIFIER; + +#define USB_KEYCODE_MAX_MAKE 0x64 + +#define USBKBD_VALID_KEYCODE(key) ((UINT8) (key) > 3) + +typedef struct { + UINT8 NumLock : 1; + UINT8 CapsLock : 1; + UINT8 Resrvd : 6; +} LED_MAP; +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c new file mode 100644 index 0000000000..1328e6a098 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.c @@ -0,0 +1,1150 @@ +/*++ + +Copyright (c) 2006, 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: + + Keyboard.c + +Abstract: + + Helper functions for USB Keyboard Driver + +Revision History + +--*/ + +#include "keyboard.h" + +// +// USB Key Code to Efi key mapping table +// Format:, , +// +STATIC +UINT8 KeyConvertionTable[USB_KEYCODE_MAX_MAKE][3] = { + { SCAN_NULL, 'a', 'A' }, // 0x04 + { SCAN_NULL, 'b', 'B' }, // 0x05 + { SCAN_NULL, 'c', 'C' }, // 0x06 + { SCAN_NULL, 'd', 'D' }, // 0x07 + { SCAN_NULL, 'e', 'E' }, // 0x08 + { SCAN_NULL, 'f', 'F' }, // 0x09 + { SCAN_NULL, 'g', 'G' }, // 0x0A + { SCAN_NULL, 'h', 'H' }, // 0x0B + { SCAN_NULL, 'i', 'I' }, // 0x0C + { SCAN_NULL, 'j', 'J' }, // 0x0D + { SCAN_NULL, 'k', 'K' }, // 0x0E + { SCAN_NULL, 'l', 'L' }, // 0x0F + { SCAN_NULL, 'm', 'M' }, // 0x10 + { SCAN_NULL, 'n', 'N' }, // 0x11 + { SCAN_NULL, 'o', 'O' }, // 0x12 + { SCAN_NULL, 'p', 'P' }, // 0x13 + { SCAN_NULL, 'q', 'Q' }, // 0x14 + { SCAN_NULL, 'r', 'R' }, // 0x15 + { SCAN_NULL, 's', 'S' }, // 0x16 + { SCAN_NULL, 't', 'T' }, // 0x17 + { SCAN_NULL, 'u', 'U' }, // 0x18 + { SCAN_NULL, 'v', 'V' }, // 0x19 + { SCAN_NULL, 'w', 'W' }, // 0x1A + { SCAN_NULL, 'x', 'X' }, // 0x1B + { SCAN_NULL, 'y', 'Y' }, // 0x1C + { SCAN_NULL, 'z', 'Z' }, // 0x1D + { SCAN_NULL, '1', '!' }, // 0x1E + { SCAN_NULL, '2', '@' }, // 0x1F + { SCAN_NULL, '3', '#' }, // 0x20 + { SCAN_NULL, '4', '$' }, // 0x21 + { SCAN_NULL, '5', '%' }, // 0x22 + { SCAN_NULL, '6', '^' }, // 0x23 + { SCAN_NULL, '7', '&' }, // 0x24 + { SCAN_NULL, '8', '*' }, // 0x25 + { SCAN_NULL, '9', '(' }, // 0x26 + { SCAN_NULL, '0', ')' }, // 0x27 + { SCAN_NULL, 0x0d, 0x0d }, // 0x28 Enter + { SCAN_ESC, 0x00, 0x00 }, // 0x29 Esc + { SCAN_NULL, 0x08, 0x08 }, // 0x2A Backspace + { SCAN_NULL, 0x09, 0x09 }, // 0x2B Tab + { SCAN_NULL, ' ', ' ' }, // 0x2C Spacebar + { SCAN_NULL, '-', '_' }, // 0x2D + { SCAN_NULL, '=', '+' }, // 0x2E + { SCAN_NULL, '[', '{' }, // 0x2F + { SCAN_NULL, ']', '}' }, // 0x30 + { SCAN_NULL, '\\', '|' }, // 0x31 + { SCAN_NULL, '\\', '|' }, // 0x32 Keyboard US \ and | + { SCAN_NULL, ';', ':' }, // 0x33 + { SCAN_NULL, '\'', '"' }, // 0x34 + { SCAN_NULL, '`', '~' }, // 0x35 Keyboard Grave Accent and Tlide + { SCAN_NULL, ',', '<' }, // 0x36 + { SCAN_NULL, '.', '>' }, // 0x37 + { SCAN_NULL, '/', '?' }, // 0x38 + { SCAN_NULL, 0x00, 0x00 }, // 0x39 CapsLock + { SCAN_F1, 0x00, 0x00 }, // 0x3A + { SCAN_F2, 0x00, 0x00 }, // 0x3B + { SCAN_F3, 0x00, 0x00 }, // 0x3C + { SCAN_F4, 0x00, 0x00 }, // 0x3D + { SCAN_F5, 0x00, 0x00 }, // 0x3E + { SCAN_F6, 0x00, 0x00 }, // 0x3F + { SCAN_F7, 0x00, 0x00 }, // 0x40 + { SCAN_F8, 0x00, 0x00 }, // 0x41 + { SCAN_F9, 0x00, 0x00 }, // 0x42 + { SCAN_F10, 0x00, 0x00 }, // 0x43 + { SCAN_NULL, 0x00, 0x00 }, // 0x44 F11 + { SCAN_NULL, 0x00, 0x00 }, // 0x45 F12 + { SCAN_NULL, 0x00, 0x00 }, // 0x46 PrintScreen + { SCAN_NULL, 0x00, 0x00 }, // 0x47 Scroll Lock + { SCAN_NULL, 0x00, 0x00 }, // 0x48 Pause + { SCAN_INSERT, 0x00, 0x00 }, // 0x49 + { SCAN_HOME, 0x00, 0x00 }, // 0x4A + { SCAN_PAGE_UP, 0x00, 0x00 }, // 0x4B + { SCAN_DELETE, 0x00, 0x00 }, // 0x4C + { SCAN_END, 0x00, 0x00 }, // 0x4D + { SCAN_PAGE_DOWN, 0x00, 0x00 }, // 0x4E + { SCAN_RIGHT, 0x00, 0x00 }, // 0x4F + { SCAN_LEFT, 0x00, 0x00 }, // 0x50 + { SCAN_DOWN, 0x00, 0x00 }, // 0x51 + { SCAN_UP, 0x00, 0x00 }, // 0x52 + { SCAN_NULL, 0x00, 0x00 }, // 0x53 NumLock + { SCAN_NULL, '/', '/' }, // 0x54 + { SCAN_NULL, '*', '*' }, // 0x55 + { SCAN_NULL, '-', '-' }, // 0x56 + { SCAN_NULL, '+', '+' }, // 0x57 + { SCAN_NULL, 0x0d, 0x0d }, // 0x58 + { SCAN_END, '1', '1' }, // 0x59 + { SCAN_DOWN, '2', '2' }, // 0x5A + { SCAN_PAGE_DOWN, '3', '3' }, // 0x5B + { SCAN_LEFT, '4', '4' }, // 0x5C + { SCAN_NULL, '5', '5' }, // 0x5D + { SCAN_RIGHT, '6', '6' }, // 0x5E + { SCAN_HOME, '7', '7' }, // 0x5F + { SCAN_UP, '8', '8' }, // 0x60 + { SCAN_PAGE_UP, '9', '9' }, // 0x61 + { SCAN_INSERT, '0', '0' }, // 0x62 + { SCAN_DELETE, '.', '.' }, // 0x63 + { SCAN_NULL, '\\', '|' }, // 0x64 Keyboard Non-US \ and | + { SCAN_NULL, 0x00, 0x00 }, // 0x65 Keyboard Application + { SCAN_NULL, 0x00, 0x00 }, // 0x66 Keyboard Power + { SCAN_NULL, '=' , '=' } // 0x67 Keypad = +}; + +STATIC KB_MODIFIER KB_Mod[8] = { + { MOD_CONTROL_L, 0xe0 }, // 11100000 + { MOD_CONTROL_R, 0xe4 }, // 11100100 + { MOD_SHIFT_L, 0xe1 }, // 11100001 + { MOD_SHIFT_R, 0xe5 }, // 11100101 + { MOD_ALT_L, 0xe2 }, // 11100010 + { MOD_ALT_R, 0xe6 }, // 11100110 + { MOD_WIN_L, 0xe3 }, // 11100011 + { MOD_WIN_R, 0xe7 } // 11100111 +}; + + +BOOLEAN +IsUSBKeyboard ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +/*++ + + Routine Description: + Uses USB I/O to check whether the device is a USB Keyboard device. + + Arguments: + UsbIo: Points to a USB I/O protocol instance. + + Returns: + +--*/ +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Get the Default interface descriptor, currently we + // assume it is interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + if (InterfaceDescriptor.InterfaceClass == CLASS_HID && + InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT && + InterfaceDescriptor.InterfaceProtocol == PROTOCOL_KEYBOARD + ) { + + return TRUE; + } + + return FALSE; +} + + +EFI_STATUS +InitUSBKeyboard ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Initialize USB Keyboard device and all private data structures. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + UINT8 ConfigValue; + UINT8 Protocol; + UINT8 ReportId; + UINT8 Duration; + EFI_STATUS Status; + UINT32 TransferResult; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbIo = UsbKeyboardDevice->UsbIo; + + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST) + ); + + InitUSBKeyBuffer (&(UsbKeyboardDevice->KeyboardBuffer)); + + // + // default configurations + // + ConfigValue = 0x01; + + // + // Uses default configuration to configure the USB Keyboard device. + // + Status = UsbSetDeviceConfiguration ( + UsbKeyboardDevice->UsbIo, + (UINT16) ConfigValue, + &TransferResult + ); + if (EFI_ERROR (Status)) { + // + // If configuration could not be set here, it means + // the keyboard interface has some errors and could + // not be initialized + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INTERFACE_ERROR) + ); + + return EFI_DEVICE_ERROR; + } + + UsbGetProtocolRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + &Protocol + ); + // + // Sets boot protocol for the USB Keyboard. + // This driver only supports boot protocol. + // !!BugBug: How about the device that does not support boot protocol? + // + if (Protocol != BOOT_PROTOCOL) { + UsbSetProtocolRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + BOOT_PROTOCOL + ); + } + // + // the duration is indefinite, so the endpoint will inhibit reporting forever, + // and only reporting when a change is detected in the report data. + // + + // + // idle value for all report ID + // + ReportId = 0; + // + // idle forever until there is a key pressed and released. + // + Duration = 0; + UsbSetIdleRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + ReportId, + Duration + ); + + UsbKeyboardDevice->CtrlOn = 0; + UsbKeyboardDevice->AltOn = 0; + UsbKeyboardDevice->ShiftOn = 0; + UsbKeyboardDevice->NumLockOn = 0; + UsbKeyboardDevice->CapsOn = 0; + ZeroMem (UsbKeyboardDevice->LastKeyCodeArray, sizeof (UINT8) * 8); + + // + // Set a timer for repeat keys' generation. + // + if (UsbKeyboardDevice->RepeatTimer) { + gBS->CloseEvent (UsbKeyboardDevice->RepeatTimer); + UsbKeyboardDevice->RepeatTimer = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBKeyboardRepeatHandler, + UsbKeyboardDevice, + &UsbKeyboardDevice->RepeatTimer + ); + + if (UsbKeyboardDevice->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbKeyboardDevice->DelayedRecoveryEvent); + UsbKeyboardDevice->DelayedRecoveryEvent = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBKeyboardRecoveryHandler, + UsbKeyboardDevice, + &UsbKeyboardDevice->DelayedRecoveryEvent + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +KeyboardHandler ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + Handler function for USB Keyboard's asynchronous interrupt transfer. + + Arguments: + Data A pointer to a buffer that is filled with key data which is + retrieved via asynchronous interrupt transfer. + DataLength Indicates the size of the data buffer. + Context Pointing to USB_KB_DEV instance. + Result Indicates the result of the asynchronous interrupt transfer. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 *CurKeyCodeBuffer; + UINT8 *OldKeyCodeBuffer; + UINT8 CurModifierMap; + UINT8 OldModifierMap; + UINT8 Index; + UINT8 Index2; + BOOLEAN Down; + EFI_STATUS Status; + BOOLEAN KeyRelease; + BOOLEAN KeyPress; + UINT8 SavedTail; + USB_KEY UsbKey; + UINT8 NewRepeatKey; + UINT32 UsbStatus; + UINT8 *DataPtr; + + ASSERT (Context); + + NewRepeatKey = 0; + DataPtr = (UINT8 *) Data; + UsbKeyboardDevice = (USB_KB_DEV *) Context; + UsbIo = UsbKeyboardDevice->UsbIo; + + // + // Analyzes the Result and performs corresponding action. + // + if (Result != EFI_USB_NOERROR) { + // + // Some errors happen during the process + // + KbdReportStatusCode ( + UsbKeyboardDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_INPUT_ERROR) + ); + + // + // stop the repeat key generation if any + // + UsbKeyboardDevice->RepeatKey = 0; + + gBS->SetTimer ( + UsbKeyboardDevice->RepeatTimer, + TimerCancel, + USBKBD_REPEAT_RATE + ); + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + UsbClearEndpointHalt ( + UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + &UsbStatus + ); + } + + // + // Delete & Submit this interrupt again + // + + Status = UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + gBS->SetTimer ( + UsbKeyboardDevice->DelayedRecoveryEvent, + TimerRelative, + EFI_USB_INTERRUPT_DELAY + ); + + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + CurKeyCodeBuffer = (UINT8 *) Data; + OldKeyCodeBuffer = UsbKeyboardDevice->LastKeyCodeArray; + + // + // checks for new key stroke. + // if no new key got, return immediately. + // + for (Index = 0; Index < 8; Index++) { + if (OldKeyCodeBuffer[Index] != CurKeyCodeBuffer[Index]) { + break; + } + } + + if (Index == 8) { + return EFI_SUCCESS; + } + + // + // Parse the modifier key + // + CurModifierMap = CurKeyCodeBuffer[0]; + OldModifierMap = OldKeyCodeBuffer[0]; + + // + // handle modifier key's pressing or releasing situation. + // + for (Index = 0; Index < 8; Index++) { + + if ((CurModifierMap & KB_Mod[Index].Mask) != (OldModifierMap & KB_Mod[Index].Mask)) { + // + // if current modifier key is up, then + // CurModifierMap & KB_Mod[Index].Mask = 0; + // otherwize it is a non-zero value. + // Inserts the pressed modifier key into key buffer. + // + Down = (UINT8) (CurModifierMap & KB_Mod[Index].Mask); + InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), KB_Mod[Index].Key, Down); + } + } + + // + // handle normal key's releasing situation + // + KeyRelease = FALSE; + for (Index = 2; Index < 8; Index++) { + + if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index])) { + continue; + } + + KeyRelease = TRUE; + for (Index2 = 2; Index2 < 8; Index2++) { + + if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index2])) { + continue; + } + + if (OldKeyCodeBuffer[Index] == CurKeyCodeBuffer[Index2]) { + KeyRelease = FALSE; + break; + } + } + + if (KeyRelease) { + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + OldKeyCodeBuffer[Index], + 0 + ); + // + // the original reapeat key is released. + // + if (OldKeyCodeBuffer[Index] == UsbKeyboardDevice->RepeatKey) { + UsbKeyboardDevice->RepeatKey = 0; + } + } + } + + // + // original repeat key is released, cancel the repeat timer + // + if (UsbKeyboardDevice->RepeatKey == 0) { + gBS->SetTimer ( + UsbKeyboardDevice->RepeatTimer, + TimerCancel, + USBKBD_REPEAT_RATE + ); + } + + // + // handle normal key's pressing situation + // + KeyPress = FALSE; + for (Index = 2; Index < 8; Index++) { + + if (!USBKBD_VALID_KEYCODE (CurKeyCodeBuffer[Index])) { + continue; + } + + KeyPress = TRUE; + for (Index2 = 2; Index2 < 8; Index2++) { + + if (!USBKBD_VALID_KEYCODE (OldKeyCodeBuffer[Index2])) { + continue; + } + + if (CurKeyCodeBuffer[Index] == OldKeyCodeBuffer[Index2]) { + KeyPress = FALSE; + break; + } + } + + if (KeyPress) { + InsertKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), CurKeyCodeBuffer[Index], 1); + // + // NumLock pressed or CapsLock pressed + // + if (CurKeyCodeBuffer[Index] == 0x53 || CurKeyCodeBuffer[Index] == 0x39) { + UsbKeyboardDevice->RepeatKey = 0; + } else { + NewRepeatKey = CurKeyCodeBuffer[Index]; + // + // do not repeat the original repeated key + // + UsbKeyboardDevice->RepeatKey = 0; + } + } + } + + // + // Update LastKeycodeArray[] buffer in the + // Usb Keyboard Device data structure. + // + for (Index = 0; Index < 8; Index++) { + UsbKeyboardDevice->LastKeyCodeArray[Index] = CurKeyCodeBuffer[Index]; + } + + // + // pre-process KeyboardBuffer, pop out the ctrl,alt,del key in sequence + // and judge whether it will invoke reset event. + // + SavedTail = UsbKeyboardDevice->KeyboardBuffer.bTail; + Index = UsbKeyboardDevice->KeyboardBuffer.bHead; + while (Index != SavedTail) { + RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey); + + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + if (UsbKey.Down) { + UsbKeyboardDevice->CtrlOn = 1; + } else { + UsbKeyboardDevice->CtrlOn = 0; + } + break; + + case 0xe2: + case 0xe6: + if (UsbKey.Down) { + UsbKeyboardDevice->AltOn = 1; + } else { + UsbKeyboardDevice->AltOn = 0; + } + break; + + // + // Del Key Code + // + case 0x4c: + case 0x63: + if (UsbKey.Down) { + if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) { + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + break; + + default: + break; + } + + // + // insert the key back to the buffer. + // so the key sequence will not be destroyed. + // + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + UsbKey.KeyCode, + UsbKey.Down + ); + Index = UsbKeyboardDevice->KeyboardBuffer.bHead; + + } + // + // If have new key pressed, update the RepeatKey value, and set the + // timer to repeate delay timer + // + if (NewRepeatKey != 0) { + // + // sets trigger time to "Repeat Delay Time", + // to trigger the repeat timer when the key is hold long + // enough time. + // + gBS->SetTimer ( + UsbKeyboardDevice->RepeatTimer, + TimerRelative, + USBKBD_REPEAT_DELAY + ); + UsbKeyboardDevice->RepeatKey = NewRepeatKey; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +USBParseKey ( + IN OUT USB_KB_DEV *UsbKeyboardDevice, + OUT UINT8 *KeyChar + ) +/*++ + + Routine Description: + Retrieves a key character after parsing the raw data in keyboard buffer. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + KeyChar Points to the Key character after key parsing. + + Returns: + EFI_SUCCESS - Success + EFI_NOT_READY - Device is not ready +--*/ +{ + USB_KEY UsbKey; + + *KeyChar = 0; + + while (!IsUSBKeyboardBufferEmpty (&UsbKeyboardDevice->KeyboardBuffer)) { + // + // pops one raw data off. + // + RemoveKeyCode (&(UsbKeyboardDevice->KeyboardBuffer), &UsbKey); + + if (!UsbKey.Down) { + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + UsbKeyboardDevice->CtrlOn = 0; + break; + + case 0xe1: + case 0xe5: + UsbKeyboardDevice->ShiftOn = 0; + break; + + case 0xe2: + case 0xe6: + UsbKeyboardDevice->AltOn = 0; + break; + + default: + break; + } + + continue; + } + + // + // Analyzes key pressing situation + // + switch (UsbKey.KeyCode) { + + case 0xe0: + case 0xe4: + UsbKeyboardDevice->CtrlOn = 1; + continue; + break; + + case 0xe1: + case 0xe5: + UsbKeyboardDevice->ShiftOn = 1; + continue; + break; + + case 0xe2: + case 0xe6: + UsbKeyboardDevice->AltOn = 1; + continue; + break; + + case 0xe3: + case 0xe7: + continue; + break; + + case 0x53: + UsbKeyboardDevice->NumLockOn ^= 1; + SetKeyLED (UsbKeyboardDevice); + continue; + break; + + case 0x39: + UsbKeyboardDevice->CapsOn ^= 1; + SetKeyLED (UsbKeyboardDevice); + continue; + break; + + // + // F11,F12,PrintScreen,ScrollLock,Pause,Application,Power + // keys are not valid EFI key + // + case 0x44: + // + // fall through + // + case 0x45: + // + // fall through + // + case 0x46: + // + // fall through + // + case 0x47: + // + // fall through + // + case 0x48: + // + // fall through + // + case 0x65: + case 0x66: + continue; + break; + + default: + break; + } + + // + // When encountered Del Key... + // + if (UsbKey.KeyCode == 0x4c || UsbKey.KeyCode == 0x63) { + if (UsbKeyboardDevice->CtrlOn && UsbKeyboardDevice->AltOn) { + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + } + } + + *KeyChar = UsbKey.KeyCode; + return EFI_SUCCESS; + } + + return EFI_NOT_READY; + +} + + +EFI_STATUS +USBKeyCodeToEFIScanCode ( + IN USB_KB_DEV *UsbKeyboardDevice, + IN UINT8 KeyChar, + OUT EFI_INPUT_KEY *Key + ) +/*++ + + Routine Description: + Converts USB Keyboard code to EFI Scan Code. + + Arguments: + UsbKeyboardDevice The USB_KB_DEV instance. + KeyChar Indicates the key code that will be interpreted. + Key A pointer to a buffer that is filled in with + the keystroke information for the key that + was pressed. + Returns: + EFI_NOT_READY - Device is not ready + EFI_SUCCESS - Success +--*/ +{ + UINT8 Index; + + if (!USBKBD_VALID_KEYCODE (KeyChar)) { + return EFI_NOT_READY; + } + + // + // valid USB Key Code starts from 4 + // + Index = (UINT8) (KeyChar - 4); + + if (Index >= USB_KEYCODE_MAX_MAKE) { + return EFI_NOT_READY; + } + + Key->ScanCode = KeyConvertionTable[Index][0]; + + if (UsbKeyboardDevice->ShiftOn) { + + Key->UnicodeChar = KeyConvertionTable[Index][2]; + + } else { + + Key->UnicodeChar = KeyConvertionTable[Index][1]; + } + + if (UsbKeyboardDevice->CapsOn) { + + if (Key->UnicodeChar >= 'a' && Key->UnicodeChar <= 'z') { + + Key->UnicodeChar = KeyConvertionTable[Index][2]; + + } else if (Key->UnicodeChar >= 'A' && Key->UnicodeChar <= 'Z') { + + Key->UnicodeChar = KeyConvertionTable[Index][1]; + + } + } + + if (KeyChar >= 0x59 && KeyChar <= 0x63) { + + if (UsbKeyboardDevice->NumLockOn && !UsbKeyboardDevice->ShiftOn) { + + Key->ScanCode = SCAN_NULL; + + } else { + + Key->UnicodeChar = 0x00; + } + } + + if (Key->UnicodeChar == 0 && Key->ScanCode == SCAN_NULL) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; + +} + + +EFI_STATUS +InitUSBKeyBuffer ( + IN OUT USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Resets USB Keyboard Buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + ZeroMem (KeyboardBuffer, sizeof (USB_KB_BUFFER)); + + KeyboardBuffer->bHead = KeyboardBuffer->bTail; + + return EFI_SUCCESS; +} + +BOOLEAN +IsUSBKeyboardBufferEmpty ( + IN USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Check whether USB Keyboard buffer is empty. + + Arguments: + KeyboardBuffer - USB Keyboard Buffer. + + Returns: + +--*/ +{ + // + // meet FIFO empty condition + // + return (BOOLEAN) (KeyboardBuffer->bHead == KeyboardBuffer->bTail); +} + + +BOOLEAN +IsUSBKeyboardBufferFull ( + IN USB_KB_BUFFER *KeyboardBuffer + ) +/*++ + + Routine Description: + Check whether USB Keyboard buffer is full. + + Arguments: + KeyboardBuffer - USB Keyboard Buffer. + + Returns: + +--*/ +{ + return (BOOLEAN)(((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)) == + KeyboardBuffer->bHead); +} + + +EFI_STATUS +InsertKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + IN UINT8 Key, + IN UINT8 Down + ) +/*++ + + Routine Description: + Inserts a key code into keyboard buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + Key - Key code + Down - Special key + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_KEY UsbKey; + + // + // if keyboard buffer is full, throw the + // first key out of the keyboard buffer. + // + if (IsUSBKeyboardBufferFull (KeyboardBuffer)) { + RemoveKeyCode (KeyboardBuffer, &UsbKey); + } + + KeyboardBuffer->buffer[KeyboardBuffer->bTail].KeyCode = Key; + KeyboardBuffer->buffer[KeyboardBuffer->bTail].Down = Down; + + // + // adjust the tail pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bTail = (UINT8) ((KeyboardBuffer->bTail + 1) % (MAX_KEY_ALLOWED + 1)); + + return EFI_SUCCESS; +} + +EFI_STATUS +RemoveKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + OUT USB_KEY *UsbKey + ) +/*++ + + Routine Description: + Pops a key code off from keyboard buffer. + + Arguments: + KeyboardBuffer - Points to the USB Keyboard Buffer. + UsbKey - Points to the buffer that contains a usb key code. + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error +--*/ +{ + if (IsUSBKeyboardBufferEmpty (KeyboardBuffer)) { + return EFI_DEVICE_ERROR; + } + + UsbKey->KeyCode = KeyboardBuffer->buffer[KeyboardBuffer->bHead].KeyCode; + UsbKey->Down = KeyboardBuffer->buffer[KeyboardBuffer->bHead].Down; + + // + // adjust the head pointer of the FIFO keyboard buffer. + // + KeyboardBuffer->bHead = (UINT8) ((KeyboardBuffer->bHead + 1) % (MAX_KEY_ALLOWED + 1)); + + return EFI_SUCCESS; +} + +EFI_STATUS +SetKeyLED ( + IN USB_KB_DEV *UsbKeyboardDevice + ) +/*++ + + Routine Description: + Sets USB Keyboard LED state. + + Arguments: + UsbKeyboardDevice - The USB_KB_DEV instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + LED_MAP Led; + UINT8 ReportId; + + // + // Set each field in Led map. + // + Led.NumLock = (UINT8) UsbKeyboardDevice->NumLockOn; + Led.CapsLock = (UINT8) UsbKeyboardDevice->CapsOn; + Led.Resrvd = 0; + + ReportId = 0; + // + // call Set Report Request to lighten the LED. + // + UsbSetReportRequest ( + UsbKeyboardDevice->UsbIo, + UsbKeyboardDevice->InterfaceDescriptor.InterfaceNumber, + ReportId, + HID_OUTPUT_REPORT, + 1, + (UINT8 *) &Led + ); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +USBKeyboardRepeatHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Repeat Key timer. + + Arguments: + Event - The Repeat Key event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + USB_KB_DEV *UsbKeyboardDevice; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + // + // Do nothing when there is no repeat key. + // + if (UsbKeyboardDevice->RepeatKey != 0) { + // + // Inserts one Repeat key into keyboard buffer, + // + InsertKeyCode ( + &(UsbKeyboardDevice->KeyboardBuffer), + UsbKeyboardDevice->RepeatKey, + 1 + ); + + // + // set repeate rate for repeat key generation. + // + gBS->SetTimer ( + UsbKeyboardDevice->RepeatTimer, + TimerRelative, + USBKBD_REPEAT_RATE + ); + + } +} + +VOID +EFIAPI +USBKeyboardRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Delayed Recovery timer. + + Arguments: + Event - The Delayed Recovery event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + + USB_KB_DEV *UsbKeyboardDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 PacketSize; + + UsbKeyboardDevice = (USB_KB_DEV *) Context; + + UsbIo = UsbKeyboardDevice->UsbIo; + + PacketSize = (UINT8) (UsbKeyboardDevice->IntEndpointDescriptor.MaxPacketSize); + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbKeyboardDevice->IntEndpointDescriptor.EndpointAddress, + TRUE, + UsbKeyboardDevice->IntEndpointDescriptor.Interval, + PacketSize, + KeyboardHandler, + UsbKeyboardDevice + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h new file mode 100644 index 0000000000..a01fda3ca4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbKb/Dxe/keyboard.h @@ -0,0 +1,106 @@ +/*++ +Copyright (c) 2006, 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: + + Keyboard.h + +Abstract: + + Function prototype for USB Keyboard Driver + +Revision History +--*/ + +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + +#include "efikey.h" + +BOOLEAN +IsUSBKeyboard ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ); + +EFI_STATUS +InitUSBKeyboard ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +EFI_STATUS +EFIAPI +KeyboardHandler ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ); + +VOID +EFIAPI +USBKeyboardRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +USBParseKey ( + IN OUT USB_KB_DEV *UsbKeyboardDevice, + OUT UINT8 *KeyChar + ); + +EFI_STATUS +USBKeyCodeToEFIScanCode ( + IN USB_KB_DEV *UsbKeyboardDevice, + IN UINT8 KeyChar, + OUT EFI_INPUT_KEY *Key + ); + +EFI_STATUS +InitUSBKeyBuffer ( + IN OUT USB_KB_BUFFER *KeyboardBuffer + ); + +BOOLEAN +IsUSBKeyboardBufferEmpty ( + IN USB_KB_BUFFER *KeyboardBuffer + ); + +BOOLEAN +IsUSBKeyboardBufferFull ( + IN USB_KB_BUFFER *KeyboardBuffer + ); + +EFI_STATUS +InsertKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + IN UINT8 Key, + IN UINT8 Down + ); + +EFI_STATUS +RemoveKeyCode ( + IN OUT USB_KB_BUFFER *KeyboardBuffer, + OUT USB_KEY *UsbKey + ); + +VOID +EFIAPI +USBKeyboardRepeatHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +SetKeyLED ( + IN USB_KB_DEV *UsbKeyboardDevice + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c new file mode 100644 index 0000000000..a021d95389 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/ComponentName.c @@ -0,0 +1,154 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "UsbMassStorage.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName = { + UsbMassStorageComponentNameGetDriverName, + UsbMassStorageComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbMassStorageDriverNameTable[] = { + { "eng", (CHAR16 *) L"Generic USB Mass Storage Driver" }, + { NULL , NULL } +}; + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbMassStorageComponentName.SupportedLanguages, + mUsbMassStorageDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbMassStorageComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return EFI_UNSUPPORTED; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c new file mode 100644 index 0000000000..932b8c5ed9 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.c @@ -0,0 +1,727 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbMassStorage.c + +Abstract: + + USB Mass Storage Driver + +Revision History + +--*/ + +#include "UsbMassStorage.h" +#include "UsbMassStorageHelper.h" + +extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName; + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBMassStorageDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Block I/O Protocol Interface +// +STATIC +EFI_STATUS +EFIAPI +USBFloppyReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +STATIC +EFI_STATUS +EFIAPI +USBFloppyFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + +// +// USB Floppy Driver Global Variables +// +EFI_DRIVER_BINDING_PROTOCOL gUSBFloppyDriverBinding = { + USBFloppyDriverBindingSupported, + USBFloppyDriverBindingStart, + USBFloppyDriverBindingStop, + 0x10, + NULL, + NULL +}; + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + + // + // check whether EFI_USB_ATAPI_PROTOCOL exists, if it does, + // then the controller must be a USB Mass Storage Controller + // + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &AtapiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus)) { + return OpenStatus; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Starting the Usb Bus Driver + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - Thios driver has been started +--*/ +{ + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + USB_FLOPPY_DEV *UsbFloppyDevice; + + UsbFloppyDevice = NULL; + // + // Check whether Usb Atapi Protocol attached on the controller handle. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + (VOID **) &AtapiProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->AllocatePool ( + EfiBootServicesData, + sizeof (USB_FLOPPY_DEV), + (VOID **) &UsbFloppyDevice + ); + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + ZeroMem (UsbFloppyDevice, sizeof (USB_FLOPPY_DEV)); + + UsbFloppyDevice->Handle = Controller; + UsbFloppyDevice->BlkIo.Media = &UsbFloppyDevice->BlkMedia; + UsbFloppyDevice->Signature = USB_FLOPPY_DEV_SIGNATURE; + UsbFloppyDevice->BlkIo.Reset = USBFloppyReset; + UsbFloppyDevice->BlkIo.ReadBlocks = USBFloppyReadBlocks; + UsbFloppyDevice->BlkIo.WriteBlocks = USBFloppyWriteBlocks; + UsbFloppyDevice->BlkIo.FlushBlocks = USBFloppyFlushBlocks; + UsbFloppyDevice->AtapiProtocol = AtapiProtocol; + + // + // Identify drive type and retrieve media information. + // + Status = USBFloppyIdentify (UsbFloppyDevice); + if (EFI_ERROR (Status)) { + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + // + // Install Block I/O protocol for the usb floppy device. + // + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiBlockIoProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbFloppyDevice->BlkIo + ); + if (EFI_ERROR (Status)) { + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; + } + + return EFI_SUCCESS; + +} + + +EFI_STATUS +EFIAPI +USBFloppyDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + + // + // First find USB_FLOPPY_DEV + // + gBS->OpenProtocol ( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **) &BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (BlkIo); + + // + // Uninstall Block I/O protocol from the device handle + // + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo + ); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Stop using EFI_USB_ATAPI_PROTOCOL + // + gBS->CloseProtocol ( + Controller, + &gEfiUsbAtapiProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + } + + gBS->FreePool (UsbFloppyDevice); + + return EFI_SUCCESS; +} + + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.Reset() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + ExtendedVerification + Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + (This parameter is ingored in this driver.) + + Returns: + EFI_SUCCESS - Success +--*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + EFI_STATUS Status; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // directly calling EFI_USB_ATAPI_PROTOCOL.Reset() to implement reset. + // + Status = UsbAtapiInterface->UsbAtapiReset (UsbAtapiInterface, TRUE); + + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + OUT VOID *Buffer + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + MediaId The media id that the read request is for. + LBA The starting logical block address to read from on the device. + BufferSize + The size of the Buffer in bytes. This must be a multiple of + the intrinsic block size of the device. + Buffer A pointer to the destination buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error + EFI_NO_MEDIA - No media + EFI_MEDIA_CHANGED - Media Change + EFI_BAD_BUFFER_SIZE - Buffer size is bad + --*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + UINT32 Retry; + + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + Status = EFI_SUCCESS; + MediaChange = FALSE; + Retry = 0; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + // + // Check parameters + // + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + UsbFloppyTestUnitReady (UsbFloppyDevice); + + Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->RestoreTPL (OldTpl); + gBS->ReinstallProtocolInterface ( + UsbFloppyDevice->Handle, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo, + &UsbFloppyDevice->BlkIo + ); + gBS->RaiseTPL (EFI_TPL_NOTIFY); + } + + Media = UsbFloppyDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto Done; + } + + if (BufferSize % BlockSize != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + if (LBA > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (!EFI_ERROR (Status)) { + + Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, 1); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + LBA += 1; + NumberOfBlocks -= 1; + Buffer = (UINT8 *) Buffer + This->Media->BlockSize; + + if (NumberOfBlocks == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + Status = USBFloppyRead10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + } + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA LBA, + IN UINTN BufferSize, + IN VOID *Buffer + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks() function. + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + MediaId The media id that the write request is for. + LBA The starting logical block address to be written. + The caller is responsible for writing to only + legitimate locations. + BufferSize + The size of the Buffer in bytes. This must be a multiple of + the intrinsic block size of the device. + Buffer A pointer to the source buffer for the data. The caller + is responsible for either having implicit or explicit ownership + of the buffer. + + Returns: + EFI_INVALID_PARAMETER - Parameter is error + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Hardware Error + EFI_NO_MEDIA - No media + EFI_MEDIA_CHANGED - Media Change + EFI_BAD_BUFFER_SIZE - Buffer size is bad + +--*/ +{ + USB_FLOPPY_DEV *UsbFloppyDevice; + EFI_STATUS Status; + EFI_BLOCK_IO_MEDIA *Media; + UINTN BlockSize; + UINTN NumberOfBlocks; + BOOLEAN MediaChange; + EFI_TPL OldTpl; + UINT32 Retry; + + OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY); + Status = EFI_SUCCESS; + MediaChange = FALSE; + Retry = 0; + + UsbFloppyDevice = USB_FLOPPY_DEV_FROM_THIS (This); + + // + // Check parameters + // + if (!Buffer) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (BufferSize == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + UsbFloppyTestUnitReady (UsbFloppyDevice); + + Status = UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + if (EFI_ERROR (Status)) { + + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (MediaChange) { + gBS->RestoreTPL (OldTpl); + gBS->ReinstallProtocolInterface ( + UsbFloppyDevice->Handle, + &gEfiBlockIoProtocolGuid, + &UsbFloppyDevice->BlkIo, + &UsbFloppyDevice->BlkIo + ); + gBS->RaiseTPL (EFI_TPL_NOTIFY); + } + + Media = UsbFloppyDevice->BlkIo.Media; + BlockSize = Media->BlockSize; + NumberOfBlocks = BufferSize / BlockSize; + + if (!(Media->MediaPresent)) { + Status = EFI_NO_MEDIA; + goto Done; + } + + if (MediaId != Media->MediaId) { + Status = EFI_MEDIA_CHANGED; + goto Done; + } + + if (BufferSize % BlockSize != 0) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + if (LBA > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (UsbFloppyDevice->BlkMedia.ReadOnly) { + Status = EFI_WRITE_PROTECTED; + goto Done; + } + + if (!EFI_ERROR (Status)) { + Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, 1); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + LBA += 1; + NumberOfBlocks -= 1; + Buffer = (UINT8 *) Buffer + This->Media->BlockSize; + + if (NumberOfBlocks == 0) { + Status = EFI_SUCCESS; + goto Done; + } + + Status = USBFloppyWrite10 (UsbFloppyDevice, Buffer, LBA, NumberOfBlocks); + if (EFI_ERROR (Status)) { + This->Reset (This, TRUE); + Status = EFI_DEVICE_ERROR; + } + } + +Done: + gBS->RestoreTPL (OldTpl); + return Status; +} + +STATIC +EFI_STATUS +EFIAPI +USBFloppyFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ) +/*++ + + Routine Description: + Implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks() function. + (In this driver, this function just returns EFI_SUCCESS.) + + Arguments: + This The EFI_BLOCK_IO_PROTOCOL instance. + + Returns: + EFI_SUCCESS - Success +--*/ +{ + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h new file mode 100644 index 0000000000..4874bb08cc --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.h @@ -0,0 +1,59 @@ +/*++ +Copyright (c) 2006, 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: + + UsbMassStorage.h + +Abstract: + + Header file for USB Mass Storage Driver's Data Structures + +Revision History +--*/ + +#ifndef _USB_FLP_H +#define _USB_FLP_H + + +#include +#include "UsbMassStorageData.h" + +#define CLASS_MASSTORAGE 8 +#define SUBCLASS_UFI 4 +#define SUBCLASS_8070 5 +#define PROTOCOL_BOT 0x50 +#define PROTOCOL_CBI0 0 +#define PROTOCOL_CBI1 1 + +#define USBFLOPPY 1 +#define USBFLOPPY2 2 // for those that use ReadCapacity(0x25) command to retrieve media capacity +#define USBCDROM 3 + +#define USB_FLOPPY_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'f', 'l', 'p') + +typedef struct { + UINTN Signature; + + EFI_HANDLE Handle; + EFI_BLOCK_IO_PROTOCOL BlkIo; + EFI_BLOCK_IO_MEDIA BlkMedia; + EFI_USB_ATAPI_PROTOCOL *AtapiProtocol; + + REQUEST_SENSE_DATA *SenseData; + UINT8 SenseDataNumber; + UINT8 DeviceType; + +} USB_FLOPPY_DEV; + +#define USB_FLOPPY_DEV_FROM_THIS(a) \ + CR(a, USB_FLOPPY_DEV, BlkIo, USB_FLOPPY_DEV_SIGNATURE) + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd new file mode 100644 index 0000000000..c9c9b5c73b --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.mbd @@ -0,0 +1,43 @@ + + + + + UsbMassStorage + A5C6D68B-E78A-4426-9278-A8F0D9EB4D8F + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa new file mode 100644 index 0000000000..d071c9f656 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorage.msa @@ -0,0 +1,70 @@ + + + + + UsbMassStorage + DXE_DRIVER + BS_DRIVER + A5C6D68B-E78A-4426-9278-A8F0D9EB4D8F + 0 + Component description file for UsbMassStorage module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + MemoryAllocationLib + UefiBootServicesTableLib + + + UsbMassStorage.h + UsbMassStorageData.h + UsbMassStorageHelper.h + UsbMassStorage.c + UsbMassStorageHelper.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + UsbAtapi + BlockIo + + + + + + + gUSBFloppyDriverBinding + gUsbMassStorageComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h new file mode 100644 index 0000000000..598c82e220 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageData.h @@ -0,0 +1,394 @@ +/*++ +Copyright (c) 2006, 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: + + UsbMassStorageData.h + +Abstract: + + Header file for USB Mass Storage Device related Data Structures + +Revision History +--*/ + +#ifndef _USB_FLP_DATA_H +#define _USB_FLP_DATA_H + +// +// bit definition +// +#define bit(a) 1 << (a) + +// +// timeout unit is in millisecond. +// +#define USBFLPTIMEOUT 2000 +#define STALL_1_MILLI_SECOND 1000 + +// +// ATAPI Packet Command +// +#pragma pack(1) + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} TEST_UNIT_READY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} INQUIRY_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 reserved_8; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} REQUEST_SENSE_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 4; + UINT8 lun : 4; + UINT8 page_code : 6; + UINT8 page_control : 2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 parameter_list_length_hi; + UINT8 parameter_list_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} MODE_SENSE_CMD_UFI; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 3; + UINT8 dbd : 1; + UINT8 reserved_2 : 1; + UINT8 lun : 3; + UINT8 page_code : 6; + UINT8 page_control : 2; + UINT8 reserved_3; + UINT8 allocation_length; + UINT8 control; +} MODE_SENSE_CMD_SCSI; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1 : 5; + UINT8 lun : 3; + UINT8 Lba0; + UINT8 Lba1; + UINT8 Lba2; + UINT8 Lba3; + UINT8 reserved_6; + UINT8 TranLen0; + UINT8 TranLen1; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ10_CMD; + +typedef struct { + UINT8 opcode; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 reserved_3; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 allocation_length_hi; + UINT8 allocation_length_lo; + UINT8 reserved_9; + UINT8 reserved_10; + UINT8 reserved_11; +} READ_FORMAT_CAP_CMD; + +typedef union { + UINT16 Data16[6]; + TEST_UNIT_READY_CMD TestUnitReady; + READ10_CMD Read10; + REQUEST_SENSE_CMD RequestSense; + INQUIRY_CMD Inquiry; + MODE_SENSE_CMD_UFI ModeSenseUFI; + READ_FORMAT_CAP_CMD ReadFormatCapacity; + MODE_SENSE_CMD_SCSI ModeSenseSCSI; +} ATAPI_PACKET_COMMAND; + +#pragma pack() +// +// Packet Command Code +// +#define TEST_UNIT_READY 0x00 +#define REZERO 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define REASSIGN_BLOCKS 0x07 +#define INQUIRY 0x12 +#define START_STOP_UNIT 0x1B +#define PREVENT_ALLOW_MEDIA_REMOVAL 0x1E +#define READ_FORMAT_CAPACITY 0x23 +#define OLD_FORMAT_UNIT 0x24 +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2A +#define SEEK 0x2B +#define SEND_DIAGNOSTICS 0x3D +#define WRITE_VERIFY 0x2E +#define VERIFY 0x2F +#define READ_DEFECT_DATA 0x37 +#define WRITE_BUFFER 0x38 +#define READ_BUFFER 0x3C +#define READ_LONG 0x3E +#define WRITE_LONG 0x3F +#define MODE_SELECT 0x55 +#define UFI_MODE_SENSE5A 0x5A +#define SCSI_MODE_SENSE1A 0x1A +#define READ_12 0xA8 +#define WRITE_12 0xAA +#define MAX_ATAPI_BYTE_COUNT (0xfffe) + +// +// Sense Key +// +#define REQUEST_SENSE_ERROR (0x70) +#define SK_NO_SENSE (0x0) +#define SK_RECOVERY_ERROR (0x1) +#define SK_NOT_READY (0x2) +#define SK_MEDIUM_ERROR (0x3) +#define SK_HARDWARE_ERROR (0x4) +#define SK_ILLEGAL_REQUEST (0x5) +#define SK_UNIT_ATTENTION (0x6) +#define SK_DATA_PROTECT (0x7) +#define SK_BLANK_CHECK (0x8) +#define SK_VENDOR_SPECIFIC (0x9) +#define SK_RESERVED_A (0xA) +#define SK_ABORT (0xB) +#define SK_RESERVED_C (0xC) +#define SK_OVERFLOW (0xD) +#define SK_MISCOMPARE (0xE) +#define SK_RESERVED_F (0xF) + +// +// Additional Sense Codes +// +#define ASC_NOT_READY (0x04) +#define ASC_MEDIA_ERR1 (0x10) +#define ASC_MEDIA_ERR2 (0x11) +#define ASC_MEDIA_ERR3 (0x14) +#define ASC_MEDIA_ERR4 (0x30) +#define ASC_MEDIA_UPSIDE_DOWN (0x06) +#define ASC_INVALID_CMD (0x20) +#define ASC_LBA_OUT_OF_RANGE (0x21) +#define ASC_INVALID_FIELD (0x24) +#define ASC_WRITE_PROTECTED (0x27) +#define ASC_MEDIA_CHANGE (0x28) +#define ASC_RESET (0x29) /* Power On Reset or Bus Reset occurred */ +#define ASC_ILLEGAL_FIELD (0x26) +#define ASC_NO_MEDIA (0x3A) +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK (0x64) +#define ASC_LOGICAL_UNIT_STATUS (0x08) + +// +// Additional Sense Code Qualifier +// +#define ASCQ_IN_PROGRESS (0x01) +#define ASCQ_DEVICE_BUSY (0xff) +#define ASCQ_LOGICAL_UNIT_FAILURE (0x00) +#define ASCQ_LOGICAL_UNIT_TIMEOUT (0x01) +#define ASCQ_LOGICAL_UNIT_OVERRUN (0x80) + +#define SETFEATURE TRUE +#define CLEARFEATURE FALSE + +// +// ATAPI Data structure +// +#pragma pack(1) + +typedef struct { + UINT8 peripheral_type; + UINT8 RMB; + UINT8 version; + UINT8 response_data_format; + UINT8 addnl_length; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; + UINT8 vendor_info[8]; + UINT8 product_id[12]; + UINT8 eeprom_product_code[4]; + UINT8 firmware_rev_level[4]; +} USB_INQUIRY_DATA; + +typedef struct { + UINT8 error_code : 7; + UINT8 valid : 1; + UINT8 reserved_1; + UINT8 sense_key : 4; + UINT8 reserved_21 : 1; + UINT8 ILI : 1; + UINT8 reserved_22 : 2; + UINT8 vendor_specific_3; + UINT8 vendor_specific_4; + UINT8 vendor_specific_5; + UINT8 vendor_specific_6; + UINT8 addnl_sense_length; // n - 7 + UINT8 vendor_specific_8; + UINT8 vendor_specific_9; + UINT8 vendor_specific_10; + UINT8 vendor_specific_11; + UINT8 addnl_sense_code; // mandatory + UINT8 addnl_sense_code_qualifier; // mandatory + UINT8 field_replaceable_unit_code; // optional + UINT8 reserved_15; + UINT8 reserved_16; + UINT8 reserved_17; + // + // Followed by additional sense bytes : FIXME + // +} REQUEST_SENSE_DATA; + +typedef struct { + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 BlockSize3; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_CAPACITY_DATA; + +typedef struct { + UINT8 reserved_0; + UINT8 reserved_1; + UINT8 reserved_2; + UINT8 Capacity_Length; + UINT8 LastLba3; + UINT8 LastLba2; + UINT8 LastLba1; + UINT8 LastLba0; + UINT8 DesCode : 2; + UINT8 reserved_9 : 6; + UINT8 BlockSize2; + UINT8 BlockSize1; + UINT8 BlockSize0; +} READ_FORMAT_CAPACITY_DATA; + +typedef struct { + UINT8 mode_data_len_hi; + UINT8 mode_data_len_lo; + UINT8 media_type_code; + UINT8 reserved_3_0 : 4; + UINT8 dpofua : 1; + UINT8 reserved_3_1 : 2; + UINT8 write_protected : 1; + UINT8 reserved_4; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; +} UFI_MODE_PARAMETER_HEADER; + +typedef struct { + UINT8 mode_data_len; + UINT8 media_type_code; + UINT8 speed : 4; + UINT8 buffered_mode : 3; + UINT8 write_protected : 1; + UINT8 block_descritptor_length; +} SCSI_MODE_PARAMETER_HEADER6; + +typedef struct { + UINT8 page_code : 6; + UINT8 reserved_0 : 1; + UINT8 parameter_savable : 1; + UINT8 page_length; + UINT8 transfer_rate_msb; + UINT8 transfer_rate_lsb; + UINT8 number_of_heads; + UINT8 sectors_per_track; + UINT8 databytes_per_sector_msb; + UINT8 databytes_per_sector_lsb; + UINT8 number_of_cylinders_msb; + UINT8 number_of_cylinders_lsb; + UINT8 reserved_10_18[9]; + UINT8 motor_on_delay; + UINT8 motor_off_delay; + UINT8 reserved_21_27[7]; + UINT8 medium_rotation_rate_msb; + UINT8 medium_rotation_rate_lsb; + UINT8 reserved_30_31[2]; +} FLEXIBLE_DISK_PAGE; + +typedef struct { + UFI_MODE_PARAMETER_HEADER mode_param_header; + FLEXIBLE_DISK_PAGE flex_disk_page; +} UFI_MODE_PARAMETER_PAGE_5; + +typedef struct { + UINT8 page_code : 6; + UINT8 reserved_0 : 1; + UINT8 parameter_savable : 1; + UINT8 page_length; + UINT8 reserved_2; + UINT8 inactive_time_multplier : 4; + UINT8 reserved_3 : 4; + UINT8 software_write_protect : 1; + UINT8 disable_media_access : 1; + UINT8 reserved_4 : 6; + UINT8 reserved_5; + UINT8 reserved_6; + UINT8 reserved_7; +} TIMER_AND_PROTECT_PAGE; + +typedef struct { + UFI_MODE_PARAMETER_HEADER mode_param_header; + TIMER_AND_PROTECT_PAGE time_and_protect_page; +} UFI_MODE_PARAMETER_PAGE_1C; + +#pragma pack() + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c new file mode 100644 index 0000000000..b8ed813ea2 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.c @@ -0,0 +1,1653 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbMassStorageHelper.c + +Abstract: + + Helper functions for USB Mass Storage Driver + +Revision History + +--*/ + +#include "UsbMassStorageHelper.h" + +STATIC +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ); + +STATIC +BOOLEAN +IsMediaWriteProtected ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +STATIC +BOOLEAN +IsLogicalUnitCommunicationOverRun ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ); + +EFI_STATUS +USBFloppyPacketCommand ( + USB_FLOPPY_DEV *UsbFloppyDevice, + VOID *Command, + UINT8 CommandSize, + VOID *DataBuffer, + UINT32 BufferLength, + EFI_USB_DATA_DIRECTION Direction, + UINT16 TimeOutInMilliSeconds + ) +/*++ + + Routine Description: + Sends Packet Command to USB Floppy Drive. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Command - A pointer to the command packet. + CommandSize - Indicates the size of the command packet. + DataBuffer - A pointer to the buffer for the data transfer + after the command packet. + BufferLength - Indicates the size of the Data Buffer. + Direction - Transfer Direction + TimeOutInMilliSeconds - Timeout Value + Returns: + EFI_SUCCESS - Success +--*/ +{ + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + EFI_STATUS Status; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + // + // Directly calling EFI_USB_ATAPI_PROTOCOL.UsbAtapiPacketCmd() + // to perform the command request. + // + Status = UsbAtapiInterface->UsbAtapiPacketCmd ( + UsbAtapiInterface, + Command, + CommandSize, + DataBuffer, + BufferLength, + Direction, + TimeOutInMilliSeconds + ); + + return Status; +} + +EFI_STATUS +USBFloppyIdentify ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves device information to tell the device type. + + Arguments: + UsbFloppyDevice The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + + EFI_STATUS Status; + USB_INQUIRY_DATA *Idata; + BOOLEAN MediaChange; + + // + // Send Inquiry Packet Command to get INQUIRY data. + // + Status = USBFloppyInquiry (UsbFloppyDevice, &Idata); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + // + // Get media removable info from INQUIRY data. + // + UsbFloppyDevice->BlkIo.Media->RemovableMedia = (UINT8) ((Idata->RMB & 0x80) == 0x80); + + // + // Identify device type via INQUIRY data. + // + switch ((Idata->peripheral_type) & 0x1f) { + // + // Floppy + // + case 0x00: + UsbFloppyDevice->DeviceType = USBFLOPPY; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + break; + + // + // CD-ROM + // + case 0x05: + UsbFloppyDevice->DeviceType = USBCDROM; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + break; + + default: + gBS->FreePool (Idata); + return EFI_DEVICE_ERROR; + }; + + // + // Initialize some device specific data. + // + // + // original sense data numbers + // + UsbFloppyDevice->SenseDataNumber = 6; + + if (UsbFloppyDevice->SenseData != NULL) { + gBS->FreePool (UsbFloppyDevice->SenseData); + UsbFloppyDevice->SenseData = NULL; + } + + UsbFloppyDevice->SenseData = AllocatePool (UsbFloppyDevice->SenseDataNumber * sizeof (REQUEST_SENSE_DATA)); + + if (UsbFloppyDevice->SenseData == NULL) { + gBS->FreePool (Idata); + return EFI_DEVICE_ERROR; + } + + // + // Get media information. + // + UsbFloppyDetectMedia (UsbFloppyDevice, &MediaChange); + + gBS->FreePool (Idata); + + return EFI_SUCCESS; +} + +EFI_STATUS +USBFloppyInquiry ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT USB_INQUIRY_DATA **Idata + ) +/*++ + + Routine Description: + Send Inquiry Packet Command to device and retrieve Inquiry Data. + + Arguments: + UsbFloppyDevice The USB_FLOPPY_DEV instance. + Idata A pointer pointing to the address of + Inquiry Data. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = INQUIRY; + Packet.Inquiry.page_code = 0; + Packet.Inquiry.allocation_length = sizeof (USB_INQUIRY_DATA); + + *Idata = AllocateZeroPool (sizeof (USB_INQUIRY_DATA)); + if (*Idata == NULL) { + return EFI_DEVICE_ERROR; + } + // + // Send command packet and retrieve requested Inquiry Data. + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) (*Idata), + sizeof (USB_INQUIRY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT * 3 + ); + if (EFI_ERROR (Status)) { + gBS->FreePool (*Idata); + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +USBFloppyRead10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + + Routine Description: + Sends Read10 Packet Command to device to perform data transfer + from device to host. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Buffer - A pointer to the destination buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the buffer. + Lba - The starting logical block address to read from + on the device. + NumberOfBlocks - Indicates the number of blocks that the read + operation requests. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Read10Packet; + UINT16 MaxBlock; + UINT16 BlocksRemaining; + UINT16 SectorCount; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + VOID *ptrBuffer; + EFI_STATUS Status; + UINT16 TimeOut; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINTN SenseCounts; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Inquiry Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Read10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; + + MaxBlock = (UINT16) (65536 / BlockSize); + BlocksRemaining = (UINT16) NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + if (BlocksRemaining <= MaxBlock) { + SectorCount = BlocksRemaining; + } else { + SectorCount = MaxBlock; + } + // + // fill the Packet data structure + // + Read10Packet->opcode = READ_10; + + // + // Lba0 ~ Lba3 specify the start logical block address of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Read10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Read10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Read10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT); + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataIn, + TimeOut + ); + if (EFI_ERROR (Status)) { + + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + if (!EFI_ERROR (Status)) { + if (IsLogicalUnitCommunicationOverRun ( + UsbFloppyDevice->SenseData, + SenseCounts + )) { + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlocksRemaining = (UINT16) NumberOfBlocks; + MaxBlock = (UINT16) (MaxBlock / 4); + if (MaxBlock < 1) { + MaxBlock = 1; + } + + continue; + } + } else { + return EFI_DEVICE_ERROR; + } + // + // retry read10 command + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataIn, + TimeOut + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + Lba32 += SectorCount; + ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; + BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); + } + + return Status; +} + +EFI_STATUS +USBFloppyReadCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via + sending Read Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + // + // used for capacity data returned from Usb Floppy + // + READ_CAPACITY_DATA Data; + + ZeroMem (&Data, sizeof (Data)); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.Inquiry.opcode = READ_CAPACITY; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &Data, + sizeof (READ_CAPACITY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) | + (Data.LastLba2 << 16) | + (Data.LastLba1 << 8) | + Data.LastLba0; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x800; + + return EFI_SUCCESS; + +} + +EFI_STATUS +USBFloppyReadFormatCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + // + // used for capacity data returned from Usb Floppy + // + READ_FORMAT_CAPACITY_DATA FormatData; + + ZeroMem (&FormatData, sizeof (FormatData)); + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY; + Packet.ReadFormatCapacity.allocation_length_lo = 12; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &FormatData, + sizeof (READ_FORMAT_CAPACITY_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + if (FormatData.DesCode == 3) { + // + // Media is not present + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } else { + + UsbFloppyDevice->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) | + (FormatData.LastLba2 << 16) | + (FormatData.LastLba1 << 8) | + FormatData.LastLba0; + + UsbFloppyDevice->BlkIo.Media->LastBlock--; + + UsbFloppyDevice->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) | + (FormatData.BlockSize1 << 8) | + FormatData.BlockSize0; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + + } + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbFloppyRequestSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT UINTN *SenseCounts + ) +/*++ + + Routine Description: + Retrieves Sense Data from device via + sending Request Sense Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + SenseCounts - A pointer to the number of Sense Data returned. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + EFI_STATUS Status; + REQUEST_SENSE_DATA *Sense; + UINT8 *Ptr; + BOOLEAN SenseReq; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + *SenseCounts = 0; + + ZeroMem ( + UsbFloppyDevice->SenseData, + sizeof (REQUEST_SENSE_DATA) * (UsbFloppyDevice->SenseDataNumber) + ); + // + // fill command packet for Request Sense Packet Command + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.RequestSense.opcode = REQUEST_SENSE; + Packet.RequestSense.allocation_length = sizeof (REQUEST_SENSE_DATA); + + // + // initialize pointer + // + Ptr = (UINT8 *) (UsbFloppyDevice->SenseData); + + // + // request sense data from device continuously + // until no sense data exists in the device. + // + for (SenseReq = TRUE; SenseReq;) { + + Sense = (REQUEST_SENSE_DATA *) Ptr; + + // + // send out Request Sense Packet Command and get one Sense + // data from device. + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) Ptr, + sizeof (REQUEST_SENSE_DATA), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + // + // failed to get Sense data + // + if (EFI_ERROR (Status)) { + // + // Recovery the device back to normal state. + // + UsbFloppyDevice->AtapiProtocol->UsbAtapiReset ( + UsbFloppyDevice->AtapiProtocol, + TRUE + ); + + if (*SenseCounts == 0) { + // + // never retrieved any sense data from device, + // just return error. + // + return EFI_DEVICE_ERROR; + } else { + // + // has retrieved some sense data from device, + // so return success. + // + return EFI_SUCCESS; + } + } + + if (Sense->sense_key != SK_NO_SENSE) { + // + // Ptr is byte based pointer + // + Ptr += sizeof (REQUEST_SENSE_DATA); + + (*SenseCounts)++; + + } else { + // + // when no sense key, skip out the loop + // + SenseReq = FALSE; + } + + // + // If the sense key numbers exceed Sense Data Buffer size, + // just skip the loop and do not fetch the sense key in this function. + // + if (*SenseCounts == UsbFloppyDevice->SenseDataNumber) { + SenseReq = FALSE; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +UsbFloppyTestUnitReady ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Sends Test Unit ReadyPacket Command to the device. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + EFI_STATUS Status; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINT32 RetryIndex; + UINT32 MaximumRetryTimes; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + MaximumRetryTimes = 2; + // + // fill command packet + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.TestUnitReady.opcode = TEST_UNIT_READY; + + // + // send command packet + // + Status = EFI_DEVICE_ERROR; + + for (RetryIndex = 0; RetryIndex < MaximumRetryTimes && EFI_ERROR (Status); RetryIndex++) { + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + NULL, + 0, + EfiUsbNoData, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + gBS->Stall (100 * STALL_1_MILLI_SECOND); + } + } + + return Status; +} + +EFI_STATUS +USBFloppyWrite10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ) +/*++ + + Routine Description: + Sends Write10 Packet Command to device to perform data transfer + from host to device. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + Buffer - A pointer to the source buffer for the data. + The caller is responsible for either having implicit + or explicit ownership of the buffer. + Lba - The starting logical block address to written to + the device. + NumberOfBlocks - Indicates the number of blocks that the write + operation requests. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success +--*/ +{ + ATAPI_PACKET_COMMAND Packet; + READ10_CMD *Write10Packet; + UINT16 MaxBlock; + UINT16 BlocksRemaining; + UINT16 SectorCount; + UINT32 Lba32; + UINT32 BlockSize; + UINT32 ByteCount; + VOID *ptrBuffer; + EFI_STATUS Status; + UINT16 TimeOut; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UINTN SenseCounts; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + // + // prepare command packet for the Write10 Packet Command. + // + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Write10Packet = &Packet.Read10; + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlockSize = UsbFloppyDevice->BlkIo.Media->BlockSize; + + MaxBlock = (UINT16) (65536 / BlockSize); + BlocksRemaining = (UINT16) NumberOfBlocks; + + Status = EFI_SUCCESS; + while (BlocksRemaining > 0) { + + if (BlocksRemaining <= MaxBlock) { + + SectorCount = BlocksRemaining; + } else { + + SectorCount = MaxBlock; + } + // + // fill the Packet data structure + // + Write10Packet->opcode = WRITE_10; + + // + // Lba0 ~ Lba3 specify the start logical block address + // of the data transfer. + // Lba0 is MSB, Lba3 is LSB + // + Write10Packet->Lba3 = (UINT8) (Lba32 & 0xff); + Write10Packet->Lba2 = (UINT8) (Lba32 >> 8); + Write10Packet->Lba1 = (UINT8) (Lba32 >> 16); + Write10Packet->Lba0 = (UINT8) (Lba32 >> 24); + + // + // TranLen0 ~ TranLen1 specify the transfer length in block unit. + // TranLen0 is MSB, TranLen is LSB + // + Write10Packet->TranLen1 = (UINT8) (SectorCount & 0xff); + Write10Packet->TranLen0 = (UINT8) (SectorCount >> 8); + + ByteCount = SectorCount * BlockSize; + + TimeOut = (UINT16) (SectorCount * USBFLPTIMEOUT); + + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataOut, + TimeOut + ); + if (EFI_ERROR (Status)) { + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + if (!EFI_ERROR (Status)) { + if (IsLogicalUnitCommunicationOverRun ( + UsbFloppyDevice->SenseData, + SenseCounts + )) { + Lba32 = (UINT32) Lba; + ptrBuffer = Buffer; + BlocksRemaining = (UINT16) NumberOfBlocks; + MaxBlock = (UINT16) (MaxBlock / 4); + if (MaxBlock < 1) { + MaxBlock = 1; + } + + continue; + } + } + // + // retry write10 command + // + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) ptrBuffer, + ByteCount, + EfiUsbDataOut, + TimeOut + ); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + Lba32 += SectorCount; + ptrBuffer = (UINT8 *) ptrBuffer + SectorCount * BlockSize; + BlocksRemaining = (UINT16) (BlocksRemaining - SectorCount); + } + + return Status; +} + +EFI_STATUS +UsbFloppyDetectMedia ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT BOOLEAN *MediaChange + ) +/*++ + + Routine Description: + Retrieves media information. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + MediaChange - Indicates whether media was changed. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + EFI_INVALID_PARAMETER - Parameter is error +--*/ +{ + EFI_STATUS Status; + EFI_STATUS FloppyStatus; + // + // the following variables are used to record previous media information + // + EFI_BLOCK_IO_MEDIA OldMediaInfo; + UINTN SenseCounts; + UINTN RetryIndex; + UINTN RetryTimes; + UINTN MaximumRetryTimes; + BOOLEAN NeedRetry; + + // + // a flag used to determine whether need to perform Read Capacity command. + // + BOOLEAN NeedReadCapacity; + + REQUEST_SENSE_DATA *SensePtr; + + // + // init + // + Status = EFI_SUCCESS; + FloppyStatus = EFI_SUCCESS; + CopyMem (&OldMediaInfo, UsbFloppyDevice->BlkIo.Media, sizeof (OldMediaInfo)); + //OldMediaInfo = *UsbFloppyDevice->BlkIo.Media; + *MediaChange = FALSE; + NeedReadCapacity = TRUE; + + // + // if there is no media present,or media not changed, + // the request sense command will detect faster than read capacity command. + // read capacity command can be bypassed, thus improve performance. + // + SenseCounts = 0; + Status = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + + if (!EFI_ERROR (Status)) { + + SensePtr = UsbFloppyDevice->SenseData; + + // + // No Media + // + if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { + + NeedReadCapacity = FALSE; + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } else { + // + // Media Changed + // + if (IsMediaChange (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->MediaId++; + } + + // + // Media Write-protected + // + if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + } + + // + // Media Error + // + if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + } + + } + + } + + if (NeedReadCapacity) { + // + // at most retry 5 times + // + MaximumRetryTimes = 5; + // + // initial retry twice + // + RetryTimes = 2; + + for (RetryIndex = 0; (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes); RetryIndex++) { + // + // Using different command to retrieve media capacity. + // + switch (UsbFloppyDevice->DeviceType) { + + case USBCDROM: + Status = USBFloppyReadCapacity (UsbFloppyDevice); + break; + + case USBFLOPPY: + UsbMassStorageModeSense (UsbFloppyDevice); + Status = USBFloppyReadFormatCapacity (UsbFloppyDevice); + if (EFI_ERROR (Status) || !UsbFloppyDevice->BlkMedia.MediaPresent) { + // + // retry the ReadCapacity command + // + UsbFloppyDevice->DeviceType = USBFLOPPY2; + Status = EFI_DEVICE_ERROR; + } + break; + + case USBFLOPPY2: + UsbMassStorageModeSense (UsbFloppyDevice); + Status = USBFloppyReadCapacity (UsbFloppyDevice); + if (EFI_ERROR (Status)) { + // + // retry the ReadFormatCapacity command + // + UsbFloppyDevice->DeviceType = USBFLOPPY; + } + // + // force the BlockSize to be 0x200. + // + UsbFloppyDevice->BlkIo.Media->BlockSize = 0x200; + break; + + default: + return EFI_INVALID_PARAMETER; + } + + if (!EFI_ERROR (Status)) { + // + // skip the loop when read capacity succeeds. + // + break; + } + + SenseCounts = 0; + + FloppyStatus = UsbFloppyRequestSense (UsbFloppyDevice, &SenseCounts); + + // + // If Request Sense data failed,retry. + // + if (EFI_ERROR (FloppyStatus)) { + // + // retry once more + // + RetryTimes++; + continue; + } + // + // No Media + // + if (IsNoMedia (UsbFloppyDevice->SenseData, SenseCounts)) { + + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + break; + } + + if (IsMediaError (UsbFloppyDevice->SenseData, SenseCounts)) { + // + // if media error encountered, make it look like no media present. + // + UsbFloppyDevice->BlkIo.Media->MediaId = 0; + UsbFloppyDevice->BlkIo.Media->MediaPresent = FALSE; + UsbFloppyDevice->BlkIo.Media->LastBlock = 0; + break; + } + + if (IsMediaWriteProtected (UsbFloppyDevice->SenseData, SenseCounts)) { + UsbFloppyDevice->BlkIo.Media->ReadOnly = TRUE; + continue; + } + + if (!IsDriveReady (UsbFloppyDevice->SenseData, SenseCounts, &NeedRetry)) { + + // + // Drive not ready: if NeedRetry, then retry once more; + // else return error + // + if (NeedRetry) { + // + // Stall 0.1 second to wait for drive becoming ready + // + gBS->Stall (100 * STALL_1_MILLI_SECOND); + // + // reset retry variable to zero, + // to make it retry for "drive in progress of becoming ready". + // + RetryIndex = 0; + continue; + } else { + return EFI_DEVICE_ERROR; + } + } + // + // if read capacity fail not for above reasons, retry once more + // + RetryTimes++; + + } + // + // ENDFOR + // + + // + // tell whether the readcapacity process is successful or not + // ("Status" variable record the latest status returned + // by ReadCapacity AND "FloppyStatus" record the latest status + // returned by RequestSense) + // + if (EFI_ERROR (Status) && EFI_ERROR (FloppyStatus)) { + return EFI_DEVICE_ERROR; + } + + } + + if (UsbFloppyDevice->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) { + + if (UsbFloppyDevice->BlkIo.Media->MediaPresent) { + UsbFloppyDevice->BlkIo.Media->MediaId = 1; + } + + *MediaChange = TRUE; + } + + if (UsbFloppyDevice->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) { + *MediaChange = TRUE; + UsbFloppyDevice->BlkIo.Media->MediaId += 1; + } + + if (UsbFloppyDevice->BlkIo.Media->MediaId != OldMediaInfo.MediaId) { + *MediaChange = TRUE; + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +UsbFloppyModeSense5APage5 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_PAGE_5 ModePage5; + EFI_LBA LastBlock; + UINT32 SectorsPerTrack; + UINT32 NumberOfCylinders; + UINT32 NumberOfHeads; + UINT32 DataBytesPerSector; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&ModePage5, sizeof (UFI_MODE_PARAMETER_PAGE_5)); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + // + // Flexible Disk Page + // + Packet.ModeSenseUFI.page_code = 5; + // + // current values + // + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_5); + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &ModePage5, + sizeof (UFI_MODE_PARAMETER_PAGE_5), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + NumberOfHeads = ModePage5.flex_disk_page.number_of_heads; + SectorsPerTrack = ModePage5.flex_disk_page.sectors_per_track; + NumberOfCylinders = ModePage5.flex_disk_page.number_of_cylinders_msb << 8 | + ModePage5.flex_disk_page.number_of_cylinders_lsb; + + LastBlock = SectorsPerTrack * NumberOfHeads * NumberOfCylinders; + DataBytesPerSector = ModePage5.flex_disk_page.databytes_per_sector_msb << 8 | + ModePage5.flex_disk_page.databytes_per_sector_lsb; + + UsbFloppyDevice->BlkIo.Media->LastBlock = LastBlock; + + UsbFloppyDevice->BlkIo.Media->LastBlock--; + + UsbFloppyDevice->BlkIo.Media->BlockSize = DataBytesPerSector; + + UsbFloppyDevice->BlkIo.Media->MediaPresent = TRUE; + + UsbFloppyDevice->BlkIo.Media->ReadOnly = + ModePage5.mode_param_header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbFloppyModeSense5APage1C ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves media capacity information via sending Read Format + Capacity Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_PAGE_1C ModePage1C; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + ZeroMem (&ModePage1C, sizeof (UFI_MODE_PARAMETER_PAGE_1C)); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + // + // Flexible Disk Page + // + Packet.ModeSenseUFI.page_code = 0x1C; + // + // current values + // + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = sizeof (UFI_MODE_PARAMETER_PAGE_1C); + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + (VOID *) &ModePage1C, + sizeof (UFI_MODE_PARAMETER_PAGE_1C), + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = ModePage1C.mode_param_header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbMassStorageModeSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +{ + if (UsbFloppyDevice->AtapiProtocol->CommandProtocol == EFI_USB_SUBCLASS_SCSI) { + return UsbSCSIModeSense1APage3F (UsbFloppyDevice); + } else { + return UsbFloppyModeSense5APage3F (UsbFloppyDevice); + } +} + +EFI_STATUS +UsbFloppyModeSense5APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves mode sense information via sending Mode Sense + Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + UFI_MODE_PARAMETER_HEADER Header; + UINT32 Size; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + Size = sizeof (UFI_MODE_PARAMETER_HEADER); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseUFI.opcode = UFI_MODE_SENSE5A; + Packet.ModeSenseUFI.page_code = 0x3F; + Packet.ModeSenseUFI.page_control = 0; + Packet.ModeSenseUFI.parameter_list_length_hi = 0; + Packet.ModeSenseUFI.parameter_list_length_lo = (UINT8) Size; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (ATAPI_PACKET_COMMAND), + &Header, + Size, + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; + + return EFI_SUCCESS; + +} + +EFI_STATUS +UsbSCSIModeSense1APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ) +/*++ + + Routine Description: + Retrieves mode sense information via sending Mode Sense + Packet Command. + + Arguments: + UsbFloppyDevice - The USB_FLOPPY_DEV instance. + + Returns: + EFI_DEVICE_ERROR - Hardware error + EFI_SUCCESS - Success + +--*/ +{ + // + // status returned by Read Capacity Packet Command + // + EFI_STATUS Status; + ATAPI_PACKET_COMMAND Packet; + EFI_USB_ATAPI_PROTOCOL *UsbAtapiInterface; + SCSI_MODE_PARAMETER_HEADER6 Header; + UINT32 Size; + + UsbAtapiInterface = UsbFloppyDevice->AtapiProtocol; + + Size = sizeof (SCSI_MODE_PARAMETER_HEADER6); + + ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND)); + Packet.ModeSenseSCSI.opcode = SCSI_MODE_SENSE1A; + Packet.ModeSenseSCSI.page_code = 0x3F; + Packet.ModeSenseSCSI.page_control = 0; + Packet.ModeSenseSCSI.allocation_length = (UINT8) Size; + Status = USBFloppyPacketCommand ( + UsbFloppyDevice, + &Packet, + sizeof (MODE_SENSE_CMD_SCSI), + &Header, + Size, + EfiUsbDataIn, + USBFLPTIMEOUT + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + UsbFloppyDevice->BlkIo.Media->ReadOnly = Header.write_protected; + return EFI_SUCCESS; + +} + +/*++ + + The following functions are a set of helper functions, + which are used to parse sense key returned by the device. + +--*/ +BOOLEAN +IsNoMedia ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN NoMedia; + + NoMedia = FALSE; + + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_NO_MEDIA)) { + + NoMedia = TRUE; + } + + SensePtr++; + } + + return NoMedia; +} + + +BOOLEAN +IsMediaError ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsError; + + IsError = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + switch (SensePtr->sense_key) { + + // + // Medium error case + // + case SK_MEDIUM_ERROR: + switch (SensePtr->addnl_sense_code) { + + case ASC_MEDIA_ERR1: + case ASC_MEDIA_ERR2: + case ASC_MEDIA_ERR3: + case ASC_MEDIA_ERR4: + IsError = TRUE; + break; + + default: + break; + } + + break; + + // + // Medium upside-down case + // + case SK_NOT_READY: + switch (SensePtr->addnl_sense_code) { + case ASC_MEDIA_UPSIDE_DOWN: + IsError = TRUE; + break; + + default: + break; + } + break; + + default: + break; + } + + SensePtr++; + } + + return IsError; +} + +BOOLEAN +IsMediaChange ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN MediaChanged; + + MediaChanged = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_UNIT_ATTENTION) && + (SensePtr->addnl_sense_code == ASC_MEDIA_CHANGE)) { + + MediaChanged = TRUE; + } + + SensePtr++; + } + + return MediaChanged; +} + +BOOLEAN +IsDriveReady ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts, + OUT BOOLEAN *NeedRetry + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsReady; + + IsReady = TRUE; + *NeedRetry = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_NOT_READY)) { + + switch (SensePtr->addnl_sense_code_qualifier) { + + case ASCQ_IN_PROGRESS: + case ASCQ_DEVICE_BUSY: + IsReady = FALSE; + *NeedRetry = TRUE; + break; + + default: + // + // Drive is in error condition, + // no need to retry. + // + IsReady = FALSE; + *NeedRetry = FALSE; + break; + } + } + + SensePtr++; + } + + return IsReady; +} + +BOOLEAN +IsMediaWriteProtected ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsWriteProtected; + + IsWriteProtected = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + // + // catch media write-protected condition. + // + if ((SensePtr->sense_key == SK_DATA_PROTECT) && + (SensePtr->addnl_sense_code == ASC_WRITE_PROTECTED)) { + + IsWriteProtected = TRUE; + } + + SensePtr++; + } + + return IsWriteProtected; +} + +BOOLEAN +IsLogicalUnitCommunicationOverRun ( + IN REQUEST_SENSE_DATA *SenseData, + IN UINTN SenseCounts + ) +{ + REQUEST_SENSE_DATA *SensePtr; + UINTN Index; + BOOLEAN IsOverRun; + + IsOverRun = FALSE; + SensePtr = SenseData; + + for (Index = 0; Index < SenseCounts; Index++) { + + if ((SensePtr->sense_key == SK_NOT_READY) && + (SensePtr->addnl_sense_code == ASC_LOGICAL_UNIT_STATUS) && + (SensePtr->addnl_sense_code_qualifier == ASCQ_LOGICAL_UNIT_OVERRUN)) { + IsOverRun = TRUE; + } + + SensePtr++; + } + + return IsOverRun; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h new file mode 100644 index 0000000000..f41241adc4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/UsbMassStorageHelper.h @@ -0,0 +1,111 @@ +/*++ +Copyright (c) 2006, 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: + + UsbMassStorageHelper.h + +Abstract: + + Function prototype for USB Mass Storage Driver + +Revision History +--*/ +#ifndef _USB_FLPHLP_H +#define _USB_FLPHLP_H + +#include "UsbMassStorage.h" + +EFI_STATUS +USBFloppyIdentify ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +USBFloppyPacketCommand ( + USB_FLOPPY_DEV *UsbFloppyDevice, + VOID *Command, + UINT8 CommandSize, + VOID *DataBuffer, + UINT32 BufferLength, + EFI_USB_DATA_DIRECTION Direction, + UINT16 TimeOutInMilliSeconds + ); + +EFI_STATUS +USBFloppyInquiry ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT USB_INQUIRY_DATA **Idata + ); + +EFI_STATUS +USBFloppyRead10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +USBFloppyReadFormatCapacity ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyRequestSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT UINTN *SenseCounts + ); + +EFI_STATUS +UsbFloppyTestUnitReady ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +USBFloppyWrite10 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + IN VOID *Buffer, + IN EFI_LBA Lba, + IN UINTN NumberOfBlocks + ); + +EFI_STATUS +UsbFloppyDetectMedia ( + IN USB_FLOPPY_DEV *UsbFloppyDevice, + OUT BOOLEAN *MediaChange + ); + +EFI_STATUS +UsbFloppyModeSense5APage5 ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyModeSense5APage1C ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbFloppyModeSense5APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbSCSIModeSense1APage3F ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +EFI_STATUS +UsbMassStorageModeSense ( + IN USB_FLOPPY_DEV *UsbFloppyDevice + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml new file mode 100644 index 0000000000..d2e48d3027 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMassStorage/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c new file mode 100644 index 0000000000..5b01cea9d4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/ComponentName.c @@ -0,0 +1,216 @@ +/*++ + +Copyright (c) 2006, 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: + + ComponentName.c + +Abstract: + +--*/ + +#include "usbmouse.h" + +// +// EFI Component Name Functions +// +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ); + +// +// EFI Component Name Protocol +// +EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName = { + UsbMouseComponentNameGetDriverName, + UsbMouseComponentNameGetControllerName, + "eng" +}; + +STATIC EFI_UNICODE_STRING_TABLE mUsbMouseDriverNameTable[] = { + { "eng", (CHAR16 *) L"Usb Mouse Driver" }, + { NULL , NULL } +}; + + +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + Language - A pointer to a three character ISO 639-2 language identifier. + This is the language of the driver name that that the caller + is requesting, and it must match one of the languages specified + in SupportedLanguages. The number of languages supported by a + driver is up to the driver writer. + DriverName - A pointer to the Unicode string to return. This Unicode string + is the name of the driver specified by This in the language + specified by Language. + + Returns: + EFI_SUCCESS - The Unicode string for the Driver specified by This + and the language specified by Language was returned + in DriverName. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - DriverName is NULL. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + return LookupUnicodeString ( + Language, + gUsbMouseComponentName.SupportedLanguages, + mUsbMouseDriverNameTable, + DriverName + ); +} + +EFI_STATUS +EFIAPI +UsbMouseComponentNameGetControllerName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_HANDLE ChildHandle OPTIONAL, + IN CHAR8 *Language, + OUT CHAR16 **ControllerName + ) +/*++ + + Routine Description: + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by an EFI Driver. + + Arguments: + This - A pointer to the EFI_COMPONENT_NAME_PROTOCOL instance. + ControllerHandle - The handle of a controller that the driver specified by + This is managing. This handle specifies the controller + whose name is to be returned. + ChildHandle - The handle of the child controller to retrieve the name + of. This is an optional parameter that may be NULL. It + will be NULL for device drivers. It will also be NULL + for a bus drivers that wish to retrieve the name of the + bus controller. It will not be NULL for a bus driver + that wishes to retrieve the name of a child controller. + Language - A pointer to a three character ISO 639-2 language + identifier. This is the language of the controller name + that that the caller is requesting, and it must match one + of the languages specified in SupportedLanguages. The + number of languages supported by a driver is up to the + driver writer. + ControllerName - A pointer to the Unicode string to return. This Unicode + string is the name of the controller specified by + ControllerHandle and ChildHandle in the language specified + by Language from the point of view of the driver specified + by This. + + Returns: + EFI_SUCCESS - The Unicode string for the user readable name in the + language specified by Language for the driver + specified by This was returned in DriverName. + EFI_INVALID_PARAMETER - ControllerHandle is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - ChildHandle is not NULL and it is not a valid EFI_HANDLE. + EFI_INVALID_PARAMETER - Language is NULL. + EFI_INVALID_PARAMETER - ControllerName is NULL. + EFI_UNSUPPORTED - The driver specified by This is not currently managing + the controller specified by ControllerHandle and + ChildHandle. + EFI_UNSUPPORTED - The driver specified by This does not support the + language specified by Language. + +--*/ +{ + EFI_STATUS Status; + USB_MOUSE_DEV *UsbMouseDev; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; + EFI_USB_IO_PROTOCOL *UsbIoProtocol; + + // + // This is a device driver, so ChildHandle must be NULL. + // + if (ChildHandle != NULL) { + return EFI_UNSUPPORTED; + } + + // + // Check Controller's handle + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIoProtocol, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (!EFI_ERROR (Status)) { + gBS->CloseProtocol ( + ControllerHandle, + &gEfiUsbIoProtocolGuid, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle + ); + + return EFI_UNSUPPORTED; + } + + if (Status != EFI_ALREADY_STARTED) { + return EFI_UNSUPPORTED; + } + // + // Get the device context + // + Status = gBS->OpenProtocol ( + ControllerHandle, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointerProtocol, + gUsbMouseDriverBinding.DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + UsbMouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol); + + return LookupUnicodeString ( + Language, + gUsbMouseComponentName.SupportedLanguages, + UsbMouseDev->ControllerNameTable, + ControllerName + ); + +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd new file mode 100644 index 0000000000..88b3e47a97 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.mbd @@ -0,0 +1,43 @@ + + + + + UsbMouse + 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE + 0 + FIX ME! + Copyright (c) 2004-2006, 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. + + 2006-03-12 17:09 + 2006-03-19 15:18 + + + UefiBootServicesTableLib + UefiMemoryLib + UefiLib + UefiDriverEntryPoint + UefiDriverModelLib + DxeReportStatusCodeLib + BaseDebugLibReportStatusCode + EdkDxePrintLib + BaseLib + EdkUsbLib + DxeMemoryAllocationLib + + diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa new file mode 100644 index 0000000000..8d2e1a2999 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/UsbMouse.msa @@ -0,0 +1,71 @@ + + + + + UsbMouse + DXE_DRIVER + BS_DRIVER + 2D2E62AA-9ECF-43b7-8219-94E7FC713DFE + 0 + Component description file for UsbMouse module + FIX ME! + Copyright (c) 2004-2006, 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. + + 0 + 2006-03-12 17:09 + 2006-03-19 15:18 + + + DebugLib + UefiDriverModelLib + UefiDriverEntryPoint + BaseLib + UefiLib + BaseMemoryLib + EdkUsbLib + ReportStatusCodeLib + MemoryAllocationLib + UefiBootServicesTableLib + + + usbmouse.h + usbmouse.c + mousehid.h + mousehid.c + ComponentName.c + + + MdePkg + EdkModulePkg + + + DevicePath + UsbIo + SimplePointer + + + + + + + gUsbMouseDriverBinding + gUsbMouseComponentName + + + diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml new file mode 100644 index 0000000000..081a9e0582 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/build.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c new file mode 100644 index 0000000000..cbe0970484 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.c @@ -0,0 +1,395 @@ +/*++ + +Copyright (c) 2006, 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: + + Mousehid.c + +Abstract: + Parse mouse hid descriptor + +--*/ + +#include "usbmouse.h" +#include "mousehid.h" + +// +// Get an item from report descriptor +// +STATIC +UINT8 * +GetNextItem ( + IN UINT8 *StartPos, + IN UINT8 *EndPos, + OUT HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Get Next Item + +Arguments: + + StartPos - Start Position + EndPos - End Position + HidItem - HidItem to return + +Returns: + Position + +--*/ +{ + UINT8 Temp; + + if ((EndPos - StartPos) <= 0) { + return NULL; + } + + Temp = *StartPos; + StartPos++; + // + // bit 2,3 + // + HidItem->Type = (UINT8) ((Temp >> 2) & 0x03); + // + // bit 4-7 + // + HidItem->Tag = (UINT8) ((Temp >> 4) & 0x0F); + + if (HidItem->Tag == HID_ITEM_TAG_LONG) { + // + // Long Items are not supported by HID rev1.0, + // although we try to parse it. + // + HidItem->Format = HID_ITEM_FORMAT_LONG; + + if ((EndPos - StartPos) >= 2) { + HidItem->Size = *StartPos++; + HidItem->Tag = *StartPos++; + + if ((EndPos - StartPos) >= HidItem->Size) { + HidItem->Data.LongData = StartPos; + StartPos += HidItem->Size; + return StartPos; + } + } + } else { + HidItem->Format = HID_ITEM_FORMAT_SHORT; + // + // bit 0, 1 + // + HidItem->Size = (UINT8) (Temp & 0x03); + switch (HidItem->Size) { + + case 0: + // + // No data + // + return StartPos; + + case 1: + // + // One byte data + // + if ((EndPos - StartPos) >= 1) { + HidItem->Data.U8 = *StartPos++; + return StartPos; + } + + case 2: + // + // Two byte data + // + if ((EndPos - StartPos) >= 2) { + CopyMem (&HidItem->Data.U16, StartPos, sizeof (UINT16)); + StartPos += 2; + return StartPos; + } + + case 3: + // + // 4 byte data, adjust size + // + HidItem->Size++; + if ((EndPos - StartPos) >= 4) { + CopyMem (&HidItem->Data.U32, StartPos, sizeof (UINT32)); + StartPos += 4; + return StartPos; + } + } + } + + return NULL; +} + +STATIC +UINT32 +GetItemData ( + IN HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Get Item Data + +Arguments: + + HidItem - HID_ITEM + +Returns: + HidItem Data + + +--*/ +{ + // + // Get Data from HID_ITEM structure + // + switch (HidItem->Size) { + + case 1: + return HidItem->Data.U8; + + case 2: + return HidItem->Data.U16; + + case 4: + return HidItem->Data.U32; + } + + return 0; +} + +STATIC +VOID +ParseLocalItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *LocalItem + ) +/*++ + +Routine Description: + + Parse Local Item + +Arguments: + + UsbMouse - USB_MOUSE_DEV + LocalItem - Local Item + +Returns: + +--*/ +{ + UINT32 Data; + + if (LocalItem->Size == 0) { + // + // No expected data for local item + // + return ; + } + + Data = GetItemData (LocalItem); + + switch (LocalItem->Tag) { + + case HID_LOCAL_ITEM_TAG_DELIMITER: + // + // we don't support delimiter here + // + return ; + + case HID_LOCAL_ITEM_TAG_USAGE: + return ; + + case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMinIndex = (UINT8) Data; + } + + return ; + + case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: + { + if (UsbMouse->PrivateData.ButtonDetected) { + UsbMouse->PrivateData.ButtonMaxIndex = (UINT8) Data; + } + + return ; + } + } +} + +STATIC +VOID +ParseGlobalItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *GlobalItem + ) +{ + UINT8 UsagePage; + + switch (GlobalItem->Tag) { + case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: + { + UsagePage = (UINT8) GetItemData (GlobalItem); + + // + // We only care Button Page here + // + if (UsagePage == 0x09) { + // + // Button Page + // + UsbMouse->PrivateData.ButtonDetected = TRUE; + return ; + } + break; + } + + } +} + + +STATIC +VOID +ParseMainItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *MainItem + ) +/*++ + +Routine Description: + + Parse Main Item + +Arguments: + + UsbMouse - TODO: add argument description + MainItem - HID_ITEM to parse + +Returns: + + VOID + +--*/ +{ + // + // we don't care any main items, just skip + // + return ; +} + +STATIC +VOID +ParseHidItem ( + IN USB_MOUSE_DEV *UsbMouse, + IN HID_ITEM *HidItem + ) +/*++ + +Routine Description: + + Parse Hid Item + +Arguments: + + UsbMouse - USB_MOUSE_DEV + HidItem - HidItem to parse + +Returns: + + VOID + +--*/ +{ + switch (HidItem->Type) { + + case HID_ITEM_TYPE_MAIN: + // + // For Main Item, parse main item + // + ParseMainItem (UsbMouse, HidItem); + break; + + case HID_ITEM_TYPE_GLOBAL: + // + // For global Item, parse global item + // + ParseGlobalItem (UsbMouse, HidItem); + break; + + case HID_ITEM_TYPE_LOCAL: + // + // For Local Item, parse local item + // + ParseLocalItem (UsbMouse, HidItem); + break; + } +} +// +// A simple parse just read some field we are interested in +// +EFI_STATUS +ParseMouseReportDescriptor ( + IN USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ) +/*++ + +Routine Description: + + Parse Mouse Report Descriptor + +Arguments: + + UsbMouse - USB_MOUSE_DEV + ReportDescriptor - Report descriptor to parse + ReportSize - Report descriptor size + +Returns: + + EFI_DEVICE_ERROR - Report descriptor error + EFI_SUCCESS - Success + +--*/ +{ + UINT8 *DescriptorEnd; + UINT8 *ptr; + HID_ITEM HidItem; + + DescriptorEnd = ReportDescriptor + ReportSize; + + ptr = GetNextItem (ReportDescriptor, DescriptorEnd, &HidItem); + + while (ptr != NULL) { + if (HidItem.Format != HID_ITEM_FORMAT_SHORT) { + // + // Long Format Item is not supported at current HID revision + // + return EFI_DEVICE_ERROR; + } + + ParseHidItem (UsbMouse, &HidItem); + + ptr = GetNextItem (ptr, DescriptorEnd, &HidItem); + } + + UsbMouse->NumberOfButtons = (UINT8) (UsbMouse->PrivateData.ButtonMaxIndex - UsbMouse->PrivateData.ButtonMinIndex + 1); + UsbMouse->XLogicMax = UsbMouse->YLogicMax = 127; + UsbMouse->XLogicMin = UsbMouse->YLogicMin = -127; + + return EFI_SUCCESS; +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h new file mode 100644 index 0000000000..ccce8354ea --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/mousehid.h @@ -0,0 +1,84 @@ +/*++ + +Copyright (c) 2006, 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: + + MouseHid.h + +Abstract: + +--*/ + +#ifndef __MOUSE_HID_H +#define __MOUSE_HID_H + +#include "usbmouse.h" + +// +// HID Item general structure +// +typedef struct _hid_item { + UINT16 Format; + UINT8 Size; + UINT8 Type; + UINT8 Tag; + union { + UINT8 U8; + UINT16 U16; + UINT32 U32; + INT8 I8; + INT16 I16; + INT32 I32; + UINT8 *LongData; + } Data; +} HID_ITEM; + +typedef struct { + UINT16 UsagePage; + INT32 LogicMin; + INT32 LogicMax; + INT32 PhysicalMin; + INT32 PhysicalMax; + UINT16 UnitExp; + UINT16 UINT; + UINT16 ReportId; + UINT16 ReportSize; + UINT16 ReportCount; +} HID_GLOBAL; + +typedef struct { + UINT16 Usage[16]; /* usage array */ + UINT16 UsageIndex; + UINT16 UsageMin; +} HID_LOCAL; + +typedef struct { + UINT16 Type; + UINT16 Usage; +} HID_COLLECTION; + +typedef struct { + HID_GLOBAL Global; + HID_GLOBAL GlobalStack[8]; + UINT32 GlobalStackPtr; + HID_LOCAL Local; + HID_COLLECTION CollectionStack[8]; + UINT32 CollectionStackPtr; +} HID_PARSER; + +EFI_STATUS +ParseMouseReportDescriptor ( + IN USB_MOUSE_DEV *UsbMouse, + IN UINT8 *ReportDescriptor, + IN UINTN ReportSize + ); + +#endif diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c new file mode 100644 index 0000000000..81da0205a4 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.c @@ -0,0 +1,1028 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbMouse.c + + Abstract: + +--*/ + +#include "usbmouse.h" +#include "mousehid.h" + +// +// Prototypes +// Driver model protocol interface +// +EFI_STATUS +EFIAPI +USBMouseDriverBindingEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + + +EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding = { + USBMouseDriverBindingSupported, + USBMouseDriverBindingStart, + USBMouseDriverBindingStop, + 0x10, + NULL, + NULL +}; + +// +// helper functions +// +STATIC +BOOLEAN +IsUsbMouse ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ); + +STATIC +EFI_STATUS +InitializeUsbMouseDevice ( + IN USB_MOUSE_DEV *UsbMouseDev + ); + +STATIC +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Mouse interrupt handler +// +STATIC +EFI_STATUS +EFIAPI +OnMouseInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ); + +// +// Mouse Protocol +// +STATIC +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ); + +STATIC +EFI_STATUS +EFIAPI +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +EFI_STATUS +EFIAPI +USBMouseDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Test to see if this driver supports ControllerHandle. Any ControllerHandle + that has UsbHcProtocol installed will be supported. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + +--*/ +{ + EFI_STATUS OpenStatus; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_STATUS Status; + + OpenStatus = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (OpenStatus) && (OpenStatus != EFI_ALREADY_STARTED)) { + return EFI_UNSUPPORTED; + } + + if (OpenStatus == EFI_ALREADY_STARTED) { + return EFI_ALREADY_STARTED; + } + + // + // Use the USB I/O protocol interface to see the Controller is + // the Mouse controller that can be managed by this driver. + // + Status = EFI_SUCCESS; + if (!IsUsbMouse (UsbIo)) { + Status = EFI_UNSUPPORTED; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + return Status; +} + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ) +/*++ + + Routine Description: + Starting the Usb Bus Driver + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to test + RemainingDevicePath - Not used + + Returns: + EFI_SUCCESS - This driver supports this device. + EFI_UNSUPPORTED - This driver does not support this device. + EFI_DEVICE_ERROR - This driver cannot be started due to device + Error + EFI_OUT_OF_RESOURCES- Can't allocate memory resources + EFI_ALREADY_STARTED - Thios driver has been started +--*/ +{ + EFI_STATUS Status; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDesc; + USB_MOUSE_DEV *UsbMouseDevice; + UINT8 EndpointNumber; + UINT8 Index; + UINT8 EndpointAddr; + UINT8 PollingInterval; + UINT8 PacketSize; + + UsbMouseDevice = NULL; + Status = EFI_SUCCESS; + + Status = gBS->OpenProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + (VOID **) &UsbIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + UsbMouseDevice = AllocateZeroPool (sizeof (USB_MOUSE_DEV)); + if (UsbMouseDevice == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + UsbMouseDevice->UsbIo = UsbIo; + + UsbMouseDevice->Signature = USB_MOUSE_DEV_SIGNATURE; + + UsbMouseDevice->InterfaceDescriptor = AllocatePool (sizeof (EFI_USB_INTERFACE_DESCRIPTOR)); + if (UsbMouseDevice->InterfaceDescriptor == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + EndpointDesc = AllocatePool (sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)); + if (EndpointDesc == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + // + // Get the Device Path Protocol on Controller's handle + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiDevicePathProtocolGuid, + (VOID **) &UsbMouseDevice->DevicePath, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + // + // Get interface & endpoint descriptor + // + UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + UsbMouseDevice->InterfaceDescriptor + ); + + EndpointNumber = UsbMouseDevice->InterfaceDescriptor->NumEndpoints; + + for (Index = 0; Index < EndpointNumber; Index++) { + UsbIo->UsbGetEndpointDescriptor ( + UsbIo, + Index, + EndpointDesc + ); + + if ((EndpointDesc->Attributes & 0x03) == 0x03) { + + // + // We only care interrupt endpoint here + // + UsbMouseDevice->IntEndpointDescriptor = EndpointDesc; + } + } + + if (UsbMouseDevice->IntEndpointDescriptor == NULL) { + // + // No interrupt endpoint, then error + // + Status = EFI_UNSUPPORTED; + goto ErrorExit; + } + + Status = InitializeUsbMouseDevice (UsbMouseDevice); + if (EFI_ERROR (Status)) { + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INTERFACE_ERROR) + ); + + goto ErrorExit; + } + + UsbMouseDevice->SimplePointerProtocol.GetState = GetMouseState; + UsbMouseDevice->SimplePointerProtocol.Reset = UsbMouseReset; + UsbMouseDevice->SimplePointerProtocol.Mode = &UsbMouseDevice->Mode; + + Status = gBS->CreateEvent ( + EFI_EVENT_NOTIFY_WAIT, + EFI_TPL_NOTIFY, + UsbMouseWaitForInput, + UsbMouseDevice, + &((UsbMouseDevice->SimplePointerProtocol).WaitForInput) + ); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + Status = gBS->InstallProtocolInterface ( + &Controller, + &gEfiSimplePointerProtocolGuid, + EFI_NATIVE_INTERFACE, + &UsbMouseDevice->SimplePointerProtocol + ); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ErrorExit; + } + + // + // After Enabling Async Interrupt Transfer on this mouse Device + // we will be able to get key data from it. Thus this is deemed as + // the enable action of the mouse + // + + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE) + ); + + // + // submit async interrupt transfer + // + EndpointAddr = UsbMouseDevice->IntEndpointDescriptor->EndpointAddress; + PollingInterval = UsbMouseDevice->IntEndpointDescriptor->Interval; + PacketSize = (UINT8) (UsbMouseDevice->IntEndpointDescriptor->MaxPacketSize); + + Status = UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + EndpointAddr, + TRUE, + PollingInterval, + PacketSize, + OnMouseInterruptComplete, + UsbMouseDevice + ); + + if (!EFI_ERROR (Status)) { + + UsbMouseDevice->ControllerNameTable = NULL; + AddUnicodeString ( + "eng", + gUsbMouseComponentName.SupportedLanguages, + &UsbMouseDevice->ControllerNameTable, + (CHAR16 *) L"Generic Usb Mouse" + ); + + return EFI_SUCCESS; + } + + // + // If submit error, uninstall that interface + // + Status = EFI_DEVICE_ERROR; + gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + +ErrorExit: + if (EFI_ERROR (Status)) { + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + if (UsbMouseDevice != NULL) { + if (UsbMouseDevice->InterfaceDescriptor != NULL) { + gBS->FreePool (UsbMouseDevice->InterfaceDescriptor); + } + + if (UsbMouseDevice->IntEndpointDescriptor != NULL) { + gBS->FreePool (UsbMouseDevice->IntEndpointDescriptor); + } + + if ((UsbMouseDevice->SimplePointerProtocol).WaitForInput != NULL) { + gBS->CloseEvent ((UsbMouseDevice->SimplePointerProtocol).WaitForInput); + } + + gBS->FreePool (UsbMouseDevice); + UsbMouseDevice = NULL; + } + } + + return Status; +} + +EFI_STATUS +EFIAPI +USBMouseDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +/*++ + + Routine Description: + Stop this driver on ControllerHandle. Support stoping any child handles + created by this driver. + + Arguments: + This - Protocol instance pointer. + Controller - Handle of device to stop driver on + NumberOfChildren - Number of Children in the ChildHandleBuffer + ChildHandleBuffer - List of handles for the children we need to stop. + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + others + +--*/ +{ + EFI_STATUS Status; + USB_MOUSE_DEV *UsbMouseDevice; + EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol; + EFI_USB_IO_PROTOCOL *UsbIo; + + // + // Get our context back. + // + Status = gBS->OpenProtocol ( + Controller, + &gEfiSimplePointerProtocolGuid, + (VOID **) &SimplePointerProtocol, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (SimplePointerProtocol); + + gBS->CloseProtocol ( + Controller, + &gEfiSimplePointerProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + UsbIo = UsbMouseDevice->UsbIo; + + // + // Uninstall the Asyn Interrupt Transfer from this device + // will disable the mouse data input from this device + // + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE) + ); + + // + // Delete Mouse Async Interrupt Transfer + // + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDevice->IntEndpointDescriptor->EndpointAddress, + FALSE, + UsbMouseDevice->IntEndpointDescriptor->Interval, + 0, + NULL, + NULL + ); + + gBS->CloseEvent (UsbMouseDevice->SimplePointerProtocol.WaitForInput); + + if (UsbMouseDevice->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbMouseDevice->DelayedRecoveryEvent); + UsbMouseDevice->DelayedRecoveryEvent = 0; + } + + Status = gBS->UninstallProtocolInterface ( + Controller, + &gEfiSimplePointerProtocolGuid, + &UsbMouseDevice->SimplePointerProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + gBS->CloseProtocol ( + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + gBS->FreePool (UsbMouseDevice->InterfaceDescriptor); + gBS->FreePool (UsbMouseDevice->IntEndpointDescriptor); + + if (UsbMouseDevice->ControllerNameTable) { + FreeUnicodeStringTable (UsbMouseDevice->ControllerNameTable); + } + + gBS->FreePool (UsbMouseDevice); + + return EFI_SUCCESS; + +} + +BOOLEAN +IsUsbMouse ( + IN EFI_USB_IO_PROTOCOL *UsbIo + ) +/*++ + + Routine Description: + Tell if a Usb Controller is a mouse + + Arguments: + UsbIo - Protocol instance pointer. + + Returns: + TRUE - It is a mouse + FALSE - It is not a mouse +--*/ +{ + EFI_STATUS Status; + EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + // + // Get the Default interface descriptor, now we only + // suppose it is interface 1 + // + Status = UsbIo->UsbGetInterfaceDescriptor ( + UsbIo, + &InterfaceDescriptor + ); + + if (EFI_ERROR (Status)) { + return FALSE; + } + + if ((InterfaceDescriptor.InterfaceClass == CLASS_HID) && + (InterfaceDescriptor.InterfaceSubClass == SUBCLASS_BOOT) && + (InterfaceDescriptor.InterfaceProtocol == PROTOCOL_MOUSE) + ) { + return TRUE; + } + + return FALSE; +} + +STATIC +EFI_STATUS +InitializeUsbMouseDevice ( + IN USB_MOUSE_DEV *UsbMouseDev + ) +/*++ + + Routine Description: + Initialize the Usb Mouse Device. + + Arguments: + UsbMouseDev - Device instance to be initialized + + Returns: + EFI_SUCCESS - Success + EFI_DEVICE_ERROR - Init error. + EFI_OUT_OF_RESOURCES- Can't allocate memory +--*/ +{ + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 Protocol; + EFI_STATUS Status; + EFI_USB_HID_DESCRIPTOR MouseHidDesc; + UINT8 *ReportDesc; + + UsbIo = UsbMouseDev->UsbIo; + + // + // Get HID descriptor + // + Status = UsbGetHidDescriptor ( + UsbIo, + UsbMouseDev->InterfaceDescriptor->InterfaceNumber, + &MouseHidDesc + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get Report descriptor + // + if (MouseHidDesc.HidClassDesc[0].DescriptorType != 0x22) { + return EFI_UNSUPPORTED; + } + + ReportDesc = AllocateZeroPool (MouseHidDesc.HidClassDesc[0].DescriptorLength); + if (ReportDesc == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = UsbGetReportDescriptor ( + UsbIo, + UsbMouseDev->InterfaceDescriptor->InterfaceNumber, + MouseHidDesc.HidClassDesc[0].DescriptorLength, + ReportDesc + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return Status; + } + + // + // Parse report descriptor + // + Status = ParseMouseReportDescriptor ( + UsbMouseDev, + ReportDesc, + MouseHidDesc.HidClassDesc[0].DescriptorLength + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return Status; + } + + if (UsbMouseDev->NumberOfButtons >= 1) { + UsbMouseDev->Mode.LeftButton = TRUE; + } + + if (UsbMouseDev->NumberOfButtons > 1) { + UsbMouseDev->Mode.RightButton = TRUE; + } + + UsbMouseDev->Mode.ResolutionX = 8; + UsbMouseDev->Mode.ResolutionY = 8; + UsbMouseDev->Mode.ResolutionZ = 0; + // + // Here we just assume interface 0 is the mouse interface + // + UsbGetProtocolRequest ( + UsbIo, + 0, + &Protocol + ); + + if (Protocol != BOOT_PROTOCOL) { + Status = UsbSetProtocolRequest ( + UsbIo, + 0, + BOOT_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + gBS->FreePool (ReportDesc); + return EFI_DEVICE_ERROR; + } + } + + // + // Set indefinite Idle rate for USB Mouse + // + UsbSetIdleRequest ( + UsbIo, + 0, + 0, + 0 + ); + + gBS->FreePool (ReportDesc); + + if (UsbMouseDev->DelayedRecoveryEvent) { + gBS->CloseEvent (UsbMouseDev->DelayedRecoveryEvent); + UsbMouseDev->DelayedRecoveryEvent = 0; + } + + Status = gBS->CreateEvent ( + EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_NOTIFY, + USBMouseRecoveryHandler, + UsbMouseDev, + &UsbMouseDev->DelayedRecoveryEvent + ); + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +OnMouseInterruptComplete ( + IN VOID *Data, + IN UINTN DataLength, + IN VOID *Context, + IN UINT32 Result + ) +/*++ + + Routine Description: + It is called whenever there is data received from async interrupt + transfer. + + Arguments: + Data - Data received. + DataLength - Length of Data + Context - Passed in context + Result - Async Interrupt Transfer result + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + +--*/ +{ + USB_MOUSE_DEV *UsbMouseDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + UINT8 EndpointAddr; + UINT32 UsbResult; + + UsbMouseDevice = (USB_MOUSE_DEV *) Context; + UsbIo = UsbMouseDevice->UsbIo; + + if (Result != EFI_USB_NOERROR) { + // + // Some errors happen during the process + // + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (EFI_PERIPHERAL_MOUSE | EFI_P_EC_INPUT_ERROR) + ); + + if ((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) { + EndpointAddr = UsbMouseDevice->IntEndpointDescriptor->EndpointAddress; + + UsbClearEndpointHalt ( + UsbIo, + EndpointAddr, + &UsbResult + ); + } + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDevice->IntEndpointDescriptor->EndpointAddress, + FALSE, + 0, + 0, + NULL, + NULL + ); + + gBS->SetTimer ( + UsbMouseDevice->DelayedRecoveryEvent, + TimerRelative, + EFI_USB_INTERRUPT_DELAY + ); + return EFI_DEVICE_ERROR; + } + + if (DataLength == 0 || Data == NULL) { + return EFI_SUCCESS; + } + + UsbMouseDevice->StateChanged = TRUE; + + // + // Check mouse Data + // + UsbMouseDevice->State.LeftButton = (BOOLEAN) (*(UINT8 *) Data & 0x01); + UsbMouseDevice->State.RightButton = (BOOLEAN) (*(UINT8 *) Data & 0x02); + UsbMouseDevice->State.RelativeMovementX += *((INT8 *) Data + 1); + UsbMouseDevice->State.RelativeMovementY += *((INT8 *) Data + 2); + + if (DataLength > 3) { + UsbMouseDevice->State.RelativeMovementZ += *((INT8 *) Data + 3); + } + + return EFI_SUCCESS; +} + +/* +STATIC VOID +PrintMouseState( + IN EFI_MOUSE_STATE *MouseState + ) +{ + Aprint("(%x: %x, %x)\n", + MouseState->ButtonStates, + MouseState->dx, + MouseState->dy + ); +} +*/ +STATIC +EFI_STATUS +EFIAPI +GetMouseState ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + OUT EFI_SIMPLE_POINTER_STATE *MouseState + ) +/*++ + + Routine Description: + Get the mouse state, see SIMPLE POINTER PROTOCOL. + + Arguments: + This - Protocol instance pointer. + MouseState - Current mouse state + + Returns: + EFI_SUCCESS + EFI_DEVICE_ERROR + EFI_NOT_READY + +--*/ +{ + USB_MOUSE_DEV *MouseDev; + + if (MouseState == NULL) { + return EFI_DEVICE_ERROR; + } + + MouseDev = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + if (!MouseDev->StateChanged) { + return EFI_NOT_READY; + } + + CopyMem ( + MouseState, + &MouseDev->State, + sizeof (EFI_SIMPLE_POINTER_STATE) + ); + + // + // Clear previous move state + // + MouseDev->State.RelativeMovementX = 0; + MouseDev->State.RelativeMovementY = 0; + MouseDev->State.RelativeMovementZ = 0; + + MouseDev->StateChanged = FALSE; + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +UsbMouseReset ( + IN EFI_SIMPLE_POINTER_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ) +/*++ + + Routine Description: + Reset the mouse device, see SIMPLE POINTER PROTOCOL. + + Arguments: + This - Protocol instance pointer. + ExtendedVerification - Ignored here/ + + Returns: + EFI_SUCCESS + +--*/ +{ + USB_MOUSE_DEV *UsbMouseDevice; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbMouseDevice = USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL (This); + + UsbIo = UsbMouseDevice->UsbIo; + + MouseReportStatusCode ( + UsbMouseDevice->DevicePath, + EFI_PROGRESS_CODE, + (EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET) + ); + + ZeroMem ( + &UsbMouseDevice->State, + sizeof (EFI_SIMPLE_POINTER_STATE) + ); + UsbMouseDevice->StateChanged = FALSE; + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +UsbMouseWaitForInput ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + +Routine Description: + + Event notification function for SIMPLE_POINTER.WaitForInput event + Signal the event if there is input from mouse + +Arguments: + Event - Wait Event + Context - Passed parameter to event handler +Returns: + VOID +--*/ +{ + USB_MOUSE_DEV *UsbMouseDev; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + // + // Someone is waiting on the mouse event, if there's + // input from mouse, signal the event + // + if (UsbMouseDev->StateChanged) { + gBS->SignalEvent (Event); + } +} + +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ) +/*++ + + Routine Description: + Timer handler for Delayed Recovery timer. + + Arguments: + Event - The Delayed Recovery event. + Context - Points to the USB_KB_DEV instance. + + Returns: + +--*/ +{ + USB_MOUSE_DEV *UsbMouseDev; + EFI_USB_IO_PROTOCOL *UsbIo; + + UsbMouseDev = (USB_MOUSE_DEV *) Context; + + UsbIo = UsbMouseDev->UsbIo; + + UsbIo->UsbAsyncInterruptTransfer ( + UsbIo, + UsbMouseDev->IntEndpointDescriptor->EndpointAddress, + TRUE, + UsbMouseDev->IntEndpointDescriptor->Interval, + UsbMouseDev->IntEndpointDescriptor->MaxPacketSize, + OnMouseInterruptComplete, + UsbMouseDev + ); +} + +VOID +MouseReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ) +/*++ + + Routine Description: + Report Status Code in Usb Bot Driver + + Arguments: + DevicePath - Use this to get Device Path + CodeType - Status Code Type + CodeValue - Status Code Value + + Returns: + None + +--*/ +{ + + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + CodeType, + Value, + DevicePath + ); +} diff --git a/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h new file mode 100644 index 0000000000..8a7dd753b1 --- /dev/null +++ b/EdkModulePkg/Bus/Usb/UsbMouse/Dxe/usbmouse.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) 2006, 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: + + UsbMouse.h + + Abstract: + +--*/ + +#ifndef _USB_MOUSE_H +#define _USB_MOUSE_H + +#include + +#define CLASS_HID 3 +#define SUBCLASS_BOOT 1 +#define PROTOCOL_MOUSE 2 + +#define BOOT_PROTOCOL 0 +#define REPORT_PROTOCOL 1 + +#define USB_MOUSE_DEV_SIGNATURE EFI_SIGNATURE_32 ('u', 'm', 'o', 'u') + +typedef struct { + BOOLEAN ButtonDetected; + UINT8 ButtonMinIndex; + UINT8 ButtonMaxIndex; + UINT8 Reserved; +} PRIVATE_DATA; + +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_EVENT DelayedRecoveryEvent; + EFI_USB_IO_PROTOCOL *UsbIo; + EFI_USB_INTERFACE_DESCRIPTOR *InterfaceDescriptor; + EFI_USB_ENDPOINT_DESCRIPTOR *IntEndpointDescriptor; + UINT8 NumberOfButtons; + INT32 XLogicMax; + INT32 XLogicMin; + INT32 YLogicMax; + INT32 YLogicMin; + EFI_SIMPLE_POINTER_PROTOCOL SimplePointerProtocol; + EFI_SIMPLE_POINTER_STATE State; + EFI_SIMPLE_POINTER_MODE Mode; + BOOLEAN StateChanged; + PRIVATE_DATA PrivateData; + EFI_UNICODE_STRING_TABLE *ControllerNameTable; +} USB_MOUSE_DEV; + +#define USB_MOUSE_DEV_FROM_MOUSE_PROTOCOL(a) \ + CR(a, USB_MOUSE_DEV, SimplePointerProtocol, USB_MOUSE_DEV_SIGNATURE) + +VOID +EFIAPI +USBMouseRecoveryHandler ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +// +// Global Variables +// +extern EFI_DRIVER_BINDING_PROTOCOL gUsbMouseDriverBinding; +extern EFI_COMPONENT_NAME_PROTOCOL gUsbMouseComponentName; +extern EFI_GUID gEfiUsbMouseDriverGuid; + +VOID +MouseReportStatusCode ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN EFI_STATUS_CODE_TYPE CodeType, + IN EFI_STATUS_CODE_VALUE Value + ); + +#endif -- cgit v1.2.3