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 // GetIdeRegistersBaseAddr
235 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
236 use fixed addresses. In Native-PCI mode, get base addresses from BARs in
237 the PCI IDE controller's Configuration Space.
239 The steps to get IDE IO port registers' base addresses for each channel
242 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
243 controller's Configuration Space to determine the operating mode.
245 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
247 ___________________________________________
248 | | Command Block | Control Block |
249 | Channel | Registers | Registers |
250 |___________|_______________|_______________|
251 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
252 |___________|_______________|_______________|
253 | Secondary | 170h - 177h | 376h - 377h |
254 |___________|_______________|_______________|
256 Table 1. Compatibility resource mappings
259 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
260 in IDE controller's PCI Configuration Space, shown in the Table 2 below.
262 ___________________________________________________
263 | | Command Block | Control Block |
264 | Channel | Registers | Registers |
265 |___________|___________________|___________________|
266 | Primary | BAR at offset 0x10| BAR at offset 0x14|
267 |___________|___________________|___________________|
268 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
269 |___________|___________________|___________________|
271 Table 2. BARs for Register Mapping
273 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
274 primary, 0374h for secondary. So 2 bytes extra offset should be
275 added to the base addresses read from BARs.
277 For more details, please refer to PCI IDE Controller Specification and Intel
280 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
281 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
282 receive IDE IO port registers' base addresses
286 GetIdeRegistersBaseAddr (
287 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
288 OUT IDE_REGISTERS_BASE_ADDR
*IdeRegsBaseAddr
290 // TODO: EFI_UNSUPPORTED - add return value to function comment
291 // TODO: EFI_UNSUPPORTED - add return value to function comment
292 // TODO: EFI_SUCCESS - add return value to function comment
297 Status
= PciIo
->Pci
.Read (
305 if (EFI_ERROR (Status
)) {
309 if ((PciData
.Hdr
.ClassCode
[0] & IDE_PRIMARY_OPERATING_MODE
) == 0) {
310 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
= 0x1f0;
311 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
= 0x3f6;
312 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
313 (UINT16
)((PciData
.Device
.Bar
[4] & 0x0000fff0));
316 // The BARs should be of IO type
318 if ((PciData
.Device
.Bar
[0] & BIT0
) == 0 ||
319 (PciData
.Device
.Bar
[1] & BIT0
) == 0) {
320 return EFI_UNSUPPORTED
;
323 IdeRegsBaseAddr
[IdePrimary
].CommandBlockBaseAddr
=
324 (UINT16
) (PciData
.Device
.Bar
[0] & 0x0000fff8);
325 IdeRegsBaseAddr
[IdePrimary
].ControlBlockBaseAddr
=
326 (UINT16
) ((PciData
.Device
.Bar
[1] & 0x0000fffc) + 2);
327 IdeRegsBaseAddr
[IdePrimary
].BusMasterBaseAddr
=
328 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
331 if ((PciData
.Hdr
.ClassCode
[0] & IDE_SECONDARY_OPERATING_MODE
) == 0) {
332 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
= 0x170;
333 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
= 0x376;
334 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
335 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
338 // The BARs should be of IO type
340 if ((PciData
.Device
.Bar
[2] & BIT0
) == 0 ||
341 (PciData
.Device
.Bar
[3] & BIT0
) == 0) {
342 return EFI_UNSUPPORTED
;
345 IdeRegsBaseAddr
[IdeSecondary
].CommandBlockBaseAddr
=
346 (UINT16
) (PciData
.Device
.Bar
[2] & 0x0000fff8);
347 IdeRegsBaseAddr
[IdeSecondary
].ControlBlockBaseAddr
=
348 (UINT16
) ((PciData
.Device
.Bar
[3] & 0x0000fffc) + 2);
349 IdeRegsBaseAddr
[IdeSecondary
].BusMasterBaseAddr
=
350 (UINT16
) ((PciData
.Device
.Bar
[4] & 0x0000fff0));
357 This function is used to requery IDE resources. The IDE controller will
358 probably switch between native and legacy modes during the EFI->CSM->OS
359 transfer. We do this everytime before an BlkIo operation to ensure its
362 @param IdeDev The BLK_IO private data which specifies the IDE device
366 ReassignIdeResources (
367 IN IDE_BLK_IO_DEV
*IdeDev
369 // TODO: EFI_SUCCESS - add return value to function comment
372 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr
[IdeMaxChannel
];
373 UINT16 CommandBlockBaseAddr
;
374 UINT16 ControlBlockBaseAddr
;
377 // Requery IDE IO port registers' base addresses in case of the switch of
378 // native and legacy modes
380 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
381 if (EFI_ERROR (Status
)) {
385 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
386 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
387 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
389 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
390 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
391 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
392 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
393 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
394 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
395 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
397 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
398 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
399 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
400 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
402 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
410 Detect if there is disk connected to this port
412 @param IdeDev The BLK_IO private data which specifies the IDE device
417 IN IDE_BLK_IO_DEV
*IdeDev
419 // TODO: EFI_NOT_FOUND - add return value to function comment
420 // TODO: EFI_NOT_FOUND - add return value to function comment
421 // TODO: EFI_SUCCESS - add return value to function comment
426 // If a channel has not been checked, check it now. Then set it to "checked" state
427 // After this step, all devices in this channel have been checked.
429 if (ChannelDeviceDetected
== FALSE
) {
430 Status
= DetectIDEController (IdeDev
);
431 if (EFI_ERROR (Status
)) {
432 return EFI_NOT_FOUND
;
436 Status
= EFI_NOT_FOUND
;
439 // Device exists. test if it is an ATA device.
440 // Prefer the result from DetectIDEController,
441 // if failed, try another device type to handle
442 // devices that not follow the spec.
444 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
445 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
446 Status
= ATAIdentify (IdeDev
);
447 if (EFI_ERROR (Status
)) {
448 Status
= ATAPIIdentify (IdeDev
);
449 if (!EFI_ERROR (Status
)) {
450 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
454 Status
= ATAPIIdentify (IdeDev
);
455 if (EFI_ERROR (Status
)) {
456 Status
= ATAIdentify (IdeDev
);
457 if (!EFI_ERROR (Status
)) {
458 MasterDeviceType
= ATA_DEVICE_TYPE
;
463 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
464 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
465 Status
= ATAIdentify (IdeDev
);
466 if (EFI_ERROR (Status
)) {
467 Status
= ATAPIIdentify (IdeDev
);
468 if (!EFI_ERROR (Status
)) {
469 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
473 Status
= ATAPIIdentify (IdeDev
);
474 if (EFI_ERROR (Status
)) {
475 Status
= ATAIdentify (IdeDev
);
476 if (!EFI_ERROR (Status
)) {
477 SlaveDeviceType
= ATA_DEVICE_TYPE
;
482 if (EFI_ERROR (Status
)) {
483 return EFI_NOT_FOUND
;
486 // Init Block I/O interface
488 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
489 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
490 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
491 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
492 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
494 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
495 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
498 // Init Disk Info interface
500 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
501 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
502 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
503 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
504 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
510 This interface is used to initialize all state data related to the detection of one
513 @retval EFI_SUCCESS Completed Successfully.
517 InitializeIDEChannelData (
521 ChannelDeviceDetected
= FALSE
;
522 MasterDeviceExist
= FALSE
;
523 MasterDeviceType
= 0xff;
524 SlaveDeviceExist
= FALSE
;
525 SlaveDeviceType
= 0xff;
530 This function is called by DiscoverIdeDevice(). It is used for detect
531 whether the IDE device exists in the specified Channel as the specified
534 There is two IDE channels: one is Primary Channel, the other is
535 Secondary Channel.(Channel is the logical name for the physical "Cable".)
536 Different channel has different register group.
538 On each IDE channel, at most two IDE devices attach,
539 one is called Device 0 (Master device), the other is called Device 1
540 (Slave device). The devices on the same channel co-use the same register
541 group, so before sending out a command for a specified device via command
542 register, it is a must to select the current device to accept the command
543 by set the device number in the Head/Device Register.
546 pointer pointing to IDE_BLK_IO_DEV data structure, used
547 to record all the information of the IDE device.
550 successfully detects device.
553 any failure during detection process will return this
557 TODO: EFI_SUCCESS - add return value to function comment
558 TODO: EFI_NOT_FOUND - add return value to function comment
562 DetectIDEController (
563 IN IDE_BLK_IO_DEV
*IdeDev
567 UINT8 SectorCountReg
;
575 // Select slave device
579 IdeDev
->IoPort
->Head
,
580 (UINT8
) ((1 << 4) | 0xe0)
585 // Save the init slave status register
587 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
590 // Select Master back
594 IdeDev
->IoPort
->Head
,
595 (UINT8
) ((0 << 4) | 0xe0)
600 // Send ATA Device Execut Diagnostic command.
601 // This command should work no matter DRDY is ready or not
603 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
605 Status
= WaitForBSYClear (IdeDev
, 3500);
606 if (EFI_ERROR (Status
)) {
607 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
611 // Read device signature
618 IdeDev
->IoPort
->Head
,
619 (UINT8
) ((0 << 4) | 0xe0)
622 SectorCountReg
= IDEReadPortB (
624 IdeDev
->IoPort
->SectorCount
626 LBALowReg
= IDEReadPortB (
628 IdeDev
->IoPort
->SectorNumber
630 LBAMidReg
= IDEReadPortB (
632 IdeDev
->IoPort
->CylinderLsb
634 LBAHighReg
= IDEReadPortB (
636 IdeDev
->IoPort
->CylinderMsb
638 if ((SectorCountReg
== 0x1) &&
639 (LBALowReg
== 0x1) &&
640 (LBAMidReg
== 0x0) &&
641 (LBAHighReg
== 0x0)) {
642 MasterDeviceExist
= TRUE
;
643 MasterDeviceType
= ATA_DEVICE_TYPE
;
645 if ((LBAMidReg
== 0x14) &&
646 (LBAHighReg
== 0xeb)) {
647 MasterDeviceExist
= TRUE
;
648 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
653 // For some Hard Drive, it takes some time to get
654 // the right signature when operating in single slave mode.
655 // We stall 20ms to work around this.
657 if (!MasterDeviceExist
) {
666 IdeDev
->IoPort
->Head
,
667 (UINT8
) ((1 << 4) | 0xe0)
670 SectorCountReg
= IDEReadPortB (
672 IdeDev
->IoPort
->SectorCount
674 LBALowReg
= IDEReadPortB (
676 IdeDev
->IoPort
->SectorNumber
678 LBAMidReg
= IDEReadPortB (
680 IdeDev
->IoPort
->CylinderLsb
682 LBAHighReg
= IDEReadPortB (
684 IdeDev
->IoPort
->CylinderMsb
686 StatusReg
= IDEReadPortB (
688 IdeDev
->IoPort
->Reg
.Status
690 if ((SectorCountReg
== 0x1) &&
691 (LBALowReg
== 0x1) &&
692 (LBAMidReg
== 0x0) &&
693 (LBAHighReg
== 0x0)) {
694 SlaveDeviceExist
= TRUE
;
695 SlaveDeviceType
= ATA_DEVICE_TYPE
;
697 if ((LBAMidReg
== 0x14) &&
698 (LBAHighReg
== 0xeb)) {
699 SlaveDeviceExist
= TRUE
;
700 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
705 // When single master is plugged, slave device
706 // will be wrongly detected. Here's the workaround
707 // for ATA devices by detecting DRY bit in status
709 // NOTE: This workaround doesn't apply to ATAPI.
711 if (MasterDeviceExist
&& SlaveDeviceExist
&&
712 (StatusReg
& ATA_STSREG_DRDY
) == 0 &&
713 (InitStatusReg
& ATA_STSREG_DRDY
) == 0 &&
714 MasterDeviceType
== SlaveDeviceType
&&
715 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
716 SlaveDeviceExist
= FALSE
;
720 // Indicate this channel has been detected
722 ChannelDeviceDetected
= TRUE
;
727 This function is used to poll for the DRQ bit clear in the Status
728 Register. DRQ is cleared when the device is finished transferring data.
729 So this function is called after data transfer is finished.
732 pointer pointing to IDE_BLK_IO_DEV data structure, used
733 to record all the information of the IDE device.
735 @param[in] TimeoutInMilliSeconds
736 used to designate the timeout for the DRQ clear.
739 DRQ bit clear within the time out.
742 DRQ bit not clear within the time out.
745 Read Status Register will clear interrupt status.
750 IN IDE_BLK_IO_DEV
*IdeDev
,
751 IN UINTN TimeoutInMilliSeconds
753 // TODO: function comment is missing 'Routine Description:'
754 // TODO: function comment is missing 'Arguments:'
755 // TODO: IdeDev - add argument and description to function comment
756 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
757 // TODO: EFI_ABORTED - add return value to function comment
760 UINT8 StatusRegister
;
763 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
766 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
769 // wait for BSY == 0 and DRQ == 0
771 if ((StatusRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
775 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
777 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
778 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
800 This function is used to poll for the DRQ bit clear in the Alternate
801 Status Register. DRQ is cleared when the device is finished
802 transferring data. So this function is called after data transfer
806 pointer pointing to IDE_BLK_IO_DEV data structure, used
807 to record all the information of the IDE device.
809 @param[in] TimeoutInMilliSeconds
810 used to designate the timeout for the DRQ clear.
813 DRQ bit clear within the time out.
816 DRQ bit not clear within the time out.
819 Read Alternate Status Register will not clear interrupt status.
824 IN IDE_BLK_IO_DEV
*IdeDev
,
825 IN UINTN TimeoutInMilliSeconds
827 // TODO: function comment is missing 'Routine Description:'
828 // TODO: function comment is missing 'Arguments:'
829 // TODO: IdeDev - add argument and description to function comment
830 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
831 // TODO: EFI_ABORTED - add return value to function comment
837 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
840 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
843 // wait for BSY == 0 and DRQ == 0
845 if ((AltRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
849 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
851 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
852 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
874 This function is used to poll for the DRQ bit set in the
876 DRQ is set when the device is ready to transfer data. So this function
877 is called after the command is sent to the device and before required
880 @param[in] IDE_BLK_IO_DEV IN *IdeDev
881 pointer pointing to IDE_BLK_IO_DEV data structure,used
882 to record all the information of the IDE device.
884 @param[in] UINTN IN TimeoutInMilliSeconds
885 used to designate the timeout for the DRQ ready.
888 DRQ bit set within the time out.
891 DRQ bit not set within the time out.
894 DRQ bit not set caused by the command abort.
897 Read Status Register will clear interrupt status.
902 IN IDE_BLK_IO_DEV
*IdeDev
,
903 IN UINTN TimeoutInMilliSeconds
905 // TODO: function comment is missing 'Routine Description:'
906 // TODO: function comment is missing 'Arguments:'
907 // TODO: IdeDev - add argument and description to function comment
908 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
911 UINT8 StatusRegister
;
914 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
917 // read Status Register will clear interrupt
919 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
924 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
928 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
930 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
931 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
952 This function is used to poll for the DRQ bit set in the
953 Alternate Status Register. DRQ is set when the device is ready to
954 transfer data. So this function is called after the command
955 is sent to the device and before required data is transferred.
957 @param[in] IDE_BLK_IO_DEV IN *IdeDev
958 pointer pointing to IDE_BLK_IO_DEV data structure, used
959 to record all the information of the IDE device.
961 @param[in] UINTN IN TimeoutInMilliSeconds
962 used to designate the timeout for the DRQ ready.
965 DRQ bit set within the time out.
968 DRQ bit not set within the time out.
971 DRQ bit not set caused by the command abort.
974 Read Alternate Status Register will not clear interrupt status.
979 IN IDE_BLK_IO_DEV
*IdeDev
,
980 IN UINTN TimeoutInMilliSeconds
982 // TODO: function comment is missing 'Routine Description:'
983 // TODO: function comment is missing 'Arguments:'
984 // TODO: IdeDev - add argument and description to function comment
985 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
991 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
995 // Read Alternate Status Register will not clear interrupt status
997 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
999 // BSY == 0 , DRQ == 1
1001 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
1005 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1007 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1008 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1029 This function is used to poll for the BSY bit clear in the
1030 Status Register. BSY is clear when the device is not busy.
1031 Every command must be sent after device is not busy.
1033 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1034 pointer pointing to IDE_BLK_IO_DEV data structure, used
1035 to record all the information of the IDE device.
1037 @param[in] UINTN IN TimeoutInMilliSeconds
1038 used to designate the timeout for the DRQ ready.
1041 BSY bit clear within the time out.
1044 BSY bit not clear within the time out.
1047 Read Status Register will clear interrupt status.
1052 IN IDE_BLK_IO_DEV
*IdeDev
,
1053 IN UINTN TimeoutInMilliSeconds
1055 // TODO: function comment is missing 'Routine Description:'
1056 // TODO: function comment is missing 'Arguments:'
1057 // TODO: IdeDev - add argument and description to function comment
1058 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1061 UINT8 StatusRegister
;
1063 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1066 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1067 if ((StatusRegister
& ATA_STSREG_BSY
) == 0x00) {
1090 This function is used to poll for the BSY bit clear in the
1091 Alternate Status Register. BSY is clear when the device is not busy.
1092 Every command must be sent after device is not busy.
1094 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1095 pointer pointing to IDE_BLK_IO_DEV data structure, used
1096 to record all the information of the IDE device.
1098 @param[in] UINTN IN TimeoutInMilliSeconds
1099 used to designate the timeout for the DRQ ready.
1102 BSY bit clear within the time out.
1105 BSY bit not clear within the time out.
1108 Read Alternate Status Register will not clear interrupt status.
1113 IN IDE_BLK_IO_DEV
*IdeDev
,
1114 IN UINTN TimeoutInMilliSeconds
1116 // TODO: function comment is missing 'Routine Description:'
1117 // TODO: function comment is missing 'Arguments:'
1118 // TODO: IdeDev - add argument and description to function comment
1119 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1124 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1126 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1127 if ((AltRegister
& ATA_STSREG_BSY
) == 0x00) {
1148 This function is used to poll for the DRDY bit set in the
1149 Status Register. DRDY bit is set when the device is ready
1150 to accept command. Most ATA commands must be sent after
1151 DRDY set except the ATAPI Packet Command.
1153 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1154 pointer pointing to IDE_BLK_IO_DEV data structure, used
1155 to record all the information of the IDE device.
1157 @param[in] UINTN IN TimeoutInMilliSeconds
1158 used to designate the timeout for the DRQ ready.
1161 DRDY bit set within the time out.
1164 DRDY bit not set within the time out.
1167 Read Status Register will clear interrupt status.
1172 IN IDE_BLK_IO_DEV
*IdeDev
,
1173 IN UINTN DelayInMilliSeconds
1175 // TODO: function comment is missing 'Routine Description:'
1176 // TODO: function comment is missing 'Arguments:'
1177 // TODO: IdeDev - add argument and description to function comment
1178 // TODO: DelayInMilliSeconds - add argument and description to function comment
1179 // TODO: EFI_ABORTED - add return value to function comment
1182 UINT8 StatusRegister
;
1183 UINT8 ErrorRegister
;
1185 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1187 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1189 // BSY == 0 , DRDY == 1
1191 if ((StatusRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1195 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1197 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1198 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1219 This function is used to poll for the DRDY bit set in the
1220 Alternate Status Register. DRDY bit is set when the device is ready
1221 to accept command. Most ATA commands must be sent after
1222 DRDY set except the ATAPI Packet Command.
1224 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1225 pointer pointing to IDE_BLK_IO_DEV data structure, used
1226 to record all the information of the IDE device.
1228 @param[in] UINTN IN TimeoutInMilliSeconds
1229 used to designate the timeout for the DRQ ready.
1232 DRDY bit set within the time out.
1235 DRDY bit not set within the time out.
1238 Read Alternate Status Register will clear interrupt status.
1243 IN IDE_BLK_IO_DEV
*IdeDev
,
1244 IN UINTN DelayInMilliSeconds
1246 // TODO: function comment is missing 'Routine Description:'
1247 // TODO: function comment is missing 'Arguments:'
1248 // TODO: IdeDev - add argument and description to function comment
1249 // TODO: DelayInMilliSeconds - add argument and description to function comment
1250 // TODO: EFI_ABORTED - add return value to function comment
1254 UINT8 ErrorRegister
;
1256 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1258 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1260 // BSY == 0 , DRDY == 1
1262 if ((AltRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1266 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1268 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1269 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1290 This function is a helper function used to change the char order in a
1291 string. It is designed specially for the PrintAtaModuleName() function.
1292 After the IDE device is detected, the IDE driver gets the device module
1293 name by sending ATA command called ATA Identify Command or ATAPI
1294 Identify Command to the specified IDE device. The module name returned
1295 is a string of ASCII characters: the first character is bit8--bit15
1296 of the first word, the second character is BIT0--bit7 of the first word
1297 and so on. Thus the string can not be print directly before it is
1298 preprocessed by this func to change the order of characters in
1299 each word in the string.
1301 @param[in] CHAR8 IN *Destination
1302 Indicates the destination string.
1304 @param[in] CHAR8 IN *Source
1305 Indicates the source string.
1307 @param[in] UINT8 IN Size
1308 the length of the string
1313 IN CHAR8
*Destination
,
1321 for (Index
= 0; Index
< Size
; Index
+= 2) {
1323 Temp
= Source
[Index
+ 1];
1324 Destination
[Index
+ 1] = Source
[Index
];
1325 Destination
[Index
] = Temp
;
1330 // ReleaseIdeResources
1333 Release resources of an IDE device before stopping it.
1335 @param[in] *IdeBlkIoDevice Standard IDE device private data structure
1339 ReleaseIdeResources (
1340 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1343 if (IdeBlkIoDevice
== NULL
) {
1348 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1351 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1352 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1353 IdeBlkIoDevice
->SenseData
= NULL
;
1356 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1357 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1358 IdeBlkIoDevice
->Cache
= NULL
;
1361 if (IdeBlkIoDevice
->pIdData
!= NULL
) {
1362 gBS
->FreePool (IdeBlkIoDevice
->pIdData
);
1363 IdeBlkIoDevice
->pIdData
= NULL
;
1366 if (IdeBlkIoDevice
->pInquiryData
!= NULL
) {
1367 gBS
->FreePool (IdeBlkIoDevice
->pInquiryData
);
1368 IdeBlkIoDevice
->pInquiryData
= NULL
;
1371 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1372 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1373 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1376 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1377 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1380 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1381 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1384 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1385 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1386 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1389 gBS
->FreePool (IdeBlkIoDevice
);
1390 IdeBlkIoDevice
= NULL
;
1396 // SetDeviceTransferMode
1399 Set the calculated Best transfer mode to a detected device
1401 @param[in] *IdeDev Standard IDE device private data structure
1402 @param[in] *TransferMode The device transfer mode to be set
1404 @return Set transfer mode Command execute status
1408 SetDeviceTransferMode (
1409 IN IDE_BLK_IO_DEV
*IdeDev
,
1410 IN ATA_TRANSFER_MODE
*TransferMode
1412 // TODO: function comment is missing 'Routine Description:'
1419 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1420 SectorCount
= *((UINT8
*) TransferMode
);
1423 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1425 Status
= AtaNonDataCommandIn (
1427 ATA_CMD_SET_FEATURES
,
1440 Send ATA command into device with NON_DATA protocol
1442 @param IdeDev Standard IDE device private data structure
1443 @param AtaCommand The ATA command to be sent
1444 @param Device The value in Device register
1445 @param Feature The value in Feature register
1446 @param SectorCount The value in SectorCount register
1447 @param LbaLow The value in LBA_LOW register
1448 @param LbaMiddle The value in LBA_MIDDLE register
1449 @param LbaHigh The value in LBA_HIGH register
1451 @retval EFI_SUCCESS Reading succeed
1452 @retval EFI_ABORTED Command failed
1453 @retval EFI_DEVICE_ERROR Device status error
1457 AtaNonDataCommandIn (
1458 IN IDE_BLK_IO_DEV
*IdeDev
,
1459 IN UINT8 AtaCommand
,
1462 IN UINT8 SectorCount
,
1469 UINT8 StatusRegister
;
1471 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1472 if (EFI_ERROR (Status
)) {
1473 return EFI_DEVICE_ERROR
;
1477 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1481 IdeDev
->IoPort
->Head
,
1482 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1486 // ATA commands for ATA device must be issued when DRDY is set
1488 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1489 if (EFI_ERROR (Status
)) {
1490 return EFI_DEVICE_ERROR
;
1494 // Pass parameter into device register block
1496 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1497 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1498 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1499 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1500 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1501 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1504 // Send command via Command Register
1506 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1509 // Wait for command completion
1510 // For ATAPI_SMART_CMD, we may need more timeout to let device
1511 // adjust internal states.
1513 if (AtaCommand
== ATA_CMD_SMART
) {
1514 Status
= WaitForBSYClear (IdeDev
, ATASMARTTIMEOUT
);
1516 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1518 if (EFI_ERROR (Status
)) {
1519 return EFI_DEVICE_ERROR
;
1522 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1523 if ((StatusRegister
& ATA_STSREG_ERR
) == ATA_STSREG_ERR
) {
1525 // Failed to execute command, abort operation
1534 Send ATA Ext command into device with NON_DATA protocol
1536 @param IdeDev Standard IDE device private data structure
1537 @param AtaCommand The ATA command to be sent
1538 @param Device The value in Device register
1539 @param Feature The value in Feature register
1540 @param SectorCount The value in SectorCount register
1541 @param LbaAddress The LBA address in 48-bit mode
1543 @retval EFI_SUCCESS Reading succeed
1544 @retval EFI_ABORTED Command failed
1545 @retval EFI_DEVICE_ERROR Device status error
1549 AtaNonDataCommandInExt (
1550 IN IDE_BLK_IO_DEV
*IdeDev
,
1551 IN UINT8 AtaCommand
,
1554 IN UINT16 SectorCount
,
1555 IN EFI_LBA LbaAddress
1559 UINT8 StatusRegister
;
1566 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1567 if (EFI_ERROR (Status
)) {
1568 return EFI_DEVICE_ERROR
;
1572 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1576 IdeDev
->IoPort
->Head
,
1577 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1581 // ATA commands for ATA device must be issued when DRDY is set
1583 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1584 if (EFI_ERROR (Status
)) {
1585 return EFI_DEVICE_ERROR
;
1589 // Pass parameter into device register block
1591 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1594 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1596 Feature8
= (UINT8
) (Feature
>> 8);
1597 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1599 Feature8
= (UINT8
) Feature
;
1600 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1603 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1605 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1606 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1608 SectorCount8
= (UINT8
) SectorCount
;
1609 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1612 // Fill the start LBA registers, which are also two-byte FIFO
1614 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1615 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1616 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1617 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1618 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1619 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1621 LbaLow
= (UINT8
) LbaAddress
;
1622 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1623 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1624 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1625 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1626 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1629 // Send command via Command Register
1631 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1634 // Wait for command completion
1636 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1637 if (EFI_ERROR (Status
)) {
1638 return EFI_DEVICE_ERROR
;
1641 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1642 if ((StatusRegister
& ATA_STSREG_ERR
) == ATA_STSREG_ERR
) {
1644 // Failed to execute command, abort operation
1653 // SetDriveParameters
1656 Set drive parameters for devices not support PACKETS command
1658 @param[in] IdeDev Standard IDE device private data structure
1659 @param[in] DriveParameters The device parameters to be set into the disk
1661 @return SetParameters Command execute status
1665 SetDriveParameters (
1666 IN IDE_BLK_IO_DEV
*IdeDev
,
1667 IN ATA_DRIVE_PARMS
*DriveParameters
1674 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1677 // Send Init drive parameters
1679 Status
= AtaNonDataCommandIn (
1681 ATA_CMD_INIT_DRIVE_PARAM
,
1682 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1684 DriveParameters
->Sector
,
1691 // Send Set Multiple parameters
1693 Status
= AtaNonDataCommandIn (
1695 ATA_CMD_SET_MULTIPLE_MODE
,
1698 DriveParameters
->MultipleSector
,
1707 TODO: Add function description
1709 @param IdeDev TODO: add argument description
1711 @retval EFI_SUCCESS TODO: Add description for return value
1716 IN IDE_BLK_IO_DEV
*IdeDev
1719 UINT8 DeviceControl
;
1722 // Enable interrupt for DMA operation
1725 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);
1731 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
1733 @param[in] Event Pointer to this event
1734 @param[in] Context Event hanlder private data
1745 UINT64 IoPortForBmis
;
1746 UINT8 RegisterValue
;
1747 IDE_BLK_IO_DEV
*IdeDev
;
1752 IdeDev
= (IDE_BLK_IO_DEV
*) Context
;
1755 // Obtain IDE IO port registers' base addresses
1757 Status
= ReassignIdeResources (IdeDev
);
1758 if (EFI_ERROR (Status
)) {
1763 // Check whether interrupt is pending
1767 // Reset IDE device to force it de-assert interrupt pin
1768 // Note: this will reset all devices on this IDE channel
1770 AtaSoftReset (IdeDev
);
1771 if (EFI_ERROR (Status
)) {
1776 // Get base address of IDE Bus Master Status Regsiter
1778 if (IdePrimary
== IdeDev
->Channel
) {
1779 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISP_OFFSET
;
1781 if (IdeSecondary
== IdeDev
->Channel
) {
1782 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISS_OFFSET
;
1788 // Read BMIS register and clear ERROR and INTR bit
1790 IdeDev
->PciIo
->Io
.Read (
1793 EFI_PCI_IO_PASS_THROUGH_BAR
,
1799 RegisterValue
|= (BMIS_INTERRUPT
| BMIS_ERROR
);
1801 IdeDev
->PciIo
->Io
.Write (
1804 EFI_PCI_IO_PASS_THROUGH_BAR
,
1811 // Select the other device on this channel to ensure this device to release the interrupt pin
1813 if (IdeDev
->Device
== 0) {
1814 RegisterValue
= (1 << 4) | 0xe0;
1816 RegisterValue
= (0 << 4) | 0xe0;
1820 IdeDev
->IoPort
->Head
,