2 Copyright (c) 2006, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 BOOLEAN ChannelDeviceDetected
= FALSE
;
16 BOOLEAN SlaveDeviceExist
= FALSE
;
17 UINT8 SlaveDeviceType
= INVALID_DEVICE_TYPE
;
18 BOOLEAN MasterDeviceExist
= FALSE
;
19 UINT8 MasterDeviceType
= INVALID_DEVICE_TYPE
;
22 TODO: Add function description
24 @param PciIo TODO: add argument description
25 @param Port TODO: add argument description
27 TODO: add return values
32 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
40 // perform 1-byte data read from register
45 EFI_PCI_IO_PASS_THROUGH_BAR
,
54 Reads multiple words of data from the IDE data port.
55 Call the IO abstraction once to do the complete read,
56 not one word at a time
58 @param PciIo Pointer to the EFI_PCI_IO instance
59 @param Port IO port to read
60 @param Count No. of UINT16's to read
61 @param Buffer Pointer to the data buffer for read
65 IDEReadPortWMultiple (
66 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
72 UINT16
*AlignedBuffer
;
73 UINT16
*WorkingBuffer
;
77 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
78 // not perform actual I/O operations if buffer pointer passed in is not at
79 // natural boundary. The "Buffer" argument is passed in by user and may not
80 // at 16-bit natural boundary.
82 Size
= sizeof (UINT16
) * Count
;
87 (VOID
**)&WorkingBuffer
90 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
93 // Perform UINT16 data read from FIFO
97 EfiPciIoWidthFifoUint16
,
98 EFI_PCI_IO_PASS_THROUGH_BAR
,
101 (UINT16
*)AlignedBuffer
105 // Copy data to user buffer
107 CopyMem (Buffer
, (UINT16
*)AlignedBuffer
, Size
);
108 gBS
->FreePool (WorkingBuffer
);
112 TODO: Add function description
114 @param PciIo TODO: add argument description
115 @param Port TODO: add argument description
116 @param Data TODO: add argument description
118 TODO: add return values
123 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
129 // perform 1-byte data write to register
134 EFI_PCI_IO_PASS_THROUGH_BAR
,
143 TODO: Add function description
145 @param PciIo TODO: add argument description
146 @param Port TODO: add argument description
147 @param Data TODO: add argument description
149 TODO: add return values
154 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
160 // perform 1-word data write to register
165 EFI_PCI_IO_PASS_THROUGH_BAR
,
173 Write multiple words of data to the IDE data port.
174 Call the IO abstraction once to do the complete read,
175 not one word at a time
177 @param PciIo Pointer to the EFI_PCI_IO instance
178 @param Port IO port to read
179 @param Count No. of UINT16's to read
180 @param Buffer Pointer to the data buffer for read
184 IDEWritePortWMultiple (
185 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
191 UINT16
*AlignedBuffer
;
192 UINT32
*WorkingBuffer
;
196 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
197 // not perform actual I/O operations if buffer pointer passed in is not at
198 // natural boundary. The "Buffer" argument is passed in by user and may not
199 // at 16-bit natural boundary.
201 Size
= sizeof (UINT16
) * Count
;
206 (VOID
**) &WorkingBuffer
209 AlignedBuffer
= (UINT16
*) ((UINTN
)(((UINTN
) WorkingBuffer
+ 0x1) & (~0x1)));
212 // Copy data from user buffer to working buffer
214 CopyMem ((UINT16
*) AlignedBuffer
, Buffer
, Size
);
217 // perform UINT16 data write to the FIFO
221 EfiPciIoWidthFifoUint16
,
222 EFI_PCI_IO_PASS_THROUGH_BAR
,
225 (UINT16
*) AlignedBuffer
228 gBS
->FreePool (WorkingBuffer
);
232 TODO: Add function description
234 @param IdeDev TODO: add argument description
236 TODO: add return values
242 IN IDE_BLK_IO_DEV
*IdeDev
246 // check whether all registers return 0xff,
247 // if so, deem the channel is disabled.
251 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Data
) != 0xff) {
255 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
) != 0xff) {
259 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
) != 0xff) {
263 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
) != 0xff) {
267 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
) != 0xff) {
271 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
) != 0xff) {
275 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
) != 0xff) {
279 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
) != 0xff) {
283 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
) != 0xff) {
297 // GetIdeRegistersBaseAddr
300 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
301 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
302 the PCI IDE controller's Configuration Space.
304 The steps to get IDE IO port registers' base addresses for each channel
307 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
308 controller's Configuration Space to determine the operating mode.
310 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
312 ___________________________________________
313 | | Command Block | Control Block |
314 | Channel | Registers | Registers |
315 |___________|_______________|_______________|
316 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
317 |___________|_______________|_______________|
318 | Secondary | 170h - 177h | 376h - 377h |
319 |___________|_______________|_______________|
321 Table 1. Compatibility resource mappings
324 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
325 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
327 ___________________________________________________
328 | | Command Block | Control Block |
329 | Channel | Registers | Registers |
330 |___________|___________________|___________________|
331 | Primary | BAR at offset 0x10| BAR at offset 0x14|
332 |___________|___________________|___________________|
333 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
334 |___________|___________________|___________________|
336 Table 2. BARs for Register Mapping
338 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
339 primary, 0374h for secondary. So 2 bytes extra offset should be
340 added to the base addresses read from BARs.
342 For more details, please refer to PCI IDE Controller Specification and Intel
345 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
346 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
347 receive IDE IO port registers' base addresses
351 GetIdeRegistersBaseAddr (
352 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
353 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
355 // TODO: EFI_UNSUPPORTED - add return value to function comment
356 // TODO: EFI_UNSUPPORTED - add return value to function comment
357 // TODO: EFI_SUCCESS - add return value to function comment
362 Status
= PciIo
->Pci
.Read (
370 if (EFI_ERROR (Status
)) {
374 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
375 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
376 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
377 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
378 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
381 // The BARs should be of IO type
383 if ((PciData
.Device
.Bar
[0] & bit0
) == 0 ||
384 (PciData
.Device
.Bar
[1] & bit0
) == 0) {
385 return EFI_UNSUPPORTED
;
388 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
389 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
390 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
391 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
392 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
393 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
396 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
397 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
398 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
399 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
400 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
403 // The BARs should be of IO type
405 if ((PciData
.Device
.Bar
[2] & bit0
) == 0 ||
406 (PciData
.Device
.Bar
[3] & bit0
) == 0) {
407 return EFI_UNSUPPORTED
;
410 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
411 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
412 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
413 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
414 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
415 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
422 This function is used to requery IDE resources. The IDE controller will
423 probably switch between native and legacy modes during the EFI->CSM->OS
424 transfer. We do this everytime before an BlkIo operation to ensure its
427 @param IdeDev The BLK_IO private data which specifies the IDE device
431 ReassignIdeResources (
432 IN IDE_BLK_IO_DEV
*IdeDev
434 // TODO: EFI_SUCCESS - add return value to function comment
437 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
438 UINT16 CommandBlockBaseAddr
;
439 UINT16 ControlBlockBaseAddr
;
442 // Requery IDE IO port registers' base addresses in case of the switch of
443 // native and legacy modes
445 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
446 if (EFI_ERROR (Status
)) {
450 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
451 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
452 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
454 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
455 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
456 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
457 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
458 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
459 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
460 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
462 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
463 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
464 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
465 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
467 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
475 Detect if there is disk connected to this port
477 @param IdeDev The BLK_IO private data which specifies the IDE device
482 IN IDE_BLK_IO_DEV
*IdeDev
484 // TODO: EFI_NOT_FOUND - add return value to function comment
485 // TODO: EFI_NOT_FOUND - add return value to function comment
486 // TODO: EFI_SUCCESS - add return value to function comment
491 // If a channel has not been checked, check it now. Then set it to "checked" state
492 // After this step, all devices in this channel have been checked.
494 if (ChannelDeviceDetected
== FALSE
) {
495 Status
= DetectIDEController (IdeDev
);
496 if (EFI_ERROR (Status
)) {
497 return EFI_NOT_FOUND
;
501 Status
= EFI_NOT_FOUND
;
504 // Device exists. test if it is an ATA device.
505 // Prefer the result from DetectIDEController,
506 // if failed, try another device type to handle
507 // devices that not follow the spec.
509 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
510 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
511 Status
= ATAIdentify (IdeDev
);
512 if (EFI_ERROR (Status
)) {
513 Status
= ATAPIIdentify (IdeDev
);
514 if (!EFI_ERROR (Status
)) {
515 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
519 Status
= ATAPIIdentify (IdeDev
);
520 if (EFI_ERROR (Status
)) {
521 Status
= ATAIdentify (IdeDev
);
522 if (!EFI_ERROR (Status
)) {
523 MasterDeviceType
= ATA_DEVICE_TYPE
;
528 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
529 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
530 Status
= ATAIdentify (IdeDev
);
531 if (EFI_ERROR (Status
)) {
532 Status
= ATAPIIdentify (IdeDev
);
533 if (!EFI_ERROR (Status
)) {
534 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
538 Status
= ATAPIIdentify (IdeDev
);
539 if (EFI_ERROR (Status
)) {
540 Status
= ATAIdentify (IdeDev
);
541 if (!EFI_ERROR (Status
)) {
542 SlaveDeviceType
= ATA_DEVICE_TYPE
;
547 if (EFI_ERROR (Status
)) {
548 return EFI_NOT_FOUND
;
551 // Init Block I/O interface
553 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
554 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
555 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
556 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
557 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
559 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
560 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
563 // Init Disk Info interface
565 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
566 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
567 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
568 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
569 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
575 This interface is used to initialize all state data related to the detection of one
578 @retval EFI_SUCCESS Completed Successfully.
582 InitializeIDEChannelData (
586 ChannelDeviceDetected
= FALSE
;
587 MasterDeviceExist
= FALSE
;
588 MasterDeviceType
= 0xff;
589 SlaveDeviceExist
= FALSE
;
590 SlaveDeviceType
= 0xff;
595 This function is called by DiscoverIdeDevice(). It is used for detect
596 whether the IDE device exists in the specified Channel as the specified
599 There is two IDE channels: one is Primary Channel, the other is
600 Secondary Channel.(Channel is the logical name for the physical "Cable".)
601 Different channel has different register group.
603 On each IDE channel, at most two IDE devices attach,
604 one is called Device 0 (Master device), the other is called Device 1
605 (Slave device). The devices on the same channel co-use the same register
606 group, so before sending out a command for a specified device via command
607 register, it is a must to select the current device to accept the command
608 by set the device number in the Head/Device Register.
611 pointer pointing to IDE_BLK_IO_DEV data structure, used
612 to record all the information of the IDE device.
615 successfully detects device.
618 any failure during detection process will return this
622 TODO: EFI_SUCCESS - add return value to function comment
623 TODO: EFI_NOT_FOUND - add return value to function comment
627 DetectIDEController (
628 IN IDE_BLK_IO_DEV
*IdeDev
632 UINT8 SectorCountReg
;
640 // Select slave device
644 IdeDev
->IoPort
->Head
,
645 (UINT8
) ((1 << 4) | 0xe0)
650 // Save the init slave status register
652 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
655 // Select Master back
659 IdeDev
->IoPort
->Head
,
660 (UINT8
) ((0 << 4) | 0xe0)
665 // Send ATA Device Execut Diagnostic command.
666 // This command should work no matter DRDY is ready or not
668 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
670 Status
= WaitForBSYClear (IdeDev
, 3500);
671 if (EFI_ERROR (Status
)) {
672 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
676 // Read device signature
683 IdeDev
->IoPort
->Head
,
684 (UINT8
) ((0 << 4) | 0xe0)
687 SectorCountReg
= IDEReadPortB (
689 IdeDev
->IoPort
->SectorCount
691 LBALowReg
= IDEReadPortB (
693 IdeDev
->IoPort
->SectorNumber
695 LBAMidReg
= IDEReadPortB (
697 IdeDev
->IoPort
->CylinderLsb
699 LBAHighReg
= IDEReadPortB (
701 IdeDev
->IoPort
->CylinderMsb
703 if ((SectorCountReg
== 0x1) &&
704 (LBALowReg
== 0x1) &&
705 (LBAMidReg
== 0x0) &&
706 (LBAHighReg
== 0x0)) {
707 MasterDeviceExist
= TRUE
;
708 MasterDeviceType
= ATA_DEVICE_TYPE
;
710 if ((LBAMidReg
== 0x14) &&
711 (LBAHighReg
== 0xeb)) {
712 MasterDeviceExist
= TRUE
;
713 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
718 // For some Hard Drive, it takes some time to get
719 // the right signature when operating in single slave mode.
720 // We stall 20ms to work around this.
722 if (!MasterDeviceExist
) {
731 IdeDev
->IoPort
->Head
,
732 (UINT8
) ((1 << 4) | 0xe0)
735 SectorCountReg
= IDEReadPortB (
737 IdeDev
->IoPort
->SectorCount
739 LBALowReg
= IDEReadPortB (
741 IdeDev
->IoPort
->SectorNumber
743 LBAMidReg
= IDEReadPortB (
745 IdeDev
->IoPort
->CylinderLsb
747 LBAHighReg
= IDEReadPortB (
749 IdeDev
->IoPort
->CylinderMsb
751 StatusReg
= IDEReadPortB (
753 IdeDev
->IoPort
->Reg
.Status
755 if ((SectorCountReg
== 0x1) &&
756 (LBALowReg
== 0x1) &&
757 (LBAMidReg
== 0x0) &&
758 (LBAHighReg
== 0x0)) {
759 SlaveDeviceExist
= TRUE
;
760 SlaveDeviceType
= ATA_DEVICE_TYPE
;
762 if ((LBAMidReg
== 0x14) &&
763 (LBAHighReg
== 0xeb)) {
764 SlaveDeviceExist
= TRUE
;
765 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
770 // When single master is plugged, slave device
771 // will be wrongly detected. Here's the workaround
772 // for ATA devices by detecting DRY bit in status
774 // NOTE: This workaround doesn't apply to ATAPI.
776 if (MasterDeviceExist
&& SlaveDeviceExist
&&
777 (StatusReg
& DRDY
) == 0 &&
778 (InitStatusReg
& DRDY
) == 0 &&
779 MasterDeviceType
== SlaveDeviceType
&&
780 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
781 SlaveDeviceExist
= FALSE
;
785 // Indicate this channel has been detected
787 ChannelDeviceDetected
= TRUE
;
792 This function is used to poll for the DRQ bit clear in the Status
793 Register. DRQ is cleared when the device is finished transferring data.
794 So this function is called after data transfer is finished.
797 pointer pointing to IDE_BLK_IO_DEV data structure, used
798 to record all the information of the IDE device.
800 @param[in] TimeoutInMilliSeconds
801 used to designate the timeout for the DRQ clear.
804 DRQ bit clear within the time out.
807 DRQ bit not clear within the time out.
810 Read Status Register will clear interrupt status.
815 IN IDE_BLK_IO_DEV
*IdeDev
,
816 IN UINTN TimeoutInMilliSeconds
818 // TODO: function comment is missing 'Routine Description:'
819 // TODO: function comment is missing 'Arguments:'
820 // TODO: IdeDev - add argument and description to function comment
821 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
822 // TODO: EFI_ABORTED - add return value to function comment
825 UINT8 StatusRegister
;
828 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
831 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
834 // wait for BSY == 0 and DRQ == 0
836 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
840 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
842 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
843 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
865 This function is used to poll for the DRQ bit clear in the Alternate
866 Status Register. DRQ is cleared when the device is finished
867 transferring data. So this function is called after data transfer
871 pointer pointing to IDE_BLK_IO_DEV data structure, used
872 to record all the information of the IDE device.
874 @param[in] TimeoutInMilliSeconds
875 used to designate the timeout for the DRQ clear.
878 DRQ bit clear within the time out.
881 DRQ bit not clear within the time out.
884 Read Alternate Status Register will not clear interrupt status.
889 IN IDE_BLK_IO_DEV
*IdeDev
,
890 IN UINTN TimeoutInMilliSeconds
892 // TODO: function comment is missing 'Routine Description:'
893 // TODO: function comment is missing 'Arguments:'
894 // TODO: IdeDev - add argument and description to function comment
895 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
896 // TODO: EFI_ABORTED - add return value to function comment
902 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
905 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
908 // wait for BSY == 0 and DRQ == 0
910 if ((AltRegister
& (DRQ
| BSY
)) == 0) {
914 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
916 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
917 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
939 This function is used to poll for the DRQ bit set in the
941 DRQ is set when the device is ready to transfer data. So this function
942 is called after the command is sent to the device and before required
945 @param[in] IDE_BLK_IO_DEV IN *IdeDev
946 pointer pointing to IDE_BLK_IO_DEV data structure,used
947 to record all the information of the IDE device.
949 @param[in] UINTN IN TimeoutInMilliSeconds
950 used to designate the timeout for the DRQ ready.
953 DRQ bit set within the time out.
956 DRQ bit not set within the time out.
959 DRQ bit not set caused by the command abort.
962 Read Status Register will clear interrupt status.
967 IN IDE_BLK_IO_DEV
*IdeDev
,
968 IN UINTN TimeoutInMilliSeconds
970 // TODO: function comment is missing 'Routine Description:'
971 // TODO: function comment is missing 'Arguments:'
972 // TODO: IdeDev - add argument and description to function comment
973 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
976 UINT8 StatusRegister
;
979 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
982 // read Status Register will clear interrupt
984 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
989 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
993 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
995 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
996 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1017 This function is used to poll for the DRQ bit set in the
1018 Alternate Status Register. DRQ is set when the device is ready to
1019 transfer data. So this function is called after the command
1020 is sent to the device and before required data is transferred.
1022 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1023 pointer pointing to IDE_BLK_IO_DEV data structure, used
1024 to record all the information of the IDE device.
1026 @param[in] UINTN IN TimeoutInMilliSeconds
1027 used to designate the timeout for the DRQ ready.
1030 DRQ bit set within the time out.
1033 DRQ bit not set within the time out.
1036 DRQ bit not set caused by the command abort.
1039 Read Alternate Status Register will not clear interrupt status.
1044 IN IDE_BLK_IO_DEV
*IdeDev
,
1045 IN UINTN TimeoutInMilliSeconds
1047 // TODO: function comment is missing 'Routine Description:'
1048 // TODO: function comment is missing 'Arguments:'
1049 // TODO: IdeDev - add argument and description to function comment
1050 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1054 UINT8 ErrorRegister
;
1056 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1060 // Read Alternate Status Register will not clear interrupt status
1062 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1064 // BSY == 0 , DRQ == 1
1066 if ((AltRegister
& (BSY
| DRQ
)) == DRQ
) {
1070 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1072 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1073 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1094 This function is used to poll for the BSY bit clear in the
1095 Status Register. BSY is clear when the device is not busy.
1096 Every command must be sent after device is not busy.
1098 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1099 pointer pointing to IDE_BLK_IO_DEV data structure, used
1100 to record all the information of the IDE device.
1102 @param[in] UINTN IN TimeoutInMilliSeconds
1103 used to designate the timeout for the DRQ ready.
1106 BSY bit clear within the time out.
1109 BSY bit not clear within the time out.
1112 Read Status Register will clear interrupt status.
1117 IN IDE_BLK_IO_DEV
*IdeDev
,
1118 IN UINTN TimeoutInMilliSeconds
1120 // TODO: function comment is missing 'Routine Description:'
1121 // TODO: function comment is missing 'Arguments:'
1122 // TODO: IdeDev - add argument and description to function comment
1123 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1126 UINT8 StatusRegister
;
1128 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1131 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1132 if ((StatusRegister
& BSY
) == 0x00) {
1155 This function is used to poll for the BSY bit clear in the
1156 Alternate Status Register. BSY is clear when the device is not busy.
1157 Every command must be sent after device is not busy.
1159 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1160 pointer pointing to IDE_BLK_IO_DEV data structure, used
1161 to record all the information of the IDE device.
1163 @param[in] UINTN IN TimeoutInMilliSeconds
1164 used to designate the timeout for the DRQ ready.
1167 BSY bit clear within the time out.
1170 BSY bit not clear within the time out.
1173 Read Alternate Status Register will not clear interrupt status.
1178 IN IDE_BLK_IO_DEV
*IdeDev
,
1179 IN UINTN TimeoutInMilliSeconds
1181 // TODO: function comment is missing 'Routine Description:'
1182 // TODO: function comment is missing 'Arguments:'
1183 // TODO: IdeDev - add argument and description to function comment
1184 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1189 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1191 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1192 if ((AltRegister
& BSY
) == 0x00) {
1213 This function is used to poll for the DRDY bit set in the
1214 Status Register. DRDY bit is set when the device is ready
1215 to accept command. Most ATA commands must be sent after
1216 DRDY set except the ATAPI Packet Command.
1218 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1219 pointer pointing to IDE_BLK_IO_DEV data structure, used
1220 to record all the information of the IDE device.
1222 @param[in] UINTN IN TimeoutInMilliSeconds
1223 used to designate the timeout for the DRQ ready.
1226 DRDY bit set within the time out.
1229 DRDY bit not set within the time out.
1232 Read Status Register will clear interrupt status.
1237 IN IDE_BLK_IO_DEV
*IdeDev
,
1238 IN UINTN DelayInMilliSeconds
1240 // TODO: function comment is missing 'Routine Description:'
1241 // TODO: function comment is missing 'Arguments:'
1242 // TODO: IdeDev - add argument and description to function comment
1243 // TODO: DelayInMilliSeconds - add argument and description to function comment
1244 // TODO: EFI_ABORTED - add return value to function comment
1247 UINT8 StatusRegister
;
1248 UINT8 ErrorRegister
;
1250 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1252 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1254 // BSY == 0 , DRDY == 1
1256 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1260 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1262 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1263 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1284 This function is used to poll for the DRDY bit set in the
1285 Alternate Status Register. DRDY bit is set when the device is ready
1286 to accept command. Most ATA commands must be sent after
1287 DRDY set except the ATAPI Packet Command.
1289 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1290 pointer pointing to IDE_BLK_IO_DEV data structure, used
1291 to record all the information of the IDE device.
1293 @param[in] UINTN IN TimeoutInMilliSeconds
1294 used to designate the timeout for the DRQ ready.
1297 DRDY bit set within the time out.
1300 DRDY bit not set within the time out.
1303 Read Alternate Status Register will clear interrupt status.
1308 IN IDE_BLK_IO_DEV
*IdeDev
,
1309 IN UINTN DelayInMilliSeconds
1311 // TODO: function comment is missing 'Routine Description:'
1312 // TODO: function comment is missing 'Arguments:'
1313 // TODO: IdeDev - add argument and description to function comment
1314 // TODO: DelayInMilliSeconds - add argument and description to function comment
1315 // TODO: EFI_ABORTED - add return value to function comment
1319 UINT8 ErrorRegister
;
1321 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1323 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1325 // BSY == 0 , DRDY == 1
1327 if ((AltRegister
& (DRDY
| BSY
)) == DRDY
) {
1331 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1333 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1334 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1355 This function is a helper function used to change the char order in a
1356 string. It is designed specially for the PrintAtaModuleName() function.
1357 After the IDE device is detected, the IDE driver gets the device module
1358 name by sending ATA command called ATA Identify Command or ATAPI
1359 Identify Command to the specified IDE device. The module name returned
1360 is a string of ASCII characters: the first character is bit8--bit15
1361 of the first word, the second character is bit0--bit7 of the first word
1362 and so on. Thus the string can not be print directly before it is
1363 preprocessed by this func to change the order of characters in
1364 each word in the string.
1366 @param[in] CHAR8 IN *Destination
1367 Indicates the destination string.
1369 @param[in] CHAR8 IN *Source
1370 Indicates the source string.
1372 @param[in] UINT8 IN Size
1373 the length of the string
1378 IN CHAR8
*Destination
,
1386 for (Index
= 0; Index
< Size
; Index
+= 2) {
1388 Temp
= Source
[Index
+ 1];
1389 Destination
[Index
+ 1] = Source
[Index
];
1390 Destination
[Index
] = Temp
;
1395 // ReleaseIdeResources
1398 Release resources of an IDE device before stopping it.
1400 @param[in] *IdeBlkIoDevice Standard IDE device private data structure
1404 ReleaseIdeResources (
1405 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1408 if (IdeBlkIoDevice
== NULL
) {
1413 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1416 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1417 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1418 IdeBlkIoDevice
->SenseData
= NULL
;
1421 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1422 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1423 IdeBlkIoDevice
->Cache
= NULL
;
1426 if (IdeBlkIoDevice
->pIdData
!= NULL
) {
1427 gBS
->FreePool (IdeBlkIoDevice
->pIdData
);
1428 IdeBlkIoDevice
->pIdData
= NULL
;
1431 if (IdeBlkIoDevice
->pInquiryData
!= NULL
) {
1432 gBS
->FreePool (IdeBlkIoDevice
->pInquiryData
);
1433 IdeBlkIoDevice
->pInquiryData
= NULL
;
1436 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1437 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1438 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1441 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1442 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1445 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1446 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1449 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1450 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1451 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1454 gBS
->FreePool (IdeBlkIoDevice
);
1455 IdeBlkIoDevice
= NULL
;
1461 // SetDeviceTransferMode
1464 Set the calculated Best transfer mode to a detected device
1466 @param[in] *IdeDev Standard IDE device private data structure
1467 @param[in] *TransferMode The device transfer mode to be set
1469 @return Set transfer mode Command execute status
1473 SetDeviceTransferMode (
1474 IN IDE_BLK_IO_DEV
*IdeDev
,
1475 IN ATA_TRANSFER_MODE
*TransferMode
1477 // TODO: function comment is missing 'Routine Description:'
1484 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1485 SectorCount
= *((UINT8
*) TransferMode
);
1488 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1490 Status
= AtaNonDataCommandIn (
1505 Send ATA command into device with NON_DATA protocol
1507 @param IdeDev Standard IDE device private data structure
1508 @param AtaCommand The ATA command to be sent
1509 @param Device The value in Device register
1510 @param Feature The value in Feature register
1511 @param SectorCount The value in SectorCount register
1512 @param LbaLow The value in LBA_LOW register
1513 @param LbaMiddle The value in LBA_MIDDLE register
1514 @param LbaHigh The value in LBA_HIGH register
1516 @retval EFI_SUCCESS Reading succeed
1517 @retval EFI_ABORTED Command failed
1518 @retval EFI_DEVICE_ERROR Device status error
1522 AtaNonDataCommandIn (
1523 IN IDE_BLK_IO_DEV
*IdeDev
,
1524 IN UINT8 AtaCommand
,
1527 IN UINT8 SectorCount
,
1534 UINT8 StatusRegister
;
1536 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1537 if (EFI_ERROR (Status
)) {
1538 return EFI_DEVICE_ERROR
;
1542 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1546 IdeDev
->IoPort
->Head
,
1547 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1551 // ATA commands for ATA device must be issued when DRDY is set
1553 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1554 if (EFI_ERROR (Status
)) {
1555 return EFI_DEVICE_ERROR
;
1559 // Pass parameter into device register block
1561 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1562 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1563 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1564 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1565 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1566 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1569 // Send command via Command Register
1571 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1574 // Wait for command completion
1575 // For ATA_SMART_CMD, we may need more timeout to let device
1576 // adjust internal states.
1578 if (AtaCommand
== ATA_SMART_CMD
) {
1579 Status
= WaitForBSYClear (IdeDev
, ATASMARTTIMEOUT
);
1581 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1583 if (EFI_ERROR (Status
)) {
1584 return EFI_DEVICE_ERROR
;
1587 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1588 if ((StatusRegister
& ERR
) == ERR
) {
1590 // Failed to execute command, abort operation
1599 Send ATA Ext command into device with NON_DATA protocol
1601 @param IdeDev Standard IDE device private data structure
1602 @param AtaCommand The ATA command to be sent
1603 @param Device The value in Device register
1604 @param Feature The value in Feature register
1605 @param SectorCount The value in SectorCount register
1606 @param LbaAddress The LBA address in 48-bit mode
1608 @retval EFI_SUCCESS Reading succeed
1609 @retval EFI_ABORTED Command failed
1610 @retval EFI_DEVICE_ERROR Device status error
1614 AtaNonDataCommandInExt (
1615 IN IDE_BLK_IO_DEV
*IdeDev
,
1616 IN UINT8 AtaCommand
,
1619 IN UINT16 SectorCount
,
1620 IN EFI_LBA LbaAddress
1624 UINT8 StatusRegister
;
1631 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1632 if (EFI_ERROR (Status
)) {
1633 return EFI_DEVICE_ERROR
;
1637 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1641 IdeDev
->IoPort
->Head
,
1642 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1646 // ATA commands for ATA device must be issued when DRDY is set
1648 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1649 if (EFI_ERROR (Status
)) {
1650 return EFI_DEVICE_ERROR
;
1654 // Pass parameter into device register block
1656 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1659 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1661 Feature8
= (UINT8
) (Feature
>> 8);
1662 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1664 Feature8
= (UINT8
) Feature
;
1665 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1668 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1670 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1671 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1673 SectorCount8
= (UINT8
) SectorCount
;
1674 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1677 // Fill the start LBA registers, which are also two-byte FIFO
1679 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1680 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1681 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1682 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1683 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1684 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1686 LbaLow
= (UINT8
) LbaAddress
;
1687 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1688 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1689 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1690 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1691 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1694 // Send command via Command Register
1696 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1699 // Wait for command completion
1701 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1702 if (EFI_ERROR (Status
)) {
1703 return EFI_DEVICE_ERROR
;
1706 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1707 if ((StatusRegister
& ERR
) == ERR
) {
1709 // Failed to execute command, abort operation
1718 // SetDriveParameters
1721 Set drive parameters for devices not support PACKETS command
1723 @param[in] IdeDev Standard IDE device private data structure
1724 @param[in] DriveParameters The device parameters to be set into the disk
1726 @return SetParameters Command execute status
1730 SetDriveParameters (
1731 IN IDE_BLK_IO_DEV
*IdeDev
,
1732 IN ATA_DRIVE_PARMS
*DriveParameters
1739 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1742 // Send Init drive parameters
1744 Status
= AtaNonDataCommandIn (
1746 INIT_DRIVE_PARAM_CMD
,
1747 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1749 DriveParameters
->Sector
,
1756 // Send Set Multiple parameters
1758 Status
= AtaNonDataCommandIn (
1760 SET_MULTIPLE_MODE_CMD
,
1763 DriveParameters
->MultipleSector
,
1772 TODO: Add function description
1774 @param IdeDev TODO: add argument description
1776 @retval EFI_SUCCESS TODO: Add description for return value
1781 IN IDE_BLK_IO_DEV
*IdeDev
1784 UINT8 DeviceControl
;
1787 // Enable interrupt for DMA operation
1790 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);
1796 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
1798 @param[in] Event Pointer to this event
1799 @param[in] Context Event hanlder private data
1810 UINT64 IoPortForBmis
;
1811 UINT8 RegisterValue
;
1812 IDE_BLK_IO_DEV
*IdeDev
;
1817 IdeDev
= (IDE_BLK_IO_DEV
*) Context
;
1820 // Obtain IDE IO port registers' base addresses
1822 Status
= ReassignIdeResources (IdeDev
);
1823 if (EFI_ERROR (Status
)) {
1828 // Check whether interrupt is pending
1832 // Reset IDE device to force it de-assert interrupt pin
1833 // Note: this will reset all devices on this IDE channel
1835 AtaSoftReset (IdeDev
);
1836 if (EFI_ERROR (Status
)) {
1841 // Get base address of IDE Bus Master Status Regsiter
1843 if (IdePrimary
== IdeDev
->Channel
) {
1844 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISP_OFFSET
;
1846 if (IdeSecondary
== IdeDev
->Channel
) {
1847 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISS_OFFSET
;
1853 // Read BMIS register and clear ERROR and INTR bit
1855 IdeDev
->PciIo
->Io
.Read (
1858 EFI_PCI_IO_PASS_THROUGH_BAR
,
1864 RegisterValue
|= (BMIS_INTERRUPT
| BMIS_ERROR
);
1866 IdeDev
->PciIo
->Io
.Write (
1869 EFI_PCI_IO_PASS_THROUGH_BAR
,
1876 // Select the other device on this channel to ensure this device to release the interrupt pin
1878 if (IdeDev
->Device
== 0) {
1879 RegisterValue
= (1 << 4) | 0xe0;
1881 RegisterValue
= (0 << 4) | 0xe0;
1885 IdeDev
->IoPort
->Head
,