mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-30 12:43:41 +01:00
7c0aa811ec
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
1555 lines
45 KiB
C
1555 lines
45 KiB
C
/* $Id: IdeBus.c 33540 2010-10-28 09:27:05Z vboxsync $ */
|
|
/** @file
|
|
* IdeBus.c
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2009-2010 Oracle Corporation
|
|
*
|
|
* This file is part of VirtualBox Open Source Edition (OSE), as
|
|
* available from http://www.virtualbox.org. This file is free software;
|
|
* you can redistribute it and/or modify it under the terms of the GNU
|
|
* General Public License (GPL) as published by the Free Software
|
|
* Foundation, in version 2 as it comes in the "COPYING" file of the
|
|
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
|
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
|
*/
|
|
|
|
/** @file
|
|
This file implement UEFI driver for IDE Bus which includes device identification,
|
|
Child device(Disk, CDROM, etc) enumeration and child handler installation, and
|
|
driver stop.
|
|
|
|
Copyright (c) 2006 - 2009, 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.
|
|
|
|
@par Revision Reference:
|
|
This module is modified from DXE\IDE module for Ide Controller 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,
|
|
0xa,
|
|
NULL,
|
|
NULL
|
|
};
|
|
/**
|
|
Deregister an IDE device and free resources
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Ide device handle
|
|
@param Handle Handle of device to deregister driver on
|
|
|
|
@retval EFI_SUCCESS Deregister a specific IDE device successfully
|
|
|
|
|
|
**/
|
|
EFI_STATUS
|
|
DeRegisterIdeDevice (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_HANDLE Handle
|
|
)
|
|
{
|
|
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;
|
|
if (Index < MAX_IDE_DEVICE) {
|
|
IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE;
|
|
}
|
|
ReleaseIdeResources (IdeBlkIoDevice);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
/**
|
|
Supported function of Driver Binding protocol for this driver.
|
|
|
|
@param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
|
|
@param ControllerHandle The handle of the controller to test.
|
|
@param RemainingDevicePath A pointer to the remaining portion of a device path.
|
|
|
|
@retval EFI_SUCCESS Driver loaded.
|
|
@retval other Driver not loaded.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBusDriverBindingSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
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;
|
|
//
|
|
// Check if RemainingDevicePath is the End of Device Path Node,
|
|
// if yes, go on checking other conditions
|
|
//
|
|
if (!IsDevicePathEnd (Node)) {
|
|
//
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
// check its validation
|
|
//
|
|
if (Node->DevPath.Type != MESSAGING_DEVICE_PATH ||
|
|
Node->DevPath.SubType != MSG_ATAPI_DP ||
|
|
DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Close the I/O Abstraction(s) used to perform the supported test
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiIdeControllerInitProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
//
|
|
// Open the EFI Device Path protocol 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;
|
|
}
|
|
|
|
//
|
|
// Close protocol, don't use device path protocol in the Support() function
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiDevicePathProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Start function of Driver binding protocol which start this driver on Controller
|
|
by detecting all disks and installing BlockIo protocol on them.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Handle of device to bind driver to.
|
|
@param RemainingDevicePath produce all possible children.
|
|
|
|
@retval EFI_SUCCESS This driver is added to ControllerHandle.
|
|
@retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBusDriverBindingStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
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;
|
|
IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
|
|
UINT64 Supports;
|
|
|
|
//
|
|
// Local variables declaration for IdeControllerInit support
|
|
//
|
|
EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
|
|
BOOLEAN EnumAll;
|
|
BOOLEAN ChannelEnabled;
|
|
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. Step7.2
|
|
//
|
|
EnumAll = IdeInit->EnumAll;
|
|
|
|
//
|
|
// 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,
|
|
EfiPciIoAttributeOperationSupported,
|
|
0,
|
|
&Supports
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Supports &= EFI_PCI_DEVICE_ENABLE;
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationEnable,
|
|
Supports,
|
|
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,
|
|
NULL,
|
|
&DataSize,
|
|
&ConfigurationOptions
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ConfigurationOptions = 0x0f;
|
|
}
|
|
|
|
if (EnumAll || RemainingDevicePath == NULL) {
|
|
//
|
|
// If IdeInit->EnumAll is TRUE or RemainingDevicePath is NULL,
|
|
// must enumerate all IDE devices anyway
|
|
//
|
|
BeginningIdeChannel = IdePrimary;
|
|
EndIdeChannel = IdeSecondary;
|
|
BeginningIdeDevice = IdeMaster;
|
|
EndIdeDevice = IdeSlave;
|
|
|
|
} else if (!IsDevicePathEnd (RemainingDevicePath)) {
|
|
//
|
|
// If RemainingDevicePath isn't the End of Device Path Node,
|
|
// only scan the specified device by RemainingDevicePath
|
|
//
|
|
Node = (EFI_DEV_PATH *) RemainingDevicePath;
|
|
BeginningIdeChannel = Node->Atapi.PrimarySecondary;
|
|
EndIdeChannel = BeginningIdeChannel;
|
|
BeginningIdeDevice = Node->Atapi.SlaveMaster;
|
|
EndIdeDevice = BeginningIdeDevice;
|
|
if (BeginningIdeChannel >= IdeMaxChannel || EndIdeChannel >= IdeMaxChannel) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto ErrorExit;
|
|
}
|
|
if (BeginningIdeDevice >= IdeMaxDevice|| EndIdeDevice >= IdeMaxDevice) {
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// If RemainingDevicePath is the End of Device Path Node,
|
|
// skip enumerate any device and return EFI_SUCCESS
|
|
//
|
|
BeginningIdeChannel = IdeMaxChannel;
|
|
EndIdeChannel = IdeMaxChannel - 1;
|
|
BeginningIdeDevice = IdeMaxDevice;
|
|
EndIdeDevice = IdeMaxDevice - 1;
|
|
}
|
|
|
|
//
|
|
// 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) MIN ((MaxDevices - 1), EndIdeDevice);
|
|
ASSERT (EndIdeDevice < IdeMaxDevice);
|
|
//
|
|
// 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
|
|
);
|
|
|
|
//
|
|
// Prepare to detect IDE device of this channel
|
|
//
|
|
InitializeIDEChannelData ();
|
|
|
|
//
|
|
// -- 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))) == 0) {
|
|
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 = (EFI_IDE_CHANNEL) IdeChannel;
|
|
IdeBlkIoDevicePtr->Device = (EFI_IDE_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_EX (
|
|
EFI_PROGRESS_CODE,
|
|
(EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
|
|
0,
|
|
&gEfiCallerIdGuid,
|
|
NULL,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Discover device, now!
|
|
//
|
|
PERF_START (NULL, "DiscoverIdeDevice", "IDE", 0);
|
|
Status = DiscoverIdeDevice (IdeBlkIoDevicePtr);
|
|
PERF_END (NULL, "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->IdData, sizeof (IdentifyData));
|
|
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 <= AtaPioMode2) {
|
|
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 cannot
|
|
// 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;
|
|
}
|
|
//
|
|
// Record Udma Mode
|
|
//
|
|
IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE;
|
|
IdeBlkIoDevicePtr->UdmaMode.Mode = SupportedModes->UdmaMode.Mode;
|
|
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
|
|
//
|
|
//Slice
|
|
ATA5_IDENTIFY_DATA * Ata5Data = (ATA5_IDENTIFY_DATA *)&IdeBlkIoDevicePtr->IdData->AtaData;
|
|
DriveParameters.Sector = (UINT8)Ata5Data->sectors_per_track;
|
|
DriveParameters.Heads = (UINT8)(Ata5Data->heads - 1);
|
|
DriveParameters.MultipleSector = (UINT8)Ata5Data->multi_sector_cmd_max_sct_cnt;
|
|
// DriveParameters.Sector = (UINT8) IdeBlkIoDevicePtr->IdData->AtaData.sectors_per_track;
|
|
// DriveParameters.Heads = (UINT8) (IdeBlkIoDevicePtr->IdData->AtaData.heads - 1);
|
|
//DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->IdData->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 = (ATA_PIO_MODE) 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_IDE_ATAPI_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 enabled!
|
|
//
|
|
REPORT_STATUS_CODE_WITH_DEVICE_PATH (
|
|
EFI_PROGRESS_CODE,
|
|
(EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE),
|
|
IdeBlkIoDevicePtr->DevicePath
|
|
);
|
|
|
|
//
|
|
// Create event to clear pending IDE interrupt
|
|
//
|
|
Status = gBS->CreateEventEx (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
ClearInterrupt,
|
|
IdeBlkIoDevicePtr,
|
|
&gEfiEventExitBootServicesGuid,
|
|
&IdeBlkIoDevicePtr->ExitBootServiceEvent
|
|
);
|
|
|
|
//
|
|
// 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) {
|
|
FreePool (SupportedModes);
|
|
}
|
|
|
|
PERF_START (NULL, "Finish IDE detection", "IDE", 1);
|
|
PERF_END (NULL, "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;
|
|
|
|
}
|
|
/**
|
|
Stop function of Driver Binding Protocol which is to stop the driver on Controller Handle and all
|
|
child handle attached to the controller handle if there are.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param Controller Handle of device to stop driver on
|
|
@param NumberOfChildren Not used
|
|
@param ChildHandleBuffer Not used
|
|
|
|
@retval EFI_SUCCESS This driver is removed DeviceHandle
|
|
@retval other This driver was not removed from this device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBusDriverBindingStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
BOOLEAN AllChildrenStopped;
|
|
UINTN Index;
|
|
IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
|
|
UINT64 Supports;
|
|
|
|
IdeBusDriverPrivateData = NULL;
|
|
|
|
if (NumberOfChildren == 0) {
|
|
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiPciIoProtocolGuid,
|
|
(VOID **) &PciIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Status = PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationSupported,
|
|
0,
|
|
&Supports
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
Supports &= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE;
|
|
PciIo->Attributes (
|
|
PciIo,
|
|
EfiPciIoAttributeOperationDisable,
|
|
Supports,
|
|
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;
|
|
}
|
|
|
|
/**
|
|
issue ATA or ATAPI command to reset a block IO device.
|
|
@param This Block IO protocol instance pointer.
|
|
@param ExtendedVerification If FALSE,for ATAPI device, driver will only invoke ATAPI reset method
|
|
If TRUE, for ATAPI device, driver need invoke ATA reset method after
|
|
invoke ATAPI reset method
|
|
|
|
@retval EFI_DEVICE_ERROR When the device is neighther ATA device or ATAPI device.
|
|
@retval EFI_SUCCESS The device reset successfully
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBlkIoReset (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
IDE_BLK_IO_DEV *IdeBlkIoDevice;
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
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 ||
|
|
IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
|
|
Status = AtaSoftReset (IdeBlkIoDevice);
|
|
goto Done;
|
|
}
|
|
|
|
if (IdeBlkIoDevice->Type == IdeUnknown) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// for ATAPI device, using ATAPI reset method
|
|
//
|
|
Status = AtapiSoftReset (IdeBlkIoDevice);
|
|
if (ExtendedVerification) {
|
|
Status = AtaSoftReset (IdeBlkIoDevice);
|
|
}
|
|
|
|
Done:
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Read data from a block IO device
|
|
|
|
@param This Block IO protocol instance pointer.
|
|
@param MediaId The media ID of the device
|
|
@param Lba Starting LBA address to read data
|
|
@param BufferSize The size of data to be read
|
|
@param Buffer Caller supplied buffer to save data
|
|
|
|
@retval EFI_DEVICE_ERROR unknown device type
|
|
@retval other read data status.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBlkIoReadBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
OUT VOID *Buffer
|
|
)
|
|
{
|
|
IDE_BLK_IO_DEV *IdeBlkIoDevice;
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
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) {
|
|
Status = AtaBlkIoReadBlocks (
|
|
IdeBlkIoDevice,
|
|
MediaId,
|
|
Lba,
|
|
BufferSize,
|
|
Buffer
|
|
);
|
|
goto Done;
|
|
}
|
|
|
|
if (IdeBlkIoDevice->Type == IdeUnknown) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// for ATAPI device, using ATAPI read block's mechanism
|
|
//
|
|
Status = AtapiBlkIoReadBlocks (
|
|
IdeBlkIoDevice,
|
|
MediaId,
|
|
Lba,
|
|
BufferSize,
|
|
Buffer
|
|
);
|
|
|
|
Done:
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Write data to block io device.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param MediaId The media ID of the device
|
|
@param Lba Starting LBA address to write data
|
|
@param BufferSize The size of data to be written
|
|
@param Buffer Caller supplied buffer to save data
|
|
|
|
@retval EFI_DEVICE_ERROR unknown device type
|
|
@retval other write data status
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBlkIoWriteBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This,
|
|
IN UINT32 MediaId,
|
|
IN EFI_LBA Lba,
|
|
IN UINTN BufferSize,
|
|
IN VOID *Buffer
|
|
)
|
|
{
|
|
IDE_BLK_IO_DEV *IdeBlkIoDevice;
|
|
EFI_STATUS Status;
|
|
EFI_TPL OldTpl;
|
|
|
|
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
|
|
|
|
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) {
|
|
|
|
Status = AtaBlkIoWriteBlocks (
|
|
IdeBlkIoDevice,
|
|
MediaId,
|
|
Lba,
|
|
BufferSize,
|
|
Buffer
|
|
);
|
|
goto Done;
|
|
}
|
|
|
|
if (IdeBlkIoDevice->Type == IdeUnknown) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// for ATAPI device, using ATAPI write block's mechanism
|
|
//
|
|
Status = AtapiBlkIoWriteBlocks (
|
|
IdeBlkIoDevice,
|
|
MediaId,
|
|
Lba,
|
|
BufferSize,
|
|
Buffer
|
|
);
|
|
|
|
Done:
|
|
gBS->RestoreTPL (OldTpl);
|
|
return Status;
|
|
}
|
|
/**
|
|
Flushes all modified data to a physical block devices
|
|
|
|
@param This Indicates a pointer to the calling context which to specify a
|
|
specific block device
|
|
|
|
@retval EFI_SUCCESS Always return success.
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEBlkIoFlushBlocks (
|
|
IN EFI_BLOCK_IO_PROTOCOL *This
|
|
)
|
|
{
|
|
//
|
|
// return directly
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get inquiry data.
|
|
Data format of Identify data is defined by the Interface GUID.
|
|
|
|
@param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param InquiryData Pointer to a buffer for the inquiry data.
|
|
@param InquiryDataSize Pointer to the value for the inquiry data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading InquiryData from device
|
|
@retval EFI_BUFFER_TOO_SMALL InquiryDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEDiskInfoInquiry (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *InquiryData,
|
|
IN OUT UINT32 *InquiryDataSize
|
|
)
|
|
{
|
|
IDE_BLK_IO_DEV *IdeBlkIoDevice;
|
|
|
|
IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
|
|
|
|
if (*InquiryDataSize < sizeof (ATAPI_INQUIRY_DATA)) {
|
|
*InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
if (IdeBlkIoDevice->InquiryData == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
gBS->CopyMem (InquiryData, IdeBlkIoDevice->InquiryData, sizeof (ATAPI_INQUIRY_DATA));
|
|
*InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get identify data.
|
|
Data format of Identify data is defined by the Interface GUID.
|
|
|
|
@param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param IdentifyData Pointer to a buffer for the identify data.
|
|
@param IdentifyDataSize Pointer to the value for the identify data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading IdentifyData from device
|
|
@retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEDiskInfoIdentify (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *IdentifyData,
|
|
IN OUT UINT32 *IdentifyDataSize
|
|
)
|
|
{
|
|
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->IdData == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
gBS->CopyMem (IdentifyData, IdeBlkIoDevice->IdData, sizeof (EFI_IDENTIFY_DATA));
|
|
*IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get sense data.
|
|
Data format of Sense data is defined by the Interface GUID.
|
|
|
|
@param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param SenseData Pointer to the SenseData.
|
|
@param SenseDataSize Size of SenseData in bytes.
|
|
@param SenseDataNumber Pointer to the value for the identify data size.
|
|
|
|
@retval EFI_SUCCESS The command was accepted without any errors.
|
|
@retval EFI_NOT_FOUND Device does not support this data class
|
|
@retval EFI_DEVICE_ERROR Error reading InquiryData from device
|
|
@retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEDiskInfoSenseData (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
IN OUT VOID *SenseData,
|
|
IN OUT UINT32 *SenseDataSize,
|
|
OUT UINT8 *SenseDataNumber
|
|
)
|
|
{
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
This function is used by the IDE bus driver to get controller information.
|
|
|
|
@param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
|
|
@param IdeChannel Pointer to the Ide Channel number. Primary or secondary.
|
|
@param IdeDevice Pointer to the Ide Device number. Master or slave.
|
|
|
|
@retval EFI_SUCCESS IdeChannel and IdeDevice are valid
|
|
@retval EFI_UNSUPPORTED This is not an IDE device
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
IDEDiskInfoWhichIde (
|
|
IN EFI_DISK_INFO_PROTOCOL *This,
|
|
OUT UINT32 *IdeChannel,
|
|
OUT UINT32 *IdeDevice
|
|
)
|
|
{
|
|
IDE_BLK_IO_DEV *IdeBlkIoDevice;
|
|
|
|
IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
|
|
*IdeChannel = IdeBlkIoDevice->Channel;
|
|
*IdeDevice = IdeBlkIoDevice->Device;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
The is an event(generally the event is exitBootService event) call back function.
|
|
Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
|
|
|
|
@param Event Pointer to this event
|
|
@param Context Event handler private data
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ClearInterrupt (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT64 IoPortForBmis;
|
|
UINT8 RegisterValue;
|
|
IDE_BLK_IO_DEV *IdeDev;
|
|
|
|
//
|
|
// Get our context
|
|
//
|
|
IdeDev = (IDE_BLK_IO_DEV *) Context;
|
|
|
|
//
|
|
// Obtain IDE IO port registers' base addresses
|
|
//
|
|
Status = ReassignIdeResources (IdeDev);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check whether interrupt is pending
|
|
//
|
|
|
|
//
|
|
// Reset IDE device to force it de-assert interrupt pin
|
|
// Note: this will reset all devices on this IDE channel
|
|
//
|
|
AtaSoftReset (IdeDev);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get base address of IDE Bus Master Status Register
|
|
//
|
|
if (IdePrimary == IdeDev->Channel) {
|
|
IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
|
|
} else {
|
|
if (IdeSecondary == IdeDev->Channel) {
|
|
IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
//
|
|
// 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
|
|
);
|
|
|
|
//
|
|
// Select the other device on this channel to ensure this device to release the interrupt pin
|
|
//
|
|
if (IdeDev->Device == 0) {
|
|
RegisterValue = (1 << 4) | 0xe0;
|
|
} else {
|
|
RegisterValue = (0 << 4) | 0xe0;
|
|
}
|
|
IDEWritePortB (
|
|
IdeDev->PciIo,
|
|
IdeDev->IoPort->Head,
|
|
RegisterValue
|
|
);
|
|
|
|
}
|
|
|
|
/**
|
|
The user Entry Point for module IdeBus. The user code starts with this function.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeIdeBus(
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
//
|
|
// Install driver model protocol(s).
|
|
//
|
|
Status = EfiLibInstallAllDriverProtocols2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gIDEBusDriverBinding,
|
|
ImageHandle,
|
|
&gIDEBusComponentName,
|
|
&gIDEBusComponentName2,
|
|
NULL,
|
|
NULL,
|
|
&gIDEBusDriverDiagnostics,
|
|
&gIDEBusDriverDiagnostics2
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
return Status;
|
|
}
|