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