2 Copyright (c) 2006 - 2008, 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
;
376 if (IdeDev
->Channel
>= IdeMaxChannel
) {
377 return EFI_INVALID_PARAMETER
;
381 // Requery IDE IO port registers' base addresses in case of the switch of
382 // native and legacy modes
384 Status
= GetIdeRegistersBaseAddr (IdeDev
->PciIo
, IdeRegsBaseAddr
);
385 if (EFI_ERROR (Status
)) {
389 ZeroMem (IdeDev
->IoPort
, sizeof (IDE_BASE_REGISTERS
));
390 CommandBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].CommandBlockBaseAddr
;
391 ControlBlockBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].ControlBlockBaseAddr
;
393 IdeDev
->IoPort
->Data
= CommandBlockBaseAddr
;
394 (*(UINT16
*) &IdeDev
->IoPort
->Reg1
) = (UINT16
) (CommandBlockBaseAddr
+ 0x01);
395 IdeDev
->IoPort
->SectorCount
= (UINT16
) (CommandBlockBaseAddr
+ 0x02);
396 IdeDev
->IoPort
->SectorNumber
= (UINT16
) (CommandBlockBaseAddr
+ 0x03);
397 IdeDev
->IoPort
->CylinderLsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x04);
398 IdeDev
->IoPort
->CylinderMsb
= (UINT16
) (CommandBlockBaseAddr
+ 0x05);
399 IdeDev
->IoPort
->Head
= (UINT16
) (CommandBlockBaseAddr
+ 0x06);
401 (*(UINT16
*) &IdeDev
->IoPort
->Reg
) = (UINT16
) (CommandBlockBaseAddr
+ 0x07);
402 (*(UINT16
*) &IdeDev
->IoPort
->Alt
) = ControlBlockBaseAddr
;
403 IdeDev
->IoPort
->DriveAddress
= (UINT16
) (ControlBlockBaseAddr
+ 0x01);
404 IdeDev
->IoPort
->MasterSlave
= (UINT16
) ((IdeDev
->Device
== IdeMaster
) ? 1 : 0);
406 IdeDev
->IoPort
->BusMasterBaseAddr
= IdeRegsBaseAddr
[IdeDev
->Channel
].BusMasterBaseAddr
;
414 Detect if there is disk connected to this port
416 @param IdeDev The BLK_IO private data which specifies the IDE device.
421 IN IDE_BLK_IO_DEV
*IdeDev
423 // TODO: EFI_NOT_FOUND - add return value to function comment
424 // TODO: EFI_NOT_FOUND - add return value to function comment
425 // TODO: EFI_SUCCESS - add return value to function comment
428 EFI_STATUS LongPhyStatus
;
431 // If a channel has not been checked, check it now. Then set it to "checked" state
432 // After this step, all devices in this channel have been checked.
434 if (!ChannelDeviceDetected
) {
435 Status
= DetectIDEController (IdeDev
);
436 if (EFI_ERROR (Status
)) {
437 return EFI_NOT_FOUND
;
441 Status
= EFI_NOT_FOUND
;
444 // Device exists. test if it is an ATA device.
445 // Prefer the result from DetectIDEController,
446 // if failed, try another device type to handle
447 // devices that not follow the spec.
449 if ((IdeDev
->Device
== IdeMaster
) && (MasterDeviceExist
)) {
450 if (MasterDeviceType
== ATA_DEVICE_TYPE
) {
451 Status
= ATAIdentify (IdeDev
);
452 if (EFI_ERROR (Status
)) {
453 Status
= ATAPIIdentify (IdeDev
);
454 if (!EFI_ERROR (Status
)) {
455 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
459 Status
= ATAPIIdentify (IdeDev
);
460 if (EFI_ERROR (Status
)) {
461 Status
= ATAIdentify (IdeDev
);
462 if (!EFI_ERROR (Status
)) {
463 MasterDeviceType
= ATA_DEVICE_TYPE
;
468 if ((IdeDev
->Device
== IdeSlave
) && (SlaveDeviceExist
)) {
469 if (SlaveDeviceType
== ATA_DEVICE_TYPE
) {
470 Status
= ATAIdentify (IdeDev
);
471 if (EFI_ERROR (Status
)) {
472 Status
= ATAPIIdentify (IdeDev
);
473 if (!EFI_ERROR (Status
)) {
474 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
478 Status
= ATAPIIdentify (IdeDev
);
479 if (EFI_ERROR (Status
)) {
480 Status
= ATAIdentify (IdeDev
);
481 if (!EFI_ERROR (Status
)) {
482 SlaveDeviceType
= ATA_DEVICE_TYPE
;
487 if (EFI_ERROR (Status
)) {
488 return EFI_NOT_FOUND
;
491 // Init Block I/O interface
493 LongPhyStatus
= AtaEnableLongPhysicalSector (IdeDev
);
494 if (!EFI_ERROR (LongPhyStatus
)) {
495 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION2
;
497 IdeDev
->BlkIo
.Revision
= EFI_BLOCK_IO_PROTOCOL_REVISION
;
499 IdeDev
->BlkIo
.Reset
= IDEBlkIoReset
;
500 IdeDev
->BlkIo
.ReadBlocks
= IDEBlkIoReadBlocks
;
501 IdeDev
->BlkIo
.WriteBlocks
= IDEBlkIoWriteBlocks
;
502 IdeDev
->BlkIo
.FlushBlocks
= IDEBlkIoFlushBlocks
;
504 IdeDev
->BlkMedia
.LogicalPartition
= FALSE
;
505 IdeDev
->BlkMedia
.WriteCaching
= FALSE
;
508 // Init Disk Info interface
510 gBS
->CopyMem (&IdeDev
->DiskInfo
.Interface
, &gEfiDiskInfoIdeInterfaceGuid
, sizeof (EFI_GUID
));
511 IdeDev
->DiskInfo
.Inquiry
= IDEDiskInfoInquiry
;
512 IdeDev
->DiskInfo
.Identify
= IDEDiskInfoIdentify
;
513 IdeDev
->DiskInfo
.SenseData
= IDEDiskInfoSenseData
;
514 IdeDev
->DiskInfo
.WhichIde
= IDEDiskInfoWhichIde
;
520 This interface is used to initialize all state data related to the detection of one
523 @retval EFI_SUCCESS Completed Successfully.
527 InitializeIDEChannelData (
531 ChannelDeviceDetected
= FALSE
;
532 MasterDeviceExist
= FALSE
;
533 MasterDeviceType
= 0xff;
534 SlaveDeviceExist
= FALSE
;
535 SlaveDeviceType
= 0xff;
540 This function is called by DiscoverIdeDevice(). It is used for detect
541 whether the IDE device exists in the specified Channel as the specified
544 There is two IDE channels: one is Primary Channel, the other is
545 Secondary Channel.(Channel is the logical name for the physical "Cable".)
546 Different channel has different register group.
548 On each IDE channel, at most two IDE devices attach,
549 one is called Device 0 (Master device), the other is called Device 1
550 (Slave device). The devices on the same channel co-use the same register
551 group, so before sending out a command for a specified device via command
552 register, it is a must to select the current device to accept the command
553 by set the device number in the Head/Device Register.
556 pointer pointing to IDE_BLK_IO_DEV data structure, used
557 to record all the information of the IDE device.
560 successfully detects device.
563 any failure during detection process will return this
567 TODO: EFI_SUCCESS - add return value to function comment
568 TODO: EFI_NOT_FOUND - add return value to function comment
572 DetectIDEController (
573 IN IDE_BLK_IO_DEV
*IdeDev
577 UINT8 SectorCountReg
;
585 // Select slave device
589 IdeDev
->IoPort
->Head
,
590 (UINT8
) ((1 << 4) | 0xe0)
595 // Save the init slave status register
597 InitStatusReg
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
600 // Select Master back
604 IdeDev
->IoPort
->Head
,
605 (UINT8
) ((0 << 4) | 0xe0)
610 // Send ATA Device Execut Diagnostic command.
611 // This command should work no matter DRDY is ready or not
613 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, 0x90);
615 Status
= WaitForBSYClear (IdeDev
, 3500);
616 if (EFI_ERROR (Status
)) {
617 DEBUG((EFI_D_ERROR
, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status
));
621 // Read device signature
628 IdeDev
->IoPort
->Head
,
629 (UINT8
) ((0 << 4) | 0xe0)
632 SectorCountReg
= IDEReadPortB (
634 IdeDev
->IoPort
->SectorCount
636 LBALowReg
= IDEReadPortB (
638 IdeDev
->IoPort
->SectorNumber
640 LBAMidReg
= IDEReadPortB (
642 IdeDev
->IoPort
->CylinderLsb
644 LBAHighReg
= IDEReadPortB (
646 IdeDev
->IoPort
->CylinderMsb
648 if ((SectorCountReg
== 0x1) &&
649 (LBALowReg
== 0x1) &&
650 (LBAMidReg
== 0x0) &&
651 (LBAHighReg
== 0x0)) {
652 MasterDeviceExist
= TRUE
;
653 MasterDeviceType
= ATA_DEVICE_TYPE
;
655 if ((LBAMidReg
== 0x14) &&
656 (LBAHighReg
== 0xeb)) {
657 MasterDeviceExist
= TRUE
;
658 MasterDeviceType
= ATAPI_DEVICE_TYPE
;
663 // For some Hard Drive, it takes some time to get
664 // the right signature when operating in single slave mode.
665 // We stall 20ms to work around this.
667 if (!MasterDeviceExist
) {
676 IdeDev
->IoPort
->Head
,
677 (UINT8
) ((1 << 4) | 0xe0)
680 SectorCountReg
= IDEReadPortB (
682 IdeDev
->IoPort
->SectorCount
684 LBALowReg
= IDEReadPortB (
686 IdeDev
->IoPort
->SectorNumber
688 LBAMidReg
= IDEReadPortB (
690 IdeDev
->IoPort
->CylinderLsb
692 LBAHighReg
= IDEReadPortB (
694 IdeDev
->IoPort
->CylinderMsb
696 StatusReg
= IDEReadPortB (
698 IdeDev
->IoPort
->Reg
.Status
700 if ((SectorCountReg
== 0x1) &&
701 (LBALowReg
== 0x1) &&
702 (LBAMidReg
== 0x0) &&
703 (LBAHighReg
== 0x0)) {
704 SlaveDeviceExist
= TRUE
;
705 SlaveDeviceType
= ATA_DEVICE_TYPE
;
707 if ((LBAMidReg
== 0x14) &&
708 (LBAHighReg
== 0xeb)) {
709 SlaveDeviceExist
= TRUE
;
710 SlaveDeviceType
= ATAPI_DEVICE_TYPE
;
715 // When single master is plugged, slave device
716 // will be wrongly detected. Here's the workaround
717 // for ATA devices by detecting DRY bit in status
719 // NOTE: This workaround doesn't apply to ATAPI.
721 if (MasterDeviceExist
&& SlaveDeviceExist
&&
722 (StatusReg
& ATA_STSREG_DRDY
) == 0 &&
723 (InitStatusReg
& ATA_STSREG_DRDY
) == 0 &&
724 MasterDeviceType
== SlaveDeviceType
&&
725 SlaveDeviceType
!= ATAPI_DEVICE_TYPE
) {
726 SlaveDeviceExist
= FALSE
;
730 // Indicate this channel has been detected
732 ChannelDeviceDetected
= TRUE
;
737 This function is used to poll for the DRQ bit clear in the Status
738 Register. DRQ is cleared when the device is finished transferring data.
739 So this function is called after data transfer is finished.
742 pointer pointing to IDE_BLK_IO_DEV data structure, used
743 to record all the information of the IDE device.
745 @param[in] TimeoutInMilliSeconds
746 used to designate the timeout for the DRQ clear.
749 DRQ bit clear within the time out.
752 DRQ bit not clear within the time out.
755 Read Status Register will clear interrupt status.
760 IN IDE_BLK_IO_DEV
*IdeDev
,
761 IN UINTN TimeoutInMilliSeconds
763 // TODO: function comment is missing 'Routine Description:'
764 // TODO: function comment is missing 'Arguments:'
765 // TODO: IdeDev - add argument and description to function comment
766 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
767 // TODO: EFI_ABORTED - add return value to function comment
770 UINT8 StatusRegister
;
773 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
776 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
779 // wait for BSY == 0 and DRQ == 0
781 if ((StatusRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
785 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
787 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
788 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
810 This function is used to poll for the DRQ bit clear in the Alternate
811 Status Register. DRQ is cleared when the device is finished
812 transferring data. So this function is called after data transfer
816 pointer pointing to IDE_BLK_IO_DEV data structure, used
817 to record all the information of the IDE device.
819 @param[in] TimeoutInMilliSeconds
820 used to designate the timeout for the DRQ clear.
823 DRQ bit clear within the time out.
826 DRQ bit not clear within the time out.
829 Read Alternate Status Register will not clear interrupt status.
834 IN IDE_BLK_IO_DEV
*IdeDev
,
835 IN UINTN TimeoutInMilliSeconds
837 // TODO: function comment is missing 'Routine Description:'
838 // TODO: function comment is missing 'Arguments:'
839 // TODO: IdeDev - add argument and description to function comment
840 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
841 // TODO: EFI_ABORTED - add return value to function comment
847 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
850 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
853 // wait for BSY == 0 and DRQ == 0
855 if ((AltRegister
& (ATA_STSREG_DRQ
| ATA_STSREG_BSY
)) == 0) {
859 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
861 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
862 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
884 This function is used to poll for the DRQ bit set in the
886 DRQ is set when the device is ready to transfer data. So this function
887 is called after the command is sent to the device and before required
890 @param[in] IDE_BLK_IO_DEV IN *IdeDev
891 pointer pointing to IDE_BLK_IO_DEV data structure,used
892 to record all the information of the IDE device.
894 @param[in] UINTN IN TimeoutInMilliSeconds
895 used to designate the timeout for the DRQ ready.
898 DRQ bit set within the time out.
901 DRQ bit not set within the time out.
904 DRQ bit not set caused by the command abort.
907 Read Status Register will clear interrupt status.
912 IN IDE_BLK_IO_DEV
*IdeDev
,
913 IN UINTN TimeoutInMilliSeconds
915 // TODO: function comment is missing 'Routine Description:'
916 // TODO: function comment is missing 'Arguments:'
917 // TODO: IdeDev - add argument and description to function comment
918 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
921 UINT8 StatusRegister
;
924 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
927 // read Status Register will clear interrupt
929 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
934 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
938 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
940 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
941 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
962 This function is used to poll for the DRQ bit set in the
963 Alternate Status Register. DRQ is set when the device is ready to
964 transfer data. So this function is called after the command
965 is sent to the device and before required data is transferred.
967 @param[in] IDE_BLK_IO_DEV IN *IdeDev
968 pointer pointing to IDE_BLK_IO_DEV data structure, used
969 to record all the information of the IDE device.
971 @param[in] UINTN IN TimeoutInMilliSeconds
972 used to designate the timeout for the DRQ ready.
975 DRQ bit set within the time out.
978 DRQ bit not set within the time out.
981 DRQ bit not set caused by the command abort.
984 Read Alternate Status Register will not clear interrupt status.
989 IN IDE_BLK_IO_DEV
*IdeDev
,
990 IN UINTN TimeoutInMilliSeconds
992 // TODO: function comment is missing 'Routine Description:'
993 // TODO: function comment is missing 'Arguments:'
994 // TODO: IdeDev - add argument and description to function comment
995 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1001 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1005 // Read Alternate Status Register will not clear interrupt status
1007 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1009 // BSY == 0 , DRQ == 1
1011 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_DRQ
)) == ATA_STSREG_DRQ
) {
1015 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1017 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1018 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1029 } while (Delay
> 0);
1039 This function is used to poll for the BSY bit clear in the
1040 Status Register. BSY is clear when the device is not busy.
1041 Every command must be sent after device is not busy.
1043 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1044 pointer pointing to IDE_BLK_IO_DEV data structure, used
1045 to record all the information of the IDE device.
1047 @param[in] UINTN IN TimeoutInMilliSeconds
1048 used to designate the timeout for the DRQ ready.
1051 BSY bit clear within the time out.
1054 BSY bit not clear within the time out.
1057 Read Status Register will clear interrupt status.
1062 IN IDE_BLK_IO_DEV
*IdeDev
,
1063 IN UINTN TimeoutInMilliSeconds
1065 // TODO: function comment is missing 'Routine Description:'
1066 // TODO: function comment is missing 'Arguments:'
1067 // TODO: IdeDev - add argument and description to function comment
1068 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1071 UINT8 StatusRegister
;
1073 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1076 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1077 if ((StatusRegister
& ATA_STSREG_BSY
) == 0x00) {
1088 } while (Delay
> 0);
1100 This function is used to poll for the BSY bit clear in the
1101 Alternate Status Register. BSY is clear when the device is not busy.
1102 Every command must be sent after device is not busy.
1104 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1105 pointer pointing to IDE_BLK_IO_DEV data structure, used
1106 to record all the information of the IDE device.
1108 @param[in] UINTN IN TimeoutInMilliSeconds
1109 used to designate the timeout for the DRQ ready.
1112 BSY bit clear within the time out.
1115 BSY bit not clear within the time out.
1118 Read Alternate Status Register will not clear interrupt status.
1123 IN IDE_BLK_IO_DEV
*IdeDev
,
1124 IN UINTN TimeoutInMilliSeconds
1126 // TODO: function comment is missing 'Routine Description:'
1127 // TODO: function comment is missing 'Arguments:'
1128 // TODO: IdeDev - add argument and description to function comment
1129 // TODO: TimeoutInMilliSeconds - add argument and description to function comment
1134 Delay
= (UINT32
) (((TimeoutInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1136 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1137 if ((AltRegister
& ATA_STSREG_BSY
) == 0x00) {
1145 } while (Delay
> 0);
1158 This function is used to poll for the DRDY bit set in the
1159 Status Register. DRDY bit is set when the device is ready
1160 to accept command. Most ATA commands must be sent after
1161 DRDY set except the ATAPI Packet Command.
1163 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1164 pointer pointing to IDE_BLK_IO_DEV data structure, used
1165 to record all the information of the IDE device.
1167 @param[in] UINTN IN DelayInMilliSeconds
1168 used to designate the timeout for the DRQ ready.
1171 DRDY bit set within the time out.
1174 DRDY bit not set within the time out.
1177 Read Status Register will clear interrupt status.
1182 IN IDE_BLK_IO_DEV
*IdeDev
,
1183 IN UINTN DelayInMilliSeconds
1185 // TODO: function comment is missing 'Routine Description:'
1186 // TODO: function comment is missing 'Arguments:'
1187 // TODO: IdeDev - add argument and description to function comment
1188 // TODO: DelayInMilliSeconds - add argument and description to function comment
1189 // TODO: EFI_ABORTED - add return value to function comment
1192 UINT8 StatusRegister
;
1193 UINT8 ErrorRegister
;
1195 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1197 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1199 // BSY == 0 , DRDY == 1
1201 if ((StatusRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1205 if ((StatusRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1207 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1208 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1216 } while (Delay
> 0);
1229 This function is used to poll for the DRDY bit set in the
1230 Alternate Status Register. DRDY bit is set when the device is ready
1231 to accept command. Most ATA commands must be sent after
1232 DRDY set except the ATAPI Packet Command.
1234 @param[in] IDE_BLK_IO_DEV IN *IdeDev
1235 pointer pointing to IDE_BLK_IO_DEV data structure, used
1236 to record all the information of the IDE device.
1238 @param[in] UINTN IN DelayInMilliSeconds
1239 used to designate the timeout for the DRQ ready.
1242 DRDY bit set within the time out.
1245 DRDY bit not set within the time out.
1248 Read Alternate Status Register will clear interrupt status.
1253 IN IDE_BLK_IO_DEV
*IdeDev
,
1254 IN UINTN DelayInMilliSeconds
1256 // TODO: function comment is missing 'Routine Description:'
1257 // TODO: function comment is missing 'Arguments:'
1258 // TODO: IdeDev - add argument and description to function comment
1259 // TODO: DelayInMilliSeconds - add argument and description to function comment
1260 // TODO: EFI_ABORTED - add return value to function comment
1264 UINT8 ErrorRegister
;
1266 Delay
= (UINT32
) (((DelayInMilliSeconds
* STALL_1_MILLI_SECOND
) / 30) + 1);
1268 AltRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.AltStatus
);
1270 // BSY == 0 , DRDY == 1
1272 if ((AltRegister
& (ATA_STSREG_DRDY
| ATA_STSREG_BSY
)) == ATA_STSREG_DRDY
) {
1276 if ((AltRegister
& (ATA_STSREG_BSY
| ATA_STSREG_ERR
)) == ATA_STSREG_ERR
) {
1278 ErrorRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Error
);
1279 if ((ErrorRegister
& ATA_ERRREG_ABRT
) == ATA_ERRREG_ABRT
) {
1287 } while (Delay
> 0);
1300 This function is a helper function used to change the char order in a
1301 string. It is designed specially for the PrintAtaModuleName() function.
1302 After the IDE device is detected, the IDE driver gets the device module
1303 name by sending ATA command called ATA Identify Command or ATAPI
1304 Identify Command to the specified IDE device. The module name returned
1305 is a string of ASCII characters: the first character is bit8--bit15
1306 of the first word, the second character is BIT0--bit7 of the first word
1307 and so on. Thus the string can not be print directly before it is
1308 preprocessed by this func to change the order of characters in
1309 each word in the string.
1311 @param[in] CHAR8 IN *Destination
1312 Indicates the destination string.
1314 @param[in] CHAR8 IN *Source
1315 Indicates the source string.
1317 @param[in] UINT8 IN Size
1318 the length of the string
1323 IN CHAR8
*Destination
,
1331 for (Index
= 0; Index
< Size
; Index
+= 2) {
1333 Temp
= Source
[Index
+ 1];
1334 Destination
[Index
+ 1] = Source
[Index
];
1335 Destination
[Index
] = Temp
;
1340 // ReleaseIdeResources
1343 Release resources of an IDE device before stopping it.
1345 @param[in] *IdeBlkIoDevice Standard IDE device private data structure
1349 ReleaseIdeResources (
1350 IN IDE_BLK_IO_DEV
*IdeBlkIoDevice
1353 if (IdeBlkIoDevice
== NULL
) {
1358 // Release all the resourses occupied by the IDE_BLK_IO_DEV
1361 if (IdeBlkIoDevice
->SenseData
!= NULL
) {
1362 gBS
->FreePool (IdeBlkIoDevice
->SenseData
);
1363 IdeBlkIoDevice
->SenseData
= NULL
;
1366 if (IdeBlkIoDevice
->Cache
!= NULL
) {
1367 gBS
->FreePool (IdeBlkIoDevice
->Cache
);
1368 IdeBlkIoDevice
->Cache
= NULL
;
1371 if (IdeBlkIoDevice
->IdData
!= NULL
) {
1372 gBS
->FreePool (IdeBlkIoDevice
->IdData
);
1373 IdeBlkIoDevice
->IdData
= NULL
;
1376 if (IdeBlkIoDevice
->InquiryData
!= NULL
) {
1377 gBS
->FreePool (IdeBlkIoDevice
->InquiryData
);
1378 IdeBlkIoDevice
->InquiryData
= NULL
;
1381 if (IdeBlkIoDevice
->ControllerNameTable
!= NULL
) {
1382 FreeUnicodeStringTable (IdeBlkIoDevice
->ControllerNameTable
);
1383 IdeBlkIoDevice
->ControllerNameTable
= NULL
;
1386 if (IdeBlkIoDevice
->IoPort
!= NULL
) {
1387 gBS
->FreePool (IdeBlkIoDevice
->IoPort
);
1390 if (IdeBlkIoDevice
->DevicePath
!= NULL
) {
1391 gBS
->FreePool (IdeBlkIoDevice
->DevicePath
);
1394 if (IdeBlkIoDevice
->ExitBootServiceEvent
!= NULL
) {
1395 gBS
->CloseEvent (IdeBlkIoDevice
->ExitBootServiceEvent
);
1396 IdeBlkIoDevice
->ExitBootServiceEvent
= NULL
;
1399 gBS
->FreePool (IdeBlkIoDevice
);
1400 IdeBlkIoDevice
= NULL
;
1406 // SetDeviceTransferMode
1409 Set the calculated Best transfer mode to a detected device
1411 @param[in] *IdeDev Standard IDE device private data structure
1412 @param[in] *TransferMode The device transfer mode to be set
1414 @return Set transfer mode Command execute status.
1418 SetDeviceTransferMode (
1419 IN IDE_BLK_IO_DEV
*IdeDev
,
1420 IN ATA_TRANSFER_MODE
*TransferMode
1422 // TODO: function comment is missing 'Routine Description:'
1429 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1430 SectorCount
= *((UINT8
*) TransferMode
);
1433 // Send SET FEATURE command (sub command 0x03) to set pio mode.
1435 Status
= AtaNonDataCommandIn (
1437 ATA_CMD_SET_FEATURES
,
1450 Send ATA command into device with NON_DATA protocol
1452 @param IdeDev Standard IDE device private data structure
1453 @param AtaCommand The ATA command to be sent
1454 @param Device The value in Device register
1455 @param Feature The value in Feature register
1456 @param SectorCount The value in SectorCount register
1457 @param LbaLow The value in LBA_LOW register
1458 @param LbaMiddle The value in LBA_MIDDLE register
1459 @param LbaHigh The value in LBA_HIGH register
1461 @retval EFI_SUCCESS Reading succeed
1462 @retval EFI_ABORTED Command failed
1463 @retval EFI_DEVICE_ERROR Device status error.
1467 AtaNonDataCommandIn (
1468 IN IDE_BLK_IO_DEV
*IdeDev
,
1469 IN UINT8 AtaCommand
,
1472 IN UINT8 SectorCount
,
1479 UINT8 StatusRegister
;
1481 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1482 if (EFI_ERROR (Status
)) {
1483 return EFI_DEVICE_ERROR
;
1487 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1491 IdeDev
->IoPort
->Head
,
1492 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1496 // ATA commands for ATA device must be issued when DRDY is set
1498 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1499 if (EFI_ERROR (Status
)) {
1500 return EFI_DEVICE_ERROR
;
1504 // Pass parameter into device register block
1506 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1507 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature
);
1508 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount
);
1509 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1510 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMiddle
);
1511 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1514 // Send command via Command Register
1516 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1519 // Wait for command completion
1520 // For ATAPI_SMART_CMD, we may need more timeout to let device
1521 // adjust internal states.
1523 if (AtaCommand
== ATA_CMD_SMART
) {
1524 Status
= WaitForBSYClear (IdeDev
, ATASMARTTIMEOUT
);
1526 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1528 if (EFI_ERROR (Status
)) {
1529 return EFI_DEVICE_ERROR
;
1532 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1533 if ((StatusRegister
& ATA_STSREG_ERR
) == ATA_STSREG_ERR
) {
1535 // Failed to execute command, abort operation
1544 Send ATA Ext command into device with NON_DATA protocol
1546 @param IdeDev Standard IDE device private data structure
1547 @param AtaCommand The ATA command to be sent
1548 @param Device The value in Device register
1549 @param Feature The value in Feature register
1550 @param SectorCount The value in SectorCount register
1551 @param LbaAddress The LBA address in 48-bit mode
1553 @retval EFI_SUCCESS Reading succeed
1554 @retval EFI_ABORTED Command failed
1555 @retval EFI_DEVICE_ERROR Device status error.
1559 AtaNonDataCommandInExt (
1560 IN IDE_BLK_IO_DEV
*IdeDev
,
1561 IN UINT8 AtaCommand
,
1564 IN UINT16 SectorCount
,
1565 IN EFI_LBA LbaAddress
1569 UINT8 StatusRegister
;
1576 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1577 if (EFI_ERROR (Status
)) {
1578 return EFI_DEVICE_ERROR
;
1582 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
1586 IdeDev
->IoPort
->Head
,
1587 (UINT8
) ((IdeDev
->Device
<< 4) | 0xe0)
1591 // ATA commands for ATA device must be issued when DRDY is set
1593 Status
= DRDYReady (IdeDev
, ATATIMEOUT
);
1594 if (EFI_ERROR (Status
)) {
1595 return EFI_DEVICE_ERROR
;
1599 // Pass parameter into device register block
1601 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Head
, Device
);
1604 // Fill the feature register, which is a two-byte FIFO. Need write twice.
1606 Feature8
= (UINT8
) (Feature
>> 8);
1607 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1609 Feature8
= (UINT8
) Feature
;
1610 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg1
.Feature
, Feature8
);
1613 // Fill the sector count register, which is a two-byte FIFO. Need write twice.
1615 SectorCount8
= (UINT8
) (SectorCount
>> 8);
1616 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1618 SectorCount8
= (UINT8
) SectorCount
;
1619 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorCount
, SectorCount8
);
1622 // Fill the start LBA registers, which are also two-byte FIFO
1624 LbaLow
= (UINT8
) RShiftU64 (LbaAddress
, 24);
1625 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 32);
1626 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 40);
1627 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1628 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1629 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1631 LbaLow
= (UINT8
) LbaAddress
;
1632 LbaMid
= (UINT8
) RShiftU64 (LbaAddress
, 8);
1633 LbaHigh
= (UINT8
) RShiftU64 (LbaAddress
, 16);
1634 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->SectorNumber
, LbaLow
);
1635 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderLsb
, LbaMid
);
1636 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->CylinderMsb
, LbaHigh
);
1639 // Send command via Command Register
1641 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Command
, AtaCommand
);
1644 // Wait for command completion
1646 Status
= WaitForBSYClear (IdeDev
, ATATIMEOUT
);
1647 if (EFI_ERROR (Status
)) {
1648 return EFI_DEVICE_ERROR
;
1651 StatusRegister
= IDEReadPortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Reg
.Status
);
1652 if ((StatusRegister
& ATA_STSREG_ERR
) == ATA_STSREG_ERR
) {
1654 // Failed to execute command, abort operation
1663 // SetDriveParameters
1666 Set drive parameters for devices not support PACKETS command
1668 @param[in] IdeDev Standard IDE device private data structure
1669 @param[in] DriveParameters The device parameters to be set into the disk
1671 @return SetParameters Command execute status.
1675 SetDriveParameters (
1676 IN IDE_BLK_IO_DEV
*IdeDev
,
1677 IN ATA_DRIVE_PARMS
*DriveParameters
1684 DeviceSelect
= (UINT8
) ((IdeDev
->Device
) << 4);
1687 // Send Init drive parameters
1689 Status
= AtaNonDataCommandIn (
1691 ATA_CMD_INIT_DRIVE_PARAM
,
1692 (UINT8
) (DeviceSelect
+ DriveParameters
->Heads
),
1694 DriveParameters
->Sector
,
1701 // Send Set Multiple parameters
1703 Status
= AtaNonDataCommandIn (
1705 ATA_CMD_SET_MULTIPLE_MODE
,
1708 DriveParameters
->MultipleSector
,
1717 TODO: Add function description
1719 @param IdeDev TODO: add argument description
1721 @retval EFI_SUCCESS TODO: Add description for return value.
1726 IN IDE_BLK_IO_DEV
*IdeDev
1729 UINT8 DeviceControl
;
1732 // Enable interrupt for DMA operation
1735 IDEWritePortB (IdeDev
->PciIo
, IdeDev
->IoPort
->Alt
.DeviceControl
, DeviceControl
);
1741 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
1743 @param[in] Event Pointer to this event
1744 @param[in] Context Event hanlder private data
1755 UINT64 IoPortForBmis
;
1756 UINT8 RegisterValue
;
1757 IDE_BLK_IO_DEV
*IdeDev
;
1762 IdeDev
= (IDE_BLK_IO_DEV
*) Context
;
1765 // Obtain IDE IO port registers' base addresses
1767 Status
= ReassignIdeResources (IdeDev
);
1768 if (EFI_ERROR (Status
)) {
1773 // Check whether interrupt is pending
1777 // Reset IDE device to force it de-assert interrupt pin
1778 // Note: this will reset all devices on this IDE channel
1780 AtaSoftReset (IdeDev
);
1781 if (EFI_ERROR (Status
)) {
1786 // Get base address of IDE Bus Master Status Regsiter
1788 if (IdePrimary
== IdeDev
->Channel
) {
1789 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISP_OFFSET
;
1791 if (IdeSecondary
== IdeDev
->Channel
) {
1792 IoPortForBmis
= IdeDev
->IoPort
->BusMasterBaseAddr
+ BMISS_OFFSET
;
1798 // Read BMIS register and clear ERROR and INTR bit
1800 IdeDev
->PciIo
->Io
.Read (
1803 EFI_PCI_IO_PASS_THROUGH_BAR
,
1809 RegisterValue
|= (BMIS_INTERRUPT
| BMIS_ERROR
);
1811 IdeDev
->PciIo
->Io
.Write (
1814 EFI_PCI_IO_PASS_THROUGH_BAR
,
1821 // Select the other device on this channel to ensure this device to release the interrupt pin
1823 if (IdeDev
->Device
== 0) {
1824 RegisterValue
= (1 << 4) | 0xe0;
1826 RegisterValue
= (0 << 4) | 0xe0;
1830 IdeDev
->IoPort
->Head
,