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
241 IN IDE_BLK_IO_DEV
*IdeDev
245 // check whether all registers return 0xff,
246 // if so, deem the channel is disabled.
250 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Data
) != 0xff) {
254 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
) != 0xff) {
258 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
) != 0xff) {
262 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
) != 0xff) {
266 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
) != 0xff) {
270 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
) != 0xff) {
274 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
) != 0xff) {
278 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
) != 0xff) {
282 if (IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
) != 0xff) {
296 // GetIdeRegistersBaseAddr
299 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
300 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
301 the PCI IDE controller's Configuration Space.
303 The steps to get IDE IO port registers' base addresses for each channel
306 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
307 controller's Configuration Space to determine the operating mode.
309 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
311 ___________________________________________
312 | | Command Block | Control Block |
313 | Channel | Registers | Registers |
314 |___________|_______________|_______________|
315 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
316 |___________|_______________|_______________|
317 | Secondary | 170h - 177h | 376h - 377h |
318 |___________|_______________|_______________|
320 Table 1. Compatibility resource mappings
323 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
324 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
326 ___________________________________________________
327 | | Command Block | Control Block |
328 | Channel | Registers | Registers |
329 |___________|___________________|___________________|
330 | Primary | BAR at offset 0x10| BAR at offset 0x14|
331 |___________|___________________|___________________|
332 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
333 |___________|___________________|___________________|
335 Table 2. BARs for Register Mapping
337 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
338 primary, 0374h for secondary. So 2 bytes extra offset should be
339 added to the base addresses read from BARs.
341 For more details, please refer to PCI IDE Controller Specification and Intel
344 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
345 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
346 receive IDE IO port registers' base addresses
350 GetIdeRegistersBaseAddr (
351 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
352 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
354 // TODO: EFI_UNSUPPORTED - add return value to function comment
355 // TODO: EFI_UNSUPPORTED - add return value to function comment
356 // TODO: EFI_SUCCESS - add return value to function comment
361 Status
= PciIo
->Pci
.Read (
369 if (EFI_ERROR (Status
)) {
373 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
374 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
375 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
376 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
377 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
380 // The BARs should be of IO type
382 if ((PciData
.Device
.Bar
[0] & bit0
) == 0 ||
383 (PciData
.Device
.Bar
[1] & bit0
) == 0) {
384 return EFI_UNSUPPORTED
;
387 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
388 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
389 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
390 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
391 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
392 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
395 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
396 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
397 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
398 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
399 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
402 // The BARs should be of IO type
404 if ((PciData
.Device
.Bar
[2] & bit0
) == 0 ||
405 (PciData
.Device
.Bar
[3] & bit0
) == 0) {
406 return EFI_UNSUPPORTED
;
409 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
410 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
411 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
412 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
413 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
414 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
421 This function is used to requery IDE resources. The IDE controller will
422 probably switch between native and legacy modes during the EFI->CSM->OS
423 transfer. We do this everytime before an BlkIo operation to ensure its
426 @param IdeDev The BLK_IO private data which specifies the IDE device
430 ReassignIdeResources (
431 IN IDE_BLK_IO_DEV
*IdeDev
433 // TODO: EFI_SUCCESS - add return value to function comment
436 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
437 UINT16 CommandBlockBaseAddr
;
438 UINT16 ControlBlockBaseAddr
;
441 // Requery IDE IO port registers' base addresses in case of the switch of
442 // native and legacy modes
444 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
445 if (EFI_ERROR (Status
)) {
449 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
450 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
451 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
453 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
454 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
455 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
456 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
457 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
458 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
459 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
461 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
462 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
463 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
464 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
466 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
474 Detect if there is disk connected to this port
476 @param IdeDev The BLK_IO private data which specifies the IDE device
481 IN IDE_BLK_IO_DEV
*IdeDev
483 // TODO: EFI_NOT_FOUND - add return value to function comment
484 // TODO: EFI_NOT_FOUND - add return value to function comment
485 // TODO: EFI_SUCCESS - add return value to function comment
490 // If a channel has not been checked, check it now. Then set it to "checked" state
491 // After this step, all devices in this channel have been checked.
493 if (ChannelDeviceDetected
== FALSE
) {
494 Status
= DetectIDEController (IdeDev
);
495 if (EFI_ERROR (Status
)) {
496 return EFI_NOT_FOUND
;
500 Status
= EFI_NOT_FOUND
;
503 // Device exists. test if it is an ATA device.
504 // Prefer the result from DetectIDEController,
505 // if failed, try another device type to handle
506 // devices that not follow the spec.
508 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
509 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
510 Status
= ATAIdentify (IdeDev
);
511 if (EFI_ERROR (Status
)) {
512 Status
= ATAPIIdentify (IdeDev
);
513 if (!EFI_ERROR (Status
)) {
514 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
518 Status
= ATAPIIdentify (IdeDev
);
519 if (EFI_ERROR (Status
)) {
520 Status
= ATAIdentify (IdeDev
);
521 if (!EFI_ERROR (Status
)) {
522 MasterDeviceType
= ATA_DEVICE_TYPE
;
527 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
528 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
529 Status
= ATAIdentify (IdeDev
);
530 if (EFI_ERROR (Status
)) {
531 Status
= ATAPIIdentify (IdeDev
);
532 if (!EFI_ERROR (Status
)) {
533 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
537 Status
= ATAPIIdentify (IdeDev
);
538 if (EFI_ERROR (Status
)) {
539 Status
= ATAIdentify (IdeDev
);
540 if (!EFI_ERROR (Status
)) {
541 SlaveDeviceType
= ATA_DEVICE_TYPE
;
546 if (EFI_ERROR (Status
)) {
547 return EFI_NOT_FOUND
;
550 // Init Block I/O interface
552 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
553 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
554 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
555 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
556 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
558 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
559 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
562 // Init Disk Info interface
564 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
565 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
566 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
567 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
568 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
574 This interface is used to initialize all state data related to the detection of one
577 @retval EFI_SUCCESS Completed Successfully.
581 InitializeIDEChannelData (
585 ChannelDeviceDetected
= FALSE
;
586 MasterDeviceExist
= FALSE
;
587 MasterDeviceType
= 0xff;
588 SlaveDeviceExist
= FALSE
;
589 SlaveDeviceType
= 0xff;
594 This function is called by DiscoverIdeDevice(). It is used for detect
595 whether the IDE device exists in the specified Channel as the specified
598 There is two IDE channels: one is Primary Channel, the other is
599 Secondary Channel.(Channel is the logical name for the physical "Cable".)
600 Different channel has different register group.
602 On each IDE channel, at most two IDE devices attach,
603 one is called Device 0 (Master device), the other is called Device 1
604 (Slave device). The devices on the same channel co-use the same register
605 group, so before sending out a command for a specified device via command
606 register, it is a must to select the current device to accept the command
607 by set the device number in the Head/Device Register.
610 pointer pointing to IDE_BLK_IO_DEV data structure, used
611 to record all the information of the IDE device.
614 successfully detects device.
617 any failure during detection process will return this
621 TODO: EFI_SUCCESS - add return value to function comment
622 TODO: EFI_NOT_FOUND - add return value to function comment
626 DetectIDEController (
627 IN IDE_BLK_IO_DEV
*IdeDev
631 UINT8 SectorCountReg
;
639 // Select slave device
643 IdeDev
->IoPort
->Head
,
644 (UINT8
) ((1 << 4) | 0xe0)
649 // Save the init slave status register
651 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
654 // Select Master back
658 IdeDev
->IoPort
->Head
,
659 (UINT8
) ((0 << 4) | 0xe0)
664 // Send ATA Device Execut Diagnostic command.
665 // This command should work no matter DRDY is ready or not
667 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
669 Status
= WaitForBSYClear (IdeDev
, 3500);
670 if (EFI_ERROR (Status
)) {
671 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
675 // Read device signature
682 IdeDev
->IoPort
->Head
,
683 (UINT8
) ((0 << 4) | 0xe0)
686 SectorCountReg
= IDEReadPortB (
688 IdeDev
->IoPort
->SectorCount
690 LBALowReg
= IDEReadPortB (
692 IdeDev
->IoPort
->SectorNumber
694 LBAMidReg
= IDEReadPortB (
696 IdeDev
->IoPort
->CylinderLsb
698 LBAHighReg
= IDEReadPortB (
700 IdeDev
->IoPort
->CylinderMsb
702 if ((SectorCountReg
== 0x1) &&
703 (LBALowReg
== 0x1) &&
704 (LBAMidReg
== 0x0) &&
705 (LBAHighReg
== 0x0)) {
706 MasterDeviceExist
= TRUE
;
707 MasterDeviceType
= ATA_DEVICE_TYPE
;
709 if ((LBAMidReg
== 0x14) &&
710 (LBAHighReg
== 0xeb)) {
711 MasterDeviceExist
= TRUE
;
712 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
717 // For some Hard Drive, it takes some time to get
718 // the right signature when operating in single slave mode.
719 // We stall 20ms to work around this.
721 if (!MasterDeviceExist
) {
730 IdeDev
->IoPort
->Head
,
731 (UINT8
) ((1 << 4) | 0xe0)
734 SectorCountReg
= IDEReadPortB (
736 IdeDev
->IoPort
->SectorCount
738 LBALowReg
= IDEReadPortB (
740 IdeDev
->IoPort
->SectorNumber
742 LBAMidReg
= IDEReadPortB (
744 IdeDev
->IoPort
->CylinderLsb
746 LBAHighReg
= IDEReadPortB (
748 IdeDev
->IoPort
->CylinderMsb
750 StatusReg
= IDEReadPortB (
752 IdeDev
->IoPort
->Reg
.Status
754 if ((SectorCountReg
== 0x1) &&
755 (LBALowReg
== 0x1) &&
756 (LBAMidReg
== 0x0) &&
757 (LBAHighReg
== 0x0)) {
758 SlaveDeviceExist
= TRUE
;
759 SlaveDeviceType
= ATA_DEVICE_TYPE
;
761 if ((LBAMidReg
== 0x14) &&
762 (LBAHighReg
== 0xeb)) {
763 SlaveDeviceExist
= TRUE
;
764 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
769 // When single master is plugged, slave device
770 // will be wrongly detected. Here's the workaround
771 // for ATA devices by detecting DRY bit in status
773 // NOTE: This workaround doesn't apply to ATAPI.
775 if (MasterDeviceExist
&& SlaveDeviceExist
&&
776 (StatusReg
& DRDY
) == 0 &&
777 (InitStatusReg
& DRDY
) == 0 &&
778 MasterDeviceType
== SlaveDeviceType
&&
779 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
780 SlaveDeviceExist
= FALSE
;
784 // Indicate this channel has been detected
786 ChannelDeviceDetected
= TRUE
;
791 This function is used to poll for the DRQ bit clear in the Status
792 Register. DRQ is cleared when the device is finished transferring data.
793 So this function is called after data transfer is finished.
796 pointer pointing to IDE_BLK_IO_DEV data structure, used
797 to record all the information of the IDE device.
799 @param[in] TimeoutInMilliSeconds
800 used to designate the timeout for the DRQ clear.
803 DRQ bit clear within the time out.
806 DRQ bit not clear within the time out.
809 Read Status Register will clear interrupt status.
814 IN IDE_BLK_IO_DEV
*IdeDev
,
815 IN UINTN TimeoutInMilliSeconds
817 // TODO: function comment is missing 'Routine Description:'
818 // TODO: function comment is missing 'Arguments:'
819 // TODO: IdeDev - add argument and description to function comment
820 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
821 // TODO: EFI_ABORTED - add return value to function comment
824 UINT8 StatusRegister
;
827 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
830 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
833 // wait for BSY == 0 and DRQ == 0
835 if ((StatusRegister
& (DRQ
| BSY
)) == 0) {
839 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
841 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
842 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
864 This function is used to poll for the DRQ bit clear in the Alternate
865 Status Register. DRQ is cleared when the device is finished
866 transferring data. So this function is called after data transfer
870 pointer pointing to IDE_BLK_IO_DEV data structure, used
871 to record all the information of the IDE device.
873 @param[in] TimeoutInMilliSeconds
874 used to designate the timeout for the DRQ clear.
877 DRQ bit clear within the time out.
880 DRQ bit not clear within the time out.
883 Read Alternate Status Register will not clear interrupt status.
888 IN IDE_BLK_IO_DEV
*IdeDev
,
889 IN UINTN TimeoutInMilliSeconds
891 // TODO: function comment is missing 'Routine Description:'
892 // TODO: function comment is missing 'Arguments:'
893 // TODO: IdeDev - add argument and description to function comment
894 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
895 // TODO: EFI_ABORTED - add return value to function comment
901 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
904 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
907 // wait for BSY == 0 and DRQ == 0
909 if ((AltRegister
& (DRQ
| BSY
)) == 0) {
913 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
915 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
916 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
938 This function is used to poll for the DRQ bit set in the
940 DRQ is set when the device is ready to transfer data. So this function
941 is called after the command is sent to the device and before required
944 @param[in] IDE_BLK_IO_DEV IN *IdeDev
945 pointer pointing to IDE_BLK_IO_DEV data structure,used
946 to record all the information of the IDE device.
948 @param[in] UINTN IN TimeoutInMilliSeconds
949 used to designate the timeout for the DRQ ready.
952 DRQ bit set within the time out.
955 DRQ bit not set within the time out.
958 DRQ bit not set caused by the command abort.
961 Read Status Register will clear interrupt status.
966 IN IDE_BLK_IO_DEV
*IdeDev
,
967 IN UINTN TimeoutInMilliSeconds
969 // TODO: function comment is missing 'Routine Description:'
970 // TODO: function comment is missing 'Arguments:'
971 // TODO: IdeDev - add argument and description to function comment
972 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
975 UINT8 StatusRegister
;
978 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
981 // read Status Register will clear interrupt
983 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
988 if ((StatusRegister
& (BSY
| DRQ
)) == DRQ
) {
992 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
994 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
995 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1016 This function is used to poll for the DRQ bit set in the
1017 Alternate Status Register. DRQ is set when the device is ready to
1018 transfer data. So this function is called after the command
1019 is sent to the device and before required data is transferred.
1021 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1022 pointer pointing to IDE_BLK_IO_DEV data structure, used
1023 to record all the information of the IDE device.
1025 @param[in] UINTN IN TimeoutInMilliSeconds
1026 used to designate the timeout for the DRQ ready.
1029 DRQ bit set within the time out.
1032 DRQ bit not set within the time out.
1035 DRQ bit not set caused by the command abort.
1038 Read Alternate Status Register will not clear interrupt status.
1043 IN IDE_BLK_IO_DEV
*IdeDev
,
1044 IN UINTN TimeoutInMilliSeconds
1046 // TODO: function comment is missing 'Routine Description:'
1047 // TODO: function comment is missing 'Arguments:'
1048 // TODO: IdeDev - add argument and description to function comment
1049 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1053 UINT8 ErrorRegister
;
1055 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1059 // Read Alternate Status Register will not clear interrupt status
1061 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1063 // BSY == 0 , DRQ == 1
1065 if ((AltRegister
& (BSY
| DRQ
)) == DRQ
) {
1069 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1071 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1072 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1093 This function is used to poll for the BSY bit clear in the
1094 Status Register. BSY is clear when the device is not busy.
1095 Every command must be sent after device is not busy.
1097 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1098 pointer pointing to IDE_BLK_IO_DEV data structure, used
1099 to record all the information of the IDE device.
1101 @param[in] UINTN IN TimeoutInMilliSeconds
1102 used to designate the timeout for the DRQ ready.
1105 BSY bit clear within the time out.
1108 BSY bit not clear within the time out.
1111 Read Status Register will clear interrupt status.
1116 IN IDE_BLK_IO_DEV
*IdeDev
,
1117 IN UINTN TimeoutInMilliSeconds
1119 // TODO: function comment is missing 'Routine Description:'
1120 // TODO: function comment is missing 'Arguments:'
1121 // TODO: IdeDev - add argument and description to function comment
1122 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1125 UINT8 StatusRegister
;
1127 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1130 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1131 if ((StatusRegister
& BSY
) == 0x00) {
1154 This function is used to poll for the BSY bit clear in the
1155 Alternate Status Register. BSY is clear when the device is not busy.
1156 Every command must be sent after device is not busy.
1158 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1159 pointer pointing to IDE_BLK_IO_DEV data structure, used
1160 to record all the information of the IDE device.
1162 @param[in] UINTN IN TimeoutInMilliSeconds
1163 used to designate the timeout for the DRQ ready.
1166 BSY bit clear within the time out.
1169 BSY bit not clear within the time out.
1172 Read Alternate Status Register will not clear interrupt status.
1177 IN IDE_BLK_IO_DEV
*IdeDev
,
1178 IN UINTN TimeoutInMilliSeconds
1180 // TODO: function comment is missing 'Routine Description:'
1181 // TODO: function comment is missing 'Arguments:'
1182 // TODO: IdeDev - add argument and description to function comment
1183 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1188 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1190 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1191 if ((AltRegister
& BSY
) == 0x00) {
1212 This function is used to poll for the DRDY bit set in the
1213 Status Register. DRDY bit is set when the device is ready
1214 to accept command. Most ATA commands must be sent after
1215 DRDY set except the ATAPI Packet Command.
1217 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1218 pointer pointing to IDE_BLK_IO_DEV data structure, used
1219 to record all the information of the IDE device.
1221 @param[in] UINTN IN TimeoutInMilliSeconds
1222 used to designate the timeout for the DRQ ready.
1225 DRDY bit set within the time out.
1228 DRDY bit not set within the time out.
1231 Read Status Register will clear interrupt status.
1236 IN IDE_BLK_IO_DEV
*IdeDev
,
1237 IN UINTN DelayInMilliSeconds
1239 // TODO: function comment is missing 'Routine Description:'
1240 // TODO: function comment is missing 'Arguments:'
1241 // TODO: IdeDev - add argument and description to function comment
1242 // TODO: DelayInMilliSeconds - add argument and description to function comment
1243 // TODO: EFI_ABORTED - add return value to function comment
1246 UINT8 StatusRegister
;
1247 UINT8 ErrorRegister
;
1249 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1251 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1253 // BSY == 0 , DRDY == 1
1255 if ((StatusRegister
& (DRDY
| BSY
)) == DRDY
) {
1259 if ((StatusRegister
& (BSY
| ERR
)) == ERR
) {
1261 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1262 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1283 This function is used to poll for the DRDY bit set in the
1284 Alternate Status Register. DRDY bit is set when the device is ready
1285 to accept command. Most ATA commands must be sent after
1286 DRDY set except the ATAPI Packet Command.
1288 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1289 pointer pointing to IDE_BLK_IO_DEV data structure, used
1290 to record all the information of the IDE device.
1292 @param[in] UINTN IN TimeoutInMilliSeconds
1293 used to designate the timeout for the DRQ ready.
1296 DRDY bit set within the time out.
1299 DRDY bit not set within the time out.
1302 Read Alternate Status Register will clear interrupt status.
1307 IN IDE_BLK_IO_DEV
*IdeDev
,
1308 IN UINTN DelayInMilliSeconds
1310 // TODO: function comment is missing 'Routine Description:'
1311 // TODO: function comment is missing 'Arguments:'
1312 // TODO: IdeDev - add argument and description to function comment
1313 // TODO: DelayInMilliSeconds - add argument and description to function comment
1314 // TODO: EFI_ABORTED - add return value to function comment
1318 UINT8 ErrorRegister
;
1320 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1322 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1324 // BSY == 0 , DRDY == 1
1326 if ((AltRegister
& (DRDY
| BSY
)) == DRDY
) {
1330 if ((AltRegister
& (BSY
| ERR
)) == ERR
) {
1332 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1333 if ((ErrorRegister
& ABRT_ERR
) == ABRT_ERR
) {
1354 This function is a helper function used to change the char order in a
1355 string. It is designed specially for the PrintAtaModuleName() function.
1356 After the IDE device is detected, the IDE driver gets the device module
1357 name by sending ATA command called ATA Identify Command or ATAPI
1358 Identify Command to the specified IDE device. The module name returned
1359 is a string of ASCII characters: the first character is bit8--bit15
1360 of the first word, the second character is bit0--bit7 of the first word
1361 and so on. Thus the string can not be print directly before it is
1362 preprocessed by this func to change the order of characters in
1363 each word in the string.
1365 @param[in] CHAR8 IN *Destination
1366 Indicates the destination string.
1368 @param[in] CHAR8 IN *Source
1369 Indicates the source string.
1371 @param[in] UINT8 IN Size
1372 the length of the string
1377 IN CHAR8
*Destination
,
1385 for (Index
= 0; Index
< Size
; Index
+= 2) {
1387 Temp
= Source
[Index
+ 1];
1388 Destination
[Index
+ 1] = Source
[Index
];
1389 Destination
[Index
] = Temp
;
1394 // ReleaseIdeResources
1397 Release resources of an IDE device before stopping it.
1399 @param[in] *IdeBlkIoDevice Standard IDE device private data structure
1403 ReleaseIdeResources (
1404 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1407 if (IdeBlkIoDevice
== NULL
) {
1412 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1415 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1416 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1417 IdeBlkIoDevice
->SenseData
= NULL
;
1420 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1421 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1422 IdeBlkIoDevice
->Cache
= NULL
;
1425 if (IdeBlkIoDevice
->pIdData
!= NULL
) {
1426 gBS
->FreePool (IdeBlkIoDevice
->pIdData
);
1427 IdeBlkIoDevice
->pIdData
= NULL
;
1430 if (IdeBlkIoDevice
->pInquiryData
!= NULL
) {
1431 gBS
->FreePool (IdeBlkIoDevice
->pInquiryData
);
1432 IdeBlkIoDevice
->pInquiryData
= NULL
;
1435 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1436 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1437 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1440 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1441 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1444 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1445 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1448 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1449 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1450 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1453 gBS
->FreePool (IdeBlkIoDevice
);
1454 IdeBlkIoDevice
= NULL
;
1460 // SetDeviceTransferMode
1463 Set the calculated Best transfer mode to a detected device
1465 @param[in] *IdeDev Standard IDE device private data structure
1466 @param[in] *TransferMode The device transfer mode to be set
1468 @return Set transfer mode Command execute status
1472 SetDeviceTransferMode (
1473 IN IDE_BLK_IO_DEV
*IdeDev
,
1474 IN ATA_TRANSFER_MODE
*TransferMode
1476 // TODO: function comment is missing 'Routine Description:'
1483 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1484 SectorCount
= *((UINT8
*) TransferMode
);
1487 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1489 Status
= AtaNonDataCommandIn (
1504 Send ATA command into device with NON_DATA protocol
1506 @param IdeDev Standard IDE device private data structure
1507 @param AtaCommand The ATA command to be sent
1508 @param Device The value in Device register
1509 @param Feature The value in Feature register
1510 @param SectorCount The value in SectorCount register
1511 @param LbaLow The value in LBA_LOW register
1512 @param LbaMiddle The value in LBA_MIDDLE register
1513 @param LbaHigh The value in LBA_HIGH register
1515 @retval EFI_SUCCESS Reading succeed
1516 @retval EFI_ABORTED Command failed
1517 @retval EFI_DEVICE_ERROR Device status error
1521 AtaNonDataCommandIn (
1522 IN IDE_BLK_IO_DEV
*IdeDev
,
1523 IN UINT8 AtaCommand
,
1526 IN UINT8 SectorCount
,
1533 UINT8 StatusRegister
;
1535 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1536 if (EFI_ERROR (Status
)) {
1537 return EFI_DEVICE_ERROR
;
1541 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1545 IdeDev
->IoPort
->Head
,
1546 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1550 // ATA commands for ATA device must be issued when DRDY is set
1552 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1553 if (EFI_ERROR (Status
)) {
1554 return EFI_DEVICE_ERROR
;
1558 // Pass parameter into device register block
1560 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1561 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1562 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1563 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1564 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1565 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1568 // Send command via Command Register
1570 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1573 // Wait for command completion
1574 // For ATA_SMART_CMD, we may need more timeout to let device
1575 // adjust internal states.
1577 if (AtaCommand
== ATA_SMART_CMD
) {
1578 Status
= WaitForBSYClear (IdeDev
, ATASMARTTIMEOUT
);
1580 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1582 if (EFI_ERROR (Status
)) {
1583 return EFI_DEVICE_ERROR
;
1586 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1587 if ((StatusRegister
& ERR
) == ERR
) {
1589 // Failed to execute command, abort operation
1598 Send ATA Ext command into device with NON_DATA protocol
1600 @param IdeDev Standard IDE device private data structure
1601 @param AtaCommand The ATA command to be sent
1602 @param Device The value in Device register
1603 @param Feature The value in Feature register
1604 @param SectorCount The value in SectorCount register
1605 @param LbaAddress The LBA address in 48-bit mode
1607 @retval EFI_SUCCESS Reading succeed
1608 @retval EFI_ABORTED Command failed
1609 @retval EFI_DEVICE_ERROR Device status error
1613 AtaNonDataCommandInExt (
1614 IN IDE_BLK_IO_DEV
*IdeDev
,
1615 IN UINT8 AtaCommand
,
1618 IN UINT16 SectorCount
,
1619 IN EFI_LBA LbaAddress
1623 UINT8 StatusRegister
;
1630 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1631 if (EFI_ERROR (Status
)) {
1632 return EFI_DEVICE_ERROR
;
1636 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1640 IdeDev
->IoPort
->Head
,
1641 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1645 // ATA commands for ATA device must be issued when DRDY is set
1647 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1648 if (EFI_ERROR (Status
)) {
1649 return EFI_DEVICE_ERROR
;
1653 // Pass parameter into device register block
1655 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1658 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1660 Feature8
= (UINT8
) (Feature
>> 8);
1661 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1663 Feature8
= (UINT8
) Feature
;
1664 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1667 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1669 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1670 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1672 SectorCount8
= (UINT8
) SectorCount
;
1673 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1676 // Fill the start LBA registers, which are also two-byte FIFO
1678 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1679 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1680 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1681 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1682 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1683 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1685 LbaLow
= (UINT8
) LbaAddress
;
1686 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1687 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1688 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1689 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1690 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1693 // Send command via Command Register
1695 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1698 // Wait for command completion
1700 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1701 if (EFI_ERROR (Status
)) {
1702 return EFI_DEVICE_ERROR
;
1705 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1706 if ((StatusRegister
& ERR
) == ERR
) {
1708 // Failed to execute command, abort operation
1717 // SetDriveParameters
1720 Set drive parameters for devices not support PACKETS command
1722 @param[in] IdeDev Standard IDE device private data structure
1723 @param[in] DriveParameters The device parameters to be set into the disk
1725 @return SetParameters Command execute status
1729 SetDriveParameters (
1730 IN IDE_BLK_IO_DEV
*IdeDev
,
1731 IN ATA_DRIVE_PARMS
*DriveParameters
1738 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1741 // Send Init drive parameters
1743 Status
= AtaNonDataCommandIn (
1745 INIT_DRIVE_PARAM_CMD
,
1746 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1748 DriveParameters
->Sector
,
1755 // Send Set Multiple parameters
1757 Status
= AtaNonDataCommandIn (
1759 SET_MULTIPLE_MODE_CMD
,
1762 DriveParameters
->MultipleSector
,
1771 TODO: Add function description
1773 @param IdeDev TODO: add argument description
1775 @retval EFI_SUCCESS TODO: Add description for return value
1780 IN IDE_BLK_IO_DEV
*IdeDev
1783 UINT8 DeviceControl
;
1786 // Enable interrupt for DMA operation
1789 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);
1795 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
1797 @param[in] Event Pointer to this event
1798 @param[in] Context Event hanlder private data
1809 UINT64 IoPortForBmis
;
1810 UINT8 RegisterValue
;
1811 IDE_BLK_IO_DEV
*IdeDev
;
1816 IdeDev
= (IDE_BLK_IO_DEV
*) Context
;
1819 // Obtain IDE IO port registers' base addresses
1821 Status
= ReassignIdeResources (IdeDev
);
1822 if (EFI_ERROR (Status
)) {
1827 // Check whether interrupt is pending
1831 // Reset IDE device to force it de-assert interrupt pin
1832 // Note: this will reset all devices on this IDE channel
1834 AtaSoftReset (IdeDev
);
1835 if (EFI_ERROR (Status
)) {
1840 // Get base address of IDE Bus Master Status Regsiter
1842 if (IdePrimary
== IdeDev
->Channel
) {
1843 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISP_OFFSET
;
1845 if (IdeSecondary
== IdeDev
->Channel
) {
1846 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISS_OFFSET
;
1852 // Read BMIS register and clear ERROR and INTR bit
1854 IdeDev
->PciIo
->Io
.Read (
1857 EFI_PCI_IO_PASS_THROUGH_BAR
,
1863 RegisterValue
|= (BMIS_INTERRUPT
| BMIS_ERROR
);
1865 IdeDev
->PciIo
->Io
.Write (
1868 EFI_PCI_IO_PASS_THROUGH_BAR
,
1875 // Select the other device on this channel to ensure this device to release the interrupt pin
1877 if (IdeDev
->Device
== 0) {
1878 RegisterValue
= (1 << 4) | 0xe0;
1880 RegisterValue
= (0 << 4) | 0xe0;
1884 IdeDev
->IoPort
->Head
,