summaryrefslogtreecommitdiff
path: root/EdkModulePkg/Bus/Pci/IdeBus
diff options
context:
space:
mode:
authorbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
committerbbahnsen <bbahnsen@6f19259b-4bc3-4df7-8a09-765794883524>2006-04-21 22:54:32 +0000
commit878ddf1fc3540a715f63594ed22b6929e881afb4 (patch)
treec56c44dac138137b510e1fba7c3efe5e4d84bea2 /EdkModulePkg/Bus/Pci/IdeBus
downloadedk2-platforms-878ddf1fc3540a715f63594ed22b6929e881afb4.tar.xz
Initial import.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'EdkModulePkg/Bus/Pci/IdeBus')
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c224
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h118
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c378
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c225
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c3690
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c2591
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml74
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c1964
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h1806
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c1400
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h439
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd45
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa90
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd44
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa86
-rw-r--r--EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h879
16 files changed, 14053 insertions, 0 deletions
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c
new file mode 100644
index 0000000000..8008527dd1
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.c
@@ -0,0 +1,224 @@
+/*++
+
+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 "IDEBus.h"
+
+//
+// EFI Component Name Protocol
+//
+EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName = {
+ IDEBusComponentNameGetDriverName,
+ IDEBusComponentNameGetControllerName,
+ "eng"
+};
+
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = {
+ { "eng", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" },
+ { NULL , NULL }
+};
+
+STATIC EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = {
+ { "eng", (CHAR16 *) L"PCI IDE/ATAPI Controller" },
+ { NULL , NULL }
+};
+
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ 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,
+ gIDEBusComponentName.SupportedLanguages,
+ mIDEBusDriverNameTable,
+ DriverName
+ );
+}
+
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+ 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;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ //
+ // Get the controller context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ChildHandle == NULL) {
+ return LookupUnicodeString (
+ Language,
+ gIDEBusComponentName.SupportedLanguages,
+ mIDEBusControllerNameTable,
+ ControllerName
+ );
+ }
+
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo);
+
+ return LookupUnicodeString (
+ Language,
+ gIDEBusComponentName.SupportedLanguages,
+ IdeBlkIoDevice->ControllerNameTable,
+ ControllerName
+ );
+}
+
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ )
+/*++
+
+ Routine Description:
+ Add the component name for the IDE/ATAPI device
+
+ Arguments:
+ IdeBlkIoDevicePtr - A pointer to the IDE_BLK_IO_DEV instance.
+
+ Returns:
+
+--*/
+{
+ UINTN StringIndex;
+ CHAR16 ModelName[41];
+
+ //
+ // Add Component Name for the IDE/ATAPI device that was discovered.
+ //
+ IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+ for (StringIndex = 0; StringIndex < 41; StringIndex++) {
+ ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex];
+ }
+
+ AddUnicodeString (
+ "eng",
+ gIDEBusComponentName.SupportedLanguages,
+ &IdeBlkIoDevicePtr->ControllerNameTable,
+ ModelName
+ );
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.h
new file mode 100644
index 0000000000..f6c3feb436
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ComponentName.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:
+
+ ComponentName.h
+
+Abstract:
+
+
+Revision History
+--*/
+
+#ifndef _IDE_BUS_COMPONENT_NAME_H
+#define _IDE_BUS_COMPONENT_NAME_H
+
+
+#ifndef EFI_SIZE_REDUCTION_APPLIED
+
+#define ADD_NAME(x) AddName ((x));
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName;
+
+#else
+
+#define ADD_NAME(x)
+
+#endif
+
+
+//
+// EFI Component Name Functions
+//
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Language - TODO: add argument description
+ DriverName - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ ControllerHandle - TODO: add argument description
+ ChildHandle - TODO: add argument description
+ Language - TODO: add argument description
+ ControllerName - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevicePtr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c
new file mode 100644
index 0000000000..b8f71fdc8d
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverConfiguration.c
@@ -0,0 +1,378 @@
+/*++
+
+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:
+
+ DriverConfiguration.c
+
+Abstract:
+
+--*/
+
+#include "IDEBus.h"
+
+CHAR16 *OptionString[4] = {
+ L"Enable Primary Master (Y/N)? -->",
+ L"Enable Primary Slave (Y/N)? -->",
+ L"Enable Secondary Master (Y/N)? -->",
+ L"Enable Secondary Slave (Y/N)? -->"
+};
+//
+// EFI Driver Configuration Functions
+//
+EFI_STATUS
+IDEBusDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+EFI_STATUS
+IDEBusDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+EFI_STATUS
+IDEBusDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+//
+// EFI Driver Configuration Protocol
+//
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {
+ IDEBusDriverConfigurationSetOptions,
+ IDEBusDriverConfigurationOptionsValid,
+ IDEBusDriverConfigurationForceDefaults,
+ "eng"
+};
+
+EFI_STATUS
+GetResponse (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ None
+
+Returns:
+
+ EFI_ABORTED - TODO: Add description for return value
+ EFI_SUCCESS - TODO: Add description for return value
+ EFI_NOT_FOUND - TODO: Add description for return value
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status)) {
+ if (Key.ScanCode == SCAN_ESC) {
+ return EFI_ABORTED;
+ }
+
+ switch (Key.UnicodeChar) {
+
+ //
+ // fall through
+ //
+ case L'y':
+ case L'Y':
+ gST->ConOut->OutputString (gST->ConOut, L"Y\n");
+ return EFI_SUCCESS;
+
+ //
+ // fall through
+ //
+ case L'n':
+ case L'N':
+ gST->ConOut->OutputString (gST->ConOut, L"N\n");
+ return EFI_NOT_FOUND;
+ }
+
+ }
+ }
+}
+
+EFI_STATUS
+IDEBusDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+ Routine Description:
+ Allows the user to set controller specific options for a controller that a
+ driver is currently managing.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL
+ instance.
+ ControllerHandle - The handle of the controller to set options on.
+ ChildHandle - The handle of the child controller to set options on.
+ This is an optional parameter that may be NULL.
+ It will be NULL for device drivers, and for a bus drivers
+ that wish to set options for the bus controller.
+ It will not be NULL for a bus driver that wishes to set
+ options for one of its child controllers.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language of the user interface
+ that should be presented to the user, 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.
+ ActionRequired - A pointer to the action that the calling agent is
+ required to perform when this function returns.
+ See "Related Definitions" for a list of the actions that
+ the calling agent is required to perform prior to
+ accessing ControllerHandle again.
+
+ Returns:
+ EFI_SUCCESS - The driver specified by This successfully set the
+ configuration options for the controller specified
+ by ControllerHandle..
+ 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 - ActionRequired is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ setting configuration options for the controller
+ specified by ControllerHandle and ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+ EFI_DEVICE_ERROR - A device error occurred while attempt to set the
+ configuration options for the controller specified
+ by ControllerHandle and ChildHandle.
+ EFI_OUT_RESOURCES - There are not enough resources available to set the
+ configuration options for the controller specified
+ by ControllerHandle and ChildHandle.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+ UINT8 NewValue;
+ UINTN DataSize;
+ UINTN Index;
+ UINT32 Attributes;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ &Attributes,
+ &DataSize,
+ &Value
+ );
+
+ gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n");
+ gST->ConOut->OutputString (gST->ConOut, L"===============================\n");
+
+ NewValue = 0;
+ for (Index = 0; Index < 4; Index++) {
+ gST->ConOut->OutputString (gST->ConOut, OptionString[Index]);
+
+ Status = GetResponse ();
+ if (Status == EFI_ABORTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ NewValue |= (UINT8) (1 << Index);
+ }
+ }
+
+ if (EFI_ERROR (Status) || (NewValue != Value)) {
+ gRT->SetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (NewValue),
+ &NewValue
+ );
+
+ *ActionRequired = EfiDriverConfigurationActionRestartController;
+ } else {
+ *ActionRequired = EfiDriverConfigurationActionNone;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+IDEBusDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+/*++
+
+ Routine Description:
+ Tests to see if a controller's current configuration options are valid.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL
+ instance.
+ ControllerHandle - The handle of the controller to test if it's current
+ configuration options are valid.
+ ChildHandle - The handle of the child controller to test if it's
+ current
+ configuration options are valid. 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 test the configuration options for the bus
+ controller. It will not be NULL for a bus driver that
+ wishes to test configuration options for one of
+ its child controllers.
+
+ Returns:
+ EFI_SUCCESS - The controller specified by ControllerHandle and
+ ChildHandle that is being managed by the driver
+ specified by This has a valid set of configuration
+ options.
+ 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_UNSUPPORTED - The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ EFI_DEVICE_ERROR - The controller specified by ControllerHandle and
+ ChildHandle that is being managed by the driver
+ specified by This has an invalid set of
+ configuration options.
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+ UINTN DataSize;
+ UINT32 Attributes;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ &Attributes,
+ &DataSize,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value > 0x0f) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+IDEBusDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+/*++
+
+ Routine Description:
+ Forces a driver to set the default configuration options for a controller.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL
+ instance.
+ ControllerHandle - The handle of the controller to force default
+ configuration options on.
+ ChildHandle - The handle of the child controller to force default
+ configuration options on 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
+ force default configuration options for the bus
+ controller. It will not be NULL for a bus driver that
+ wishes to force default configuration options for one
+ of its child controllers.
+ DefaultType - The type of default configuration options to force on
+ the controller specified by ControllerHandle and
+ ChildHandle. See Table 9-1 for legal values.
+ A DefaultType of 0x00000000 must be supported
+ by this protocol.
+ ActionRequired - A pointer to the action that the calling agent
+ is required to perform when this function returns.
+
+
+ Returns:
+ EFI_SUCCESS - The driver specified by This successfully forced
+ the default configuration options on the
+ controller specified by ControllerHandle and
+ ChildHandle.
+ 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 - ActionRequired is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ forcing the default configuration options on
+ the controller specified by ControllerHandle
+ and ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ the configuration type specified by DefaultType.
+ EFI_DEVICE_ERROR - A device error occurred while attempt to force
+ the default configuration options on the controller
+ specified by ControllerHandle and ChildHandle.
+ EFI_OUT_RESOURCES - There are not enough resources available to force
+ the default configuration options on the controller
+ specified by ControllerHandle and ChildHandle.
+
+--*/
+{
+ UINT8 Value;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Value = 0x0f;
+ gRT->SetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Value),
+ &Value
+ );
+ *ActionRequired = EfiDriverConfigurationActionRestartController;
+ return EFI_SUCCESS;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c
new file mode 100644
index 0000000000..ce3be14234
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/DriverDiagnostics.c
@@ -0,0 +1,225 @@
+/*++
+
+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:
+
+ DriverDiagnostics.c
+
+Abstract:
+
+--*/
+
+#include "IDEBus.h"
+
+#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed"
+
+//
+// EFI Driver Diagnostics Functions
+//
+EFI_STATUS
+IDEBusDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ );
+
+//
+// EFI Driver Diagnostics Protocol
+//
+EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {
+ IDEBusDriverDiagnosticsRunDiagnostics,
+ "eng"
+};
+
+EFI_STATUS
+IDEBusDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ )
+/*++
+
+ Routine Description:
+ Runs diagnostics on a controller.
+
+ Arguments:
+ This - A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOL
+ instance.
+ ControllerHandle - The handle of the controller to run diagnostics on.
+ ChildHandle - The handle of the child controller to run diagnostics on
+ 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 run diagnostics on the bus
+ controller. It will not be NULL for a bus driver that
+ wishes to run diagnostics on one of its child
+ controllers.
+ DiagnosticType - Indicates type of diagnostics to perform on the
+ controller specified by ControllerHandle and ChildHandle.
+ See "Related Definitions" for the list of supported
+ types.
+ Language - A pointer to a three character ISO 639-2 language
+ identifier. This is the language in which the optional
+ error message should be returned in Buffer, 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.
+ ErrorType - A GUID that defines the format of the data returned in
+ Buffer.
+ BufferSize - The size, in bytes, of the data returned in Buffer.
+ Buffer - A buffer that contains a Null-terminated Unicode string
+ plus some additional data whose format is defined by
+ ErrorType. Buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility
+ to free it with a call to FreePool().
+
+ Returns:
+ EFI_SUCCESS - The controller specified by ControllerHandle and
+ ChildHandle passed the diagnostic.
+ 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 - ErrorType is NULL.
+ EFI_INVALID_PARAMETER - BufferType is NULL.
+ EFI_INVALID_PARAMETER - Buffer is NULL.
+ EFI_UNSUPPORTED - The driver specified by This does not support
+ running diagnostics for the controller specified
+ by ControllerHandle and ChildHandle.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ EFI_UNSUPPORTED - The driver specified by This does not support the
+ language specified by Language.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to complete
+ the diagnostics.
+ EFI_OUT_OF_RESOURCES - There are not enough resources available to return
+ the status information in ErrorType, BufferSize,
+ and Buffer.
+ EFI_DEVICE_ERROR - The controller specified by ControllerHandle and
+ ChildHandle did not pass the diagnostic.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ UINT32 VendorDeviceId;
+ VOID *BlockBuffer;
+
+ *ErrorType = NULL;
+ *BufferSize = 0;
+
+ if (ChildHandle == NULL) {
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller
+ // The following test simply reads the Device ID and Vendor ID.
+ // It should never fail. A real test would perform more advanced
+ // diagnostics.
+ //
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);
+ if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+ //
+ // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ IdeBlkIoDevice->BlkMedia.BlockSize,
+ (VOID **) &BlockBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IdeBlkIoDevice->BlkIo.ReadBlocks (
+ &IdeBlkIoDevice->BlkIo,
+ IdeBlkIoDevice->BlkMedia.MediaId,
+ 0,
+ IdeBlkIoDevice->BlkMedia.BlockSize,
+ BlockBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ *ErrorType = &gEfiCallerIdGuid;
+ *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN) (*BufferSize),
+ (VOID **) Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ EfiCopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->FreePool (BlockBuffer);
+
+ return Status;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c
new file mode 100644
index 0000000000..88e81c0ada
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ata.c
@@ -0,0 +1,3690 @@
+/*++
+
+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:
+
+ ata.c
+
+Abstract:
+
+Revision History
+
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+ update - ATAIdentity() func
+ update - AtaBlockIoReadBlocks() func
+ update - AtaBlockIoWriteBlocks() func
+ add - AtaAtapi6Identify() func
+ add - AtaReadSectorsExt() func
+ add - AtaWriteSectorsExt() func
+ add - AtaPioDataInExt() func
+ add - AtaPioDataOutExt() func
+
+--*/
+
+#include "idebus.h"
+
+
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN OUT VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ );
+
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ );
+
+EFI_STATUS
+AtaPioDataInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN OUT VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ );
+
+EFI_STATUS
+AtaPioDataOutExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ );
+
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ ATAIdentify
+
+
+ Purpose:
+ This function is called by DiscoverIdeDevice() during its device
+ identification. It sends out the ATA Identify Command to the
+ specified device. Only ATA device responses to this command. If
+ the command succeeds, it returns the Identify data structure which
+ contains information about the device. This function extracts the
+ information it needs to fill the IDE_BLK_IO_DEV data structure,
+ including device type, media block size, media capacity, and etc.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+
+ Returns:
+ EFI_SUCCESS
+ Identify ATA device successfully.
+
+ EFI_DEVICE_ERROR
+ ATA Identify Device Command failed or device is not
+ ATA device.
+
+
+ Notes:
+ parameter IdeDev will be updated in this function.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ EFI_IDENTIFY_DATA *AtaIdentifyPointer;
+ UINT32 Capacity;
+ UINT8 DeviceSelect;
+
+ //
+ // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of
+ // the ATA Identify command
+ //
+ AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+
+ //
+ // use ATA PIO Data In protocol to send ATA Identify command
+ // and receive data from device
+ //
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) AtaIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ IDENTIFY_DRIVE_CMD,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+ //
+ // If ATA Identify command succeeds, then according to the received
+ // IDENTIFY data,
+ // identify the device type ( ATA or not ).
+ // If ATA device, fill the information in IdeDev.
+ // If not ATA device, return IDE_DEVICE_ERROR
+ //
+ if (!EFI_ERROR (Status)) {
+
+ IdeDev->pIdData = AtaIdentifyPointer;
+
+ //
+ // Print ATA Module Name
+ //
+ PrintAtaModuleName (IdeDev);
+
+ //
+ // bit 15 of pAtaIdentify->config is used to identify whether device is
+ // ATA device or ATAPI device.
+ // if 0, means ATA device; if 1, means ATAPI device.
+ //
+ if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {
+ //
+ // Detect if support S.M.A.R.T. If yes, enable it as default
+ //
+ AtaSMARTSupport (IdeDev);
+
+ //
+ // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)
+ //
+ Status = AtaAtapi6Identify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ //
+ // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+ //
+ IdeDev->Type = IdeHardDisk;
+
+ //
+ // Block Media Information:
+ // Media->LogicalPartition , Media->WriteCaching will be filled
+ // in the DiscoverIdeDevcie() function.
+ //
+ IdeDev->BlkIo.Media->IoAlign = 4;
+ IdeDev->BlkIo.Media->MediaId = 1;
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+
+ //
+ // Calculate device capacity
+ //
+ Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |
+ AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;
+
+ return EFI_SUCCESS;
+
+ }
+ }
+
+ gBS->FreePool (AtaIdentifyPointer);
+ //
+ // Make sure the pIdData will not be freed again.
+ //
+ IdeDev->pIdData = NULL;
+
+ return EFI_DEVICE_ERROR;
+}
+
+
+EFI_STATUS
+AtaAtapi6Identify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+
+ AtaAtapi6Identify
+
+ Purpose:
+
+ This function is called by ATAIdentify() to identity whether this disk
+ supports ATA/ATAPI6 48bit addressing, ie support >120G capacity
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+
+ EFI_SUCCESS - The disk specified by IdeDev is a Atapi6 supported one
+ and 48-bit addressing must be used
+
+ EFI_UNSUPPORTED - The disk dosn't not support Atapi6 or it supports but
+ the capacity is below 120G, 48bit addressing is not
+ needed
+
+ Notes:
+
+ This function must be called after DEVICE_IDENTITY command has been
+ successfully returned
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ UINT8 Index;
+ EFI_LBA TmpLba;
+ EFI_LBA Capacity;
+ EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;
+
+ if (IdeDev->pIdData == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Atapi6IdentifyStruct = IdeDev->pIdData;
+
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & bit10) == 0) {
+ //
+ // The device dosn't support 48 bit addressing
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // 48 bit address feature set is supported, get maximum capacity
+ //
+ Capacity = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[0];
+ for (Index = 1; Index < 4; Index++) {
+ //
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+ //
+ TmpLba = Atapi6IdentifyStruct->AtapiData.max_user_lba_for_48bit_addr[Index];
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);
+ }
+
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+ //
+ // Capacity exceeds 120GB. 48-bit addressing is really needed
+ //
+ IdeDev->Type = Ide48bitAddressingHardDisk;
+
+ //
+ // Fill block media information:Media->LogicalPartition ,
+ // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.
+ //
+ IdeDev->BlkIo.Media->IoAlign = 4;
+ IdeDev->BlkIo.Media->MediaId = 1;
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ PrintAtaModuleName
+
+
+ Purpose:
+ This function is called by ATAIdentify() or ATAPIIdentify()
+ to print device's module name.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ no returns.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ if (IdeDev->pIdData == NULL) {
+ return ;
+ }
+
+ SwapStringChars (IdeDev->ModelName, IdeDev->pIdData->AtaData.ModelName, 40);
+ IdeDev->ModelName[40] = 0x00;
+}
+
+EFI_STATUS
+AtaPioDataIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+/*++
+ Name:
+ AtaPioDataIn
+
+
+ Purpose:
+ This function is used to send out ATA commands conforms to the
+ PIO Data In Protocol.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ buffer contained data transferred from device to host.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINT8 IN AtaCommand
+ value of the Command Register
+
+ UINT8 IN Head
+ value of the Head/Device Register
+
+ UINT8 IN SectorCount
+ value of the Sector Count Register
+
+ UINT8 IN SectorNumber
+ value of the Sector Number Register
+
+ UINT8 IN CylinderLsb
+ value of the low byte of the Cylinder Register
+
+ UINT8 IN CylinderMsb
+ value of the high byte of the Cylinder Register
+
+
+ Returns:
+ EFI_SUCCESS
+ send out the ATA command and device send required
+ data successfully.
+
+ EFI_DEVICE_ERROR
+ command sent failed.
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: AtaCommand - add argument and description to function comment
+// TODO: Head - add argument and description to function comment
+// TODO: SectorCount - add argument and description to function comment
+// TODO: SectorNumber - add argument and description to function comment
+// TODO: CylinderLsb - add argument and description to function comment
+// TODO: CylinderMsb - add argument and description to function comment
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.
+ // bit6 set means LBA mode
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+ );
+
+ //
+ // All ATAPI device's ATA commands can be issued regardless of the
+ // state of the DRDY
+ //
+ if (IdeDev->Type == IdeHardDisk) {
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (AtaCommand == SET_FEATURES_CMD) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+ //
+ // send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data in protocol, host can perform a series of reads to
+ // the data register after each time device set DRQ ready;
+ // The data size of "a series of read" is command specific.
+ // For most ATA command, data size received from device will not exceed
+ // 1 sector, hence the data size for "a series of read" can be the whole data
+ // size of one command request.
+ // For ATA command such as Read Sector command, the data size of one ATA
+ // command request is often larger than 1 sector, according to the
+ // Read Sector command, the data size of "a series of read" is exactly 1
+ // sector.
+ // Here for simplification reason, we specify the data size for
+ // "a series of read" to 1 sector (256 words) if data size of one ATA command
+ // request is larger than 256 words.
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ DRQClear (IdeDev, ATATIMEOUT);
+
+ return CheckErrorStatus (IdeDev);
+}
+
+EFI_STATUS
+AtaPioDataOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+/*++
+ Name:
+ AtaPioDataOut
+
+
+ Purpose:
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ buffer contained data transferred from host to device.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINT8 IN AtaCommand
+ value of the Command Register
+
+ UINT8 IN Head
+ value of the Head/Device Register
+
+ UINT8 IN SectorCount
+ value of the Sector Count Register
+
+ UINT8 IN SectorNumber
+ value of the Sector Number Register
+
+ UINT8 IN CylinderLsb
+ value of the low byte of the Cylinder Register
+
+ UINT8 IN CylinderMsb
+ value of the high byte of the Cylinder Register
+
+
+ Returns:
+ EFI_SUCCESS
+ send out the ATA command and device received required
+ data successfully.
+
+ EFI_DEVICE_ERROR
+ command sent failed.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: AtaCommand - add argument and description to function comment
+// TODO: Head - add argument and description to function comment
+// TODO: SectorCount - add argument and description to function comment
+// TODO: SectorNumber - add argument and description to function comment
+// TODO: CylinderLsb - add argument and description to function comment
+// TODO: CylinderMsb - add argument and description to function comment
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // select device via Head/Device register.
+ // Before write Head/Device register, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.
+ // bit6 set means LBA mode
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+ );
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+ //
+ // send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data out protocol, host can perform a series of
+ // writes to the data register after each time device set DRQ ready;
+ // The data size of "a series of read" is command specific.
+ // For most ATA command, data size written to device will not exceed 1 sector,
+ // hence the data size for "a series of write" can be the data size of one
+ // command request.
+ // For ATA command such as Write Sector command, the data size of one
+ // ATA command request is often larger than 1 sector, according to the
+ // Write Sector command, the data size of "a series of read" is exactly
+ // 1 sector.
+ // Here for simplification reason, we specify the data size for
+ // "a series of write" to 1 sector (256 words) if data size of one ATA command
+ // request is larger than 256 words.
+ //
+ Increment = 256;
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+
+ //
+ // DRQReady2-- read Alternate Status Register to determine the DRQ bit
+ // data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check the remaining byte count is less than 512 bytes
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+ //
+ // perform a series of write without check DRQ ready
+ //
+
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ DRQClear (IdeDev, ATATIMEOUT);
+
+ return CheckErrorStatus (IdeDev);
+}
+
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ CheckErrorStatus
+
+
+ Purpose:
+ This function is used to analyze the Status Register and print out
+ some debug information and if there is ERR bit set in the Status
+ Register, the Error Register's value is also be parsed and print out.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ No err information in the Status Register.
+
+ EFI_DEVICE_ERROR
+ Any err information in the Status Register.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ UINT8 StatusRegister;
+
+//#ifdef EFI_DEBUG
+
+ UINT8 ErrorRegister;
+
+//#endif
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ DEBUG_CODE (
+
+ if (StatusRegister & DWF) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Write Fault\n",
+ StatusRegister)
+ );
+ }
+
+ if (StatusRegister & CORR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Corrected Data\n",
+ StatusRegister)
+ );
+ }
+
+ if (StatusRegister & ERR) {
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ if (ErrorRegister & BBK_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & UNC_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & MC_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Media Change\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & ABRT_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Abort\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & TK0NF_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
+ ErrorRegister)
+ );
+ }
+
+ if (ErrorRegister & AMNF_ERR) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
+ ErrorRegister)
+ );
+ }
+
+ }
+ );
+
+ if ((StatusRegister & (ERR | DWF | CORR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+}
+
+EFI_STATUS
+AtaReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+ AtaReadSectors
+
+
+ Purpose:
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the destination buffer for the data.
+
+ EFI_LBA IN Lba
+ The starting logical block address to read from
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+ return status is fully dependent on the return status
+ of AtaPioDataIn() function.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: Lba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+ UINT8 AtaCommand;
+ UINT8 SectorCount8;
+ UINT16 SectorCount;
+ UINTN ByteCount;
+ VOID *Buffer;
+
+ Buffer = DataBuffer;
+
+ //
+ // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol
+ //
+ AtaCommand = READ_SECTORS_CMD;
+
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Lba32 = (UINT32) Lba;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ //
+ // in ATA-3 spec, LBA is in 28 bit width
+ //
+ Lba0 = (UINT8) Lba32;
+ Lba1 = (UINT8) (Lba32 >> 8);
+ Lba2 = (UINT8) (Lba32 >> 16);
+ //
+ // low 4 bit of Lba3 stands for LBA bit24~bit27.
+ //
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+ if (BlocksRemaining >= 0x100) {
+
+ //
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256
+ // sectors to be read
+ //
+ SectorCount8 = 0x00;
+ //
+ // SectorCount is used to record the number of sectors to be read
+ //
+ SectorCount = 256;
+ } else {
+
+ SectorCount8 = (UINT8) BlocksRemaining;
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be read
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // call AtaPioDataIn() to send Read Sector Command and receive data read
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ Buffer,
+ (UINT32) ByteCount,
+ AtaCommand,
+ Lba3,
+ SectorCount8,
+ Lba0,
+ Lba1,
+ Lba2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtaWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *BufferData,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+ AtaWriteSectors
+
+
+ Purpose:
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing onto media in block unit.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ VOID IN *BufferData
+ A pointer to the source buffer for the data.
+
+ EFI_LBA IN Lba
+ The starting logical block address to write onto
+ the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+
+ Returns:
+ return status is fully dependent on the return status
+ of AtaPioDataOut() function.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: BufferData - add argument and description to function comment
+// TODO: Lba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+ UINT8 AtaCommand;
+ UINT8 SectorCount8;
+ UINT16 SectorCount;
+ UINTN ByteCount;
+ VOID *Buffer;
+
+ Buffer = BufferData;
+
+ //
+ // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol
+ //
+ AtaCommand = WRITE_SECTORS_CMD;
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Lba32 = (UINT32) Lba;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ Lba0 = (UINT8) Lba32;
+ Lba1 = (UINT8) (Lba32 >> 8);
+ Lba2 = (UINT8) (Lba32 >> 16);
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+ if (BlocksRemaining >= 0x100) {
+
+ //
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors
+ // to be written
+ //
+ SectorCount8 = 0x00;
+ //
+ // SectorCount is used to record the number of sectors to be written
+ //
+ SectorCount = 256;
+ } else {
+
+ SectorCount8 = (UINT8) BlocksRemaining;
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ Status = AtaPioDataOut (
+ IdeDev,
+ Buffer,
+ (UINT32) ByteCount,
+ AtaCommand,
+ Lba3,
+ SectorCount8,
+ Lba0,
+ Lba1,
+ Lba2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtaSoftReset
+
+ Purpose:
+ This function is used to implement the Soft Reset on the specified
+ device. But, the ATA Soft Reset mechanism is so strong a reset method
+ that it will force resetting on both devices connected to the
+ same cable.
+ It is called by IdeBlkIoReset(), a interface function of Block
+ I/O protocol.
+ This function can also be used by the ATAPI device to perform reset when
+ ATAPI Reset command is failed.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ Returns:
+ EFI_SUCCESS
+ Soft reset completes successfully.
+
+ EFI_DEVICE_ERROR
+ Any step during the reset process is failed.
+ Notes:
+ The registers initial values after ATA soft reset are different
+ to the ATA device and ATAPI device.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+
+ UINT8 DeviceControl;
+
+ DeviceControl = 0;
+ //
+ // set SRST bit to initiate soft reset
+ //
+ DeviceControl |= SRST;
+
+ //
+ // disable Interrupt
+ //
+ DeviceControl |= bit1;
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ gBS->Stall (10);
+
+ //
+ // Enable interrupt to support UDMA, and clear SRST bit
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ //
+ // slave device needs at most 31s to clear BSY
+ //
+ if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+ Name:
+ AtaBlkIoReadBlocks
+
+
+ Purpose:
+ This function is the ATA implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeBlkIoDevice
+ Indicates the calling context.
+
+ UINT32 IN MediaId
+ The media id that the read request is for.
+
+ EFI_LBA IN LBA
+ The starting logical block address to read from
+ on the device.
+
+ UINTN IN BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ VOID OUT *Buffer
+ A pointer to the destination buffer for the data.
+ The caller is responsible for either having implicit
+ or explicit ownership of the memory that data is read into.
+
+ Returns:
+ EFI_SUCCESS
+ Read Blocks successfully.
+
+ EFI_DEVICE_ERROR
+ Read Blocks failed.
+
+ EFI_NO_MEDIA
+ There is no media in the device.
+
+ EFI_MEDIA_CHANGE
+ The MediaId is not for the current media.
+
+ EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ EFI_INVALID_PARAMETER
+ The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ Notes:
+ If Read Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeBlkIoDevice - add argument and description to function comment
+// TODO: MediaId - add argument and description to function comment
+// TODO: LBA - add argument and description to function comment
+// TODO: BufferSize - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: EFI_MEDIA_CHANGED - add return value to function comment
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (!(Media->MediaPresent)) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (LBA > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism
+ //
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 read block mechanism
+ // Notice DMA operation can only handle 32bit address
+ //
+ if ((UINTN) Buffer <= 0xFFFFFFFF) {
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+
+ if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {
+ Status = AtaReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+ Name:
+ AtaBlkIoWriteBlocks
+
+
+ Purpose:
+ This function is the ATA implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeBlkIoDevice
+ Indicates the calling context.
+
+ UINT32 IN MediaId
+ The media id that the write request is for.
+
+ EFI_LBA IN LBA
+ The starting logical block address to write onto
+ the device.
+
+ UINTN IN BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ VOID OUT *Buffer
+ A pointer to the source buffer for the data.
+ The caller is responsible for either having implicit
+ or explicit ownership of the memory that data is
+ written from.
+
+
+ Returns:
+ EFI_SUCCESS
+ Write Blocks successfully.
+
+ EFI_DEVICE_ERROR
+ Write Blocks failed.
+
+ EFI_NO_MEDIA
+ There is no media in the device.
+
+ EFI_MEDIA_CHANGE
+ The MediaId is not for the current media.
+
+ EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ EFI_INVALID_PARAMETER
+ The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ Notes:
+ If Write Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeBlkIoDevice - add argument and description to function comment
+// TODO: MediaId - add argument and description to function comment
+// TODO: LBA - add argument and description to function comment
+// TODO: BufferSize - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: EFI_MEDIA_CHANGED - add return value to function comment
+{
+
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (LBA > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism
+ //
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 write block mechanism
+ //
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ if (EFI_ERROR (Status) || ((UINTN) Buffer > 0xFFFFFFFF)) {
+ Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaReadSectorsExt
+
+ Purpose:
+
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the destination buffer for the data.
+
+ EFI_LBA IN StartLba
+ The starting logical block address to read from
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ return status is fully dependent on the return status
+ of AtaPioDataInExt() function.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ EFI_LBA Lba64;
+ UINT8 AtaCommand;
+ UINT16 SectorCount;
+ UINT32 ByteCount;
+ VOID *Buffer;
+
+ //
+ // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol
+ //
+ AtaCommand = READ_SECTORS_EXT_CMD;
+ Buffer = DataBuffer;
+ BlocksRemaining = NumberOfBlocks;
+ Lba64 = StartLba;
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= 0x10000) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ SectorCount = 0xffff;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be read
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // call AtaPioDataInExt() to send Read Sector Command and receive data read
+ //
+ Status = AtaPioDataInExt (
+ IdeDev,
+ Buffer,
+ ByteCount,
+ AtaCommand,
+ Lba64,
+ SectorCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba64 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaWriteSectorsExt
+
+ Purpose:
+
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing onto media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the source buffer for the data.
+
+ EFI_LBA IN Lba
+ The starting logical block address to write onto
+ the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ return status is fully dependent on the return status
+ of AtaPioDataOutExt() function.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ EFI_LBA Lba64;
+ UINTN BlocksRemaining;
+ UINT8 AtaCommand;
+ UINT16 SectorCount;
+ UINT32 ByteCount;
+ VOID *Buffer;
+
+ //
+ // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol
+ //
+ AtaCommand = WRITE_SECTORS_EXT_CMD;
+ Lba64 = StartLba;
+ Buffer = DataBuffer;
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= 0x10000) {
+ //
+ // SectorCount is used to record the number of sectors to be written.
+ // Max 65536 sectors can be transfered at a time.
+ //
+ SectorCount = 0xffff;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be written
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command
+ //
+ Status = AtaPioDataOutExt (
+ IdeDev,
+ Buffer,
+ ByteCount,
+ AtaCommand,
+ Lba64,
+ SectorCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba64 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtaPioDataInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN OUT VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+/*++
+ Name:
+
+ AtaPioDataInExt
+
+ Purpose:
+
+ This function is used to send out ATA commands conforms to the
+ PIO Data In Protocol, supporting ATA/ATAPI-6 standard
+
+ Comparing with ATA-3 data in protocol, we have two differents here:
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+ wait will frequently fail... cause writing function return error)
+
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+ slow down writing performance by 100 times!)
+
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN OUT *Buffer
+ buffer contained data transferred from device to host.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINT8 IN AtaCommand
+ value of the Command Register
+
+ EFI_LBA IN StartLba
+ the start LBA of this transaction
+
+ UINT16 IN SectorCount
+ the count of sectors to be transfered
+
+ Returns:
+
+ EFI_SUCCESS
+ send out the ATA command and device send required
+ data successfully.
+
+ EFI_DEVICE_ERROR
+ command sent failed.
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: AtaCommand - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: SectorCount - add argument and description to function comment
+{
+ UINT8 DevSel;
+ UINT8 SectorCount8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device, set bit6 as 1 to indicate LBA mode is used
+ //
+ DevSel = (UINT8) (IdeDev->Device << 4);
+ DevSel |= 0x40;
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ DevSel
+ );
+
+ //
+ // Wait for DRDY singnal asserting. ATAPI device needn't wait
+ //
+ if ( (IdeDev->Type == IdeHardDisk) ||
+ (IdeDev->Type == Ide48bitAddressingHardDisk)) {
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Fill feature register if needed
+ //
+ if (AtaCommand == SET_FEATURES_CMD) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) StartLba;
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register, invoking the processing of this command
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data in protocol, host can perform a series of reads to
+ // the data register after each time device set DRQ ready;
+ //
+
+ //
+ // 256 words
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ return CheckErrorStatus (IdeDev);
+}
+
+EFI_STATUS
+AtaPioDataOutExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+/*++
+ Name:
+
+ AtaPioDataOutExt
+
+ Purpose:
+
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol, supporting ATA/ATAPI-6 standard
+
+ Comparing with ATA-3 data out protocol, we have two differents here:
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+ wait will frequently fail... cause writing function return error)
+
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+ slow down writing performance by 100 times!)
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ buffer contained data transferred from host to device.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINT8 IN AtaCommand
+ value of the Command Register
+
+ EFI_LBA IN StartLba
+ the start LBA of this transaction
+
+ UINT16 IN SectorCount
+ the count of sectors to be transfered
+
+ Returns:
+
+ EFI_SUCCESS
+ send out the ATA command and device receive required
+ data successfully.
+
+ EFI_DEVICE_ERROR
+ command sent failed.
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: AtaCommand - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: SectorCount - add argument and description to function comment
+{
+ UINT8 DevSel;
+ UINT8 SectorCount8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device. Set bit6 as 1 to indicate LBA mode is used
+ //
+ DevSel = (UINT8) (IdeDev->Device << 4);
+ DevSel |= 0x40;
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ DevSel
+ );
+
+ //
+ // Wait for DRDY singnal asserting.
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Fill feature register if needed
+ //
+ if (AtaCommand == SET_FEATURES_CMD) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) StartLba;
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register, invoking the processing of this command
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO Data Out protocol, host can perform a series of writes to
+ // the data register after each time device set DRQ ready;
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Write data into device by one series of writing to data register
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+ //
+ // while
+ //
+
+ return CheckErrorStatus (IdeDev);
+}
+
+
+VOID
+AtaSMARTSupport (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtaSMARTSupport
+
+ Purpose:
+
+ Enable SMART of the disk if supported
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ Returns:
+
+ NONE
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ BOOLEAN SMARTSupported;
+ UINT8 Device;
+ EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;
+ UINT8 DeviceSelect;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+
+ //
+ // Detect if the device supports S.M.A.R.T.
+ //
+ if ((IdeDev->pIdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {
+ //
+ // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)
+ //
+ return ;
+ } else {
+ if ((IdeDev->pIdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+ //
+ // S.M.A.R.T is not supported by the device
+ //
+ SMARTSupported = FALSE;
+ } else {
+ SMARTSupported = TRUE;
+ }
+ }
+
+ if (!SMARTSupported) {
+ //
+ // Report nonsupport status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+ );
+ } else {
+ //
+ // Enable this feature
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+ );
+
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_SMART_CMD,
+ Device,
+ ATA_SMART_ENABLE_OPERATION,
+ 0,
+ 0,
+ ATA_CONSTANT_4F,
+ ATA_CONSTANT_C2
+ );
+ //
+ // Detect if this feature is enabled
+ //
+ TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) TmpAtaIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ IDENTIFY_DRIVE_CMD,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (TmpAtaIdentifyPointer);
+ return ;
+ }
+
+ //
+ // Check if the feature is enabled
+ //
+ if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {
+ //
+ // Read status data
+ //
+ AtaNonDataCommandIn (
+ IdeDev,
+ ATA_SMART_CMD,
+ Device,
+ ATA_SMART_RETURN_STATUS,
+ 0,
+ 0,
+ ATA_CONSTANT_4F,
+ ATA_CONSTANT_C2
+ );
+ LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+ LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);
+
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+ //
+ // The threshold exceeded condition is not detected by the device
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)
+ );
+
+ } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
+ //
+ // The threshold exceeded condition is detected by the device
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+ );
+ }
+
+ } else {
+ //
+ // Report disabled status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+ );
+ }
+
+ gBS->FreePool (TmpAtaIdentifyPointer);
+ }
+
+ return ;
+}
+
+EFI_STATUS
+AtaCommandIssueExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ Send ATA Ext command into device with NON_DATA protocol
+
+Arguments:
+
+ IdeDev - Standard IDE device private data structure
+ AtaCommand - The ATA command to be sent
+ Device - The value in Device register
+ Feature - The value in Feature register
+ SectorCount - The value in SectorCount register
+ LbaAddress - The LBA address in 48-bit mode
+
+Returns:
+
+ EFI_SUCCESS - Reading succeed
+ EFI_DEVICE_ERROR - Error executing commands on this device
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) (Feature >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ LbaLow = (UINT8) LbaAddress;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Work around for Segate 160G disk writing
+ //
+ gBS->Stall (1800);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Stall at least 400ns
+ //
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaCommandIssue (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ Send ATA Ext command into device with NON_DATA protocol
+
+Arguments:
+
+ IdeDev - Standard IDE device private data structure
+ AtaCommand - The ATA command to be sent
+ Device - The value in Device register
+ Feature - The value in Feature register
+ SectorCount - The value in SectorCount register
+ LbaAddress - The LBA address in 48-bit mode
+
+Returns:
+
+ EFI_SUCCESS - Reading succeed
+ EFI_DEVICE_ERROR - Error executing commands on this device
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Lba0 = (UINT8) LbaAddress;
+ Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);
+ Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);
+ Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);
+ Device |= Lba3;
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Stall at least 400ns
+ //
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaUdmaReadExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaUdmaReadExt
+
+ Purpose:
+
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the destination buffer for the data.
+
+ EFI_LBA IN StartLba
+ The starting logical block address to read from
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_DMA_PRD *PrdAddr;
+ IDE_DMA_PRD *UsedPrdAddr;
+ IDE_DMA_PRD *TempPrdAddr;
+ UINT8 RegisterValue;
+ UINT8 Device;
+ UINT64 IoPortForBmic;
+ UINT64 IoPortForBmis;
+ UINT64 IoPortForBmid;
+ EFI_STATUS Status;
+ UINTN PrdTableNum;
+ UINTN ByteCount;
+ UINTN ByteAvailable;
+ UINT8 *PrdBuffer;
+ UINTN RemainBlockNum;
+ UINT8 DeviceControl;
+
+ //
+ // Channel and device differential. Select device.
+ //
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+
+ //
+ // Enable interrupt to support UDMA and Select device
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ RemainBlockNum = NumberOfBlocks;
+ while (RemainBlockNum > 0) {
+
+ if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;
+ RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;
+ } else {
+ NumberOfBlocks = (UINT16) RemainBlockNum;
+ RemainBlockNum = 0;
+ }
+
+ //
+ // Calculate the number of PRD table to make sure the memory region
+ // not cross 64K boundary
+ //
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+ //
+ // Build PRD table
+ //
+ PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
+
+ //
+ // To make sure PRD is allocated in one 64K page
+ //
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+ } else {
+ if ((UINTN) PrdAddr & 0x03) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+ } else {
+ UsedPrdAddr = PrdAddr;
+ }
+ }
+
+ //
+ // Build the PRD table
+ //
+ PrdBuffer = DataBuffer;
+ TempPrdAddr = UsedPrdAddr;
+ while (TRUE) {
+
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+ if (ByteCount <= ByteAvailable) {
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;
+ TempPrdAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;
+
+ ByteCount -= ByteAvailable;
+ PrdBuffer += ByteAvailable;
+ TempPrdAddr++;
+ }
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmid,
+ 1,
+ &UsedPrdAddr
+ );
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_nREAD;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIS_INTERRUPT | BMIS_ERROR;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Issue READ DMA EXT command
+ //
+ Status = AtaCommandIssueExt (
+ IdeDev,
+ READ_DMA_EXT_CMD,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_START;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ //
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
+ if (RegisterValue & BMIS_ERROR) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ }
+
+ gBS->FreePool (PrdAddr);
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue &= ~((UINT8) BMIC_START);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ if (RegisterValue & BMIS_ERROR) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ StartLba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaUdmaRead (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaUdmaRead
+
+ Purpose:
+
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the destination buffer for the data.
+
+ EFI_LBA IN StartLba
+ The starting logical block address to read from
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_DMA_PRD *PrdAddr;
+ IDE_DMA_PRD *UsedPrdAddr;
+ IDE_DMA_PRD *TempPrdAddr;
+ UINT8 RegisterValue;
+ UINT8 Device;
+ UINT64 IoPortForBmic;
+ UINT64 IoPortForBmis;
+ UINT64 IoPortForBmid;
+ EFI_STATUS Status;
+ UINTN PrdTableNum;
+ UINTN ByteCount;
+ UINTN ByteAvailable;
+ UINT8 *PrdBuffer;
+ UINTN RemainBlockNum;
+ UINT8 DeviceControl;
+
+ //
+ // Channel and device differential
+ //
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+
+ //
+ // Enable interrupt to support UDMA and Select device
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ RemainBlockNum = NumberOfBlocks;
+ while (RemainBlockNum > 0) {
+
+ if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 256 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;
+ RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;
+ } else {
+ NumberOfBlocks = (UINT16) RemainBlockNum;
+ RemainBlockNum = 0;
+ }
+
+ //
+ // Calculate the number of PRD table to make sure the memory region
+ // not cross 64K boundary
+ //
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+ //
+ // Build PRD table
+ //
+ PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
+ //
+ // To make sure PRD is allocated in one 64K page
+ //
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+ } else {
+ if ((UINTN) PrdAddr & 0x03) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+ } else {
+ UsedPrdAddr = PrdAddr;
+ }
+ }
+
+ //
+ // Build the PRD table
+ //
+ PrdBuffer = DataBuffer;
+ TempPrdAddr = UsedPrdAddr;
+ while (TRUE) {
+
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+ if (ByteCount <= ByteAvailable) {
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;
+ TempPrdAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;
+
+ ByteCount -= ByteAvailable;
+ PrdBuffer += ByteAvailable;
+ TempPrdAddr++;
+ }
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmid,
+ 1,
+ &UsedPrdAddr
+ );
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_nREAD;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Issue READ DMA command
+ //
+ Status = AtaCommandIssue (
+ IdeDev,
+ READ_DMA_CMD,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_START;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ //
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
+ if (RegisterValue & BMIS_ERROR) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ }
+
+ gBS->FreePool (PrdAddr);
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue &= ~((UINT8) BMIC_START);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ if (RegisterValue & BMIS_ERROR) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ StartLba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaUdmaWriteExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaUdmaWriteExt
+
+ Purpose:
+
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing to media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the source buffer for the data.
+
+ EFI_LBA IN StartLba
+ The starting logical block address to write to
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_DMA_PRD *PrdAddr;
+ IDE_DMA_PRD *UsedPrdAddr;
+ IDE_DMA_PRD *TempPrdAddr;
+ UINT8 RegisterValue;
+ UINT8 Device;
+ UINT64 IoPortForBmic;
+ UINT64 IoPortForBmis;
+ UINT64 IoPortForBmid;
+ EFI_STATUS Status;
+ UINTN PrdTableNum;
+ UINTN ByteCount;
+ UINTN ByteAvailable;
+ UINT8 *PrdBuffer;
+ UINTN RemainBlockNum;
+ UINT8 DeviceControl;
+
+ //
+ // Channel and device differential
+ //
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+
+ //
+ // Enable interrupt to support UDMA and Select device
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ RemainBlockNum = NumberOfBlocks;
+ while (RemainBlockNum > 0) {
+
+ if (RemainBlockNum >= MAX_DMA_EXT_COMMAND_SECTORS) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MAX_DMA_EXT_COMMAND_SECTORS;
+ RemainBlockNum -= MAX_DMA_EXT_COMMAND_SECTORS;
+ } else {
+ NumberOfBlocks = (UINT16) RemainBlockNum;
+ RemainBlockNum = 0;
+ }
+
+ //
+ // Calculate the number of PRD table to make sure the memory region
+ // not cross 64K boundary
+ //
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+ //
+ // Build PRD table
+ //
+ PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
+ //
+ // To make sure PRD is allocated in one 64K page
+ //
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+ } else {
+ if ((UINTN) PrdAddr & 0x03) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+ } else {
+ UsedPrdAddr = PrdAddr;
+ }
+ }
+
+ //
+ // Build the PRD table
+ //
+ PrdBuffer = DataBuffer;
+ TempPrdAddr = UsedPrdAddr;
+ while (TRUE) {
+
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+ if (ByteCount <= ByteAvailable) {
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;
+ TempPrdAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;
+
+ ByteCount -= ByteAvailable;
+ PrdBuffer += ByteAvailable;
+ TempPrdAddr++;
+ }
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmid,
+ 1,
+ &UsedPrdAddr
+ );
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+ //
+ // 0000 1000
+ //
+ RegisterValue &= ~((UINT8) BMIC_nREAD);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Issue WRITE DMA EXT command
+ //
+ Status = AtaCommandIssueExt (
+ IdeDev,
+ WRITE_DMA_EXT_CMD,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_START;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ //
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
+ if (RegisterValue & BMIS_ERROR) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ }
+
+ gBS->FreePool (PrdAddr);
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue &= ~((UINT8) BMIC_START);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ StartLba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaUdmaWrite (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+
+ AtaUdmaWrite
+
+ Purpose:
+
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing to media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ Parameters:
+
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *DataBuffer
+ A pointer to the source buffer for the data.
+
+ EFI_LBA IN StartLba
+ The starting logical block address to write to
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+
+ The device status of UDMA operation. If the operation is
+ successful, return EFI_SUCCESS.
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DataBuffer - add argument and description to function comment
+// TODO: StartLba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_DMA_PRD *PrdAddr;
+ IDE_DMA_PRD *UsedPrdAddr;
+ IDE_DMA_PRD *TempPrdAddr;
+ UINT8 RegisterValue;
+ UINT8 Device;
+ UINT64 IoPortForBmic;
+ UINT64 IoPortForBmis;
+ UINT64 IoPortForBmid;
+ EFI_STATUS Status;
+ UINTN PrdTableNum;
+ UINTN ByteCount;
+ UINTN ByteAvailable;
+ UINT8 *PrdBuffer;
+ UINTN RemainBlockNum;
+ UINT8 DeviceControl;
+
+ //
+ // Channel and device differential
+ //
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+
+ //
+ // Enable interrupt to support UDMA
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ RemainBlockNum = NumberOfBlocks;
+ while (RemainBlockNum > 0) {
+
+ if (RemainBlockNum >= MAX_DMA_COMMAND_SECTORS) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 256 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MAX_DMA_COMMAND_SECTORS;
+ RemainBlockNum -= MAX_DMA_COMMAND_SECTORS;
+ } else {
+ NumberOfBlocks = (UINT16) RemainBlockNum;
+ RemainBlockNum = 0;
+ }
+
+ //
+ // Calculate the number of PRD table to make sure the memory region
+ // not cross 64K boundary
+ //
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+ //
+ // Build PRD table
+ //
+ PrdAddr = (IDE_DMA_PRD *) AllocateZeroPool ((2 * PrdTableNum * sizeof (IDE_DMA_PRD)));
+
+ //
+ // To make sure PRD is allocated in one 64K page
+ //
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+ } else {
+ if ((UINTN) PrdAddr & 0x03) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+ } else {
+ UsedPrdAddr = PrdAddr;
+ }
+ }
+
+ //
+ // Build the PRD table
+ //
+ PrdBuffer = DataBuffer;
+ TempPrdAddr = UsedPrdAddr;
+ while (TRUE) {
+
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+ if (ByteCount <= ByteAvailable) {
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;
+ TempPrdAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;
+
+ ByteCount -= ByteAvailable;
+ PrdBuffer += ByteAvailable;
+ TempPrdAddr++;
+ }
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmid,
+ 1,
+ &UsedPrdAddr
+ );
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+ //
+ // 0000 1000
+ //
+ RegisterValue &= ~((UINT8) BMIC_nREAD);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Issue WRITE DMA command
+ //
+ Status = AtaCommandIssue (
+ IdeDev,
+ WRITE_DMA_CMD,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_START;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ //
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if (RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) {
+ if (RegisterValue & BMIS_ERROR) {
+ gBS->FreePool (PrdAddr);
+ return EFI_DEVICE_ERROR;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ }
+
+ gBS->FreePool (PrdAddr);
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue &= ~((UINT8) BMIC_START);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ StartLba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
new file mode 100644
index 0000000000..fa004e3d7f
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/atapi.c
@@ -0,0 +1,2591 @@
+/*++
+
+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:
+
+ atapi.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+#include "idebus.h"
+
+STATIC
+EFI_STATUS
+LS120GetMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ LS120GetMediaStatus
+
+ Purpose:
+ This function is used to get the current status of the media residing
+ in the LS-120 drive or ZIP drive. The media status is returned in the
+ Error Status.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ The media status is achieved successfully and the media
+ can be read/written.
+
+ EFI_DEVICE_ERROR
+ Get Media Status Command is failed.
+
+ EFI_NO_MEDIA
+ There is no media in the drive.
+
+ EFI_WRITE_PROTECTED
+ The media is writing protected.
+
+ Notes:
+ This function must be called after the LS120EnableMediaStatus()
+ with second parameter set to TRUE
+ (means enable media status notification) is called.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ UINT8 DeviceSelect;
+ UINT8 StatusValue;
+ EFI_STATUS EfiStatus;
+ //
+ // Poll Alternate Register for BSY clear within timeout.
+ //
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ //
+ // Poll Alternate Register for DRDY set within timeout.
+ // After device is selected, DRDY set indicates the device is ready to
+ // accept command.
+ //
+ EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get Media Status Command is sent
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);
+
+ //
+ // BSY bit will clear after command is complete.
+ //
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // the media status is returned by the command in the ERROR register
+ //
+ StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ if (StatusValue & bit1) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (StatusValue & bit6) {
+ return EFI_WRITE_PROTECTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+
+STATIC
+EFI_STATUS
+LS120EnableMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN BOOLEAN Enable
+ )
+/*++
+ Name:
+ LS120EnableMediaStatus
+
+ Purpose:
+ This function is used to send Enable Media Status Notification Command
+ or Disable Media Status Notification Command.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ BOOLEAN IN Enable
+ a flag that indicates whether enable or disable media
+ status notification.
+
+ Returns:
+ EFI_SUCCESS
+ If command completes successfully.
+
+ EFI_DEVICE_ERROR
+ If command failed.
+
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Enable - add argument and description to function comment
+{
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // Poll Alternate Register for BSY clear within timeout.
+ //
+ Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ //
+ // Poll Alternate Register for DRDY set within timeout.
+ // After device is selected, DRDY set indicates the device is ready to
+ // accept command.
+ //
+ Status = DRDYReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Enable) {
+ //
+ // 0x95: Enable media status notification
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);
+ } else {
+ //
+ // 0x31: Disable media status notification
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);
+ }
+ //
+ // Set Feature Command is sent
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);
+
+ //
+ // BSY bit will clear after command is complete.
+ //
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ ATAPIIdentify
+
+
+ Purpose:
+ This function is called by DiscoverIdeDevice() during its device
+ identification.
+
+ Its main purpose is to get enough information for the device media
+ to fill in the Media data structure of the Block I/O Protocol interface.
+
+ There are 5 steps to reach such objective:
+
+ 1. Sends out the ATAPI Identify Command to the specified device.
+ Only ATAPI device responses to this command. If the command succeeds,
+ it returns the Identify data structure which filled with information
+ about the device. Since the ATAPI device contains removable media,
+ the only meaningful information is the device module name.
+
+ 2. Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return inquiry data of the device, which contains
+ the device type information.
+
+ 3. Allocate sense data space for future use. We don't detect the media
+ presence here to improvement boot performance, especially when CD
+ media is present. The media detection will be performed just before
+ each BLK_IO read/write
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ Identify ATAPI device successfully.
+
+ EFI_DEVICE_ERROR
+ ATAPI Identify Device Command failed or device type
+ is not supported by this IDE driver.
+
+ Notes:
+ Parameter "IdeDev" will be updated in this function.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
+// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
+{
+ EFI_IDENTIFY_DATA *AtapiIdentifyPointer;
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // device select bit
+ //
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+ AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));
+ if (AtapiIdentifyPointer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Send ATAPI Identify Command to get IDENTIFY data.
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) AtapiIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATAPI_IDENTIFY_DEVICE_CMD,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (AtapiIdentifyPointer);
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->pIdData = AtapiIdentifyPointer;
+ PrintAtaModuleName (IdeDev);
+
+ //
+ // Send ATAPI Inquiry Packet Command to get INQUIRY data.
+ //
+ Status = AtapiInquiry (IdeDev);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (IdeDev->pIdData);
+ //
+ // Make sure the pIdData will not be freed again.
+ //
+ IdeDev->pIdData = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get media removable info from INQUIRY data.
+ //
+ IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->pInquiryData->RMB & 0x80) == 0x80);
+
+ //
+ // Identify device type via INQUIRY data.
+ //
+ switch (IdeDev->pInquiryData->peripheral_type & 0x1f) {
+
+ //
+ // Magnetic Disk
+ //
+ case 0x00:
+
+ //
+ // device is LS120 or ZIP drive.
+ //
+ IdeDev->Type = IdeMagnetic;
+
+ IdeDev->BlkIo.Media->MediaId = 0;
+ //
+ // Give initial value
+ //
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+ break;
+
+ //
+ // CD-ROM
+ //
+ case 0x05:
+
+ IdeDev->Type = IdeCdRom;
+ IdeDev->BlkIo.Media->MediaId = 0;
+ //
+ // Give initial value
+ //
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ IdeDev->BlkIo.Media->BlockSize = 0x800;
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+ break;
+
+ //
+ // Tape
+ //
+ case 0x01:
+
+ //
+ // WORM
+ //
+ case 0x04:
+
+ //
+ // Optical
+ //
+ case 0x07:
+
+ default:
+ IdeDev->Type = IdeUnknown;
+ gBS->FreePool (IdeDev->pIdData);
+ gBS->FreePool (IdeDev->pInquiryData);
+ //
+ // Make sure the pIdData and pInquiryData will not be freed again.
+ //
+ IdeDev->pIdData = NULL;
+ IdeDev->pInquiryData = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // original sense data numbers
+ //
+ IdeDev->SenseDataNumber = 20;
+
+ IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (REQUEST_SENSE_DATA));
+ if (IdeDev->SenseData == NULL) {
+ gBS->FreePool (IdeDev->pIdData);
+ gBS->FreePool (IdeDev->pInquiryData);
+ //
+ // Make sure the pIdData and pInquiryData will not be freed again.
+ //
+ IdeDev->pIdData = NULL;
+ IdeDev->pInquiryData = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtapiInquiry (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtapiInquiry
+
+ Purpose:
+ Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return INQUIRY data of the device.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ Inquiry command completes successfully.
+
+ EFI_DEVICE_ERROR
+ Inquiry command failed.
+ Notes:
+ Parameter "IdeDev" will be updated in this function.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ INQUIRY_DATA *InquiryData;
+
+ //
+ // prepare command packet for the ATAPI Inquiry Packet Command.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = sizeof (INQUIRY_DATA);
+
+ InquiryData = AllocatePool (sizeof (INQUIRY_DATA));
+ if (InquiryData == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send command packet and get requested Inquiry data.
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) InquiryData,
+ sizeof (INQUIRY_DATA),
+ ATAPITIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (InquiryData);
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->pInquiryData = InquiryData;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+/*++
+ Name:
+ AtapiPacketCommandIn
+
+ Purpose:
+ This function is used to send out ATAPI commands conforms to the
+ Packet Command with PIO Data In Protocol.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ ATAPI_PACKET_COMMAND IN *Packet
+ pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+
+ UINT16 IN *Buffer
+ buffer contained data transferred from device to host.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINTN IN TimeOut
+ this parameter is used to specify the timeout
+ value for the PioReadWriteData() function.
+
+ Returns:
+ EFI_SUCCESS
+ send out the ATAPI packet command successfully
+ and device sends data successfully.
+
+ EFI_DEVICE_ERROR
+ the device failed to send data.
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Packet - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: TimeOut - add argument and description to function comment
+{
+ UINT16 *CommandIndex;
+ EFI_STATUS Status;
+ UINT32 Count;
+
+ //
+ // Set all the command parameters by fill related registers.
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to MAX_ATAPI_BYTE_COUNT to let the device
+ // determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
+ );
+
+ //
+ // DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);
+
+ Status = DRQReady (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Send out command packet
+ //
+ CommandIndex = Packet->Data16;
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {
+
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+ gBS->Stall (10);
+ }
+
+ //
+ // call PioReadWriteData() function to get
+ // requested transfer data form device.
+ //
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);
+}
+
+EFI_STATUS
+AtapiPacketCommandOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+/*++
+ Name:
+ AtapiPacketCommandOut
+
+ Purpose:
+ This function is used to send out ATAPI commands conforms to the
+ Packet Command with PIO Data Out Protocol.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ ATAPI_PACKET_COMMAND IN *Packet
+ pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+
+ VOID IN *Buffer
+ buffer contained data transferred from host to device.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ UINTN IN TimeOut
+ this parameter is used to specify the timeout
+ value for the PioReadWriteData() function.
+
+ Returns:
+ EFI_SUCCESS
+ send out the ATAPI packet command successfully
+ and device received data successfully.
+
+ EFI_DEVICE_ERROR
+ the device failed to send data.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Packet - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: TimeOut - add argument and description to function comment
+{
+ UINT16 *CommandIndex;
+ EFI_STATUS Status;
+ UINT32 Count;
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to MAX_ATAPI_BYTE_COUNT to
+ // let the device determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (MAX_ATAPI_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (MAX_ATAPI_BYTE_COUNT >> 8)
+ );
+
+ //
+ // DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, PACKET_CMD);
+
+ Status = DRQReady2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Send out command packet
+ //
+ CommandIndex = Packet->Data16;
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+ gBS->Stall (10);
+ }
+
+ //
+ // call PioReadWriteData() function to send requested transfer data to device.
+ //
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);
+}
+
+EFI_STATUS
+PioReadWriteData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN BOOLEAN Read,
+ IN UINTN TimeOut
+ )
+/*++
+ Name:
+ PioReadWriteData
+
+ Purpose:
+ This function is called by either AtapiPacketCommandIn() or
+ AtapiPacketCommandOut(). It is used to transfer data between
+ host and device. The data direction is specified by the fourth
+ parameter.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ buffer contained data transferred between host and device.
+
+ UINT32 IN ByteCount
+ data size in byte unit of the buffer.
+
+ BOOLEAN IN Read
+ flag used to determine the data transfer direction.
+ Read equals 1, means data transferred from device to host;
+ Read equals 0, means data transferred from host to device.
+
+ UINTN IN TimeOut
+ timeout value for wait DRQ ready before each data
+ stream's transfer.
+
+ Returns:
+ EFI_SUCCESS
+ data is transferred successfully.
+
+ EFI_DEVICE_ERROR
+ the device failed to transfer data.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: ByteCount - add argument and description to function comment
+// TODO: Read - add argument and description to function comment
+// TODO: TimeOut - add argument and description to function comment
+{
+ //
+ // required transfer data in word unit.
+ //
+ UINT32 RequiredWordCount;
+
+ //
+ // actual transfer data in word unit.
+ //
+ UINT32 ActualWordCount;
+ UINT32 WordCount;
+ EFI_STATUS Status;
+ UINT16 *PtrBuffer;
+
+ //
+ // containing status byte read from Status Register.
+ //
+ UINT8 StatusRegister;
+
+ //
+ // No data transfer is premitted.
+ //
+ if (ByteCount == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // for performance, we assert the ByteCount is an even number
+ // which is actually a resonable assumption
+ ASSERT((ByteCount%2) == 0);
+
+ PtrBuffer = Buffer;
+ RequiredWordCount = ByteCount / 2;
+ //
+ // ActuralWordCount means the word count of data really transferred.
+ //
+ ActualWordCount = 0;
+
+ while (ActualWordCount < RequiredWordCount) {
+
+ //
+ // before each data transfer stream, the host should poll DRQ bit ready,
+ // to see whether indicates device is ready to transfer data.
+ //
+ Status = DRQReady2 (IdeDev, TimeOut);
+ if (EFI_ERROR (Status)) {
+ return CheckErrorStatus (IdeDev);
+ }
+
+ //
+ // read Status Register will clear interrupt
+ //
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // get current data transfer size from Cylinder Registers.
+ //
+ WordCount =
+ (
+ (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8) |
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb)
+ ) & 0xffff;
+ WordCount /= 2;
+
+ WordCount = EFI_MIN (WordCount, (RequiredWordCount - ActualWordCount));
+
+ if (Read) {
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ WordCount,
+ PtrBuffer
+ );
+ } else {
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ WordCount,
+ PtrBuffer
+ );
+ }
+
+ PtrBuffer += WordCount;
+ ActualWordCount += WordCount;
+ }
+
+ //
+ // After data transfer is completed, normally, DRQ bit should clear.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // read status register to check whether error happens.
+ //
+ return CheckErrorStatus (IdeDev);
+}
+
+EFI_STATUS
+AtapiTestUnitReady (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtapiTestUnitReady
+
+ Purpose:
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ device is accessible.
+
+ EFI_DEVICE_ERROR
+ device is not accessible.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
+ return Status;
+}
+
+EFI_STATUS
+AtapiRequestSense (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCounts
+ )
+/*++
+ Name:
+ AtapiRequestSense
+
+ Purpose:
+ Sends out ATAPI Request Sense Packet Command to the specified device.
+ This command will return all the current Sense data in the device.
+ This function will pack all the Sense data in one single buffer.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINT16 OUT **SenseBuffers
+ allocated in this function, and freed by the calling function.
+ This buffer is used to accommodate all the sense data returned
+ by the device.
+
+ UINTN OUT *BufUnit
+ record the unit size of the sense data block in the SenseBuffers,
+
+ UINTN OUT *BufNumbers
+ record the number of units in the SenseBuffers.
+
+ Returns:
+ EFI_SUCCESS
+ Request Sense command completes successfully.
+
+ EFI_DEVICE_ERROR
+ Request Sense command failed.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: SenseCounts - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ REQUEST_SENSE_DATA *Sense;
+ UINT16 *Ptr;
+ BOOLEAN FetchSenseData;
+ ATAPI_PACKET_COMMAND Packet;
+
+ *SenseCounts = 0;
+
+ ZeroMem (IdeDev->SenseData, sizeof (REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));
+ //
+ // fill command packet for Request Sense Packet Command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.RequestSence.opcode = REQUEST_SENSE;
+ Packet.RequestSence.allocation_length = sizeof (REQUEST_SENSE_DATA);
+
+ //
+ // initialize pointer
+ //
+ Ptr = (UINT16 *) IdeDev->SenseData;
+ //
+ // request sense data from device continuously until no sense data
+ // exists in the device.
+ //
+ for (FetchSenseData = TRUE; FetchSenseData;) {
+
+ Sense = (REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense data form device
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ Ptr,
+ sizeof (REQUEST_SENSE_DATA),
+ ATAPITIMEOUT
+ );
+ //
+ // failed to get Sense data
+ //
+ if (EFI_ERROR (Status)) {
+ if (*SenseCounts == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ (*SenseCounts)++;
+ //
+ // We limit MAX sense data count to 20 in order to avoid dead loop. Some
+ // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.
+ // In this case, dead loop occurs if we don't have a gatekeeper. 20 is
+ // supposed to be large enough for any ATAPI device.
+ //
+ if ((Sense->sense_key != SK_NO_SENSE) && ((*SenseCounts) < 20)) {
+ //
+ // Ptr is word-based pointer
+ //
+ Ptr += sizeof (REQUEST_SENSE_DATA) / 2;
+
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ FetchSenseData = FALSE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtapiReadCapacity (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtapiReadCapacity
+
+ Purpose:
+ Sends out ATAPI Read Capacity Packet Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ Current device status will impact device's response to the Read Capacity
+ Command. For example, if the device once reset, the Read Capacity
+ Command will fail. The Sense data record the current device status, so
+ if the Read Capacity Command failed, the Sense data must be requested
+ and be analyzed to determine if the Read Capacity Command should retry.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ Read Capacity Command finally completes successfully.
+
+ EFI_DEVICE_ERROR
+ Read Capacity Command failed because of device error.
+
+ Notes:
+ parameter "IdeDev" will be updated in this function.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: EFI_NOT_READY - add return value to function comment
+{
+ //
+ // status returned by Read Capacity Packet Command
+ //
+ EFI_STATUS Status;
+ ATAPI_PACKET_COMMAND Packet;
+
+ //
+ // used for capacity data returned from ATAPI device
+ //
+ READ_CAPACITY_DATA Data;
+ READ_FORMAT_CAPACITY_DATA FormatData;
+
+ ZeroMem (&Data, sizeof (Data));
+ ZeroMem (&FormatData, sizeof (FormatData));
+
+ if (IdeDev->Type == IdeCdRom) {
+
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = READ_CAPACITY;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &Data,
+ sizeof (READ_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+
+ } else {
+ //
+ // Type == IdeMagnetic
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.ReadFormatCapacity.opcode = READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &FormatData,
+ sizeof (READ_FORMAT_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+
+ if (IdeDev->Type == IdeCdRom) {
+
+ IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |
+ (Data.LastLba2 << 16) |
+ (Data.LastLba1 << 8) |
+ Data.LastLba0;
+
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {
+
+ IdeDev->BlkIo.Media->BlockSize = (Data.BlockSize3 << 24) |
+ (Data.BlockSize2 << 16) |
+ (Data.BlockSize1 << 8) |
+ Data.BlockSize0;
+
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ } else {
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+
+ //
+ // Because the user data portion in the sector of the Data CD supported
+ // is always 0x800
+ //
+ IdeDev->BlkIo.Media->BlockSize = 0x800;
+ }
+
+ if (IdeDev->Type == IdeMagnetic) {
+
+ if (FormatData.DesCode == 3) {
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ } else {
+
+ IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |
+ (FormatData.LastLba2 << 16) |
+ (FormatData.LastLba1 << 8) |
+ FormatData.LastLba0;
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {
+ IdeDev->BlkIo.Media->LastBlock--;
+
+ IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
+ (FormatData.BlockSize1 << 8) |
+ FormatData.BlockSize0;
+
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ } else {
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ //
+ // Return EFI_NOT_READY operation succeeds but returned capacity is 0
+ //
+ return EFI_NOT_READY;
+ }
+
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ } else {
+
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+EFI_STATUS
+AtapiDetectMedia (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *MediaChange
+ )
+/*++
+ Name:
+ AtapiDetectMedia
+
+ Purpose:
+ Used before read/write blocks from/to ATAPI device media.
+ Since ATAPI device media is removable, it is necessary to detect
+ whether media is present and get current present media's
+ information, and if media has been changed, Block I/O Protocol
+ need to be reinstalled.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ BOOLEAN OUT *MediaChange
+ return value that indicates if the media of the device has been
+ changed.
+
+ Returns:
+ EFI_SUCCESS
+ media found successfully.
+
+ EFI_DEVICE_ERROR
+ any error encounters during media detection.
+
+ EFI_NO_MEDIA
+ media not found.
+
+ Notes:
+ parameter IdeDev may be updated in this function.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: MediaChange - add argument and description to function comment
+{
+ EFI_STATUS Status;
+ EFI_STATUS ReadCapacityStatus;
+ EFI_BLOCK_IO_MEDIA OldMediaInfo;
+ UINTN SenseCounts;
+ UINTN RetryIndex;
+ UINTN RetryTimes;
+ UINTN MaximumRetryTimes;
+ UINTN ReadyWaitFactor;
+ BOOLEAN NeedRetry;
+ //
+ // a flag used to determine whether need to perform Read Capacity command.
+ //
+ BOOLEAN NeedReadCapacity;
+ BOOLEAN WriteProtected;
+
+ //
+ // init
+ //
+ CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (OldMediaInfo));
+ // OldMediaInfo = *(IdeDev->BlkIo.Media);
+ *MediaChange = FALSE;
+ ReadCapacityStatus = EFI_DEVICE_ERROR;
+
+ //
+ // if there is no media, or media is not changed,
+ // the request sense command will detect faster than read capacity command.
+ // read capacity command can be bypassed, thus improve performance.
+ //
+
+ //
+ // Test Unit Ready command is used to detect whether device is accessible,
+ // the device will produce corresponding Sense data.
+ //
+ for (RetryIndex = 0; RetryIndex < 2; RetryIndex++) {
+
+ Status = AtapiTestUnitReady (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ //
+ // skip the loop if test unit command succeeds.
+ //
+ break;
+ }
+
+ Status = AtapiSoftReset (IdeDev);
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeDev);
+ }
+ }
+
+ SenseCounts = 0;
+ NeedReadCapacity = TRUE;
+
+ //
+ // at most retry 5 times
+ //
+ MaximumRetryTimes = 5;
+ RetryTimes = 1;
+
+ for (RetryIndex = 0;
+ (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
+ RetryIndex++) {
+
+ Status = AtapiRequestSense (IdeDev, &SenseCounts);
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // if first time there is no Sense Key, no need to read capacity any more
+ //
+ if (!HaveSenseKey (IdeDev->SenseData, SenseCounts) &&
+ (IdeDev->BlkIo.Media->MediaPresent)) {
+
+ if (RetryIndex == 0) {
+ NeedReadCapacity = FALSE;
+ }
+
+ } else {
+ //
+ // No Media
+ //
+ if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
+ NeedReadCapacity = FALSE;
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ } else {
+ //
+ // Media Changed
+ //
+ if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
+ NeedReadCapacity = TRUE;
+ IdeDev->BlkIo.Media->MediaId++;
+ }
+ //
+ // Media Error
+ //
+ if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+ } else {
+ //
+ // retry once more, if request sense command met errors.
+ //
+ RetryTimes++;
+ }
+ }
+
+ if (NeedReadCapacity) {
+ //
+ // at most retry 5 times
+ //
+ MaximumRetryTimes = 5;
+ //
+ // initial retry twice
+ //
+ RetryTimes = 2;
+ ReadyWaitFactor = 2;
+
+ for (RetryIndex = 0;
+ (RetryIndex < RetryTimes) && (RetryIndex < MaximumRetryTimes);
+ RetryIndex++) {
+
+ ReadCapacityStatus = AtapiReadCapacity (IdeDev);
+
+ SenseCounts = 0;
+
+ if (!EFI_ERROR (ReadCapacityStatus)) {
+ //
+ // Read Capacity succeeded
+ //
+ break;
+
+ } else {
+
+ if (ReadCapacityStatus == EFI_NOT_READY) {
+ //
+ // If device not ready, wait here... waiting time increases by retry
+ // times.
+ //
+ gBS->Stall (ReadyWaitFactor * 2000 * STALL_1_MILLI_SECOND);
+ ReadyWaitFactor++;
+ //
+ // retry once more
+ //
+ RetryTimes++;
+ continue;
+ }
+
+ //
+ // Other errors returned, requery sense data
+ //
+ Status = AtapiRequestSense (IdeDev, &SenseCounts);
+
+ //
+ // If Request Sense data failed, reset the device and retry.
+ //
+ if (EFI_ERROR (Status)) {
+
+ Status = AtapiSoftReset (IdeDev);
+
+ //
+ // if ATAPI soft reset fail,
+ // use stronger reset mechanism -- ATA soft reset.
+ //
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeDev);
+ }
+ //
+ // retry once more
+ //
+ RetryTimes++;
+ continue;
+ }
+
+ //
+ // No Media
+ //
+ if (IsNoMedia (IdeDev->SenseData, SenseCounts)) {
+
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ return EFI_NO_MEDIA;
+ }
+
+ if (IsMediaError (IdeDev->SenseData, SenseCounts)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Media Changed
+ //
+ if (IsMediaChange (IdeDev->SenseData, SenseCounts)) {
+ IdeDev->BlkIo.Media->MediaId++;
+ }
+
+ if (!IsDriveReady (IdeDev->SenseData, SenseCounts, &NeedRetry)) {
+
+ //
+ // Drive not ready: if NeedRetry, then retry once more;
+ // else return error
+ //
+ if (NeedRetry) {
+ //
+ // Stall 1 second to wait for drive becoming ready
+ //
+ gBS->Stall (1000 * STALL_1_MILLI_SECOND);
+ //
+ // reset retry variable to zero,
+ // to make it retry for "drive in progress of becoming ready".
+ //
+ RetryIndex = 0;
+ continue;
+ } else {
+ AtapiSoftReset (IdeDev);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // if read capacity fail not for above reasons, retry once more
+ //
+ RetryTimes++;
+ }
+
+ }
+
+ //
+ // tell whether the readcapacity process is successful or not in the end
+ //
+ if (EFI_ERROR (ReadCapacityStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // the following code is to check the write-protected for LS120 media
+ //
+ if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {
+
+ Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);
+ if (!EFI_ERROR (Status)) {
+
+ if (WriteProtected) {
+
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+ } else {
+
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ }
+
+ }
+ }
+
+ if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {
+ //
+ // Media change information got from the device
+ //
+ *MediaChange = TRUE;
+ }
+
+ if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ //
+ // when change from no media to media present, reset the MediaId to 1.
+ //
+ IdeDev->BlkIo.Media->MediaId = 1;
+ } else {
+ //
+ // when no media, reset the MediaId to zero.
+ //
+ IdeDev->BlkIo.Media->MediaId = 0;
+ }
+
+ *MediaChange = TRUE;
+ }
+
+ //
+ // if any change on current existing media,
+ // the Block I/O protocol need to be reinstalled.
+ //
+ if (*MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ IdeDev->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &IdeDev->BlkIo,
+ &IdeDev->BlkIo
+ );
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+AtapiReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+ AtapiReadSectors
+
+ Purpose:
+ This function is called by the AtapiBlkIoReadBlocks() to perform
+ read from media in block unit.
+
+ The main command used to access media here is READ(10) Command.
+ READ(10) Command requests that the ATAPI device media transfer
+ specified data to the host. Data is transferred in block(sector)
+ unit. The maximum number of blocks that can be transferred once is
+ 65536. This is the main difference between READ(10) and READ(12)
+ Command. The maximum number of blocks in READ(12) is 2 power 32.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ A pointer to the destination buffer for the data.
+
+ EFI_LBA IN Lba
+ The starting logical block address to read from
+ on the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+ return status is fully dependent on the return status
+ of AtapiPacketCommandIn() function.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: Lba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ READ10_CMD *Read10Packet;
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT16 SectorCount;
+ VOID *PtrBuffer;
+ UINT16 MaxBlock;
+ UINTN TimeOut;
+
+ //
+ // fill command packet for Read(10) command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+ Lba32 = (UINT32) Lba;
+ PtrBuffer = Buffer;
+
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) Command
+ //
+ MaxBlock = (UINT16) (65536 / BlockSize);
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+
+ SectorCount = (UINT16) 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;
+
+ if (IdeDev->Type == IdeCdRom) {
+ TimeOut = CDROMLONGTIMEOUT;
+ } else {
+ TimeOut = ATAPILONGTIMEOUT;
+ }
+
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) PtrBuffer,
+ ByteCount,
+ TimeOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtapiWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+ Name:
+ AtapiWriteSectors
+
+ Purpose:
+ This function is called by the AtapiBlkIoWriteBlocks() to perform
+ write onto media in block unit.
+ The main command used to access media here is Write(10) Command.
+ Write(10) Command requests that the ATAPI device media transfer
+ specified data to the host. Data is transferred in block (sector)
+ unit. The maximum number of blocks that can be transferred once is
+ 65536.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ VOID IN *Buffer
+ A pointer to the source buffer for the data.
+
+ EFI_LBA IN Lba
+ The starting logical block address to write onto
+ the device media.
+
+ UINTN IN NumberOfBlocks
+ The number of transfer data blocks.
+
+ Returns:
+ return status is fully dependent on the return status
+ of AtapiPacketCommandOut() function.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: Lba - add argument and description to function comment
+// TODO: NumberOfBlocks - add argument and description to function comment
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ READ10_CMD *Read10Packet;
+
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT16 SectorCount;
+ VOID *PtrBuffer;
+ UINT16 MaxBlock;
+
+ //
+ // fill command packet for Write(10) command
+ // Write(10) command packet has the same data structure as
+ // Read(10) command packet,
+ // so here use the Read10Packet data structure
+ // for the Write(10) command packet.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+
+ Lba32 = (UINT32) Lba;
+ PtrBuffer = Buffer;
+
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) Command
+ //
+ MaxBlock = (UINT16) (65536 / BlockSize);
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= MaxBlock) {
+ SectorCount = MaxBlock;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // Command code is WRITE_10.
+ //
+ Read10Packet->opcode = WRITE_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;
+
+ Status = AtapiPacketCommandOut (
+ IdeDev,
+ &Packet,
+ (UINT16 *) PtrBuffer,
+ ByteCount,
+ ATAPILONGTIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Name:
+ AtapiSoftReset
+
+ Purpose:
+ This function is used to implement the Soft Reset on the specified
+ ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
+ Soft Reset Command special for ATAPI device, and it only take effects
+ on the specified ATAPI device, not on the whole IDE bus.
+ Since the ATAPI soft reset is needed when device is in exceptional
+ condition (such as BSY bit is always set ), I think the Soft Reset
+ command should be sent without waiting for the BSY clear and DRDY
+ set.
+ This function is called by IdeBlkIoReset(),
+ a interface function of Block I/O protocol.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ Returns:
+ EFI_SUCCESS
+ Soft reset completes successfully.
+
+ EFI_DEVICE_ERROR
+ Any step during the reset process is failed.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+{
+ UINT8 Command;
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // for ATAPI device, no need to wait DRDY ready after device selecting.
+ // (bit7 and bit5 are both set to 1 for backward compatibility)
+ //
+ DeviceSelect = (UINT8) (((bit7 | bit5) | (IdeDev->Device << 4)));
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ Command = ATAPI_SOFT_RESET_CMD;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);
+
+ //
+ // BSY cleared is the only status return to the host by the device
+ // when reset is completed.
+ // slave device needs at most 31s to clear BSY
+ //
+ Status = WaitForBSYClear (IdeDev, 31000);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // stall 5 seconds to make the device status stable
+ //
+ gBS->Stall (5000000);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+ Name:
+ AtapiBlkIoReadBlocks
+
+ Purpose:
+ This function is the ATAPI implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeBlkIoDev
+ Indicates the calling context.
+
+ UINT32 IN MediaId
+ The media id that the read request is for.
+
+ EFI_LBA IN LBA
+ The starting logical block address to read from
+ on the device.
+
+ UINTN IN BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ VOID OUT *Buffer
+ A pointer to the destination buffer for the data.
+ The caller is responsible for either having implicit
+ or explicit ownership of the memory that data is read into.
+
+ Returns:
+ EFI_SUCCESS
+ Read Blocks successfully.
+
+ EFI_DEVICE_ERROR
+ Read Blocks failed.
+
+ EFI_NO_MEDIA
+ There is no media in the device.
+
+ EFI_MEDIA_CHANGED
+ The MediaId is not for the current media.
+
+ EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ EFI_INVALID_PARAMETER
+ The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeBlkIoDevice - add argument and description to function comment
+// TODO: MediaId - add argument and description to function comment
+// TODO: LBA - add argument and description to function comment
+// TODO: BufferSize - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ BOOLEAN MediaChange;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ATAPI device media is removable, so it is a must
+ // to detect media first before read operation
+ //
+ MediaChange = FALSE;
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+ if (EFI_ERROR (Status)) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ return Status;
+ }
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_NO_MEDIA;
+
+ }
+
+ if ((MediaId != Media->MediaId) || MediaChange) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (LBA > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if all the parameters are valid, then perform read sectors command
+ // to transfer data from device to host.
+ //
+ Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Read blocks succeeded
+ //
+
+ //
+ // save the first block to the cache for performance
+ //
+ if (LBA == 0 && !IdeBlkIoDevice->Cache) {
+ IdeBlkIoDevice->Cache = AllocatePool (BlockSize);
+ if (IdeBlkIoDevice != NULL) {
+ CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+ Name:
+ AtapiBlkIoWriteBlocks
+
+ Purpose:
+ This function is the ATAPI implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ Parameters:
+ EFI_BLOCK_IO IN *This
+ Indicates the calling context.
+
+ UINT32 IN MediaId
+ The media id that the write request is for.
+
+ EFI_LBA IN LBA
+ The starting logical block address to write onto
+ the device.
+
+ UINTN IN BufferSize
+ The size of the Buffer in bytes. This must be a
+ multiple of the intrinsic block size of the device.
+
+ VOID OUT *Buffer
+ A pointer to the source buffer for the data.
+ The caller is responsible for either having implicit
+ or explicit ownership of the memory that data is
+ written from.
+
+ Returns:
+ EFI_SUCCESS
+ Write Blocks successfully.
+
+ EFI_DEVICE_ERROR
+ Write Blocks failed.
+
+ EFI_NO_MEDIA
+ There is no media in the device.
+
+ EFI_MEDIA_CHANGE
+ The MediaId is not for the current media.
+
+ EFI_BAD_BUFFER_SIZE
+ The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+
+ EFI_INVALID_PARAMETER
+ The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeBlkIoDevice - add argument and description to function comment
+// TODO: MediaId - add argument and description to function comment
+// TODO: LBA - add argument and description to function comment
+// TODO: BufferSize - add argument and description to function comment
+// TODO: Buffer - add argument and description to function comment
+// TODO: EFI_MEDIA_CHANGED - add return value to function comment
+// TODO: EFI_WRITE_PROTECTED - add return value to function comment
+{
+
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+ BOOLEAN MediaChange;
+
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ATAPI device media is removable,
+ // so it is a must to detect media first before write operation
+ //
+ MediaChange = FALSE;
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+ if (EFI_ERROR (Status)) {
+
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return Status;
+ }
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_NO_MEDIA;
+ }
+
+ if ((MediaId != Media->MediaId) || MediaChange) {
+
+ if (LBA == 0 && IdeBlkIoDevice->Cache) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (LBA > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((LBA + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if all the parameters are valid,
+ // then perform write sectors command to transfer data from host to device.
+ //
+ Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, LBA, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ 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
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ REQUEST_SENSE_DATA *SensePointer;
+ UINTN Index;
+ BOOLEAN NoMedia;
+
+ NoMedia = FALSE;
+ SensePointer = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // Sense Key is SK_NOT_READY (0x2),
+ // Additional Sense Code is ASC_NO_MEDIA (0x3A)
+ //
+ if ((SensePointer->sense_key == SK_NOT_READY) &&
+ (SensePointer->addnl_sense_code == ASC_NO_MEDIA)) {
+
+ NoMedia = TRUE;
+ }
+
+ SensePointer++;
+ }
+
+ return NoMedia;
+}
+
+BOOLEAN
+IsMediaError (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+ Name:
+ IsMediaError
+
+ Purpose:
+ Test if the device meets a media error after media changed
+
+ Parameters:
+ EQUEST_SENSE_DATA IN *SenseData
+ pointer pointing to ATAPI device sense data list.
+ UINTN IN SenseCounts
+ sense data number of the list
+
+ Returns:
+ TRUE
+ Device meets a media error
+
+ FALSE
+ No media error
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: SenseData - add argument and description to function comment
+// TODO: SenseCounts - add argument and description to function comment
+{
+ REQUEST_SENSE_DATA *SensePointer;
+ UINTN Index;
+ BOOLEAN IsError;
+
+ IsError = FALSE;
+ SensePointer = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePointer->sense_key) {
+
+ case SK_MEDIUM_ERROR:
+ //
+ // Sense Key is SK_MEDIUM_ERROR (0x3)
+ //
+ switch (SensePointer->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;
+
+ case SK_NOT_READY:
+ //
+ // Sense Key is SK_NOT_READY (0x2)
+ //
+ switch (SensePointer->addnl_sense_code) {
+ //
+ // Additional Sense Code is ASC_MEDIA_UPSIDE_DOWN (0x6)
+ //
+ case ASC_MEDIA_UPSIDE_DOWN:
+ IsError = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePointer++;
+ }
+
+ return IsError;
+}
+
+BOOLEAN
+IsMediaChange (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ REQUEST_SENSE_DATA *SensePointer;
+ UINTN Index;
+ BOOLEAN IsMediaChange;
+
+ IsMediaChange = FALSE;
+ SensePointer = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+ //
+ // Sense Key is SK_UNIT_ATTENTION (0x6)
+ //
+ if ((SensePointer->sense_key == SK_UNIT_ATTENTION) &&
+ (SensePointer->addnl_sense_code == ASC_MEDIA_CHANGE)) {
+
+ IsMediaChange = TRUE;
+ }
+
+ SensePointer++;
+ }
+
+ return IsMediaChange;
+}
+
+BOOLEAN
+IsDriveReady (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *NeedRetry
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+ NeedRetry - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ REQUEST_SENSE_DATA *SensePointer;
+ UINTN Index;
+ BOOLEAN IsReady;
+
+ IsReady = TRUE;
+ *NeedRetry = FALSE;
+ SensePointer = SenseData;
+
+ for (Index = 0; Index < SenseCounts; Index++) {
+
+ switch (SensePointer->sense_key) {
+
+ case SK_NOT_READY:
+ //
+ // Sense Key is SK_NOT_READY (0x2)
+ //
+ switch (SensePointer->addnl_sense_code) {
+ case ASC_NOT_READY:
+ //
+ // Additional Sense Code is ASC_NOT_READY (0x4)
+ //
+ switch (SensePointer->addnl_sense_code_qualifier) {
+ case ASCQ_IN_PROGRESS:
+ //
+ // Additional Sense Code Qualifier is ASCQ_IN_PROGRESS (0x1)
+ //
+ IsReady = FALSE;
+ *NeedRetry = TRUE;
+ break;
+
+ default:
+ IsReady = FALSE;
+ *NeedRetry = FALSE;
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SensePointer++;
+ }
+
+ return IsReady;
+}
+
+BOOLEAN
+HaveSenseKey (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ BOOLEAN Have;
+
+ Have = TRUE;
+
+ //
+ // if first sense key in the Sense Data Array is SK_NO_SENSE,
+ // it indicates there is no more sense key in the Sense Data Array.
+ //
+ if (SenseData->sense_key == SK_NO_SENSE) {
+ Have = FALSE;
+ }
+
+ return Have;
+}
+
+EFI_STATUS
+IsLS120orZipWriteProtected (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *WriteProtected
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ WriteProtected - TODO: add argument description
+
+Returns:
+
+ EFI_DEVICE_ERROR - TODO: Add description for return value
+ EFI_DEVICE_ERROR - TODO: Add description for return value
+ EFI_SUCCESS - TODO: Add description for return value
+
+--*/
+{
+ EFI_STATUS Status;
+
+ *WriteProtected = FALSE;
+
+ Status = LS120EnableMediaStatus (IdeDev, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // the Get Media Status Command is only valid
+ // if a Set Features/Enable Media Status Command has been priviously issued.
+ //
+ if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {
+
+ *WriteProtected = TRUE;
+ } else {
+
+ *WriteProtected = FALSE;
+ }
+
+ //
+ // After Get Media Status Command completes,
+ // Set Features/Disable Media Command should be sent.
+ //
+ Status = LS120EnableMediaStatus (IdeDev, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml
new file mode 100644
index 0000000000..3a33a2b3a9
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/build.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- 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.-->
+<project basedir="." default="IdeBus"><!--Apply external ANT tasks-->
+ <taskdef resource="GenBuild.tasks"/>
+ <taskdef resource="net/sf/antcontrib/antlib.xml"/>
+ <property environment="env"/>
+ <property name="WORKSPACE_DIR" value="${env.WORKSPACE}"/>
+ <import file="${WORKSPACE_DIR}\Tools\Conf\BuildMacro.xml"/><!--MODULE_RELATIVE PATH is relative to PACKAGE_DIR-->
+ <property name="MODULE_RELATIVE_PATH" value="Bus\Pci\IdeBus\Dxe"/>
+ <property name="MODULE_DIR" value="${PACKAGE_DIR}\${MODULE_RELATIVE_PATH}"/>
+ <property name="COMMON_FILE" value="${WORKSPACE_DIR}\Tools\Conf\Common.xml"/>
+ <target name="IdeBusLite">
+ <GenBuild baseName="IdeBusLite" mbdFilename="${MODULE_DIR}\idebusLite.mbd" msaFilename="${MODULE_DIR}\idebusLite.msa"/>
+ </target>
+ <target name="IdeBus">
+ <GenBuild baseName="IdeBus" mbdFilename="${MODULE_DIR}\idebus.mbd" msaFilename="${MODULE_DIR}\idebus.msa"/>
+ </target>
+ <target depends="IdeBus_clean" name="clean"/>
+ <target depends="IdeBus_cleanall" name="cleanall"/>
+ <target name="IdeBusLite_clean">
+ <OutputDirSetup baseName="IdeBusLite" mbdFilename="${MODULE_DIR}\idebusLite.mbd" msaFilename="${MODULE_DIR}\idebusLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\IdeBusLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\IdeBusLite_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="IdeBus_clean">
+ <OutputDirSetup baseName="IdeBus" mbdFilename="${MODULE_DIR}\idebus.mbd" msaFilename="${MODULE_DIR}\idebus.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\IdeBus_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\IdeBus_build.xml" target="clean"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}" excludes="*.xml"/>
+ </target>
+ <target name="IdeBusLite_cleanall">
+ <OutputDirSetup baseName="IdeBusLite" mbdFilename="${MODULE_DIR}\idebusLite.mbd" msaFilename="${MODULE_DIR}\idebusLite.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\IdeBusLite_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\IdeBusLite_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**IdeBusLite*"/>
+ </delete>
+ </target>
+ <target name="IdeBus_cleanall">
+ <OutputDirSetup baseName="IdeBus" mbdFilename="${MODULE_DIR}\idebus.mbd" msaFilename="${MODULE_DIR}\idebus.msa"/>
+ <if>
+ <available file="${DEST_DIR_OUTPUT}\IdeBus_build.xml"/>
+ <then>
+ <ant antfile="${DEST_DIR_OUTPUT}\IdeBus_build.xml" target="cleanall"/>
+ </then>
+ </if>
+ <delete dir="${DEST_DIR_OUTPUT}"/>
+ <delete dir="${DEST_DIR_DEBUG}"/>
+ <delete>
+ <fileset dir="${BIN_DIR}" includes="**IdeBus*"/>
+ </delete>
+ </target>
+</project> \ No newline at end of file
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c
new file mode 100644
index 0000000000..d318fd23df
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.c
@@ -0,0 +1,1964 @@
+/*++
+
+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:
+
+ ide.c
+
+Abstract:
+
+
+Revision History
+--*/
+
+#include "idebus.h"
+
+BOOLEAN SlaveDeviceExist = FALSE;
+BOOLEAN MasterDeviceExist = FALSE;
+
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ UINT8 Data;
+
+ Data = 0;
+ //
+ // perform 1-byte data read from register
+ //
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+ Reads multiple words of data from the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+
+Arguments:
+ PciIo - Pointer to the EFI_PCI_IO instance
+ Port - IO port to read
+ Count - No. of UINT16's to read
+ Buffer - Pointer to the data buffer for read
+
+++*/
+// TODO: function comment should end with '--*/'
+// TODO: function comment is missing 'Returns:'
+{
+ UINT16 *AlignedBuffer;
+ UINT16 *WorkingBuffer;
+ UINTN Size;
+
+ //
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+ // not perform actual I/O operations if buffer pointer passed in is not at
+ // natural boundary. The "Buffer" argument is passed in by user and may not
+ // at 16-bit natural boundary.
+ //
+ Size = sizeof (UINT16) * Count;
+
+ gBS->AllocatePool (
+ EfiBootServicesData,
+ Size + 1,
+ (VOID**)&WorkingBuffer
+ );
+
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+ //
+ // Perform UINT16 data read from FIFO
+ //
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16*)AlignedBuffer
+ );
+
+ //
+ // Copy data to user buffer
+ //
+ CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);
+ gBS->FreePool (WorkingBuffer);
+}
+
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // perform 1-byte data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+
+}
+
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // perform 1-word data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+}
+
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+ Write multiple words of data to the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+
+Arguments:
+ PciIo - Pointer to the EFI_PCI_IO instance
+ Port - IO port to read
+ Count - No. of UINT16's to read
+ Buffer - Pointer to the data buffer for read
+
+++*/
+// TODO: function comment should end with '--*/'
+// TODO: function comment is missing 'Returns:'
+{
+ UINT16 *AlignedBuffer;
+ UINT32 *WorkingBuffer;
+ UINTN Size;
+
+ //
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+ // not perform actual I/O operations if buffer pointer passed in is not at
+ // natural boundary. The "Buffer" argument is passed in by user and may not
+ // at 16-bit natural boundary.
+ //
+ Size = sizeof (UINT16) * Count;
+
+ gBS->AllocatePool (
+ EfiBootServicesData,
+ Size + 1,
+ (VOID **) &WorkingBuffer
+ );
+
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+ //
+ // Copy data from user buffer to working buffer
+ //
+ CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);
+
+ //
+ // perform UINT16 data write to the FIFO
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16 *) AlignedBuffer
+ );
+
+ gBS->FreePool (WorkingBuffer);
+}
+
+BOOLEAN
+BadIdeDeviceCheck (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+{
+ //
+ // check whether all registers return 0xff,
+ // if so, deem the channel is disabled.
+ //
+#ifdef EFI_DEBUG
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Data) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Head) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command) != 0xff) {
+ return FALSE;
+ }
+
+ if (IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus) != 0xff) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+#else
+
+ return FALSE;
+
+#endif
+}
+
+//
+// GetIdeRegistersBaseAddr
+//
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ )
+/*++
+
+Routine Description:
+ Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
+ use fixed addresses. In Native-PCI mode, get base addresses from BARs in
+ the PCI IDE controller's Configuration Space.
+
+ The steps to get IDE IO port registers' base addresses for each channel
+ as follows:
+
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+ controller's Configuration Space to determine the operating mode.
+
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+ ___________________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|___________________|___________________|
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|
+ |___________|___________________|___________________|
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+ |___________|___________________|___________________|
+
+ Table 2. BARs for Register Mapping
+ Note: Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
+ primary, 0374h for secondary. So 2 bytes extra offset should be
+ added to the base addresses read from BARs.
+
+ For more details, please refer to PCI IDE Controller Specification and Intel
+ ICH4 Datasheet.
+
+Arguments:
+ PciIo - Pointer to the EFI_PCI_IO_PROTOCOL instance
+ IdeRegsBaseAddr - Pointer to IDE_REGISTERS_BASE_ADDR to
+ receive IDE IO port registers' base addresses
+
+Returns:
+
+--*/
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
+ (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[0] & bit0) == 0 ||
+ (PciData.Device.Bar[1] & bit0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
+ (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
+ (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ }
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[2] & bit0) == 0 ||
+ (PciData.Device.Bar[3] & bit0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
+ (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
+ (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+ This function is used to requery IDE resources. The IDE controller will
+ probably switch between native and legacy modes during the EFI->CSM->OS
+ transfer. We do this everytime before an BlkIo operation to ensure its
+ succeess.
+
+Arguments:
+ IdeDev - The BLK_IO private data which specifies the IDE device
+
+++*/
+// TODO: function comment should end with '--*/'
+// TODO: function comment is missing 'Returns:'
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+
+ //
+ // Requery IDE IO port registers' base addresses in case of the switch of
+ // native and legacy modes
+ //
+ Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;
+
+ IdeDev->IoPort->Data = CommandBlockBaseAddr;
+ (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+
+ (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
+ (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;
+ IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
+ IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);
+
+ IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+CheckPowerMode (
+ IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Routine Description:
+
+ Read SATA registers to detect SATA disks
+
+ Arguments:
+
+ IdeDev - The BLK_IO private data which specifies the IDE device
+
+++*/
+// TODO: function comment should end with '--*/'
+// TODO: function comment is missing 'Returns:'
+// TODO: EFI_NOT_FOUND - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+// TODO: EFI_NOT_FOUND - add return value to function comment
+{
+ UINT8 ErrorRegister;
+ EFI_STATUS Status;
+
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // Wait 31 seconds for BSY clear. BSY should be in clear state if there exists
+ // a device (initial state). Normally, BSY is also in clear state if there is
+ // no device
+ //
+ Status = WaitForBSYClear (IdeDev, 31000);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // select device, read error register
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+ Status = DRDYReady (IdeDev, 200);
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister == 0x01) || (ErrorRegister == 0x81)) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+//
+// DiscoverIdeDevice
+//
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+ Routine Description:
+
+ Detect if there is disk connected to this port
+
+ Arguments:
+
+ IdeDev - The BLK_IO private data which specifies the IDE device
+
+++*/
+// TODO: function comment should end with '--*/'
+// TODO: function comment is missing 'Returns:'
+// TODO: EFI_NOT_FOUND - add return value to function comment
+// TODO: EFI_NOT_FOUND - add return value to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+ BOOLEAN SataFlag;
+
+ SataFlag = FALSE;
+ //
+ // This extra detection is for SATA disks
+ //
+ Status = CheckPowerMode (IdeDev);
+ if (Status == EFI_SUCCESS) {
+ SataFlag = TRUE;
+ }
+
+ //
+ // If a channel has not been checked, check it now. Then set it to "checked" state
+ // After this step, all devices in this channel have been checked.
+ //
+ Status = DetectIDEController (IdeDev);
+
+ if ((EFI_ERROR (Status)) && !SataFlag) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Device exists. test if it is an ATA device
+ //
+ Status = ATAIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ //
+ // if not ATA device, test if it is an ATAPI device
+ //
+ Status = ATAPIIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ //
+ // if not ATAPI device either, return error.
+ //
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Init Block I/O interface
+ //
+ IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+ IdeDev->BlkIo.Reset = IDEBlkIoReset;
+ IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;
+ IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;
+ IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;
+
+ IdeDev->BlkMedia.LogicalPartition = FALSE;
+ IdeDev->BlkMedia.WriteCaching = FALSE;
+
+ //
+ // Init Disk Info interface
+ //
+ gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));
+ IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;
+ IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;
+ IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;
+ IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DetectIDEController (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+ Name: DetectIDEController
+
+
+ Purpose:
+ This function is called by DiscoverIdeDevice(). It is used for detect
+ whether the IDE device exists in the specified Channel as the specified
+ Device Number.
+
+ There is two IDE channels: one is Primary Channel, the other is
+ Secondary Channel.(Channel is the logical name for the physical "Cable".)
+ Different channel has different register group.
+
+ On each IDE channel, at most two IDE devices attach,
+ one is called Device 0 (Master device), the other is called Device 1
+ (Slave device). The devices on the same channel co-use the same register
+ group, so before sending out a command for a specified device via command
+ register, it is a must to select the current device to accept the command
+ by set the device number in the Head/Device Register.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+
+ Returns:
+ TRUE
+ successfully detects device.
+
+ FALSE
+ any failure during detection process will return this
+ value.
+
+
+ Notes:
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+// TODO: EFI_NOT_FOUND - add return value to function comment
+{
+ EFI_STATUS Status;
+ UINT8 ErrorReg;
+ UINT8 StatusReg;
+ UINT8 InitStatusReg;
+ EFI_STATUS DeviceStatus;
+
+ //
+ // Slave device has been detected with master device.
+ //
+ if ((IdeDev->Device) == 1) {
+ if (SlaveDeviceExist) {
+ //
+ // If master not exists but slave exists, slave have to wait a while
+ //
+ if (!MasterDeviceExist) {
+ //
+ // if single slave can't be detected, add delay 4s here.
+ //
+ gBS->Stall (4000000);
+ }
+
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ //
+ // Select slave device
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((1 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+
+ //
+ // Save the init slave status register
+ //
+ InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // Select master back
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((0 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+ //
+ // Send ATA Device Execut Diagnostic command.
+ // This command should work no matter DRDY is ready or not
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
+
+ Status = WaitForBSYClear (IdeDev, 3500);
+
+ ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ //
+ // Master Error register is 0x01. D0 passed, D1 passed or not present.
+ // Master Error register is 0x81. D0 passed, D1 failed. Return.
+ // Master Error register is other value. D0 failed, D1 passed or not present..
+ //
+ if (ErrorReg == 0x01) {
+ MasterDeviceExist = TRUE;
+ DeviceStatus = EFI_SUCCESS;
+ } else if (ErrorReg == 0x81) {
+
+ MasterDeviceExist = TRUE;
+ DeviceStatus = EFI_SUCCESS;
+ SlaveDeviceExist = FALSE;
+
+ return DeviceStatus;
+ } else {
+ MasterDeviceExist = FALSE;
+ DeviceStatus = EFI_NOT_FOUND;
+ }
+
+ //
+ // Master Error register is not 0x81, Go on check Slave
+ //
+
+ //
+ // select slave
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((1 << 4) | 0xe0)
+ );
+
+ gBS->Stall (300);
+ ErrorReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ //
+ // Slave Error register is not 0x01, D1 failed. Return.
+ //
+ if (ErrorReg != 0x01) {
+ SlaveDeviceExist = FALSE;
+ return DeviceStatus;
+ }
+
+ StatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // Most ATAPI devices don't set DRDY bit, so test with a slow but accurate
+ // "ATAPI TEST UNIT READY" command
+ //
+ if (((StatusReg & DRDY) == 0) && ((InitStatusReg & DRDY) == 0)) {
+ Status = AtapiTestUnitReady (IdeDev);
+
+ //
+ // Still fail, Slave doesn't exist.
+ //
+ if (EFI_ERROR (Status)) {
+ SlaveDeviceExist = FALSE;
+ return DeviceStatus;
+ }
+ }
+
+ //
+ // Error reg is 0x01 and DRDY is ready,
+ // or ATAPI test unit ready success,
+ // or init Slave status DRDY is ready
+ // Slave exists.
+ //
+ SlaveDeviceExist = TRUE;
+
+ return DeviceStatus;
+
+}
+
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name: DRQClear
+
+
+ Purpose:
+ This function is used to poll for the DRQ bit clear in the Status
+ Register. DRQ is cleared when the device is finished transferring data.
+ So this function is called after data transfer is finished.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ clear.
+
+ Returns:
+ EFI_SUCCESS
+ DRQ bit clear within the time out.
+
+ EFI_TIMEOUT
+ DRQ bit not clear within the time out.
+
+
+ Notes:
+ Read Status Register will clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+// TODO: EFI_ABORTED - add return value to function comment
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((StatusRegister & (DRQ | BSY)) == 0) {
+ break;
+ }
+
+ if ((StatusRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name: DRQClear2
+
+
+ Purpose:
+ This function is used to poll for the DRQ bit clear in the Alternate
+ Status Register. DRQ is cleared when the device is finished
+ transferring data. So this function is called after data transfer
+ is finished.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ clear.
+
+ Returns:
+ EFI_SUCCESS
+ DRQ bit clear within the time out.
+
+ EFI_TIMEOUT
+ DRQ bit not clear within the time out.
+
+
+ Notes:
+ Read Alternate Status Register will not clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+// TODO: EFI_ABORTED - add return value to function comment
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((AltRegister & (DRQ | BSY)) == 0) {
+ break;
+ }
+
+ if ((AltRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name: DRQReady
+
+
+ Purpose:
+ This function is used to poll for the DRQ bit set in the
+ Status Register.
+ DRQ is set when the device is ready to transfer data. So this function
+ is called after the command is sent to the device and before required
+ data is transferred.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+
+ Returns:
+ EFI_SUCCESS
+ DRQ bit set within the time out.
+
+ EFI_TIMEOUT
+ DRQ bit not set within the time out.
+
+ EFI_ABORTED
+ DRQ bit not set caused by the command abort.
+
+ Notes:
+ Read Status Register will clear interrupt status.
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ //
+ // read Status Register will clear interrupt
+ //
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // BSY==0,DRQ==1
+ //
+ if ((StatusRegister & (BSY | DRQ)) == DRQ) {
+ break;
+ }
+
+ if ((StatusRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name: DRQReady2
+
+
+ Purpose:
+ This function is used to poll for the DRQ bit set in the
+ Alternate Status Register. DRQ is set when the device is ready to
+ transfer data. So this function is called after the command
+ is sent to the device and before required data is transferred.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ Returns:
+ EFI_SUCCESS
+ DRQ bit set within the time out.
+
+ EFI_TIMEOUT
+ DRQ bit not set within the time out.
+
+ EFI_ABORTED
+ DRQ bit not set caused by the command abort.
+
+ Notes:
+ Read Alternate Status Register will not clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+
+ do {
+ //
+ // Read Alternate Status Register will not clear interrupt status
+ //
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ //
+ // BSY == 0 , DRQ == 1
+ //
+ if ((AltRegister & (BSY | DRQ)) == DRQ) {
+ break;
+ }
+
+ if ((AltRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name:
+ WaitForBSYClear
+
+
+ Purpose:
+ This function is used to poll for the BSY bit clear in the
+ Status Register. BSY is clear when the device is not busy.
+ Every command must be sent after device is not busy.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ Returns:
+ EFI_SUCCESS
+ BSY bit clear within the time out.
+
+ EFI_TIMEOUT
+ BSY bit not clear within the time out.
+
+
+ Notes:
+ Read Status Register will clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & BSY) == 0x00) {
+ break;
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// WaitForBSYClear2
+//
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+ Name:
+ WaitForBSYClear2
+
+
+ Purpose:
+ This function is used to poll for the BSY bit clear in the
+ Alternate Status Register. BSY is clear when the device is not busy.
+ Every command must be sent after device is not busy.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ Returns:
+ EFI_SUCCESS
+ BSY bit clear within the time out.
+
+ EFI_TIMEOUT
+ BSY bit not clear within the time out.
+
+
+ Notes:
+ Read Alternate Status Register will not clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: TimeoutInMilliSeconds - add argument and description to function comment
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ if ((AltRegister & BSY) == 0x00) {
+ break;
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// DRDYReady
+//
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+/*++
+ Name:
+ DRDYReady
+
+
+ Purpose:
+ This function is used to poll for the DRDY bit set in the
+ Status Register. DRDY bit is set when the device is ready
+ to accept command. Most ATA commands must be sent after
+ DRDY set except the ATAPI Packet Command.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ Returns:
+ EFI_SUCCESS
+ DRDY bit set within the time out.
+
+ EFI_TIMEOUT
+ DRDY bit not set within the time out.
+
+
+ Notes:
+ Read Status Register will clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DelayInMilliSeconds - add argument and description to function comment
+// TODO: EFI_ABORTED - add return value to function comment
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ //
+ // BSY == 0 , DRDY == 1
+ //
+ if ((StatusRegister & (DRDY | BSY)) == DRDY) {
+ break;
+ }
+
+ if ((StatusRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (15);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// DRDYReady2
+//
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+/*++
+ Name:
+ DRDYReady2
+
+
+ Purpose:
+ This function is used to poll for the DRDY bit set in the
+ Alternate Status Register. DRDY bit is set when the device is ready
+ to accept command. Most ATA commands must be sent after
+ DRDY set except the ATAPI Packet Command.
+
+
+ Parameters:
+ IDE_BLK_IO_DEV IN *IdeDev
+ pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ UINTN IN TimeoutInMilliSeconds
+ used to designate the timeout for the DRQ ready.
+
+ Returns:
+ EFI_SUCCESS
+ DRDY bit set within the time out.
+
+ EFI_TIMEOUT
+ DRDY bit not set within the time out.
+
+
+ Notes:
+ Read Alternate Status Register will clear interrupt status.
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: IdeDev - add argument and description to function comment
+// TODO: DelayInMilliSeconds - add argument and description to function comment
+// TODO: EFI_ABORTED - add return value to function comment
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ //
+ // BSY == 0 , DRDY == 1
+ //
+ if ((AltRegister & (DRDY | BSY)) == DRDY) {
+ break;
+ }
+
+ if ((AltRegister & (BSY | ERR)) == ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ABRT_ERR) == ABRT_ERR) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// SwapStringChars
+//
+VOID
+SwapStringChars (
+ IN CHAR8 *Destination,
+ IN CHAR8 *Source,
+ IN UINT32 Size
+ )
+/*++
+ Name:
+ SwapStringChars
+
+
+ Purpose:
+ This function is a helper function used to change the char order in a
+ string. It is designed specially for the PrintAtaModuleName() function.
+ After the IDE device is detected, the IDE driver gets the device module
+ name by sending ATA command called ATA Identify Command or ATAPI
+ Identify Command to the specified IDE device. The module name returned
+ is a string of ASCII characters: the first character is bit8--bit15
+ of the first word, the second character is bit0--bit7 of the first word
+ and so on. Thus the string can not be print directly before it is
+ preprocessed by this func to change the order of characters in
+ each word in the string.
+
+
+ Parameters:
+ CHAR8 IN *Destination
+ Indicates the destination string.
+
+ CHAR8 IN *Source
+ Indicates the source string.
+
+ UINT8 IN Size
+ the length of the string
+
+
+ Returns:
+ none
+
+ Notes:
+
+--*/
+// TODO: function comment is missing 'Routine Description:'
+// TODO: function comment is missing 'Arguments:'
+// TODO: Destination - add argument and description to function comment
+// TODO: Source - add argument and description to function comment
+// TODO: Size - add argument and description to function comment
+{
+ UINT32 Index;
+ CHAR8 Temp;
+
+ for (Index = 0; Index < Size; Index += 2) {
+
+ Temp = Source[Index + 1];
+ Destination[Index + 1] = Source[Index];
+ Destination[Index] = Temp;
+ }
+}
+
+//
+// ReleaseIdeResources
+//
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ )
+/*++
+Routing Description:
+
+ Release resources of an IDE device before stopping it.
+
+Arguments:
+
+ IdeBlkIoDevice -- Standard IDE device private data structure
+
+
+Returns:
+
+ NONE
+
+---*/
+// TODO: function comment is missing 'Routine Description:'
+{
+ if (IdeBlkIoDevice == NULL) {
+ return ;
+ }
+
+ //
+ // Release all the resourses occupied by the IDE_BLK_IO_DEV
+ //
+
+ if (IdeBlkIoDevice->SenseData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->SenseData);
+ IdeBlkIoDevice->SenseData = NULL;
+ }
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ if (IdeBlkIoDevice->pIdData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->pIdData);
+ IdeBlkIoDevice->pIdData = NULL;
+ }
+
+ if (IdeBlkIoDevice->pInquiryData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->pInquiryData);
+ IdeBlkIoDevice->pInquiryData = NULL;
+ }
+
+ if (IdeBlkIoDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
+ IdeBlkIoDevice->ControllerNameTable = NULL;
+ }
+
+ if (IdeBlkIoDevice->IoPort != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->IoPort);
+ }
+
+ if (IdeBlkIoDevice->DevicePath != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->DevicePath);
+ }
+
+ gBS->FreePool (IdeBlkIoDevice);
+ IdeBlkIoDevice = NULL;
+
+ return ;
+}
+
+//
+// SetDeviceTransferMode
+//
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ )
+/*++
+Routing Description:
+
+ Set the calculated Best transfer mode to a detected device
+
+Arguments:
+
+ IdeDev -- Standard IDE device private data structure
+ TransferMode -- The device transfer mode to be set
+
+Returns:
+
+ Set transfer mode Command execute status
+
+---*/
+// TODO: function comment is missing 'Routine Description:'
+{
+ EFI_STATUS Status;
+ UINT8 DeviceSelect;
+ UINT8 SectorCount;
+
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+ SectorCount = *((UINT8 *) TransferMode);
+
+ //
+ // Send SET FEATURE command (sub command 0x03) to set pio mode.
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ SET_FEATURES_CMD,
+ DeviceSelect,
+ 0x03,
+ SectorCount,
+ 0,
+ 0,
+ 0
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+AtaNonDataCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT8 Feature,
+ IN UINT8 SectorCount,
+ IN UINT8 LbaLow,
+ IN UINT8 LbaMiddle,
+ IN UINT8 LbaHigh
+ )
+/*++
+
+Routine Description:
+
+ Send ATA command into device with NON_DATA protocol
+
+Arguments:
+
+ IdeDev - Standard IDE device private data structure
+ AtaCommand - The ATA command to be sent
+ Device - The value in Device register
+ Feature - The value in Feature register
+ SectorCount - The value in SectorCount register
+ LbaLow - The value in LBA_LOW register
+ LbaMiddle - The value in LBA_MIDDLE register
+ LbaHigh - The value in LBA_HIGH register
+
+Returns:
+
+ EFI_SUCCESS - Reading succeed
+ EFI_ABORTED - Command failed
+ EFI_DEVICE_ERROR - Device status error
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Wait for command completion
+ //
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ERR) == ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+AtaNonDataCommandInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ Send ATA Ext command into device with NON_DATA protocol
+
+Arguments:
+
+ IdeDev - Standard IDE device private data structure
+ AtaCommand - The ATA command to be sent
+ Device - The value in Device register
+ Feature - The value in Feature register
+ SectorCount - The value in SectorCount register
+ LbaAddress - The LBA address in 48-bit mode
+
+Returns:
+
+ EFI_SUCCESS - Reading succeed
+ EFI_ABORTED - Command failed
+ EFI_DEVICE_ERROR - Device status error
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) (Feature >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) LbaAddress;
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Wait for command completion
+ //
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ERR) == ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// SetDriveParameters
+//
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ )
+/*++
+Routine Description:
+
+ Set drive parameters for devices not support PACKETS command
+
+Arguments:
+
+ IdeDev -- Standard IDE device private data structure
+ DriveParameters -- The device parameters to be set into the disk
+
+Returns:
+
+ SetParameters Command execute status
+
+--*/
+{
+ EFI_STATUS Status;
+ UINT8 DeviceSelect;
+
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+ //
+ // Send Init drive parameters
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ NULL,
+ 0,
+ INIT_DRIVE_PARAM_CMD,
+ (UINT8) (DeviceSelect + DriveParameters->Heads),
+ DriveParameters->Sector,
+ 0,
+ 0,
+ 0
+ );
+
+ //
+ // Send Set Multiple parameters
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ NULL,
+ 0,
+ SET_MULTIPLE_MODE_CMD,
+ DeviceSelect,
+ DriveParameters->MultipleSector,
+ 0,
+ 0,
+ 0
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ EFI_SUCCESS - TODO: Add description for return value
+
+--*/
+{
+ UINT8 DeviceControl;
+
+ //
+ // Enable interrupt for DMA operation
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ return EFI_SUCCESS;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h
new file mode 100644
index 0000000000..4c43ab94cd
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/ide.h
@@ -0,0 +1,1806 @@
+/*++
+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:
+
+ ide.h
+
+Abstract:
+
+ Header file for IDE Bus Driver, containing the helper functions'
+ entire prototype.
+
+Revision History
+
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+ Add - IDEBlkIoReadBlocksExt() func definition
+ Add - IDEBlkIoWriteBlocksExt() func definition
+
+++*/
+
+// TODO: fix comment to end with --*/
+#ifndef _IDE_H
+#define _IDE_H
+
+//
+// Helper functions Prototype
+//
+EFI_STATUS
+DeRegisterIdeDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Controller - TODO: add argument description
+ Handle - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EnableIdeDevice (
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Controller - TODO: add argument description
+ PciIo - TODO: add argument description
+ ParentDevicePath - TODO: add argument description
+ RemainingDevicePath - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Count - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Port - TODO: add argument description
+ Count - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ IdeRegsBaseAddr - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DetectIDEController (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TimeoutInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DelayInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DelayInMilliSeconds - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+SwapStringChars (
+ IN CHAR8 *Destination,
+ IN CHAR8 *Source,
+ IN UINT32 Size
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Destination - TODO: add argument description
+ Source - TODO: add argument description
+ Size - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+//
+// ATA device functions' prototype
+//
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaPioDataIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Head - TODO: add argument description
+ SectorCount - TODO: add argument description
+ SectorNumber - TODO: add argument description
+ CylinderLsb - TODO: add argument description
+ CylinderMsb - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaPioDataOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Head - TODO: add argument description
+ SectorCount - TODO: add argument description
+ SectorNumber - TODO: add argument description
+ CylinderLsb - TODO: add argument description
+ CylinderMsb - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ Lba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *BufferData,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ BufferData - TODO: add argument description
+ Lba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevice - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevice - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+//
+// ATAPI device functions' prototype
+//
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiInquiry (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Packet - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ TimeOut - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiPacketCommandOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Packet - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ TimeOut - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+PioReadWriteData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN BOOLEAN Read,
+ IN UINTN TimeOut
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ Read - TODO: add argument description
+ TimeOut - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiTestUnitReady (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiRequestSense (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiReadCapacity (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiDetectMedia (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *MediaChange
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ MediaChange - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ Lba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ Lba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevice - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevice - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+IsNoMedia (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+IsMediaError (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+IsMediaChange (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+IsDriveReady (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts,
+ OUT BOOLEAN *NeedRetry
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+ NeedRetry - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+BOOLEAN
+HaveSenseKey (
+ IN REQUEST_SENSE_DATA *SenseData,
+ IN UINTN SenseCounts
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SenseData - TODO: add argument description
+ SenseCounts - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+IsLS120orZipWriteProtected (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *WriteProtected
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ WriteProtected - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeBlkIoDevice - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ TransferMode - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+ReadNativeMaxAddress (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT EFI_LBA *NativeMaxAddress
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ NativeMaxAddress - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SetMaxAddress (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN EFI_LBA MaxAddress,
+ IN BOOLEAN bVolatile
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ MaxAddress - TODO: add argument description
+ bVolatile - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaNonDataCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT8 Feature,
+ IN UINT8 SectorCount,
+ IN UINT8 LbaLow,
+ IN UINT8 LbaMiddle,
+ IN UINT8 LbaHigh
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Device - TODO: add argument description
+ Feature - TODO: add argument description
+ SectorCount - TODO: add argument description
+ LbaLow - TODO: add argument description
+ LbaMiddle - TODO: add argument description
+ LbaHigh - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaNonDataCommandInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Device - TODO: add argument description
+ Feature - TODO: add argument description
+ SectorCount - TODO: add argument description
+ LbaAddress - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaUdmaReadExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaUdmaRead (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaUdmaWriteExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaUdmaWrite (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DataBuffer - TODO: add argument description
+ StartLba - TODO: add argument description
+ NumberOfBlocks - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaCommandIssueExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Device - TODO: add argument description
+ Feature - TODO: add argument description
+ SectorCount - TODO: add argument description
+ LbaAddress - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaCommandIssue (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ Device - TODO: add argument description
+ Feature - TODO: add argument description
+ SectorCount - TODO: add argument description
+ LbaAddress - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaAtapi6Identify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+
+VOID
+AtaSMARTSupport (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaPioDataInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN OUT VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ StartLba - TODO: add argument description
+ SectorCount - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+AtaPioDataOutExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ Buffer - TODO: add argument description
+ ByteCount - TODO: add argument description
+ AtaCommand - TODO: add argument description
+ StartLba - TODO: add argument description
+ SectorCount - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+ DriveParameters - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ IdeDev - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c
new file mode 100644
index 0000000000..2b8f52aa54
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.c
@@ -0,0 +1,1400 @@
+/*++
+
+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:
+
+ idebus.c
+
+Abstract:
+
+
+Revision History
+ This module is modified from DXE\IDE module for Ide Contriller Init support
+
+--*/
+
+#include "idebus.h"
+
+#define PCI_CLASS_MASS_STORAGE 0x01
+#define PCI_SUB_CLASS_IDE 0x01
+
+
+//
+// IDE Bus Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding = {
+ IDEBusDriverBindingSupported,
+ IDEBusDriverBindingStart,
+ IDEBusDriverBindingStop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+//
+// ***********************************************************************************
+// IDEBusDriverBindingSupported
+// ***********************************************************************************
+//
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+ Register Driver Binding protocol for this driver.
+
+Arguments:
+ This -- A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ ControllerHandle -- The handle of the controller to test.
+ RemainingDevicePath -- A pointer to the remaining portion of a device path.
+
+Returns:
+ EFI_SUCCESS - Driver loaded.
+ other - Driver not loaded.
+--*/
+// TODO: Controller - add argument and description to function comment
+// TODO: EFI_UNSUPPORTED - add return value to function comment
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEV_PATH *Node;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ if (Node->DevPath.Type != MESSAGING_DEVICE_PATH ||
+ Node->DevPath.SubType != MSG_ATAPI_DP ||
+ DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Clsoe protocol, don't use device path protocol in the .Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Verify the Ide Controller Init Protocol, which installed by the
+ // IdeController module.
+ // Note 1: PciIo protocol has been opened BY_DRIVER by ide_init, so We can't
+ // open BY_DRIVER here) That's why we don't check pciio protocol
+ // Note 2: ide_init driver check ide controller's pci config space, so we dont
+ // check here any more to save code size
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If protocols were opened normally, closed it
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+//
+// ***********************************************************************************
+// IDEBusDriverBindingStart
+// ***********************************************************************************
+//
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+ Routine Description:
+ Start this driver on Controller by detecting all disks and installing
+ BlockIo protocol on them.
+
+ Arguments:
+ This - Protocol instance pointer.
+ Controller - Handle of device to bind driver to.
+ RemainingDevicePath - Not used, always produce all possible children.
+
+ Returns:
+ EFI_SUCCESS - This driver is added to ControllerHandle.
+ EFI_ALREADY_STARTED - This driver is already running on ControllerHandle.
+ other - This driver does not support this device.
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_STATUS SavedStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEV_PATH *Node;
+ UINT8 IdeChannel;
+ UINT8 BeginningIdeChannel;
+ UINT8 EndIdeChannel;
+ UINT8 IdeDevice;
+ UINT8 BeginningIdeDevice;
+ UINT8 EndIdeDevice;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice];
+ IDE_BLK_IO_DEV *IdeBlkIoDevicePtr;
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
+ ATA_TRANSFER_MODE TransferMode;
+ ATA_DRIVE_PARMS DriveParameters;
+ EFI_DEV_PATH NewNode;
+ UINT8 ConfigurationOptions;
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINTN DataSize;
+ UINT32 Attributes;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+ //
+ // Local variables declaration for IdeControllerInit support
+ //
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ BOOLEAN EnumAll;
+ BOOLEAN ChannelEnabled;
+ UINT8 ChannelCount;
+ UINT8 MaxDevices;
+ EFI_IDENTIFY_DATA IdentifyData;
+ EFI_ATA_COLLECTIVE_MODE *SupportedModes;
+
+ IdeBusDriverPrivateData = NULL;
+ SupportedModes = NULL;
+
+ //
+ // Perform IdeBus initialization
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Now open the IDE_CONTROLLER_INIT protocol. Step7.1
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ //
+ // The following OpenProtocol function with _GET_PROTOCOL attribute and
+ // will not return EFI_ALREADY_STARTED, so save it for now
+ //
+ SavedStatus = Status;
+
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status));
+ //
+ // open protocol is not SUCCESS or not ALREADY_STARTED, error exit
+ //
+ goto ErrorExit;
+ }
+
+ //
+ // Save Enumall and ChannelCount. Step7.2
+ //
+ EnumAll = IdeInit->EnumAll;
+ ChannelCount = IdeInit->ChannelCount;
+
+ //
+ // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL
+ // attribute will not return EFI_ALREADY_STARTED
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status));
+ goto ErrorExit;
+ }
+
+ //
+ // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable
+ //
+ if (SavedStatus != EFI_ALREADY_STARTED) {
+ IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+ if (IdeBusDriverPrivateData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &IdeBusDriverPrivateData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData = NULL;
+ goto ErrorExit;
+ }
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Read the environment variable that contains the IDEBus Driver's
+ // Config options that were set by the Driver Configuration Protocol
+ //
+ DataSize = sizeof (ConfigurationOptions);
+ Status = gRT->GetVariable (
+ (CHAR16 *) L"Configuration",
+ &gEfiCallerIdGuid,
+ &Attributes,
+ &DataSize,
+ &ConfigurationOptions
+ );
+ if (EFI_ERROR (Status)) {
+ ConfigurationOptions = 0x0f;
+ }
+
+ if (EnumAll) {
+ //
+ // If IdeInit->EnumAll is TRUE, must enumerate all IDE device anyway
+ //
+ BeginningIdeChannel = IdePrimary;
+ EndIdeChannel = IdeSecondary;
+ BeginningIdeDevice = IdeMaster;
+ EndIdeDevice = IdeSlave;
+ } else if (RemainingDevicePath == NULL) {
+ //
+ // RemainingDevicePath is NULL, scan IDE bus for each device;
+ //
+ BeginningIdeChannel = IdePrimary;
+ EndIdeChannel = IdeSecondary;
+ BeginningIdeDevice = IdeMaster;
+ //
+ // default, may be redefined by IdeInit
+ //
+ EndIdeDevice = IdeSlave;
+ } else {
+ //
+ // RemainingDevicePath is not NULL, only scan the specified device.
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ BeginningIdeChannel = Node->Atapi.PrimarySecondary;
+ EndIdeChannel = BeginningIdeChannel;
+ BeginningIdeDevice = Node->Atapi.SlaveMaster;
+ EndIdeDevice = BeginningIdeDevice;
+ }
+
+ //
+ // Obtain IDE IO port registers' base addresses
+ //
+ Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Report status code: begin IdeBus initialization
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+ ParentDevicePath
+ );
+
+ //
+ // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol
+ //
+ for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);
+
+ //
+ // now obtain channel information fron IdeControllerInit protocol. Step9
+ //
+ Status = IdeInit->GetChannelInfo (
+ IdeInit,
+ IdeChannel,
+ &ChannelEnabled,
+ &MaxDevices
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));
+ continue;
+ }
+
+ if (!ChannelEnabled) {
+ continue;
+ }
+
+ EndIdeDevice = (UINT8) EFI_MIN ((MaxDevices - 1), EndIdeDevice);
+
+ //
+ // Now inform the IDE Controller Init Module. Sept10
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);
+
+ //
+ // No reset channel function implemented. Sept11
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);
+
+ //
+ // Step13
+ //
+ IdeInit->NotifyPhase (
+ IdeInit,
+ EfiIdeBusBeforeDevicePresenceDetection,
+ IdeChannel
+ );
+ //
+ // -- 1st inner loop --- Master/Slave ------------ Step14
+ //
+ for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+ //
+ // Check whether the configuration options allow this device
+ //
+ if (!(ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice)))) {
+ continue;
+ }
+
+ //
+ // The device has been scanned in another Start(), No need to scan it again
+ // for perf optimization.
+ //
+ if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ //
+ // create child handle for the detected device.
+ //
+ IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV));
+ if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) {
+ continue;
+ }
+
+ IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+ ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV));
+
+ IdeBlkIoDevicePtr->Signature = IDE_BLK_IO_DEV_SIGNATURE;
+ IdeBlkIoDevicePtr->Channel = IdeChannel;
+ IdeBlkIoDevicePtr->Device = IdeDevice;
+
+ //
+ // initialize Block IO interface's Media pointer
+ //
+ IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia;
+
+ //
+ // Initialize IDE IO port addresses, including Command Block registers
+ // and Control Block registers
+ //
+ IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS));
+ if (IdeBlkIoDevicePtr->IoPort == NULL) {
+ continue;
+ }
+
+ ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS));
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
+
+ IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr;
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
+
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr;
+ IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
+
+ IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0);
+
+ IdeBlkIoDevicePtr->PciIo = PciIo;
+ IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData;
+ IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr;
+
+ //
+ // Report Status code: is about to detect IDE drive
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
+ IdeBlkIoDevicePtr->DevicePath
+ );
+
+ //
+ // Discover device, now!
+ //
+ PERF_START (0, "DiscoverIdeDevice", "IDE", 0);
+ Status = DiscoverIdeDevice (IdeBlkIoDevicePtr);
+ PERF_END (0, "DiscoverIdeDevice", "IDE", 0);
+
+ IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice] = TRUE;
+ IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = FALSE;
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set Device Path
+ //
+ ZeroMem (&NewNode, sizeof (NewNode));
+ NewNode.DevPath.Type = MESSAGING_DEVICE_PATH;
+ NewNode.DevPath.SubType = MSG_ATAPI_DP;
+ SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH));
+
+ NewNode.Atapi.PrimarySecondary = (UINT8) IdeBlkIoDevicePtr->Channel;
+ NewNode.Atapi.SlaveMaster = (UINT8) IdeBlkIoDevicePtr->Device;
+ NewNode.Atapi.Lun = IdeBlkIoDevicePtr->Lun;
+ IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ &NewNode.DevPath
+ );
+ if (IdeBlkIoDevicePtr->DevicePath == NULL) {
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ continue;
+ }
+
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ CopyMem (&IdentifyData, IdeBlkIoDevicePtr->pIdData, sizeof (IdentifyData));
+ // IdentifyData = *IdeBlkIoDevicePtr->pIdData;
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE;
+ IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData);
+ } else {
+ //
+ // Device detection failed
+ //
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL);
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ }
+ //
+ // end of 1st inner loop ---
+ //
+ }
+ //
+ // end of 1st outer loop =========
+ //
+ }
+
+ //
+ // = 2nd outer loop == Primary/Secondary =================
+ //
+ for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+ //
+ // -- 2nd inner loop --- Master/Slave --------
+ //
+ for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+
+ if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ IdeChannel,
+ IdeDevice,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status));
+ continue;
+ }
+
+ IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= ATA_PIO_MODE_2) {
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ if (SupportedModes->ExtModeCount == 0){
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+ }
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
+ // be set together. Only one DMA mode can be set to a device. If setting
+ // DMA mode operation fails, we can continue moving on because we only use
+ // PIO mode at boot time. DMA modes are used by certain kind of OS booting
+ //
+ if (SupportedModes->UdmaMode.Valid) {
+
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+
+ EnableInterrupt (IdeBlkIoDevicePtr);
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+
+ EnableInterrupt (IdeBlkIoDevicePtr);
+ }
+ //
+ // Init driver parameters
+ //
+ DriveParameters.Sector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.sectors_per_track;
+ DriveParameters.Heads = (UINT8) (IdeBlkIoDevicePtr->pIdData->AtaData.heads - 1);
+ DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->pIdData->AtaData.multi_sector_cmd_max_sct_cnt;
+ //
+ // Set Parameters for the device:
+ // 1) Init
+ // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command
+ //
+ if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) {
+ Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters);
+ }
+
+ //
+ // Record PIO mode used in private data
+ //
+ IdeBlkIoDevicePtr->PioMode = SupportedModes->PioMode.Mode;
+
+ //
+ // Set IDE controller Timing Blocks in the PCI Configuration Space
+ //
+ IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);
+
+ //
+ // Add Component Name for the IDE/ATAPI device that was discovered.
+ //
+ IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+ ADD_NAME (IdeBlkIoDevicePtr);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &IdeBlkIoDevicePtr->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IdeBlkIoDevicePtr->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &IdeBlkIoDevicePtr->BlkIo,
+ &gEfiDiskInfoProtocolGuid,
+ &IdeBlkIoDevicePtr->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ }
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ IdeBlkIoDevicePtr->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE;
+
+ //
+ // Report status code: device eanbled!
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE),
+ IdeBlkIoDevicePtr->DevicePath
+ );
+ //
+ // end of 2nd inner loop ----
+ //
+ }
+ //
+ // end of 2nd outer loop ==========
+ //
+ }
+
+ //
+ // All configurations done! Notify IdeController to do post initialization
+ // work such as saving IDE controller PCI settings for S3 resume
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);
+
+ if (SupportedModes != NULL) {
+ gBS->FreePool (SupportedModes);
+ }
+
+ PERF_START (0, "Finish IDE detection", "IDE", 1);
+ PERF_END (0, "Finish IDE detection", "IDE", 0);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+
+ //
+ // Report error code: controller error
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR),
+ ParentDevicePath
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+
+ if (IdeBusDriverPrivateData != NULL) {
+ gBS->FreePool (IdeBusDriverPrivateData);
+ }
+
+ if (SupportedModes != NULL) {
+ gBS->FreePool (SupportedModes);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+
+}
+
+//
+// ***********************************************************************************
+// IDEBusDriverBindingStop
+// ***********************************************************************************
+//
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+ Routine Description:
+ Stop this driver on Controller Handle.
+
+ Arguments:
+ This - Protocol instance pointer.
+ DeviceHandle - Handle of device to stop driver on
+ NumberOfChildren - Not used
+ ChildHandleBuffer - Not used
+
+ Returns:
+ EFI_SUCCESS - This driver is removed DeviceHandle
+ other - This driver was not removed from this device
+
+--*/
+// TODO: Controller - add argument and description to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+ IdeBusDriverPrivateData = NULL;
+
+ if (NumberOfChildren == 0) {
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &IdeBusDriverPrivateData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+
+ if (IdeBusDriverPrivateData != NULL) {
+ gBS->FreePool (IdeBusDriverPrivateData);
+ }
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = DeRegisterIdeDevice (This, Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// ***********************************************************************************
+// DeRegisterIdeDevice
+// ***********************************************************************************
+//
+EFI_STATUS
+DeRegisterIdeDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+/*++
+
+Routine Description:
+
+ Deregister an IDE device and free resources
+
+Arguments:
+
+ This - Protocol instance pointer.
+ Controller - Ide device handle
+ Handle - Handle of device to deregister driver on
+
+Returns:
+
+ EFI_STATUS
+
+--*/
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+ //
+ // Report Status code: Device disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_DISABLE),
+ IdeBlkIoDevice->DevicePath
+ );
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ IdeBlkIoDevice->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &IdeBlkIoDevice->BlkIo,
+ &gEfiDiskInfoProtocolGuid,
+ &IdeBlkIoDevice->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // Release allocated resources
+ //
+ Index = IdeBlkIoDevice->Channel * 2 + IdeBlkIoDevice->Device;
+ IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE;
+
+ ReleaseIdeResources (IdeBlkIoDevice);
+
+ return EFI_SUCCESS;
+}
+
+//
+// ***********************************************************************************
+// IDEBlkIoReset
+// ***********************************************************************************
+//
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+ None
+
+--*/
+// TODO: This - add argument and description to function comment
+// TODO: ExtendedVerification - add argument and description to function comment
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // for ATA device, using ATA reset method
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk) {
+ return AtaSoftReset (IdeBlkIoDevice);
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // for ATAPI device, using ATAPI reset method
+ //
+ Status = AtapiSoftReset (IdeBlkIoDevice);
+ if (ExtendedVerification) {
+ Status = AtaSoftReset (IdeBlkIoDevice);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Read data from block io device
+
+Arguments:
+
+ This - Protocol instance pointer.
+ MediaId - The media ID of the device
+ LBA - Starting LBA address to read data
+ BufferSize - The size of data to be read
+ Buffer - Caller supplied buffer to save data
+
+Returns:
+
+ read data status
+
+--*/
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // For ATA compatible device, use ATA read block's mechanism
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ return AtaBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // for ATAPI device, using ATAPI read block's mechanism
+ //
+ return AtapiBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+
+}
+
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ Write data to block io device
+
+Arguments:
+
+ This - Protocol instance pointer.
+ MediaId - The media ID of the device
+ LBA - Starting LBA address to write data
+ BufferSize - The size of data to be written
+ Buffer - Caller supplied buffer to save data
+
+Returns:
+
+ write data status
+
+--*/
+// TODO: EFI_DEVICE_ERROR - add return value to function comment
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // for ATA device, using ATA write block's mechanism
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+
+ return AtaBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // for ATAPI device, using ATAPI write block's mechanism
+ //
+ return AtapiBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ LBA,
+ BufferSize,
+ Buffer
+ );
+}
+
+//
+// ***********************************************************************************
+// IDEBlkIoFlushBlocks
+// ***********************************************************************************
+//
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+ None
+
+--*/
+// TODO: This - add argument and description to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+/*++
+
+ Routine Description:
+ Return the results of the Inquiry command to a drive in InquiryData.
+ Data format of Inquiry data is defined by the Interface GUID.
+
+ Arguments:
+ This - Protocol instance pointer.
+ InquiryData - Results of Inquiry command to device
+ InquiryDataSize - Size of InquiryData in bytes.
+
+ Returns:
+ EFI_SUCCESS - InquiryData valid
+ EFI_NOT_FOUND - Device does not support this data class
+ EFI_DEVICE_ERROR - Error reading InquiryData from device
+ EFI_BUFFER_TOO_SMALL - IntquiryDataSize not big enough
+
+--*/
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+ if (*InquiryDataSize < sizeof (INQUIRY_DATA)) {
+ *InquiryDataSize = sizeof (INQUIRY_DATA);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (IdeBlkIoDevice->pInquiryData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ gBS->CopyMem (InquiryData, IdeBlkIoDevice->pInquiryData, sizeof (INQUIRY_DATA));
+ *InquiryDataSize = sizeof (INQUIRY_DATA);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+/*++
+
+ Routine Description:
+ Return the results of the Identify command to a drive in IdentifyData.
+ Data format of Identify data is defined by the Interface GUID.
+
+ Arguments:
+ This - Protocol instance pointer.
+ IdentifyData - Results of Identify command to device
+ IdentifyDataSize - Size of IdentifyData in bytes.
+
+ Returns:
+ EFI_SUCCESS - IdentifyData valid
+ EFI_NOT_FOUND - Device does not support this data class
+ EFI_DEVICE_ERROR - Error reading IdentifyData from device
+ EFI_BUFFER_TOO_SMALL - IdentifyDataSize not big enough
+
+--*/
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+ if (*IdentifyDataSize < sizeof (EFI_IDENTIFY_DATA)) {
+ *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (IdeBlkIoDevice->pIdData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ gBS->CopyMem (IdentifyData, IdeBlkIoDevice->pIdData, sizeof (EFI_IDENTIFY_DATA));
+ *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+/*++
+
+ Routine Description:
+ Return the results of the Request Sense command to a drive in SenseData.
+ Data format of Sense data is defined by the Interface GUID.
+
+ Arguments:
+ This - Protocol instance pointer.
+ SenseData - Results of Request Sense command to device
+ SenseDataSize - Size of SenseData in bytes.
+ SenseDataNumber - Type of SenseData
+
+ Returns:
+ EFI_SUCCESS - InquiryData valid
+ EFI_NOT_FOUND - Device does not support this data class
+ EFI_DEVICE_ERROR - Error reading InquiryData from device
+ EFI_BUFFER_TOO_SMALL - SenseDataSize not big enough
+
+--*/
+{
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+/*++
+
+ Routine Description:
+ Return the results of the Request Sense command to a drive in SenseData.
+ Data format of Sense data is defined by the Interface GUID.
+
+ Arguments:
+ This - Protocol instance pointer.
+ IdeChannel - Primary or Secondary
+ IdeDevice - Master or Slave
+
+ Returns:
+ EFI_SUCCESS - IdeChannel and IdeDevice are valid
+ EFI_UNSUPPORTED - This is not an IDE device
+
+--*/
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+ *IdeChannel = IdeBlkIoDevice->Channel;
+ *IdeDevice = IdeBlkIoDevice->Device;
+
+ return EFI_SUCCESS;
+}
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h
new file mode 100644
index 0000000000..2e3caaf1b7
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.h
@@ -0,0 +1,439 @@
+/*++
+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:
+
+ idebus.h
+
+Abstract:
+
+ Header file for IDE Bus Driver.
+
+Revision History
+++*/
+
+// TODO: fix comment to end with --*/
+#ifndef _IDE_BUS_H
+#define _IDE_BUS_H
+
+
+#include <IndustryStandard/Pci22.h>
+#include "idedata.h"
+
+//
+// Extra Definition to porting
+//
+#define EFI_MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define MAX_IDE_DEVICE 4
+#define MAX_IDE_CHANNELS 2
+#define MAX_IDE_DRIVES 2
+
+typedef struct {
+ BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE];
+ BOOLEAN DeviceFound[MAX_IDE_DEVICE];
+ BOOLEAN DeviceProcessed[MAX_IDE_DEVICE];
+} IDE_BUS_DRIVER_PRIVATE_DATA;
+
+#define IDE_BLK_IO_DEV_SIGNATURE EFI_SIGNATURE_32 ('i', 'b', 'i', 'd')
+
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL BlkIo;
+ EFI_BLOCK_IO_MEDIA BlkMedia;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+ //
+ // Local Data for IDE interface goes here
+ //
+ EFI_IDE_CHANNEL Channel;
+ EFI_IDE_DEVICE Device;
+ UINT16 Lun;
+ IDE_DEVICE_TYPE Type;
+
+ IDE_BASE_REGISTERS *IoPort;
+ UINT16 AtapiError;
+
+ INQUIRY_DATA *pInquiryData;
+ EFI_IDENTIFY_DATA *pIdData;
+ ATA_PIO_MODE PioMode;
+ ATA_UDMA_MODE UDma_Mode;
+ CHAR8 ModelName[41];
+ REQUEST_SENSE_DATA *SenseData;
+ UINT8 SenseDataNumber;
+ UINT8 *Cache;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+} IDE_BLK_IO_DEV;
+
+#include "ComponentName.h"
+
+#define IDE_BLOCK_IO_DEV_FROM_THIS(a) CR (a, IDE_BLK_IO_DEV, BlkIo, IDE_BLK_IO_DEV_SIGNATURE)
+#define IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS(a) CR (a, IDE_BLK_IO_DEV, DiskInfo, IDE_BLK_IO_DEV_SIGNATURE)
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding;
+
+#include "ide.h"
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+EFI_STATUS
+EFIAPI
+IDEBusControllerDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ImageHandle - TODO: add argument description
+ SystemTable - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Controller - TODO: add argument description
+ RemainingDevicePath - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Controller - TODO: add argument description
+ RemainingDevicePath - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ Controller - TODO: add argument description
+ NumberOfChildren - TODO: add argument description
+ ChildHandleBuffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+//
+// Block I/O Protocol Interface
+//
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ ExtendedVerification - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA LBA,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ MediaId - TODO: add argument description
+ LBA - TODO: add argument description
+ BufferSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+IDERegisterDecodeEnableorDisable (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN BOOLEAN Enable
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PciIo - TODO: add argument description
+ Enable - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *IntquiryDataSize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ InquiryData - TODO: add argument description
+ IntquiryDataSize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ IdentifyData - TODO: add argument description
+ IdentifyDataSize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ SenseData - TODO: add argument description
+ SenseDataSize - TODO: add argument description
+ SenseDataNumber - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ This - TODO: add argument description
+ IdeChannel - TODO: add argument description
+ IdeDevice - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+#endif
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd
new file mode 100644
index 0000000000..f6e3ba1c8a
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.mbd
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>IdeBus</BaseName>
+ <Guid>69FD8E47-A161-4550-B01A-5594CEB2B2B2</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ 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.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-22 16:27</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibReportStatusCode</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>DxeMemoryAllocationLib</Library>
+ <Library>UefiDevicePathLib</Library>
+ <Library>BasePerformanceLibNull</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa
new file mode 100644
index 0000000000..1b303c6823
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebus.msa
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>IdeBus</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>69FD8E47-A161-4550-B01A-5594CEB2B2B2</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for PS2 keyboard module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ 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.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-22 16:27</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">ReportStatusCodeLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">MemoryAllocationLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PerformanceLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>idebus.h</Filename>
+ <Filename>ide.h</Filename>
+ <Filename>idedata.h</Filename>
+ <Filename>idebus.c</Filename>
+ <Filename>ide.c</Filename>
+ <Filename>ata.c</Filename>
+ <Filename>atapi.c</Filename>
+ <Filename>ComponentName.c</Filename>
+ <Filename>ComponentName.h</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="TO_START">DevicePath</Protocol>
+ <Protocol Usage="TO_START">PciIo</Protocol>
+ <Protocol Usage="TO_START">IdeControllerInit</Protocol>
+ <Protocol Usage="BY_START">BlockIo</Protocol>
+ <Protocol Usage="BY_START">DiskInfo</Protocol>
+ </Protocols>
+ <Variables>
+ <Variable Usage="ALWAYS_CONSUMED">
+ <String>Configuration</String>
+ <Guid>0x69fd8e47, 0xa161, 0x4550, 0xb0, 0x1a, 0x55, 0x94, 0xce, 0xb2, 0xb2, 0xb2</Guid>
+ </Variable>
+ </Variables>
+ <Guids>
+ <GuidEntry Usage="SOMETIMES_CONSUMED">
+ <C_Name>DiskInfoIde</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gIDEBusDriverBinding</DriverBinding>
+ <ComponentName>gIDEBusComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd
new file mode 100644
index 0000000000..fa4bc333d4
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.mbd
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<ModuleBuildDescription xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MbdHeader>
+ <BaseName>IdeBusLite</BaseName>
+ <Guid>69FD8E47-A161-4550-B01A-5594CEB2B2B2</Guid>
+ <Version>0</Version>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ 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.
+ </License>
+ <Created>2006-03-12 17:09</Created>
+ <Modified>2006-03-19 15:18</Modified>
+ </MbdHeader>
+ <Libraries>
+ <Library>UefiBootServicesTableLib</Library>
+ <Library>UefiRuntimeServicesTableLib</Library>
+ <Library>UefiMemoryLib</Library>
+ <Library>UefiLib</Library>
+ <Library>UefiDriverEntryPoint</Library>
+ <Library>UefiDriverModelLib</Library>
+ <Library>DxeReportStatusCodeLib</Library>
+ <Library>BaseDebugLibNull</Library>
+ <Library>EdkDxePrintLib</Library>
+ <Library>BaseLib</Library>
+ <Library>UefiDevicePathLib</Library>
+ <Library>BasePerformanceLibNull</Library>
+ </Libraries>
+</ModuleBuildDescription>
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa
new file mode 100644
index 0000000000..71fc18ddce
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idebusLite.msa
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.TianoCore.org/2006/Edk2.0 http://www.TianoCore.org/2006/Edk2.0/SurfaceArea.xsd">
+ <MsaHeader>
+ <BaseName>IdeBusLite</BaseName>
+ <ModuleType>DXE_DRIVER</ModuleType>
+ <ComponentType>BS_DRIVER</ComponentType>
+ <Guid>69FD8E47-A161-4550-B01A-5594CEB2B2B2</Guid>
+ <Version>0</Version>
+ <Abstract>Component description file for PS2 keyboard module.</Abstract>
+ <Description>FIX ME!</Description>
+ <Copyright>Copyright (c) 2004-2006, Intel Corporation</Copyright>
+ <License>
+ 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.
+ </License>
+ <Specification>0</Specification>
+ <Created>2006-03-12 17:09</Created>
+ <Updated>2006-03-19 15:18</Updated>
+ </MsaHeader>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DebugLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverModelLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiDriverEntryPoint</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">BaseMemoryLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">PerformanceLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiBootServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">UefiRuntimeServicesTableLib</LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">DevicePathLib</LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename>idebus.h</Filename>
+ <Filename>ide.h</Filename>
+ <Filename>idedata.h</Filename>
+ <Filename>idebus.c</Filename>
+ <Filename>ide.c</Filename>
+ <Filename>ata.c</Filename>
+ <Filename>atapi.c</Filename>
+ </SourceFiles>
+ <Includes>
+ <PackageName>MdePkg</PackageName>
+ <PackageName>EdkModulePkg</PackageName>
+ </Includes>
+ <Protocols>
+ <Protocol Usage="ALWAYS_CONSUMED">DevicePath</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">PciIo</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">IdeControllerInit</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">BlockIo</Protocol>
+ <Protocol Usage="ALWAYS_CONSUMED">DiskInfo</Protocol>
+ </Protocols>
+ <Guids>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>DiskInfoIde</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>DiskInfoScsi</C_Name>
+ </GuidEntry>
+ <GuidEntry Usage="ALWAYS_CONSUMED">
+ <C_Name>DiskInfoUsb</C_Name>
+ </GuidEntry>
+ </Guids>
+ <Externs>
+ <Extern>
+ <ModuleEntryPoint></ModuleEntryPoint>
+ </Extern>
+ <Extern>
+ <DriverBinding>gIDEBusDriverBinding</DriverBinding>
+ <ComponentName>gIDEBusComponentName</ComponentName>
+ </Extern>
+ </Externs>
+</ModuleSurfaceArea>
diff --git a/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h
new file mode 100644
index 0000000000..50b1f05a47
--- /dev/null
+++ b/EdkModulePkg/Bus/Pci/IdeBus/Dxe/idedata.h
@@ -0,0 +1,879 @@
+/*++
+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:
+
+ idedata.h
+
+Abstract:
+
+ Header file for IDE Bus Driver's Data Structures
+
+Revision History
+++*/
+
+// TODO: fix comment to end with --*/
+#ifndef _IDE_DATA_H
+#define _IDE_DATA_H
+
+//
+// bit definition
+//
+#define bit0 (1 << 0)
+#define bit1 (1 << 1)
+#define bit2 (1 << 2)
+#define bit3 (1 << 3)
+#define bit4 (1 << 4)
+#define bit5 (1 << 5)
+#define bit6 (1 << 6)
+#define bit7 (1 << 7)
+#define bit8 (1 << 8)
+#define bit9 (1 << 9)
+#define bit10 (1 << 10)
+#define bit11 (1 << 11)
+#define bit12 (1 << 12)
+#define bit13 (1 << 13)
+#define bit14 (1 << 14)
+#define bit15 (1 << 15)
+#define bit16 (1 << 16)
+#define bit17 (1 << 17)
+#define bit18 (1 << 18)
+#define bit19 (1 << 19)
+#define bit20 (1 << 20)
+#define bit21 (1 << 21)
+#define bit22 (1 << 22)
+#define bit23 (1 << 23)
+#define bit24 (1 << 24)
+#define bit25 (1 << 25)
+#define bit26 (1 << 26)
+#define bit27 (1 << 27)
+#define bit28 (1 << 28)
+#define bit29 (1 << 29)
+#define bit30 (1 << 30)
+#define bit31 (1 << 31)
+
+//
+// common constants
+//
+#define STALL_1_MILLI_SECOND 1000 // stall 1 ms
+#define STALL_1_SECOND 1000000 // stall 1 second
+typedef enum {
+ IdePrimary = 0,
+ IdeSecondary = 1,
+ IdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+ IdeMaster = 0,
+ IdeSlave = 1,
+ IdeMaxDevice = 2
+} EFI_IDE_DEVICE;
+
+typedef enum {
+ IdeMagnetic, /* ZIP Drive or LS120 Floppy Drive */
+ IdeCdRom, /* ATAPI CDROM */
+ IdeHardDisk, /* Hard Disk */
+ Ide48bitAddressingHardDisk, /* Hard Disk larger than 120GB */
+ IdeUnknown
+} IDE_DEVICE_TYPE;
+
+//
+// IDE Registers
+//
+typedef union {
+ UINT16 Command; /* when write */
+ UINT16 Status; /* when read */
+} IDE_CMD_OR_STATUS;
+
+typedef union {
+ UINT16 Error; /* when read */
+ UINT16 Feature; /* when write */
+} IDE_ERROR_OR_FEATURE;
+
+typedef union {
+ UINT16 AltStatus; /* when read */
+ UINT16 DeviceControl; /* when write */
+} IDE_AltStatus_OR_DeviceControl;
+
+//
+// IDE registers set
+//
+typedef struct {
+ UINT16 Data;
+ IDE_ERROR_OR_FEATURE Reg1;
+ UINT16 SectorCount;
+ UINT16 SectorNumber;
+ UINT16 CylinderLsb;
+ UINT16 CylinderMsb;
+ UINT16 Head;
+ IDE_CMD_OR_STATUS Reg;
+
+ IDE_AltStatus_OR_DeviceControl Alt;
+ UINT16 DriveAddress;
+
+ UINT16 MasterSlave;
+ UINT16 BusMasterBaseAddr;
+} IDE_BASE_REGISTERS;
+
+//
+// IDE registers' base addresses
+//
+typedef struct {
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINT16 BusMasterBaseAddr;
+} IDE_REGISTERS_BASE_ADDR;
+
+//
+// Bit definitions in Programming Interface byte of the Class Code field
+// in PCI IDE controller's Configuration Space
+//
+#define IDE_PRIMARY_OPERATING_MODE bit0
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR bit1
+#define IDE_SECONDARY_OPERATING_MODE bit2
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR bit3
+
+//
+// IDE registers bit definitions
+//
+
+//
+// Err Reg
+//
+#define BBK_ERR bit7 /* Bad block detected */
+#define UNC_ERR bit6 /* Uncorrectable Data */
+#define MC_ERR bit5 /* Media Change */
+#define IDNF_ERR bit4 /* ID Not Found */
+#define MCR_ERR bit3 /* Media Change Requested */
+#define ABRT_ERR bit2 /* Aborted Command */
+#define TK0NF_ERR bit1 /* Track 0 Not Found */
+#define AMNF_ERR bit0 /* Address Mark Not Found */
+
+//
+// Device/Head Reg
+//
+#define LBA_MODE bit6
+#define DEV bit4
+#define HS3 bit3
+#define HS2 bit2
+#define HS1 bit1
+#define HS0 bit0
+#define CHS_MODE (0)
+#define DRV0 (0)
+#define DRV1 (1)
+#define MST_DRV DRV0
+#define SLV_DRV DRV1
+
+//
+// Status Reg
+//
+#define BSY bit7 /* Controller Busy */
+#define DRDY bit6 /* Drive Ready */
+#define DWF bit5 /* Drive Write Fault */
+#define DSC bit4 /* Disk Seek Complete */
+#define DRQ bit3 /* Data Request */
+#define CORR bit2 /* Corrected Data */
+#define IDX bit1 /* Index */
+#define ERR bit0 /* Error */
+
+//
+// Device Control Reg
+//
+#define SRST bit2 /* Software Reset */
+#define IEN_L bit1 /* Interrupt Enable #*/
+
+//
+// Bus Master Reg
+//
+#define BMIC_nREAD bit3
+#define BMIC_START bit0
+#define BMIS_INTERRUPT bit2
+#define BMIS_ERROR bit1
+
+#define BMICP_OFFSET 0x00
+#define BMISP_OFFSET 0x02
+#define BMIDP_OFFSET 0x04
+#define BMICS_OFFSET 0x08
+#define BMISS_OFFSET 0x0A
+#define BMIDS_OFFSET 0x0C
+
+//
+// Time Out Value For IDE Device Polling
+//
+
+//
+// ATATIMEOUT is used for waiting time out for ATA device
+//
+
+//
+// 1 second
+//
+#define ATATIMEOUT 1000
+
+//
+// ATAPITIMEOUT is used for waiting operation
+// except read and write time out for ATAPI device
+//
+
+//
+// 1 second
+//
+#define ATAPITIMEOUT 1000
+
+//
+// ATAPILONGTIMEOUT is used for waiting read and
+// write operation timeout for ATAPI device
+//
+
+//
+// 2 seconds
+//
+#define CDROMLONGTIMEOUT 2000
+
+//
+// 5 seconds
+//
+#define ATAPILONGTIMEOUT 5000
+
+//
+// ATA Commands Code
+//
+#define ATA_INITIALIZE_DEVICE 0x91
+
+//
+// Class 1
+//
+#define IDENTIFY_DRIVE_CMD 0xec
+#define READ_BUFFER_CMD 0xe4
+#define READ_SECTORS_CMD 0x20
+#define READ_SECTORS_WITH_RETRY_CMD 0x21
+#define READ_LONG_CMD 0x22
+#define READ_LONG_WITH_RETRY_CMD 0x23
+//
+// Class 1 - Atapi6 enhanced commands
+//
+#define READ_SECTORS_EXT_CMD 0x24
+
+//
+// Class 2
+//
+#define FORMAT_TRACK_CMD 0x50
+#define WRITE_BUFFER_CMD 0xe8
+#define WRITE_SECTORS_CMD 0x30
+#define WRITE_SECTORS_WITH_RETRY_CMD 0x31
+#define WRITE_LONG_CMD 0x32
+#define WRITE_LONG_WITH_RETRY_CMD 0x33
+#define WRITE_VERIFY_CMD 0x3c
+//
+// Class 2 - Atapi6 enhanced commands
+//
+#define WRITE_SECTORS_EXT_CMD 0x34
+
+//
+// Class 3
+//
+#define ACK_MEDIA_CHANGE_CMD 0xdb
+#define BOOT_POST_BOOT_CMD 0xdc
+#define BOOT_PRE_BOOT_CMD 0xdd
+#define CHECK_POWER_MODE_CMD 0x98
+#define CHECK_POWER_MODE_CMD_ALIAS 0xe5
+#define DOOR_LOCK_CMD 0xde
+#define DOOR_UNLOCK_CMD 0xdf
+#define EXEC_DRIVE_DIAG_CMD 0x90
+#define IDLE_CMD_ALIAS 0x97
+#define IDLE_CMD 0xe3
+#define IDLE_IMMEDIATE_CMD 0x95
+#define IDLE_IMMEDIATE_CMD_ALIAS 0xe1
+#define INIT_DRIVE_PARAM_CMD 0x91
+#define RECALIBRATE_CMD 0x10 /* aliased to 1x */
+#define READ_DRIVE_STATE_CMD 0xe9
+#define SET_MULTIPLE_MODE_CMD 0xC6
+#define READ_DRIVE_STATE_CMD 0xe9
+#define READ_VERIFY_CMD 0x40
+#define READ_VERIFY_WITH_RETRY_CMD 0x41
+#define SEEK_CMD 0x70 /* aliased to 7x */
+#define SET_FEATURES_CMD 0xef
+#define STANDBY_CMD 0x96
+#define STANDBY_CMD_ALIAS 0xe2
+#define STANDBY_IMMEDIATE_CMD 0x94
+#define STANDBY_IMMEDIATE_CMD_ALIAS 0xe0
+
+//
+// Class 4
+//
+#define READ_DMA_CMD 0xc8
+#define READ_DMA_WITH_RETRY_CMD 0xc9
+#define READ_DMA_EXT_CMD 0x25
+#define WRITE_DMA_CMD 0xca
+#define WRITE_DMA_WITH_RETRY_CMD 0xcb
+#define WRITE_DMA_EXT_CMD 0x35
+
+//
+// Class 5
+//
+#define READ_MULTIPLE_CMD 0xc4
+#define REST_CMD 0xe7
+#define RESTORE_DRIVE_STATE_CMD 0xea
+#define SET_SLEEP_MODE_CMD 0x99
+#define SET_SLEEP_MODE_CMD_ALIAS 0xe6
+#define WRITE_MULTIPLE_CMD 0xc5
+#define WRITE_SAME_CMD 0xe9
+
+//
+// Class 6 - Host protected area access feature set
+//
+#define READ_NATIVE_MAX_ADDRESS_CMD 0xf8
+#define SET_MAX_ADDRESS_CMD 0xf9
+
+//
+// Class 6 - ATA/ATAPI-6 enhanced commands
+//
+#define READ_NATIVE_MAX_ADDRESS_EXT_CMD 0x27
+#define SET_MAX_ADDRESS_CMD_EXT 0x37
+
+//
+// Class 6 - SET_MAX related sub command (in feature register)
+//
+#define PARTIES_SET_MAX_ADDRESS_SUB_CMD 0x00
+#define PARTIES_SET_PASSWORD_SUB_CMD 0x01
+#define PARTIES_LOCK_SUB_CMD 0x02
+#define PARTIES_UNLOCK_SUB_CMD 0x03
+#define PARTIES_FREEZE_SUB_CMD 0x04
+
+//
+// S.M.A.R.T
+//
+#define ATA_SMART_CMD 0xb0
+#define ATA_CONSTANT_C2 0xc2
+#define ATA_CONSTANT_4F 0x4f
+#define ATA_SMART_ENABLE_OPERATION 0xd8
+#define ATA_SMART_RETURN_STATUS 0xda
+
+//
+// Error codes for Exec Drive Diag
+//
+#define DRIV_DIAG_NO_ERROR (0x01)
+#define DRIV_DIAG_FORMATTER_ERROR (0x02)
+#define DRIV_DIAG_DATA_BUFFER_ERROR (0x03)
+#define DRIV_DIAG_ECC_CKT_ERRROR (0x04)
+#define DRIV_DIAG_UP_ERROR (0x05)
+#define DRIV_DIAG_SLAVE_DRV_ERROR (0x80) /* aliased to 0x8x */
+
+//
+// Codes for Format Track
+//
+#define FORMAT_GOOD_SECTOR (0x00)
+#define FORMAT_SUSPEND_ALLOC (0x01)
+#define FORMAT_REALLOC_SECTOR (0x02)
+#define FORMAT_MARK_SECTOR_DEFECTIVE (0x03)
+
+//
+// IDE_IDENTIFY bits
+// config bits :
+//
+#define ID_CONFIG_RESERVED0 bit0
+#define ID_CONFIG_HARD_SECTORED_DRIVE bit1
+#define ID_CONFIG_SOFT_SECTORED_DRIVE bit2
+#define ID_CONFIG_NON_MFM bit3
+#define ID_CONFIG_15uS_HEAD_SWITCHING bit4
+#define ID_CONFIG_SPINDLE_MOTOR_CONTROL bit5
+#define ID_CONFIG_HARD_DRIVE bit6
+#define ID_CONFIG_CHANGEABLE_MEDIUM bit7
+#define ID_CONFIG_DATA_RATE_TO_5MHZ bit8
+#define ID_CONFIG_DATA_RATE_5_TO_10MHZ bit9
+#define ID_CONFIG_DATA_RATE_ABOVE_10MHZ bit10
+#define ID_CONFIG_MOTOR_SPEED_TOLERANCE_ABOVE_0_5_PERC bit11
+#define ID_CONFIG_DATA_CLK_OFFSET_AVAIL bit12
+#define ID_CONFIG_TRACK_OFFSET_AVAIL bit13
+#define ID_CONFIG_SPEED_TOLERANCE_GAP_NECESSARY bit14
+#define ID_CONFIG_RESERVED1 bit15
+
+#define ID_DOUBLE_WORD_IO_POSSIBLE bit01
+#define ID_LBA_SUPPORTED bit9
+#define ID_DMA_SUPPORTED bit8
+
+#define SET_FEATURE_ENABLE_8BIT_TRANSFER (0x01)
+#define SET_FEATURE_ENABLE_WRITE_CACHE (0x02)
+#define SET_FEATURE_TRANSFER_MODE (0x03)
+#define SET_FEATURE_WRITE_SAME_WRITE_SPECIFIC_AREA (0x22)
+#define SET_FEATURE_DISABLE_RETRIES (0x33)
+//
+// for Read & Write Longs
+//
+#define SET_FEATURE_VENDOR_SPEC_ECC_LENGTH (0x44)
+#define SET_FEATURE_PLACE_NO_OF_CACHE_SEGMENTS_IN_SECTOR_NO_REG (0x54)
+#define SET_FEATURE_DISABLE_READ_AHEAD (0x55)
+#define SET_FEATURE_MAINTAIN_PARAM_AFTER_RESET (0x66)
+#define SET_FEATURE_DISABLE_ECC (0x77)
+#define SET_FEATURE_DISABLE_8BIT_TRANSFER (0x81)
+#define SET_FEATURE_DISABLE_WRITE_CACHE (0x82)
+#define SET_FEATURE_ENABLE_ECC (0x88)
+#define SET_FEATURE_ENABLE_RETRIES (0x99)
+#define SET_FEATURE_ENABLE_READ_AHEAD (0xaa)
+#define SET_FEATURE_SET_SECTOR_CNT_REG_AS_NO_OF_READ_AHEAD_SECTORS (0xab)
+#define SET_FEATURE_ALLOW_REST_MODE (0xac)
+//
+// for Read & Write Longs
+//
+#define SET_FEATURE_4BYTE_ECC (0xbb)
+#define SET_FEATURE_DEFALUT_FEATURES_ON_SOFTWARE_RESET (0xcc)
+#define SET_FEATURE_WRITE_SAME_TO_WRITE_ENTIRE_MEDIUM (0xdd)
+
+#define BLOCK_TRANSFER_MODE (0x00)
+#define SINGLE_WORD_DMA_TRANSFER_MODE (0x10)
+#define MULTI_WORD_DMA_TRANSFER_MODE (0x20)
+#define TRANSFER_MODE_MASK (0x07) // 3 LSBs
+
+//
+// Drive 0 - Head 0
+//
+#define DEFAULT_DRIVE (0x00)
+#define DEFAULT_CMD (0xa0)
+//
+// default content of device control register, disable INT
+//
+#define DEFAULT_CTL (0x0a)
+#define DEFAULT_IDE_BM_IO_BASE_ADR (0xffa0)
+
+//
+// ATAPI6 related data structure definition
+//
+
+//
+// The maximum sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+//
+// Move the IDENTIFY section to DXE\Protocol\IdeControllerInit
+//
+
+//
+// ATAPI Command
+//
+#define ATAPI_SOFT_RESET_CMD 0x08
+#define ATAPI_PACKET_CMD 0xA0
+#define PACKET_CMD 0xA0
+#define ATAPI_IDENTIFY_DEVICE_CMD 0xA1
+#define ATAPI_SERVICE_CMD 0xA2
+
+//
+// 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 : 4;
+ UINT8 page_control : 4;
+ 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;
+
+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 RequestSence;
+ INQUIRY_CMD Inquiry;
+ MODE_SENSE_CMD ModeSense;
+ READ_FORMAT_CAP_CMD ReadFormatCapacity;
+} ATAPI_PACKET_COMMAND;
+
+typedef struct {
+ UINT32 RegionBaseAddr;
+ UINT16 ByteCount;
+ UINT16 EndOfTable;
+} IDE_DMA_PRD;
+
+#define MAX_DMA_EXT_COMMAND_SECTORS 0x10000
+#define MAX_DMA_COMMAND_SECTORS 0x100
+
+#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 MODE_SENSE 0x5A
+#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)
+
+//
+// Additional Sense Code Qualifier
+//
+#define ASCQ_IN_PROGRESS (0x01)
+
+#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];
+ UINT8 firmware_sub_rev_level[1];
+ UINT8 reserved_37;
+ UINT8 reserved_38;
+ UINT8 reserved_39;
+ UINT8 max_capacity_hi;
+ UINT8 max_capacity_mid;
+ UINT8 max_capacity_lo;
+ UINT8 reserved_43_95[95 - 43 + 1];
+} INQUIRY_DATA;
+
+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[16];
+ UINT8 product_revision_level[4];
+ UINT8 vendor_specific[20];
+ UINT8 reserved_56_95[40];
+} CDROM_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;
+
+#pragma pack()
+
+//
+// PIO mode definition
+//
+typedef enum {
+ ATA_PIO_MODE_BELOW_2,
+ ATA_PIO_MODE_2,
+ ATA_PIO_MODE_3,
+ ATA_PIO_MODE_4
+} ATA_PIO_MODE;
+
+//
+// Multi word DMA definition
+//
+typedef enum {
+ ATA_MDMA_MODE_0,
+ ATA_MDMA_MODE_1,
+ ATA_MDMA_MODE_2
+} ATA_MDMA_MODE;
+
+//
+// UDMA mode definition
+//
+typedef enum {
+ ATA_UDMA_MODE_0,
+ ATA_UDMA_MODE_1,
+ ATA_UDMA_MODE_2,
+ ATA_UDMA_MODE_3,
+ ATA_UDMA_MODE_4,
+ ATA_UDMA_MODE_5
+} ATA_UDMA_MODE;
+
+#define ATA_MODE_CATEGORY_DEFAULT_PIO 0x00
+#define ATA_MODE_CATEGORY_FLOW_PIO 0x01
+#define ATA_MODE_CATEGORY_MDMA 0x04
+#define ATA_MODE_CATEGORY_UDMA 0x08
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 ModeNumber : 3;
+ UINT8 ModeCategory : 5;
+} ATA_TRANSFER_MODE;
+
+typedef struct {
+ UINT8 Sector;
+ UINT8 Heads;
+ UINT8 MultipleSector;
+} ATA_DRIVE_PARMS;
+
+#pragma pack()
+//
+// IORDY Sample Point field value
+//
+#define ISP_5_CLK 0
+#define ISP_4_CLK 1
+#define ISP_3_CLK 2
+#define ISP_2_CLK 3
+
+//
+// Recovery Time field value
+//
+#define RECVY_4_CLK 0
+#define RECVY_3_CLK 1
+#define RECVY_2_CLK 2
+#define RECVY_1_CLK 3
+
+//
+// Slave IDE Timing Register Enable
+//
+#define SITRE bit14
+
+//
+// DMA Timing Enable Only Select 1
+//
+#define DTE1 bit7
+
+//
+// Pre-fetch and Posting Enable Select 1
+//
+#define PPE1 bit6
+
+//
+// IORDY Sample Point Enable Select 1
+//
+#define IE1 bit5
+
+//
+// Fast Timing Bank Drive Select 1
+//
+#define TIME1 bit4
+
+//
+// DMA Timing Enable Only Select 0
+//
+#define DTE0 bit3
+
+//
+// Pre-fetch and Posting Enable Select 0
+//
+#define PPE0 bit2
+
+//
+// IOREY Sample Point Enable Select 0
+//
+#define IE0 bit1
+
+//
+// Fast Timing Bank Drive Select 0
+//
+#define TIME0 bit0
+
+#endif