]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
Update structure's comments to doxygen style.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ide.c
CommitLineData
ead42efc 1/** @file\r
03417d8d 2 Copyright (c) 2006 - 2008, Intel Corporation\r
ead42efc 3 All rights reserved. This program and the accompanying materials\r
4 are licensed and made available under the terms and conditions of the BSD License\r
5 which accompanies this distribution. The full text of the license may be found at\r
6 http://opensource.org/licenses/bsd-license.php\r
7\r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10\r
11**/\r
12\r
03417d8d 13#include "IdeBus.h"\r
ead42efc 14\r
15BOOLEAN ChannelDeviceDetected = FALSE;\r
16BOOLEAN SlaveDeviceExist = FALSE;\r
17UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
18BOOLEAN MasterDeviceExist = FALSE;\r
19UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
20\r
21/**\r
22 TODO: Add function description\r
23\r
24 @param PciIo TODO: add argument description\r
25 @param Port TODO: add argument description\r
26\r
97404058 27 TODO: add return values.\r
ead42efc 28\r
29**/\r
30UINT8\r
31IDEReadPortB (\r
32 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
33 IN UINT16 Port\r
34 )\r
35{\r
36 UINT8 Data;\r
37\r
38 Data = 0;\r
39 //\r
40 // perform 1-byte data read from register\r
41 //\r
42 PciIo->Io.Read (\r
43 PciIo,\r
44 EfiPciIoWidthUint8,\r
45 EFI_PCI_IO_PASS_THROUGH_BAR,\r
46 (UINT64) Port,\r
47 1,\r
48 &Data\r
49 );\r
50 return Data;\r
51}\r
52\r
53/**\r
54 Reads multiple words of data from the IDE data port.\r
55 Call the IO abstraction once to do the complete read,\r
56 not one word at a time\r
57\r
58 @param PciIo Pointer to the EFI_PCI_IO instance\r
59 @param Port IO port to read\r
60 @param Count No. of UINT16's to read\r
61 @param Buffer Pointer to the data buffer for read\r
62\r
63**/\r
64VOID\r
65IDEReadPortWMultiple (\r
66 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
67 IN UINT16 Port,\r
68 IN UINTN Count,\r
97404058 69 OUT VOID *Buffer\r
ead42efc 70 )\r
71{\r
72 UINT16 *AlignedBuffer;\r
73 UINT16 *WorkingBuffer;\r
74 UINTN Size;\r
75\r
76 //\r
77 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
78 // not perform actual I/O operations if buffer pointer passed in is not at\r
79 // natural boundary. The "Buffer" argument is passed in by user and may not\r
80 // at 16-bit natural boundary.\r
81 //\r
82 Size = sizeof (UINT16) * Count;\r
83\r
84 gBS->AllocatePool (\r
85 EfiBootServicesData,\r
86 Size + 1,\r
87 (VOID**)&WorkingBuffer\r
88 );\r
89\r
90 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
91\r
92 //\r
93 // Perform UINT16 data read from FIFO\r
94 //\r
95 PciIo->Io.Read (\r
96 PciIo,\r
97 EfiPciIoWidthFifoUint16,\r
98 EFI_PCI_IO_PASS_THROUGH_BAR,\r
99 (UINT64) Port,\r
100 Count,\r
101 (UINT16*)AlignedBuffer\r
102 );\r
103\r
104 //\r
105 // Copy data to user buffer\r
106 //\r
107 CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);\r
108 gBS->FreePool (WorkingBuffer);\r
109}\r
110\r
111/**\r
112 TODO: Add function description\r
113\r
114 @param PciIo TODO: add argument description\r
115 @param Port TODO: add argument description\r
116 @param Data TODO: add argument description\r
117\r
97404058 118 TODO: add return values.\r
ead42efc 119\r
120**/\r
121VOID\r
122IDEWritePortB (\r
123 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
124 IN UINT16 Port,\r
125 IN UINT8 Data\r
126 )\r
127{\r
128 //\r
129 // perform 1-byte data write to register\r
130 //\r
131 PciIo->Io.Write (\r
132 PciIo,\r
133 EfiPciIoWidthUint8,\r
134 EFI_PCI_IO_PASS_THROUGH_BAR,\r
135 (UINT64) Port,\r
136 1,\r
137 &Data\r
138 );\r
139\r
140}\r
141\r
142/**\r
143 TODO: Add function description\r
144\r
145 @param PciIo TODO: add argument description\r
146 @param Port TODO: add argument description\r
147 @param Data TODO: add argument description\r
148\r
97404058 149 TODO: add return values.\r
ead42efc 150\r
151**/\r
152VOID\r
153IDEWritePortW (\r
154 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
155 IN UINT16 Port,\r
156 IN UINT16 Data\r
157 )\r
158{\r
159 //\r
160 // perform 1-word data write to register\r
161 //\r
162 PciIo->Io.Write (\r
163 PciIo,\r
164 EfiPciIoWidthUint16,\r
165 EFI_PCI_IO_PASS_THROUGH_BAR,\r
166 (UINT64) Port,\r
167 1,\r
168 &Data\r
169 );\r
170}\r
171\r
172/**\r
173 Write multiple words of data to the IDE data port.\r
174 Call the IO abstraction once to do the complete read,\r
175 not one word at a time\r
176\r
177 @param PciIo Pointer to the EFI_PCI_IO instance\r
178 @param Port IO port to read\r
179 @param Count No. of UINT16's to read\r
180 @param Buffer Pointer to the data buffer for read\r
181\r
182**/\r
183VOID\r
184IDEWritePortWMultiple (\r
185 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
186 IN UINT16 Port,\r
187 IN UINTN Count,\r
188 IN VOID *Buffer\r
189 )\r
190{\r
191 UINT16 *AlignedBuffer;\r
192 UINT32 *WorkingBuffer;\r
193 UINTN Size;\r
194\r
195 //\r
196 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
197 // not perform actual I/O operations if buffer pointer passed in is not at\r
198 // natural boundary. The "Buffer" argument is passed in by user and may not\r
199 // at 16-bit natural boundary.\r
200 //\r
201 Size = sizeof (UINT16) * Count;\r
202\r
203 gBS->AllocatePool (\r
204 EfiBootServicesData,\r
205 Size + 1,\r
206 (VOID **) &WorkingBuffer\r
207 );\r
208\r
209 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
210\r
211 //\r
212 // Copy data from user buffer to working buffer\r
213 //\r
214 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
215\r
216 //\r
217 // perform UINT16 data write to the FIFO\r
218 //\r
219 PciIo->Io.Write (\r
220 PciIo,\r
221 EfiPciIoWidthFifoUint16,\r
222 EFI_PCI_IO_PASS_THROUGH_BAR,\r
223 (UINT64) Port,\r
224 Count,\r
225 (UINT16 *) AlignedBuffer\r
226 );\r
227\r
228 gBS->FreePool (WorkingBuffer);\r
229}\r
230\r
231//\r
232// GetIdeRegistersBaseAddr\r
233//\r
234/**\r
235 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
236 use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
237 the PCI IDE controller's Configuration Space.\r
238\r
239 The steps to get IDE IO port registers' base addresses for each channel\r
240 as follows:\r
241\r
242 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
243 controller's Configuration Space to determine the operating mode.\r
244\r
245 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
246 <pre>\r
247 ___________________________________________\r
248 | | Command Block | Control Block |\r
249 | Channel | Registers | Registers |\r
250 |___________|_______________|_______________|\r
251 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
252 |___________|_______________|_______________|\r
253 | Secondary | 170h - 177h | 376h - 377h |\r
254 |___________|_______________|_______________|\r
255\r
256 Table 1. Compatibility resource mappings\r
257 </pre>\r
258\r
259 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
260 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
261 <pre>\r
262 ___________________________________________________\r
263 | | Command Block | Control Block |\r
264 | Channel | Registers | Registers |\r
265 |___________|___________________|___________________|\r
266 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
267 |___________|___________________|___________________|\r
268 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
269 |___________|___________________|___________________|\r
270\r
271 Table 2. BARs for Register Mapping\r
272 </pre>\r
273 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
274 primary, 0374h for secondary. So 2 bytes extra offset should be\r
275 added to the base addresses read from BARs.\r
276\r
277 For more details, please refer to PCI IDE Controller Specification and Intel\r
278 ICH4 Datasheet.\r
279\r
280 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
281 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
282 receive IDE IO port registers' base addresses\r
283\r
284**/\r
285EFI_STATUS\r
286GetIdeRegistersBaseAddr (\r
287 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
288 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
289 )\r
290// TODO: EFI_UNSUPPORTED - add return value to function comment\r
291// TODO: EFI_UNSUPPORTED - add return value to function comment\r
292// TODO: EFI_SUCCESS - add return value to function comment\r
293{\r
294 EFI_STATUS Status;\r
295 PCI_TYPE00 PciData;\r
296\r
297 Status = PciIo->Pci.Read (\r
298 PciIo,\r
299 EfiPciIoWidthUint8,\r
300 0,\r
301 sizeof (PciData),\r
302 &PciData\r
303 );\r
304\r
305 if (EFI_ERROR (Status)) {\r
306 return Status;\r
307 }\r
308\r
309 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
310 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
311 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
312 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
313 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
314 } else {\r
315 //\r
316 // The BARs should be of IO type\r
317 //\r
1e23bd8d 318 if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
319 (PciData.Device.Bar[1] & BIT0) == 0) {\r
ead42efc 320 return EFI_UNSUPPORTED;\r
321 }\r
322\r
323 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
324 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
325 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
326 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
327 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
328 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
329 }\r
330\r
331 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
332 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
333 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
334 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
335 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
336 } else {\r
337 //\r
338 // The BARs should be of IO type\r
339 //\r
1e23bd8d 340 if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
341 (PciData.Device.Bar[3] & BIT0) == 0) {\r
ead42efc 342 return EFI_UNSUPPORTED;\r
343 }\r
344\r
345 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
346 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
347 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
348 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
349 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
350 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
351 }\r
352\r
353 return EFI_SUCCESS;\r
354}\r
355\r
356/**\r
357 This function is used to requery IDE resources. The IDE controller will\r
358 probably switch between native and legacy modes during the EFI->CSM->OS\r
359 transfer. We do this everytime before an BlkIo operation to ensure its\r
360 succeess.\r
361\r
362 @param IdeDev The BLK_IO private data which specifies the IDE device\r
363\r
364**/\r
365EFI_STATUS\r
366ReassignIdeResources (\r
367 IN IDE_BLK_IO_DEV *IdeDev\r
368 )\r
369// TODO: EFI_SUCCESS - add return value to function comment\r
370{\r
371 EFI_STATUS Status;\r
372 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
373 UINT16 CommandBlockBaseAddr;\r
374 UINT16 ControlBlockBaseAddr;\r
375\r
aa950314 376 if (IdeDev->Channel >= IdeMaxChannel) {\r
377 return EFI_INVALID_PARAMETER;\r
378 }\r
379 \r
ead42efc 380 //\r
381 // Requery IDE IO port registers' base addresses in case of the switch of\r
382 // native and legacy modes\r
383 //\r
384 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
385 if (EFI_ERROR (Status)) {\r
386 return Status;\r
387 }\r
388\r
389 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
390 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
391 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
392\r
393 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
394 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
395 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
396 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
397 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
398 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
399 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
400\r
401 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
402 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
403 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
404 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
405\r
406 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
407 return EFI_SUCCESS;\r
408}\r
409\r
410//\r
411// DiscoverIdeDevice\r
412//\r
413/**\r
414 Detect if there is disk connected to this port\r
415\r
97404058 416 @param IdeDev The BLK_IO private data which specifies the IDE device.\r
ead42efc 417\r
418**/\r
419EFI_STATUS\r
420DiscoverIdeDevice (\r
421 IN IDE_BLK_IO_DEV *IdeDev\r
422 )\r
423// TODO: EFI_NOT_FOUND - add return value to function comment\r
424// TODO: EFI_NOT_FOUND - add return value to function comment\r
425// TODO: EFI_SUCCESS - add return value to function comment\r
426{\r
427 EFI_STATUS Status;\r
75eccf9d 428 EFI_STATUS LongPhyStatus;\r
ead42efc 429\r
430 //\r
431 // If a channel has not been checked, check it now. Then set it to "checked" state\r
432 // After this step, all devices in this channel have been checked.\r
433 //\r
97404058 434 if (!ChannelDeviceDetected) {\r
ead42efc 435 Status = DetectIDEController (IdeDev);\r
436 if (EFI_ERROR (Status)) {\r
437 return EFI_NOT_FOUND;\r
438 }\r
439 }\r
440\r
441 Status = EFI_NOT_FOUND;\r
442\r
443 //\r
444 // Device exists. test if it is an ATA device.\r
445 // Prefer the result from DetectIDEController,\r
446 // if failed, try another device type to handle\r
447 // devices that not follow the spec.\r
448 //\r
449 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
450 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
451 Status = ATAIdentify (IdeDev);\r
452 if (EFI_ERROR (Status)) {\r
453 Status = ATAPIIdentify (IdeDev);\r
454 if (!EFI_ERROR (Status)) {\r
455 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
456 }\r
457 }\r
458 } else {\r
459 Status = ATAPIIdentify (IdeDev);\r
460 if (EFI_ERROR (Status)) {\r
461 Status = ATAIdentify (IdeDev);\r
462 if (!EFI_ERROR (Status)) {\r
463 MasterDeviceType = ATA_DEVICE_TYPE;\r
464 }\r
465 }\r
466 }\r
467 }\r
468 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
469 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
470 Status = ATAIdentify (IdeDev);\r
471 if (EFI_ERROR (Status)) {\r
472 Status = ATAPIIdentify (IdeDev);\r
473 if (!EFI_ERROR (Status)) {\r
474 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
475 }\r
476 }\r
477 } else {\r
478 Status = ATAPIIdentify (IdeDev);\r
479 if (EFI_ERROR (Status)) {\r
480 Status = ATAIdentify (IdeDev);\r
481 if (!EFI_ERROR (Status)) {\r
482 SlaveDeviceType = ATA_DEVICE_TYPE;\r
483 }\r
484 }\r
485 }\r
486 }\r
487 if (EFI_ERROR (Status)) {\r
488 return EFI_NOT_FOUND;\r
489 }\r
490 //\r
491 // Init Block I/O interface\r
492 //\r
75eccf9d 493 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);\r
494 if (!EFI_ERROR (LongPhyStatus)) {\r
495 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
496 } else {\r
497 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
498 }\r
ead42efc 499 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
500 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
501 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
502 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
503\r
504 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
505 IdeDev->BlkMedia.WriteCaching = FALSE;\r
506\r
507 //\r
508 // Init Disk Info interface\r
509 //\r
510 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
511 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
512 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
513 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
514 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
515\r
516 return EFI_SUCCESS;\r
517}\r
518\r
519/**\r
520 This interface is used to initialize all state data related to the detection of one\r
521 channel.\r
522\r
523 @retval EFI_SUCCESS Completed Successfully.\r
524\r
525**/\r
526EFI_STATUS\r
527InitializeIDEChannelData (\r
528 VOID\r
529 )\r
530{\r
531 ChannelDeviceDetected = FALSE;\r
532 MasterDeviceExist = FALSE;\r
533 MasterDeviceType = 0xff;\r
534 SlaveDeviceExist = FALSE;\r
535 SlaveDeviceType = 0xff;\r
536 return EFI_SUCCESS;\r
537}\r
538\r
539/**\r
540 This function is called by DiscoverIdeDevice(). It is used for detect\r
541 whether the IDE device exists in the specified Channel as the specified\r
542 Device Number.\r
543\r
544 There is two IDE channels: one is Primary Channel, the other is\r
545 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
546 Different channel has different register group.\r
547\r
548 On each IDE channel, at most two IDE devices attach,\r
549 one is called Device 0 (Master device), the other is called Device 1\r
550 (Slave device). The devices on the same channel co-use the same register\r
551 group, so before sending out a command for a specified device via command\r
552 register, it is a must to select the current device to accept the command\r
553 by set the device number in the Head/Device Register.\r
554\r
555 @param[in] *IdeDev\r
556 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
557 to record all the information of the IDE device.\r
558\r
559 @retval TRUE\r
560 successfully detects device.\r
561\r
562 @retval FALSE\r
563 any failure during detection process will return this\r
564 value.\r
565\r
566 @note\r
567 TODO: EFI_SUCCESS - add return value to function comment\r
568 TODO: EFI_NOT_FOUND - add return value to function comment\r
569\r
570**/\r
571EFI_STATUS\r
572DetectIDEController (\r
573 IN IDE_BLK_IO_DEV *IdeDev\r
574 )\r
575{\r
576 EFI_STATUS Status;\r
577 UINT8 SectorCountReg;\r
578 UINT8 LBALowReg;\r
579 UINT8 LBAMidReg;\r
580 UINT8 LBAHighReg;\r
581 UINT8 InitStatusReg;\r
582 UINT8 StatusReg;\r
583\r
584 //\r
585 // Select slave device\r
586 //\r
587 IDEWritePortB (\r
588 IdeDev->PciIo,\r
589 IdeDev->IoPort->Head,\r
590 (UINT8) ((1 << 4) | 0xe0)\r
591 );\r
592 gBS->Stall (100);\r
593\r
594 //\r
595 // Save the init slave status register\r
596 //\r
597 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
598\r
599 //\r
600 // Select Master back\r
601 //\r
602 IDEWritePortB (\r
603 IdeDev->PciIo,\r
604 IdeDev->IoPort->Head,\r
605 (UINT8) ((0 << 4) | 0xe0)\r
606 );\r
607 gBS->Stall (100);\r
608\r
609 //\r
610 // Send ATA Device Execut Diagnostic command.\r
611 // This command should work no matter DRDY is ready or not\r
612 //\r
613 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
614\r
615 Status = WaitForBSYClear (IdeDev, 3500);\r
616 if (EFI_ERROR (Status)) {\r
617 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
618 return Status;\r
619 }\r
620 //\r
621 // Read device signature\r
622 //\r
623 //\r
624 // Select Master\r
625 //\r
626 IDEWritePortB (\r
627 IdeDev->PciIo,\r
628 IdeDev->IoPort->Head,\r
629 (UINT8) ((0 << 4) | 0xe0)\r
630 );\r
631 gBS->Stall (100);\r
632 SectorCountReg = IDEReadPortB (\r
633 IdeDev->PciIo,\r
634 IdeDev->IoPort->SectorCount\r
635 );\r
636 LBALowReg = IDEReadPortB (\r
637 IdeDev->PciIo,\r
638 IdeDev->IoPort->SectorNumber\r
639 );\r
640 LBAMidReg = IDEReadPortB (\r
641 IdeDev->PciIo,\r
642 IdeDev->IoPort->CylinderLsb\r
643 );\r
644 LBAHighReg = IDEReadPortB (\r
645 IdeDev->PciIo,\r
646 IdeDev->IoPort->CylinderMsb\r
647 );\r
648 if ((SectorCountReg == 0x1) &&\r
649 (LBALowReg == 0x1) &&\r
650 (LBAMidReg == 0x0) &&\r
651 (LBAHighReg == 0x0)) {\r
652 MasterDeviceExist = TRUE;\r
653 MasterDeviceType = ATA_DEVICE_TYPE;\r
654 } else {\r
655 if ((LBAMidReg == 0x14) &&\r
656 (LBAHighReg == 0xeb)) {\r
657 MasterDeviceExist = TRUE;\r
658 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
659 }\r
660 }\r
661\r
662 //\r
663 // For some Hard Drive, it takes some time to get\r
664 // the right signature when operating in single slave mode.\r
665 // We stall 20ms to work around this.\r
666 //\r
667 if (!MasterDeviceExist) {\r
668 gBS->Stall (20000);\r
669 }\r
670\r
671 //\r
672 // Select Slave\r
673 //\r
674 IDEWritePortB (\r
675 IdeDev->PciIo,\r
676 IdeDev->IoPort->Head,\r
677 (UINT8) ((1 << 4) | 0xe0)\r
678 );\r
679 gBS->Stall (100);\r
680 SectorCountReg = IDEReadPortB (\r
681 IdeDev->PciIo,\r
682 IdeDev->IoPort->SectorCount\r
683 );\r
684 LBALowReg = IDEReadPortB (\r
685 IdeDev->PciIo,\r
686 IdeDev->IoPort->SectorNumber\r
687 );\r
688 LBAMidReg = IDEReadPortB (\r
689 IdeDev->PciIo,\r
690 IdeDev->IoPort->CylinderLsb\r
691 );\r
692 LBAHighReg = IDEReadPortB (\r
693 IdeDev->PciIo,\r
694 IdeDev->IoPort->CylinderMsb\r
695 );\r
696 StatusReg = IDEReadPortB (\r
697 IdeDev->PciIo,\r
698 IdeDev->IoPort->Reg.Status\r
699 );\r
700 if ((SectorCountReg == 0x1) &&\r
701 (LBALowReg == 0x1) &&\r
702 (LBAMidReg == 0x0) &&\r
703 (LBAHighReg == 0x0)) {\r
704 SlaveDeviceExist = TRUE;\r
705 SlaveDeviceType = ATA_DEVICE_TYPE;\r
706 } else {\r
707 if ((LBAMidReg == 0x14) &&\r
708 (LBAHighReg == 0xeb)) {\r
709 SlaveDeviceExist = TRUE;\r
710 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
711 }\r
712 }\r
713\r
714 //\r
715 // When single master is plugged, slave device\r
716 // will be wrongly detected. Here's the workaround\r
717 // for ATA devices by detecting DRY bit in status\r
718 // register.\r
719 // NOTE: This workaround doesn't apply to ATAPI.\r
720 //\r
721 if (MasterDeviceExist && SlaveDeviceExist &&\r
1e23bd8d 722 (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
723 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
ead42efc 724 MasterDeviceType == SlaveDeviceType &&\r
725 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
726 SlaveDeviceExist = FALSE;\r
727 }\r
728\r
729 //\r
730 // Indicate this channel has been detected\r
731 //\r
732 ChannelDeviceDetected = TRUE;\r
733 return EFI_SUCCESS;\r
734}\r
735\r
736/**\r
737 This function is used to poll for the DRQ bit clear in the Status\r
738 Register. DRQ is cleared when the device is finished transferring data.\r
739 So this function is called after data transfer is finished.\r
740\r
741 @param[in] *IdeDev\r
742 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
743 to record all the information of the IDE device.\r
744\r
745 @param[in] TimeoutInMilliSeconds\r
746 used to designate the timeout for the DRQ clear.\r
747\r
748 @retval EFI_SUCCESS\r
749 DRQ bit clear within the time out.\r
750\r
751 @retval EFI_TIMEOUT\r
752 DRQ bit not clear within the time out.\r
753\r
754 @note\r
755 Read Status Register will clear interrupt status.\r
756\r
757**/\r
758EFI_STATUS\r
759DRQClear (\r
760 IN IDE_BLK_IO_DEV *IdeDev,\r
761 IN UINTN TimeoutInMilliSeconds\r
762 )\r
763// TODO: function comment is missing 'Routine Description:'\r
764// TODO: function comment is missing 'Arguments:'\r
765// TODO: IdeDev - add argument and description to function comment\r
766// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
767// TODO: EFI_ABORTED - add return value to function comment\r
768{\r
769 UINT32 Delay;\r
770 UINT8 StatusRegister;\r
771 UINT8 ErrorRegister;\r
772\r
773 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
774 do {\r
775\r
776 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
777\r
778 //\r
779 // wait for BSY == 0 and DRQ == 0\r
780 //\r
1e23bd8d 781 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 782 break;\r
783 }\r
784\r
1e23bd8d 785 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 786\r
787 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 788 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 789 return EFI_ABORTED;\r
790 }\r
791 }\r
792\r
793 //\r
794 // Stall for 30 us\r
795 //\r
796 gBS->Stall (30);\r
797\r
798 Delay--;\r
799\r
97404058 800 } while (Delay > 0);\r
ead42efc 801\r
802 if (Delay == 0) {\r
803 return EFI_TIMEOUT;\r
804 }\r
805\r
806 return EFI_SUCCESS;\r
807}\r
808\r
809/**\r
810 This function is used to poll for the DRQ bit clear in the Alternate\r
811 Status Register. DRQ is cleared when the device is finished\r
812 transferring data. So this function is called after data transfer\r
813 is finished.\r
814\r
815 @param[in] *IdeDev\r
816 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
817 to record all the information of the IDE device.\r
818\r
819 @param[in] TimeoutInMilliSeconds\r
820 used to designate the timeout for the DRQ clear.\r
821\r
822 @retval EFI_SUCCESS\r
823 DRQ bit clear within the time out.\r
824\r
825 @retval EFI_TIMEOUT\r
826 DRQ bit not clear within the time out.\r
827\r
828 @note\r
829 Read Alternate Status Register will not clear interrupt status.\r
830\r
831**/\r
832EFI_STATUS\r
833DRQClear2 (\r
834 IN IDE_BLK_IO_DEV *IdeDev,\r
835 IN UINTN TimeoutInMilliSeconds\r
836 )\r
837// TODO: function comment is missing 'Routine Description:'\r
838// TODO: function comment is missing 'Arguments:'\r
839// TODO: IdeDev - add argument and description to function comment\r
840// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
841// TODO: EFI_ABORTED - add return value to function comment\r
842{\r
843 UINT32 Delay;\r
844 UINT8 AltRegister;\r
845 UINT8 ErrorRegister;\r
846\r
847 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
848 do {\r
849\r
850 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
851\r
852 //\r
853 // wait for BSY == 0 and DRQ == 0\r
854 //\r
1e23bd8d 855 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 856 break;\r
857 }\r
858\r
1e23bd8d 859 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 860\r
861 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 862 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 863 return EFI_ABORTED;\r
864 }\r
865 }\r
866\r
867 //\r
868 // Stall for 30 us\r
869 //\r
870 gBS->Stall (30);\r
871\r
872 Delay--;\r
873\r
97404058 874 } while (Delay > 0);\r
ead42efc 875\r
876 if (Delay == 0) {\r
877 return EFI_TIMEOUT;\r
878 }\r
879\r
880 return EFI_SUCCESS;\r
881}\r
882\r
883/**\r
884 This function is used to poll for the DRQ bit set in the\r
885 Status Register.\r
886 DRQ is set when the device is ready to transfer data. So this function\r
887 is called after the command is sent to the device and before required\r
888 data is transferred.\r
889\r
890 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
891 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
892 to record all the information of the IDE device.\r
893\r
894 @param[in] UINTN IN TimeoutInMilliSeconds\r
895 used to designate the timeout for the DRQ ready.\r
896\r
897 @retval EFI_SUCCESS\r
898 DRQ bit set within the time out.\r
899\r
900 @retval EFI_TIMEOUT\r
901 DRQ bit not set within the time out.\r
902\r
903 @retval EFI_ABORTED\r
904 DRQ bit not set caused by the command abort.\r
905\r
906 @note\r
907 Read Status Register will clear interrupt status.\r
908\r
909**/\r
910EFI_STATUS\r
911DRQReady (\r
912 IN IDE_BLK_IO_DEV *IdeDev,\r
913 IN UINTN TimeoutInMilliSeconds\r
914 )\r
915// TODO: function comment is missing 'Routine Description:'\r
916// TODO: function comment is missing 'Arguments:'\r
917// TODO: IdeDev - add argument and description to function comment\r
918// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
919{\r
920 UINT32 Delay;\r
921 UINT8 StatusRegister;\r
922 UINT8 ErrorRegister;\r
923\r
924 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
925 do {\r
926 //\r
927 // read Status Register will clear interrupt\r
928 //\r
929 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
930\r
931 //\r
932 // BSY==0,DRQ==1\r
933 //\r
1e23bd8d 934 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 935 break;\r
936 }\r
937\r
1e23bd8d 938 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 939\r
940 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 941 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 942 return EFI_ABORTED;\r
943 }\r
944 }\r
945\r
946 //\r
947 // Stall for 30 us\r
948 //\r
949 gBS->Stall (30);\r
950\r
951 Delay--;\r
97404058 952 } while (Delay > 0);\r
ead42efc 953\r
954 if (Delay == 0) {\r
955 return EFI_TIMEOUT;\r
956 }\r
957\r
958 return EFI_SUCCESS;\r
959}\r
960\r
961/**\r
962 This function is used to poll for the DRQ bit set in the\r
963 Alternate Status Register. DRQ is set when the device is ready to\r
964 transfer data. So this function is called after the command\r
965 is sent to the device and before required data is transferred.\r
966\r
967 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
968 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
969 to record all the information of the IDE device.\r
970\r
971 @param[in] UINTN IN TimeoutInMilliSeconds\r
972 used to designate the timeout for the DRQ ready.\r
973\r
974 @retval EFI_SUCCESS\r
975 DRQ bit set within the time out.\r
976\r
977 @retval EFI_TIMEOUT\r
978 DRQ bit not set within the time out.\r
979\r
980 @retval EFI_ABORTED\r
981 DRQ bit not set caused by the command abort.\r
982\r
983 @note\r
984 Read Alternate Status Register will not clear interrupt status.\r
985\r
986**/\r
987EFI_STATUS\r
988DRQReady2 (\r
989 IN IDE_BLK_IO_DEV *IdeDev,\r
990 IN UINTN TimeoutInMilliSeconds\r
991 )\r
992// TODO: function comment is missing 'Routine Description:'\r
993// TODO: function comment is missing 'Arguments:'\r
994// TODO: IdeDev - add argument and description to function comment\r
995// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
996{\r
997 UINT32 Delay;\r
998 UINT8 AltRegister;\r
999 UINT8 ErrorRegister;\r
1000\r
1001 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1002\r
1003 do {\r
1004 //\r
1005 // Read Alternate Status Register will not clear interrupt status\r
1006 //\r
1007 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1008 //\r
1009 // BSY == 0 , DRQ == 1\r
1010 //\r
1e23bd8d 1011 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 1012 break;\r
1013 }\r
1014\r
1e23bd8d 1015 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1016\r
1017 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1018 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1019 return EFI_ABORTED;\r
1020 }\r
1021 }\r
1022\r
1023 //\r
1024 // Stall for 30 us\r
1025 //\r
1026 gBS->Stall (30);\r
1027\r
1028 Delay--;\r
97404058 1029 } while (Delay > 0);\r
ead42efc 1030\r
1031 if (Delay == 0) {\r
1032 return EFI_TIMEOUT;\r
1033 }\r
1034\r
1035 return EFI_SUCCESS;\r
1036}\r
1037\r
1038/**\r
1039 This function is used to poll for the BSY bit clear in the\r
1040 Status Register. BSY is clear when the device is not busy.\r
1041 Every command must be sent after device is not busy.\r
1042\r
1043 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1044 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1045 to record all the information of the IDE device.\r
1046\r
1047 @param[in] UINTN IN TimeoutInMilliSeconds\r
1048 used to designate the timeout for the DRQ ready.\r
1049\r
1050 @retval EFI_SUCCESS\r
1051 BSY bit clear within the time out.\r
1052\r
1053 @retval EFI_TIMEOUT\r
1054 BSY bit not clear within the time out.\r
1055\r
1056 @note\r
1057 Read Status Register will clear interrupt status.\r
1058\r
1059**/\r
1060EFI_STATUS\r
1061WaitForBSYClear (\r
1062 IN IDE_BLK_IO_DEV *IdeDev,\r
1063 IN UINTN TimeoutInMilliSeconds\r
1064 )\r
1065// TODO: function comment is missing 'Routine Description:'\r
1066// TODO: function comment is missing 'Arguments:'\r
1067// TODO: IdeDev - add argument and description to function comment\r
1068// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1069{\r
1070 UINT32 Delay;\r
1071 UINT8 StatusRegister;\r
1072\r
1073 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1074 do {\r
1075\r
1076 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1077 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1078 break;\r
1079 }\r
1080\r
1081 //\r
1082 // Stall for 30 us\r
1083 //\r
1084 gBS->Stall (30);\r
1085\r
1086 Delay--;\r
1087\r
97404058 1088 } while (Delay > 0);\r
ead42efc 1089\r
1090 if (Delay == 0) {\r
1091 return EFI_TIMEOUT;\r
1092 }\r
1093\r
1094 return EFI_SUCCESS;\r
1095}\r
1096//\r
1097// WaitForBSYClear2\r
1098//\r
1099/**\r
1100 This function is used to poll for the BSY bit clear in the\r
1101 Alternate Status Register. BSY is clear when the device is not busy.\r
1102 Every command must be sent after device is not busy.\r
1103\r
1104 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1105 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1106 to record all the information of the IDE device.\r
1107\r
1108 @param[in] UINTN IN TimeoutInMilliSeconds\r
1109 used to designate the timeout for the DRQ ready.\r
1110\r
1111 @retval EFI_SUCCESS\r
1112 BSY bit clear within the time out.\r
1113\r
1114 @retval EFI_TIMEOUT\r
1115 BSY bit not clear within the time out.\r
1116\r
1117 @note\r
1118 Read Alternate Status Register will not clear interrupt status.\r
1119\r
1120**/\r
1121EFI_STATUS\r
1122WaitForBSYClear2 (\r
1123 IN IDE_BLK_IO_DEV *IdeDev,\r
1124 IN UINTN TimeoutInMilliSeconds\r
1125 )\r
1126// TODO: function comment is missing 'Routine Description:'\r
1127// TODO: function comment is missing 'Arguments:'\r
1128// TODO: IdeDev - add argument and description to function comment\r
1129// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1130{\r
1131 UINT32 Delay;\r
1132 UINT8 AltRegister;\r
1133\r
1134 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1135 do {\r
1136 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1e23bd8d 1137 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1138 break;\r
1139 }\r
1140\r
1141 gBS->Stall (30);\r
1142\r
1143 Delay--;\r
1144\r
97404058 1145 } while (Delay > 0);\r
ead42efc 1146\r
1147 if (Delay == 0) {\r
1148 return EFI_TIMEOUT;\r
1149 }\r
1150\r
1151 return EFI_SUCCESS;\r
1152}\r
1153\r
1154//\r
1155// DRDYReady\r
1156//\r
1157/**\r
1158 This function is used to poll for the DRDY bit set in the\r
1159 Status Register. DRDY bit is set when the device is ready\r
1160 to accept command. Most ATA commands must be sent after\r
1161 DRDY set except the ATAPI Packet Command.\r
1162\r
1163 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1164 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1165 to record all the information of the IDE device.\r
1166\r
97404058 1167 @param[in] UINTN IN DelayInMilliSeconds\r
ead42efc 1168 used to designate the timeout for the DRQ ready.\r
1169\r
1170 @retval EFI_SUCCESS\r
1171 DRDY bit set within the time out.\r
1172\r
1173 @retval EFI_TIMEOUT\r
1174 DRDY bit not set within the time out.\r
1175\r
1176 @note\r
1177 Read Status Register will clear interrupt status.\r
1178\r
1179**/\r
1180EFI_STATUS\r
1181DRDYReady (\r
1182 IN IDE_BLK_IO_DEV *IdeDev,\r
1183 IN UINTN DelayInMilliSeconds\r
1184 )\r
1185// TODO: function comment is missing 'Routine Description:'\r
1186// TODO: function comment is missing 'Arguments:'\r
1187// TODO: IdeDev - add argument and description to function comment\r
1188// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1189// TODO: EFI_ABORTED - add return value to function comment\r
1190{\r
1191 UINT32 Delay;\r
1192 UINT8 StatusRegister;\r
1193 UINT8 ErrorRegister;\r
1194\r
1195 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1196 do {\r
1197 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1198 //\r
1199 // BSY == 0 , DRDY == 1\r
1200 //\r
1e23bd8d 1201 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1202 break;\r
1203 }\r
1204\r
1e23bd8d 1205 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1206\r
1207 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1208 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1209 return EFI_ABORTED;\r
1210 }\r
1211 }\r
1212\r
1213 gBS->Stall (30);\r
1214\r
1215 Delay--;\r
97404058 1216 } while (Delay > 0);\r
ead42efc 1217\r
1218 if (Delay == 0) {\r
1219 return EFI_TIMEOUT;\r
1220 }\r
1221\r
1222 return EFI_SUCCESS;\r
1223}\r
1224\r
1225//\r
1226// DRDYReady2\r
1227//\r
1228/**\r
1229 This function is used to poll for the DRDY bit set in the\r
1230 Alternate Status Register. DRDY bit is set when the device is ready\r
1231 to accept command. Most ATA commands must be sent after\r
1232 DRDY set except the ATAPI Packet Command.\r
1233\r
1234 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1235 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1236 to record all the information of the IDE device.\r
1237\r
97404058 1238 @param[in] UINTN IN DelayInMilliSeconds\r
ead42efc 1239 used to designate the timeout for the DRQ ready.\r
1240\r
1241 @retval EFI_SUCCESS\r
1242 DRDY bit set within the time out.\r
1243\r
1244 @retval EFI_TIMEOUT\r
1245 DRDY bit not set within the time out.\r
1246\r
1247 @note\r
1248 Read Alternate Status Register will clear interrupt status.\r
1249\r
1250**/\r
1251EFI_STATUS\r
1252DRDYReady2 (\r
1253 IN IDE_BLK_IO_DEV *IdeDev,\r
1254 IN UINTN DelayInMilliSeconds\r
1255 )\r
1256// TODO: function comment is missing 'Routine Description:'\r
1257// TODO: function comment is missing 'Arguments:'\r
1258// TODO: IdeDev - add argument and description to function comment\r
1259// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1260// TODO: EFI_ABORTED - add return value to function comment\r
1261{\r
1262 UINT32 Delay;\r
1263 UINT8 AltRegister;\r
1264 UINT8 ErrorRegister;\r
1265\r
1266 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1267 do {\r
1268 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1269 //\r
1270 // BSY == 0 , DRDY == 1\r
1271 //\r
1e23bd8d 1272 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1273 break;\r
1274 }\r
1275\r
1e23bd8d 1276 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1277\r
1278 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1279 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1280 return EFI_ABORTED;\r
1281 }\r
1282 }\r
1283\r
1284 gBS->Stall (30);\r
1285\r
1286 Delay--;\r
97404058 1287 } while (Delay > 0);\r
ead42efc 1288\r
1289 if (Delay == 0) {\r
1290 return EFI_TIMEOUT;\r
1291 }\r
1292\r
1293 return EFI_SUCCESS;\r
1294}\r
1295\r
1296//\r
1297// SwapStringChars\r
1298//\r
1299/**\r
1300 This function is a helper function used to change the char order in a\r
1301 string. It is designed specially for the PrintAtaModuleName() function.\r
1302 After the IDE device is detected, the IDE driver gets the device module\r
1303 name by sending ATA command called ATA Identify Command or ATAPI\r
1304 Identify Command to the specified IDE device. The module name returned\r
1305 is a string of ASCII characters: the first character is bit8--bit15\r
1e23bd8d 1306 of the first word, the second character is BIT0--bit7 of the first word\r
ead42efc 1307 and so on. Thus the string can not be print directly before it is\r
1308 preprocessed by this func to change the order of characters in\r
1309 each word in the string.\r
1310\r
1311 @param[in] CHAR8 IN *Destination\r
1312 Indicates the destination string.\r
1313\r
1314 @param[in] CHAR8 IN *Source\r
1315 Indicates the source string.\r
1316\r
1317 @param[in] UINT8 IN Size\r
1318 the length of the string\r
1319\r
1320**/\r
1321VOID\r
1322SwapStringChars (\r
1323 IN CHAR8 *Destination,\r
1324 IN CHAR8 *Source,\r
1325 IN UINT32 Size\r
1326 )\r
1327{\r
1328 UINT32 Index;\r
1329 CHAR8 Temp;\r
1330\r
1331 for (Index = 0; Index < Size; Index += 2) {\r
1332\r
1333 Temp = Source[Index + 1];\r
1334 Destination[Index + 1] = Source[Index];\r
1335 Destination[Index] = Temp;\r
1336 }\r
1337}\r
1338\r
1339//\r
1340// ReleaseIdeResources\r
1341//\r
1342/**\r
1343 Release resources of an IDE device before stopping it.\r
1344\r
1345 @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
1346\r
1347**/\r
1348VOID\r
1349ReleaseIdeResources (\r
1350 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1351 )\r
1352{\r
1353 if (IdeBlkIoDevice == NULL) {\r
1354 return ;\r
1355 }\r
1356\r
1357 //\r
1358 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1359 //\r
1360\r
1361 if (IdeBlkIoDevice->SenseData != NULL) {\r
1362 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1363 IdeBlkIoDevice->SenseData = NULL;\r
1364 }\r
1365\r
1366 if (IdeBlkIoDevice->Cache != NULL) {\r
1367 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1368 IdeBlkIoDevice->Cache = NULL;\r
1369 }\r
1370\r
e72ca438 1371 if (IdeBlkIoDevice->IdData != NULL) {\r
1372 gBS->FreePool (IdeBlkIoDevice->IdData);\r
1373 IdeBlkIoDevice->IdData = NULL;\r
ead42efc 1374 }\r
1375\r
e72ca438 1376 if (IdeBlkIoDevice->InquiryData != NULL) {\r
1377 gBS->FreePool (IdeBlkIoDevice->InquiryData);\r
1378 IdeBlkIoDevice->InquiryData = NULL;\r
ead42efc 1379 }\r
1380\r
1381 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1382 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1383 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1384 }\r
1385\r
1386 if (IdeBlkIoDevice->IoPort != NULL) {\r
1387 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1388 }\r
1389\r
1390 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1391 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1392 }\r
1393\r
1394 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1395 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1396 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1397 }\r
1398\r
1399 gBS->FreePool (IdeBlkIoDevice);\r
1400 IdeBlkIoDevice = NULL;\r
1401\r
1402 return ;\r
1403}\r
1404\r
1405//\r
1406// SetDeviceTransferMode\r
1407//\r
1408/**\r
1409 Set the calculated Best transfer mode to a detected device\r
1410\r
1411 @param[in] *IdeDev Standard IDE device private data structure\r
1412 @param[in] *TransferMode The device transfer mode to be set\r
1413\r
97404058 1414 @return Set transfer mode Command execute status.\r
ead42efc 1415\r
1416**/\r
1417EFI_STATUS\r
1418SetDeviceTransferMode (\r
1419 IN IDE_BLK_IO_DEV *IdeDev,\r
1420 IN ATA_TRANSFER_MODE *TransferMode\r
1421 )\r
1422// TODO: function comment is missing 'Routine Description:'\r
1423{\r
1424 EFI_STATUS Status;\r
1425 UINT8 DeviceSelect;\r
1426 UINT8 SectorCount;\r
1427\r
1428 DeviceSelect = 0;\r
1429 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1430 SectorCount = *((UINT8 *) TransferMode);\r
1431\r
1432 //\r
1433 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1434 //\r
1435 Status = AtaNonDataCommandIn (\r
1436 IdeDev,\r
1e23bd8d 1437 ATA_CMD_SET_FEATURES,\r
ead42efc 1438 DeviceSelect,\r
1439 0x03,\r
1440 SectorCount,\r
1441 0,\r
1442 0,\r
1443 0\r
1444 );\r
1445\r
1446 return Status;\r
1447}\r
1448\r
1449/**\r
1450 Send ATA command into device with NON_DATA protocol\r
1451\r
1452 @param IdeDev Standard IDE device private data structure\r
1453 @param AtaCommand The ATA command to be sent\r
1454 @param Device The value in Device register\r
1455 @param Feature The value in Feature register\r
1456 @param SectorCount The value in SectorCount register\r
1457 @param LbaLow The value in LBA_LOW register\r
1458 @param LbaMiddle The value in LBA_MIDDLE register\r
1459 @param LbaHigh The value in LBA_HIGH register\r
1460\r
1461 @retval EFI_SUCCESS Reading succeed\r
1462 @retval EFI_ABORTED Command failed\r
97404058 1463 @retval EFI_DEVICE_ERROR Device status error.\r
ead42efc 1464\r
1465**/\r
1466EFI_STATUS\r
1467AtaNonDataCommandIn (\r
1468 IN IDE_BLK_IO_DEV *IdeDev,\r
1469 IN UINT8 AtaCommand,\r
1470 IN UINT8 Device,\r
1471 IN UINT8 Feature,\r
1472 IN UINT8 SectorCount,\r
1473 IN UINT8 LbaLow,\r
1474 IN UINT8 LbaMiddle,\r
1475 IN UINT8 LbaHigh\r
1476 )\r
1477{\r
1478 EFI_STATUS Status;\r
1479 UINT8 StatusRegister;\r
1480\r
1481 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1482 if (EFI_ERROR (Status)) {\r
1483 return EFI_DEVICE_ERROR;\r
1484 }\r
1485\r
1486 //\r
1487 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1488 //\r
1489 IDEWritePortB (\r
1490 IdeDev->PciIo,\r
1491 IdeDev->IoPort->Head,\r
1492 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1493 );\r
1494\r
1495 //\r
1496 // ATA commands for ATA device must be issued when DRDY is set\r
1497 //\r
1498 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1499 if (EFI_ERROR (Status)) {\r
1500 return EFI_DEVICE_ERROR;\r
1501 }\r
1502\r
1503 //\r
1504 // Pass parameter into device register block\r
1505 //\r
1506 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1507 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
1508 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
1509 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1510 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
1511 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1512\r
1513 //\r
1514 // Send command via Command Register\r
1515 //\r
1516 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1517\r
1518 //\r
1519 // Wait for command completion\r
1e23bd8d 1520 // For ATAPI_SMART_CMD, we may need more timeout to let device\r
ead42efc 1521 // adjust internal states.\r
1522 //\r
1e23bd8d 1523 if (AtaCommand == ATA_CMD_SMART) {\r
ead42efc 1524 Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
1525 } else {\r
1526 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1527 }\r
1528 if (EFI_ERROR (Status)) {\r
1529 return EFI_DEVICE_ERROR;\r
1530 }\r
1531\r
1532 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1533 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
ead42efc 1534 //\r
1535 // Failed to execute command, abort operation\r
1536 //\r
1537 return EFI_ABORTED;\r
1538 }\r
1539\r
1540 return EFI_SUCCESS;\r
1541}\r
1542\r
1543/**\r
1544 Send ATA Ext command into device with NON_DATA protocol\r
1545\r
1546 @param IdeDev Standard IDE device private data structure\r
1547 @param AtaCommand The ATA command to be sent\r
1548 @param Device The value in Device register\r
1549 @param Feature The value in Feature register\r
1550 @param SectorCount The value in SectorCount register\r
1551 @param LbaAddress The LBA address in 48-bit mode\r
1552\r
1553 @retval EFI_SUCCESS Reading succeed\r
1554 @retval EFI_ABORTED Command failed\r
97404058 1555 @retval EFI_DEVICE_ERROR Device status error.\r
ead42efc 1556\r
1557**/\r
1558EFI_STATUS\r
1559AtaNonDataCommandInExt (\r
1560 IN IDE_BLK_IO_DEV *IdeDev,\r
1561 IN UINT8 AtaCommand,\r
1562 IN UINT8 Device,\r
1563 IN UINT16 Feature,\r
1564 IN UINT16 SectorCount,\r
1565 IN EFI_LBA LbaAddress\r
1566 )\r
1567{\r
1568 EFI_STATUS Status;\r
1569 UINT8 StatusRegister;\r
1570 UINT8 SectorCount8;\r
1571 UINT8 Feature8;\r
1572 UINT8 LbaLow;\r
1573 UINT8 LbaMid;\r
1574 UINT8 LbaHigh;\r
1575\r
1576 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1577 if (EFI_ERROR (Status)) {\r
1578 return EFI_DEVICE_ERROR;\r
1579 }\r
1580\r
1581 //\r
1582 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1583 //\r
1584 IDEWritePortB (\r
1585 IdeDev->PciIo,\r
1586 IdeDev->IoPort->Head,\r
1587 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1588 );\r
1589\r
1590 //\r
1591 // ATA commands for ATA device must be issued when DRDY is set\r
1592 //\r
1593 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1594 if (EFI_ERROR (Status)) {\r
1595 return EFI_DEVICE_ERROR;\r
1596 }\r
1597\r
1598 //\r
1599 // Pass parameter into device register block\r
1600 //\r
1601 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1602\r
1603 //\r
1604 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
1605 //\r
1606 Feature8 = (UINT8) (Feature >> 8);\r
1607 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1608\r
1609 Feature8 = (UINT8) Feature;\r
1610 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1611\r
1612 //\r
1613 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
1614 //\r
1615 SectorCount8 = (UINT8) (SectorCount >> 8);\r
1616 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1617\r
1618 SectorCount8 = (UINT8) SectorCount;\r
1619 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1620\r
1621 //\r
1622 // Fill the start LBA registers, which are also two-byte FIFO\r
1623 //\r
1624 LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
1625 LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
1626 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
1627 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1628 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1629 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1630\r
1631 LbaLow = (UINT8) LbaAddress;\r
1632 LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
1633 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
1634 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1635 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1636 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1637\r
1638 //\r
1639 // Send command via Command Register\r
1640 //\r
1641 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1642\r
1643 //\r
1644 // Wait for command completion\r
1645 //\r
1646 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1647 if (EFI_ERROR (Status)) {\r
1648 return EFI_DEVICE_ERROR;\r
1649 }\r
1650\r
1651 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1652 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
ead42efc 1653 //\r
1654 // Failed to execute command, abort operation\r
1655 //\r
1656 return EFI_ABORTED;\r
1657 }\r
1658\r
1659 return EFI_SUCCESS;\r
1660}\r
1661\r
1662//\r
1663// SetDriveParameters\r
1664//\r
1665/**\r
1666 Set drive parameters for devices not support PACKETS command\r
1667\r
1668 @param[in] IdeDev Standard IDE device private data structure\r
1669 @param[in] DriveParameters The device parameters to be set into the disk\r
1670\r
97404058 1671 @return SetParameters Command execute status.\r
ead42efc 1672\r
1673**/\r
1674EFI_STATUS\r
1675SetDriveParameters (\r
1676 IN IDE_BLK_IO_DEV *IdeDev,\r
1677 IN ATA_DRIVE_PARMS *DriveParameters\r
1678 )\r
1679{\r
1680 EFI_STATUS Status;\r
1681 UINT8 DeviceSelect;\r
1682\r
1683 DeviceSelect = 0;\r
1684 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1685\r
1686 //\r
1687 // Send Init drive parameters\r
1688 //\r
1689 Status = AtaNonDataCommandIn (\r
1690 IdeDev,\r
1e23bd8d 1691 ATA_CMD_INIT_DRIVE_PARAM,\r
ead42efc 1692 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1693 0,\r
1694 DriveParameters->Sector,\r
1695 0,\r
1696 0,\r
1697 0\r
1698 );\r
1699\r
1700 //\r
1701 // Send Set Multiple parameters\r
1702 //\r
1703 Status = AtaNonDataCommandIn (\r
1704 IdeDev,\r
1e23bd8d 1705 ATA_CMD_SET_MULTIPLE_MODE,\r
ead42efc 1706 DeviceSelect,\r
1707 0,\r
1708 DriveParameters->MultipleSector,\r
1709 0,\r
1710 0,\r
1711 0\r
1712 );\r
1713 return Status;\r
1714}\r
1715\r
1716/**\r
1717 TODO: Add function description\r
1718\r
1719 @param IdeDev TODO: add argument description\r
1720\r
97404058 1721 @retval EFI_SUCCESS TODO: Add description for return value.\r
ead42efc 1722\r
1723**/\r
1724EFI_STATUS\r
1725EnableInterrupt (\r
1726 IN IDE_BLK_IO_DEV *IdeDev\r
1727 )\r
1728{\r
1729 UINT8 DeviceControl;\r
1730\r
1731 //\r
1732 // Enable interrupt for DMA operation\r
1733 //\r
1734 DeviceControl = 0;\r
1735 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1736\r
1737 return EFI_SUCCESS;\r
1738}\r
1739\r
1740/**\r
1741 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
1742\r
1743 @param[in] Event Pointer to this event\r
1744 @param[in] Context Event hanlder private data\r
1745\r
1746**/\r
1747VOID\r
1748EFIAPI\r
1749ClearInterrupt (\r
1750 IN EFI_EVENT Event,\r
1751 IN VOID *Context\r
1752 )\r
1753{\r
1754 EFI_STATUS Status;\r
1755 UINT64 IoPortForBmis;\r
1756 UINT8 RegisterValue;\r
1757 IDE_BLK_IO_DEV *IdeDev;\r
1758\r
1759 //\r
1760 // Get our context\r
1761 //\r
1762 IdeDev = (IDE_BLK_IO_DEV *) Context;\r
1763\r
1764 //\r
1765 // Obtain IDE IO port registers' base addresses\r
1766 //\r
1767 Status = ReassignIdeResources (IdeDev);\r
1768 if (EFI_ERROR (Status)) {\r
1769 return;\r
1770 }\r
1771\r
1772 //\r
1773 // Check whether interrupt is pending\r
1774 //\r
1775\r
1776 //\r
1777 // Reset IDE device to force it de-assert interrupt pin\r
1778 // Note: this will reset all devices on this IDE channel\r
1779 //\r
1780 AtaSoftReset (IdeDev);\r
1781 if (EFI_ERROR (Status)) {\r
1782 return;\r
1783 }\r
1784\r
1785 //\r
1786 // Get base address of IDE Bus Master Status Regsiter\r
1787 //\r
1788 if (IdePrimary == IdeDev->Channel) {\r
1789 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
1790 } else {\r
1791 if (IdeSecondary == IdeDev->Channel) {\r
1792 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
1793 } else {\r
1794 return;\r
1795 }\r
1796 }\r
1797 //\r
1798 // Read BMIS register and clear ERROR and INTR bit\r
1799 //\r
1800 IdeDev->PciIo->Io.Read (\r
1801 IdeDev->PciIo,\r
1802 EfiPciIoWidthUint8,\r
1803 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1804 IoPortForBmis,\r
1805 1,\r
1806 &RegisterValue\r
1807 );\r
1808\r
1809 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
1810\r
1811 IdeDev->PciIo->Io.Write (\r
1812 IdeDev->PciIo,\r
1813 EfiPciIoWidthUint8,\r
1814 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1815 IoPortForBmis,\r
1816 1,\r
1817 &RegisterValue\r
1818 );\r
1819\r
1820 //\r
1821 // Select the other device on this channel to ensure this device to release the interrupt pin\r
1822 //\r
1823 if (IdeDev->Device == 0) {\r
1824 RegisterValue = (1 << 4) | 0xe0;\r
1825 } else {\r
1826 RegisterValue = (0 << 4) | 0xe0;\r
1827 }\r
1828 IDEWritePortB (\r
1829 IdeDev->PciIo,\r
1830 IdeDev->IoPort->Head,\r
1831 RegisterValue\r
1832 );\r
1833\r
1834}\r