]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
Function AtaEnableLongPhysicalSector () added for Long physical sector process.
[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
376 //\r
377 // Requery IDE IO port registers' base addresses in case of the switch of\r
378 // native and legacy modes\r
379 //\r
380 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
381 if (EFI_ERROR (Status)) {\r
382 return Status;\r
383 }\r
384\r
385 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
386 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
387 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
388\r
389 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
390 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
391 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
392 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
393 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
394 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
395 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
396\r
397 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
398 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
399 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
400 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
401\r
402 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
403 return EFI_SUCCESS;\r
404}\r
405\r
406//\r
407// DiscoverIdeDevice\r
408//\r
409/**\r
410 Detect if there is disk connected to this port\r
411\r
97404058 412 @param IdeDev The BLK_IO private data which specifies the IDE device.\r
ead42efc 413\r
414**/\r
415EFI_STATUS\r
416DiscoverIdeDevice (\r
417 IN IDE_BLK_IO_DEV *IdeDev\r
418 )\r
419// TODO: EFI_NOT_FOUND - add return value to function comment\r
420// TODO: EFI_NOT_FOUND - add return value to function comment\r
421// TODO: EFI_SUCCESS - add return value to function comment\r
422{\r
423 EFI_STATUS Status;\r
75eccf9d 424 EFI_STATUS LongPhyStatus;\r
ead42efc 425\r
426 //\r
427 // If a channel has not been checked, check it now. Then set it to "checked" state\r
428 // After this step, all devices in this channel have been checked.\r
429 //\r
97404058 430 if (!ChannelDeviceDetected) {\r
ead42efc 431 Status = DetectIDEController (IdeDev);\r
432 if (EFI_ERROR (Status)) {\r
433 return EFI_NOT_FOUND;\r
434 }\r
435 }\r
436\r
437 Status = EFI_NOT_FOUND;\r
438\r
439 //\r
440 // Device exists. test if it is an ATA device.\r
441 // Prefer the result from DetectIDEController,\r
442 // if failed, try another device type to handle\r
443 // devices that not follow the spec.\r
444 //\r
445 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
446 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
447 Status = ATAIdentify (IdeDev);\r
448 if (EFI_ERROR (Status)) {\r
449 Status = ATAPIIdentify (IdeDev);\r
450 if (!EFI_ERROR (Status)) {\r
451 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
452 }\r
453 }\r
454 } else {\r
455 Status = ATAPIIdentify (IdeDev);\r
456 if (EFI_ERROR (Status)) {\r
457 Status = ATAIdentify (IdeDev);\r
458 if (!EFI_ERROR (Status)) {\r
459 MasterDeviceType = ATA_DEVICE_TYPE;\r
460 }\r
461 }\r
462 }\r
463 }\r
464 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
465 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
466 Status = ATAIdentify (IdeDev);\r
467 if (EFI_ERROR (Status)) {\r
468 Status = ATAPIIdentify (IdeDev);\r
469 if (!EFI_ERROR (Status)) {\r
470 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
471 }\r
472 }\r
473 } else {\r
474 Status = ATAPIIdentify (IdeDev);\r
475 if (EFI_ERROR (Status)) {\r
476 Status = ATAIdentify (IdeDev);\r
477 if (!EFI_ERROR (Status)) {\r
478 SlaveDeviceType = ATA_DEVICE_TYPE;\r
479 }\r
480 }\r
481 }\r
482 }\r
483 if (EFI_ERROR (Status)) {\r
484 return EFI_NOT_FOUND;\r
485 }\r
486 //\r
487 // Init Block I/O interface\r
488 //\r
75eccf9d 489 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);\r
490 if (!EFI_ERROR (LongPhyStatus)) {\r
491 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
492 } else {\r
493 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
494 }\r
ead42efc 495 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
496 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
497 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
498 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
499\r
500 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
501 IdeDev->BlkMedia.WriteCaching = FALSE;\r
502\r
503 //\r
504 // Init Disk Info interface\r
505 //\r
506 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
507 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
508 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
509 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
510 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
511\r
512 return EFI_SUCCESS;\r
513}\r
514\r
515/**\r
516 This interface is used to initialize all state data related to the detection of one\r
517 channel.\r
518\r
519 @retval EFI_SUCCESS Completed Successfully.\r
520\r
521**/\r
522EFI_STATUS\r
523InitializeIDEChannelData (\r
524 VOID\r
525 )\r
526{\r
527 ChannelDeviceDetected = FALSE;\r
528 MasterDeviceExist = FALSE;\r
529 MasterDeviceType = 0xff;\r
530 SlaveDeviceExist = FALSE;\r
531 SlaveDeviceType = 0xff;\r
532 return EFI_SUCCESS;\r
533}\r
534\r
535/**\r
536 This function is called by DiscoverIdeDevice(). It is used for detect\r
537 whether the IDE device exists in the specified Channel as the specified\r
538 Device Number.\r
539\r
540 There is two IDE channels: one is Primary Channel, the other is\r
541 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
542 Different channel has different register group.\r
543\r
544 On each IDE channel, at most two IDE devices attach,\r
545 one is called Device 0 (Master device), the other is called Device 1\r
546 (Slave device). The devices on the same channel co-use the same register\r
547 group, so before sending out a command for a specified device via command\r
548 register, it is a must to select the current device to accept the command\r
549 by set the device number in the Head/Device Register.\r
550\r
551 @param[in] *IdeDev\r
552 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
553 to record all the information of the IDE device.\r
554\r
555 @retval TRUE\r
556 successfully detects device.\r
557\r
558 @retval FALSE\r
559 any failure during detection process will return this\r
560 value.\r
561\r
562 @note\r
563 TODO: EFI_SUCCESS - add return value to function comment\r
564 TODO: EFI_NOT_FOUND - add return value to function comment\r
565\r
566**/\r
567EFI_STATUS\r
568DetectIDEController (\r
569 IN IDE_BLK_IO_DEV *IdeDev\r
570 )\r
571{\r
572 EFI_STATUS Status;\r
573 UINT8 SectorCountReg;\r
574 UINT8 LBALowReg;\r
575 UINT8 LBAMidReg;\r
576 UINT8 LBAHighReg;\r
577 UINT8 InitStatusReg;\r
578 UINT8 StatusReg;\r
579\r
580 //\r
581 // Select slave device\r
582 //\r
583 IDEWritePortB (\r
584 IdeDev->PciIo,\r
585 IdeDev->IoPort->Head,\r
586 (UINT8) ((1 << 4) | 0xe0)\r
587 );\r
588 gBS->Stall (100);\r
589\r
590 //\r
591 // Save the init slave status register\r
592 //\r
593 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
594\r
595 //\r
596 // Select Master back\r
597 //\r
598 IDEWritePortB (\r
599 IdeDev->PciIo,\r
600 IdeDev->IoPort->Head,\r
601 (UINT8) ((0 << 4) | 0xe0)\r
602 );\r
603 gBS->Stall (100);\r
604\r
605 //\r
606 // Send ATA Device Execut Diagnostic command.\r
607 // This command should work no matter DRDY is ready or not\r
608 //\r
609 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
610\r
611 Status = WaitForBSYClear (IdeDev, 3500);\r
612 if (EFI_ERROR (Status)) {\r
613 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
614 return Status;\r
615 }\r
616 //\r
617 // Read device signature\r
618 //\r
619 //\r
620 // Select Master\r
621 //\r
622 IDEWritePortB (\r
623 IdeDev->PciIo,\r
624 IdeDev->IoPort->Head,\r
625 (UINT8) ((0 << 4) | 0xe0)\r
626 );\r
627 gBS->Stall (100);\r
628 SectorCountReg = IDEReadPortB (\r
629 IdeDev->PciIo,\r
630 IdeDev->IoPort->SectorCount\r
631 );\r
632 LBALowReg = IDEReadPortB (\r
633 IdeDev->PciIo,\r
634 IdeDev->IoPort->SectorNumber\r
635 );\r
636 LBAMidReg = IDEReadPortB (\r
637 IdeDev->PciIo,\r
638 IdeDev->IoPort->CylinderLsb\r
639 );\r
640 LBAHighReg = IDEReadPortB (\r
641 IdeDev->PciIo,\r
642 IdeDev->IoPort->CylinderMsb\r
643 );\r
644 if ((SectorCountReg == 0x1) &&\r
645 (LBALowReg == 0x1) &&\r
646 (LBAMidReg == 0x0) &&\r
647 (LBAHighReg == 0x0)) {\r
648 MasterDeviceExist = TRUE;\r
649 MasterDeviceType = ATA_DEVICE_TYPE;\r
650 } else {\r
651 if ((LBAMidReg == 0x14) &&\r
652 (LBAHighReg == 0xeb)) {\r
653 MasterDeviceExist = TRUE;\r
654 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
655 }\r
656 }\r
657\r
658 //\r
659 // For some Hard Drive, it takes some time to get\r
660 // the right signature when operating in single slave mode.\r
661 // We stall 20ms to work around this.\r
662 //\r
663 if (!MasterDeviceExist) {\r
664 gBS->Stall (20000);\r
665 }\r
666\r
667 //\r
668 // Select Slave\r
669 //\r
670 IDEWritePortB (\r
671 IdeDev->PciIo,\r
672 IdeDev->IoPort->Head,\r
673 (UINT8) ((1 << 4) | 0xe0)\r
674 );\r
675 gBS->Stall (100);\r
676 SectorCountReg = IDEReadPortB (\r
677 IdeDev->PciIo,\r
678 IdeDev->IoPort->SectorCount\r
679 );\r
680 LBALowReg = IDEReadPortB (\r
681 IdeDev->PciIo,\r
682 IdeDev->IoPort->SectorNumber\r
683 );\r
684 LBAMidReg = IDEReadPortB (\r
685 IdeDev->PciIo,\r
686 IdeDev->IoPort->CylinderLsb\r
687 );\r
688 LBAHighReg = IDEReadPortB (\r
689 IdeDev->PciIo,\r
690 IdeDev->IoPort->CylinderMsb\r
691 );\r
692 StatusReg = IDEReadPortB (\r
693 IdeDev->PciIo,\r
694 IdeDev->IoPort->Reg.Status\r
695 );\r
696 if ((SectorCountReg == 0x1) &&\r
697 (LBALowReg == 0x1) &&\r
698 (LBAMidReg == 0x0) &&\r
699 (LBAHighReg == 0x0)) {\r
700 SlaveDeviceExist = TRUE;\r
701 SlaveDeviceType = ATA_DEVICE_TYPE;\r
702 } else {\r
703 if ((LBAMidReg == 0x14) &&\r
704 (LBAHighReg == 0xeb)) {\r
705 SlaveDeviceExist = TRUE;\r
706 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
707 }\r
708 }\r
709\r
710 //\r
711 // When single master is plugged, slave device\r
712 // will be wrongly detected. Here's the workaround\r
713 // for ATA devices by detecting DRY bit in status\r
714 // register.\r
715 // NOTE: This workaround doesn't apply to ATAPI.\r
716 //\r
717 if (MasterDeviceExist && SlaveDeviceExist &&\r
1e23bd8d 718 (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
719 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
ead42efc 720 MasterDeviceType == SlaveDeviceType &&\r
721 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
722 SlaveDeviceExist = FALSE;\r
723 }\r
724\r
725 //\r
726 // Indicate this channel has been detected\r
727 //\r
728 ChannelDeviceDetected = TRUE;\r
729 return EFI_SUCCESS;\r
730}\r
731\r
732/**\r
733 This function is used to poll for the DRQ bit clear in the Status\r
734 Register. DRQ is cleared when the device is finished transferring data.\r
735 So this function is called after data transfer is finished.\r
736\r
737 @param[in] *IdeDev\r
738 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
739 to record all the information of the IDE device.\r
740\r
741 @param[in] TimeoutInMilliSeconds\r
742 used to designate the timeout for the DRQ clear.\r
743\r
744 @retval EFI_SUCCESS\r
745 DRQ bit clear within the time out.\r
746\r
747 @retval EFI_TIMEOUT\r
748 DRQ bit not clear within the time out.\r
749\r
750 @note\r
751 Read Status Register will clear interrupt status.\r
752\r
753**/\r
754EFI_STATUS\r
755DRQClear (\r
756 IN IDE_BLK_IO_DEV *IdeDev,\r
757 IN UINTN TimeoutInMilliSeconds\r
758 )\r
759// TODO: function comment is missing 'Routine Description:'\r
760// TODO: function comment is missing 'Arguments:'\r
761// TODO: IdeDev - add argument and description to function comment\r
762// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
763// TODO: EFI_ABORTED - add return value to function comment\r
764{\r
765 UINT32 Delay;\r
766 UINT8 StatusRegister;\r
767 UINT8 ErrorRegister;\r
768\r
769 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
770 do {\r
771\r
772 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
773\r
774 //\r
775 // wait for BSY == 0 and DRQ == 0\r
776 //\r
1e23bd8d 777 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 778 break;\r
779 }\r
780\r
1e23bd8d 781 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 782\r
783 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 784 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 785 return EFI_ABORTED;\r
786 }\r
787 }\r
788\r
789 //\r
790 // Stall for 30 us\r
791 //\r
792 gBS->Stall (30);\r
793\r
794 Delay--;\r
795\r
97404058 796 } while (Delay > 0);\r
ead42efc 797\r
798 if (Delay == 0) {\r
799 return EFI_TIMEOUT;\r
800 }\r
801\r
802 return EFI_SUCCESS;\r
803}\r
804\r
805/**\r
806 This function is used to poll for the DRQ bit clear in the Alternate\r
807 Status Register. DRQ is cleared when the device is finished\r
808 transferring data. So this function is called after data transfer\r
809 is finished.\r
810\r
811 @param[in] *IdeDev\r
812 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
813 to record all the information of the IDE device.\r
814\r
815 @param[in] TimeoutInMilliSeconds\r
816 used to designate the timeout for the DRQ clear.\r
817\r
818 @retval EFI_SUCCESS\r
819 DRQ bit clear within the time out.\r
820\r
821 @retval EFI_TIMEOUT\r
822 DRQ bit not clear within the time out.\r
823\r
824 @note\r
825 Read Alternate Status Register will not clear interrupt status.\r
826\r
827**/\r
828EFI_STATUS\r
829DRQClear2 (\r
830 IN IDE_BLK_IO_DEV *IdeDev,\r
831 IN UINTN TimeoutInMilliSeconds\r
832 )\r
833// TODO: function comment is missing 'Routine Description:'\r
834// TODO: function comment is missing 'Arguments:'\r
835// TODO: IdeDev - add argument and description to function comment\r
836// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
837// TODO: EFI_ABORTED - add return value to function comment\r
838{\r
839 UINT32 Delay;\r
840 UINT8 AltRegister;\r
841 UINT8 ErrorRegister;\r
842\r
843 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
844 do {\r
845\r
846 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
847\r
848 //\r
849 // wait for BSY == 0 and DRQ == 0\r
850 //\r
1e23bd8d 851 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
ead42efc 852 break;\r
853 }\r
854\r
1e23bd8d 855 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 856\r
857 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 858 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 859 return EFI_ABORTED;\r
860 }\r
861 }\r
862\r
863 //\r
864 // Stall for 30 us\r
865 //\r
866 gBS->Stall (30);\r
867\r
868 Delay--;\r
869\r
97404058 870 } while (Delay > 0);\r
ead42efc 871\r
872 if (Delay == 0) {\r
873 return EFI_TIMEOUT;\r
874 }\r
875\r
876 return EFI_SUCCESS;\r
877}\r
878\r
879/**\r
880 This function is used to poll for the DRQ bit set in the\r
881 Status Register.\r
882 DRQ is set when the device is ready to transfer data. So this function\r
883 is called after the command is sent to the device and before required\r
884 data is transferred.\r
885\r
886 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
887 pointer pointing to IDE_BLK_IO_DEV data structure,used\r
888 to record all the information of the IDE device.\r
889\r
890 @param[in] UINTN IN TimeoutInMilliSeconds\r
891 used to designate the timeout for the DRQ ready.\r
892\r
893 @retval EFI_SUCCESS\r
894 DRQ bit set within the time out.\r
895\r
896 @retval EFI_TIMEOUT\r
897 DRQ bit not set within the time out.\r
898\r
899 @retval EFI_ABORTED\r
900 DRQ bit not set caused by the command abort.\r
901\r
902 @note\r
903 Read Status Register will clear interrupt status.\r
904\r
905**/\r
906EFI_STATUS\r
907DRQReady (\r
908 IN IDE_BLK_IO_DEV *IdeDev,\r
909 IN UINTN TimeoutInMilliSeconds\r
910 )\r
911// TODO: function comment is missing 'Routine Description:'\r
912// TODO: function comment is missing 'Arguments:'\r
913// TODO: IdeDev - add argument and description to function comment\r
914// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
915{\r
916 UINT32 Delay;\r
917 UINT8 StatusRegister;\r
918 UINT8 ErrorRegister;\r
919\r
920 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
921 do {\r
922 //\r
923 // read Status Register will clear interrupt\r
924 //\r
925 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
926\r
927 //\r
928 // BSY==0,DRQ==1\r
929 //\r
1e23bd8d 930 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 931 break;\r
932 }\r
933\r
1e23bd8d 934 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 935\r
936 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 937 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 938 return EFI_ABORTED;\r
939 }\r
940 }\r
941\r
942 //\r
943 // Stall for 30 us\r
944 //\r
945 gBS->Stall (30);\r
946\r
947 Delay--;\r
97404058 948 } while (Delay > 0);\r
ead42efc 949\r
950 if (Delay == 0) {\r
951 return EFI_TIMEOUT;\r
952 }\r
953\r
954 return EFI_SUCCESS;\r
955}\r
956\r
957/**\r
958 This function is used to poll for the DRQ bit set in the\r
959 Alternate Status Register. DRQ is set when the device is ready to\r
960 transfer data. So this function is called after the command\r
961 is sent to the device and before required data is transferred.\r
962\r
963 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
964 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
965 to record all the information of the IDE device.\r
966\r
967 @param[in] UINTN IN TimeoutInMilliSeconds\r
968 used to designate the timeout for the DRQ ready.\r
969\r
970 @retval EFI_SUCCESS\r
971 DRQ bit set within the time out.\r
972\r
973 @retval EFI_TIMEOUT\r
974 DRQ bit not set within the time out.\r
975\r
976 @retval EFI_ABORTED\r
977 DRQ bit not set caused by the command abort.\r
978\r
979 @note\r
980 Read Alternate Status Register will not clear interrupt status.\r
981\r
982**/\r
983EFI_STATUS\r
984DRQReady2 (\r
985 IN IDE_BLK_IO_DEV *IdeDev,\r
986 IN UINTN TimeoutInMilliSeconds\r
987 )\r
988// TODO: function comment is missing 'Routine Description:'\r
989// TODO: function comment is missing 'Arguments:'\r
990// TODO: IdeDev - add argument and description to function comment\r
991// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
992{\r
993 UINT32 Delay;\r
994 UINT8 AltRegister;\r
995 UINT8 ErrorRegister;\r
996\r
997 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
998\r
999 do {\r
1000 //\r
1001 // Read Alternate Status Register will not clear interrupt status\r
1002 //\r
1003 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1004 //\r
1005 // BSY == 0 , DRQ == 1\r
1006 //\r
1e23bd8d 1007 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
ead42efc 1008 break;\r
1009 }\r
1010\r
1e23bd8d 1011 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1012\r
1013 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1014 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1015 return EFI_ABORTED;\r
1016 }\r
1017 }\r
1018\r
1019 //\r
1020 // Stall for 30 us\r
1021 //\r
1022 gBS->Stall (30);\r
1023\r
1024 Delay--;\r
97404058 1025 } while (Delay > 0);\r
ead42efc 1026\r
1027 if (Delay == 0) {\r
1028 return EFI_TIMEOUT;\r
1029 }\r
1030\r
1031 return EFI_SUCCESS;\r
1032}\r
1033\r
1034/**\r
1035 This function is used to poll for the BSY bit clear in the\r
1036 Status Register. BSY is clear when the device is not busy.\r
1037 Every command must be sent after device is not busy.\r
1038\r
1039 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1040 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1041 to record all the information of the IDE device.\r
1042\r
1043 @param[in] UINTN IN TimeoutInMilliSeconds\r
1044 used to designate the timeout for the DRQ ready.\r
1045\r
1046 @retval EFI_SUCCESS\r
1047 BSY bit clear within the time out.\r
1048\r
1049 @retval EFI_TIMEOUT\r
1050 BSY bit not clear within the time out.\r
1051\r
1052 @note\r
1053 Read Status Register will clear interrupt status.\r
1054\r
1055**/\r
1056EFI_STATUS\r
1057WaitForBSYClear (\r
1058 IN IDE_BLK_IO_DEV *IdeDev,\r
1059 IN UINTN TimeoutInMilliSeconds\r
1060 )\r
1061// TODO: function comment is missing 'Routine Description:'\r
1062// TODO: function comment is missing 'Arguments:'\r
1063// TODO: IdeDev - add argument and description to function comment\r
1064// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1065{\r
1066 UINT32 Delay;\r
1067 UINT8 StatusRegister;\r
1068\r
1069 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1070 do {\r
1071\r
1072 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1073 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1074 break;\r
1075 }\r
1076\r
1077 //\r
1078 // Stall for 30 us\r
1079 //\r
1080 gBS->Stall (30);\r
1081\r
1082 Delay--;\r
1083\r
97404058 1084 } while (Delay > 0);\r
ead42efc 1085\r
1086 if (Delay == 0) {\r
1087 return EFI_TIMEOUT;\r
1088 }\r
1089\r
1090 return EFI_SUCCESS;\r
1091}\r
1092//\r
1093// WaitForBSYClear2\r
1094//\r
1095/**\r
1096 This function is used to poll for the BSY bit clear in the\r
1097 Alternate Status Register. BSY is clear when the device is not busy.\r
1098 Every command must be sent after device is not busy.\r
1099\r
1100 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1101 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1102 to record all the information of the IDE device.\r
1103\r
1104 @param[in] UINTN IN TimeoutInMilliSeconds\r
1105 used to designate the timeout for the DRQ ready.\r
1106\r
1107 @retval EFI_SUCCESS\r
1108 BSY bit clear within the time out.\r
1109\r
1110 @retval EFI_TIMEOUT\r
1111 BSY bit not clear within the time out.\r
1112\r
1113 @note\r
1114 Read Alternate Status Register will not clear interrupt status.\r
1115\r
1116**/\r
1117EFI_STATUS\r
1118WaitForBSYClear2 (\r
1119 IN IDE_BLK_IO_DEV *IdeDev,\r
1120 IN UINTN TimeoutInMilliSeconds\r
1121 )\r
1122// TODO: function comment is missing 'Routine Description:'\r
1123// TODO: function comment is missing 'Arguments:'\r
1124// TODO: IdeDev - add argument and description to function comment\r
1125// TODO: TimeoutInMilliSeconds - add argument and description to function comment\r
1126{\r
1127 UINT32 Delay;\r
1128 UINT8 AltRegister;\r
1129\r
1130 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1131 do {\r
1132 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1e23bd8d 1133 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
ead42efc 1134 break;\r
1135 }\r
1136\r
1137 gBS->Stall (30);\r
1138\r
1139 Delay--;\r
1140\r
97404058 1141 } while (Delay > 0);\r
ead42efc 1142\r
1143 if (Delay == 0) {\r
1144 return EFI_TIMEOUT;\r
1145 }\r
1146\r
1147 return EFI_SUCCESS;\r
1148}\r
1149\r
1150//\r
1151// DRDYReady\r
1152//\r
1153/**\r
1154 This function is used to poll for the DRDY bit set in the\r
1155 Status Register. DRDY bit is set when the device is ready\r
1156 to accept command. Most ATA commands must be sent after\r
1157 DRDY set except the ATAPI Packet Command.\r
1158\r
1159 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1160 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1161 to record all the information of the IDE device.\r
1162\r
97404058 1163 @param[in] UINTN IN DelayInMilliSeconds\r
ead42efc 1164 used to designate the timeout for the DRQ ready.\r
1165\r
1166 @retval EFI_SUCCESS\r
1167 DRDY bit set within the time out.\r
1168\r
1169 @retval EFI_TIMEOUT\r
1170 DRDY bit not set within the time out.\r
1171\r
1172 @note\r
1173 Read Status Register will clear interrupt status.\r
1174\r
1175**/\r
1176EFI_STATUS\r
1177DRDYReady (\r
1178 IN IDE_BLK_IO_DEV *IdeDev,\r
1179 IN UINTN DelayInMilliSeconds\r
1180 )\r
1181// TODO: function comment is missing 'Routine Description:'\r
1182// TODO: function comment is missing 'Arguments:'\r
1183// TODO: IdeDev - add argument and description to function comment\r
1184// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1185// TODO: EFI_ABORTED - add return value to function comment\r
1186{\r
1187 UINT32 Delay;\r
1188 UINT8 StatusRegister;\r
1189 UINT8 ErrorRegister;\r
1190\r
1191 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1192 do {\r
1193 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1194 //\r
1195 // BSY == 0 , DRDY == 1\r
1196 //\r
1e23bd8d 1197 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1198 break;\r
1199 }\r
1200\r
1e23bd8d 1201 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1202\r
1203 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1204 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1205 return EFI_ABORTED;\r
1206 }\r
1207 }\r
1208\r
1209 gBS->Stall (30);\r
1210\r
1211 Delay--;\r
97404058 1212 } while (Delay > 0);\r
ead42efc 1213\r
1214 if (Delay == 0) {\r
1215 return EFI_TIMEOUT;\r
1216 }\r
1217\r
1218 return EFI_SUCCESS;\r
1219}\r
1220\r
1221//\r
1222// DRDYReady2\r
1223//\r
1224/**\r
1225 This function is used to poll for the DRDY bit set in the\r
1226 Alternate Status Register. DRDY bit is set when the device is ready\r
1227 to accept command. Most ATA commands must be sent after\r
1228 DRDY set except the ATAPI Packet Command.\r
1229\r
1230 @param[in] IDE_BLK_IO_DEV IN *IdeDev\r
1231 pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1232 to record all the information of the IDE device.\r
1233\r
97404058 1234 @param[in] UINTN IN DelayInMilliSeconds\r
ead42efc 1235 used to designate the timeout for the DRQ ready.\r
1236\r
1237 @retval EFI_SUCCESS\r
1238 DRDY bit set within the time out.\r
1239\r
1240 @retval EFI_TIMEOUT\r
1241 DRDY bit not set within the time out.\r
1242\r
1243 @note\r
1244 Read Alternate Status Register will clear interrupt status.\r
1245\r
1246**/\r
1247EFI_STATUS\r
1248DRDYReady2 (\r
1249 IN IDE_BLK_IO_DEV *IdeDev,\r
1250 IN UINTN DelayInMilliSeconds\r
1251 )\r
1252// TODO: function comment is missing 'Routine Description:'\r
1253// TODO: function comment is missing 'Arguments:'\r
1254// TODO: IdeDev - add argument and description to function comment\r
1255// TODO: DelayInMilliSeconds - add argument and description to function comment\r
1256// TODO: EFI_ABORTED - add return value to function comment\r
1257{\r
1258 UINT32 Delay;\r
1259 UINT8 AltRegister;\r
1260 UINT8 ErrorRegister;\r
1261\r
1262 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1263 do {\r
1264 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1265 //\r
1266 // BSY == 0 , DRDY == 1\r
1267 //\r
1e23bd8d 1268 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
ead42efc 1269 break;\r
1270 }\r
1271\r
1e23bd8d 1272 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
ead42efc 1273\r
1274 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1e23bd8d 1275 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
ead42efc 1276 return EFI_ABORTED;\r
1277 }\r
1278 }\r
1279\r
1280 gBS->Stall (30);\r
1281\r
1282 Delay--;\r
97404058 1283 } while (Delay > 0);\r
ead42efc 1284\r
1285 if (Delay == 0) {\r
1286 return EFI_TIMEOUT;\r
1287 }\r
1288\r
1289 return EFI_SUCCESS;\r
1290}\r
1291\r
1292//\r
1293// SwapStringChars\r
1294//\r
1295/**\r
1296 This function is a helper function used to change the char order in a\r
1297 string. It is designed specially for the PrintAtaModuleName() function.\r
1298 After the IDE device is detected, the IDE driver gets the device module\r
1299 name by sending ATA command called ATA Identify Command or ATAPI\r
1300 Identify Command to the specified IDE device. The module name returned\r
1301 is a string of ASCII characters: the first character is bit8--bit15\r
1e23bd8d 1302 of the first word, the second character is BIT0--bit7 of the first word\r
ead42efc 1303 and so on. Thus the string can not be print directly before it is\r
1304 preprocessed by this func to change the order of characters in\r
1305 each word in the string.\r
1306\r
1307 @param[in] CHAR8 IN *Destination\r
1308 Indicates the destination string.\r
1309\r
1310 @param[in] CHAR8 IN *Source\r
1311 Indicates the source string.\r
1312\r
1313 @param[in] UINT8 IN Size\r
1314 the length of the string\r
1315\r
1316**/\r
1317VOID\r
1318SwapStringChars (\r
1319 IN CHAR8 *Destination,\r
1320 IN CHAR8 *Source,\r
1321 IN UINT32 Size\r
1322 )\r
1323{\r
1324 UINT32 Index;\r
1325 CHAR8 Temp;\r
1326\r
1327 for (Index = 0; Index < Size; Index += 2) {\r
1328\r
1329 Temp = Source[Index + 1];\r
1330 Destination[Index + 1] = Source[Index];\r
1331 Destination[Index] = Temp;\r
1332 }\r
1333}\r
1334\r
1335//\r
1336// ReleaseIdeResources\r
1337//\r
1338/**\r
1339 Release resources of an IDE device before stopping it.\r
1340\r
1341 @param[in] *IdeBlkIoDevice Standard IDE device private data structure\r
1342\r
1343**/\r
1344VOID\r
1345ReleaseIdeResources (\r
1346 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1347 )\r
1348{\r
1349 if (IdeBlkIoDevice == NULL) {\r
1350 return ;\r
1351 }\r
1352\r
1353 //\r
1354 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1355 //\r
1356\r
1357 if (IdeBlkIoDevice->SenseData != NULL) {\r
1358 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1359 IdeBlkIoDevice->SenseData = NULL;\r
1360 }\r
1361\r
1362 if (IdeBlkIoDevice->Cache != NULL) {\r
1363 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1364 IdeBlkIoDevice->Cache = NULL;\r
1365 }\r
1366\r
1367 if (IdeBlkIoDevice->pIdData != NULL) {\r
1368 gBS->FreePool (IdeBlkIoDevice->pIdData);\r
1369 IdeBlkIoDevice->pIdData = NULL;\r
1370 }\r
1371\r
1372 if (IdeBlkIoDevice->pInquiryData != NULL) {\r
1373 gBS->FreePool (IdeBlkIoDevice->pInquiryData);\r
1374 IdeBlkIoDevice->pInquiryData = NULL;\r
1375 }\r
1376\r
1377 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1378 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1379 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1380 }\r
1381\r
1382 if (IdeBlkIoDevice->IoPort != NULL) {\r
1383 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1384 }\r
1385\r
1386 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1387 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1388 }\r
1389\r
1390 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1391 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1392 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1393 }\r
1394\r
1395 gBS->FreePool (IdeBlkIoDevice);\r
1396 IdeBlkIoDevice = NULL;\r
1397\r
1398 return ;\r
1399}\r
1400\r
1401//\r
1402// SetDeviceTransferMode\r
1403//\r
1404/**\r
1405 Set the calculated Best transfer mode to a detected device\r
1406\r
1407 @param[in] *IdeDev Standard IDE device private data structure\r
1408 @param[in] *TransferMode The device transfer mode to be set\r
1409\r
97404058 1410 @return Set transfer mode Command execute status.\r
ead42efc 1411\r
1412**/\r
1413EFI_STATUS\r
1414SetDeviceTransferMode (\r
1415 IN IDE_BLK_IO_DEV *IdeDev,\r
1416 IN ATA_TRANSFER_MODE *TransferMode\r
1417 )\r
1418// TODO: function comment is missing 'Routine Description:'\r
1419{\r
1420 EFI_STATUS Status;\r
1421 UINT8 DeviceSelect;\r
1422 UINT8 SectorCount;\r
1423\r
1424 DeviceSelect = 0;\r
1425 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1426 SectorCount = *((UINT8 *) TransferMode);\r
1427\r
1428 //\r
1429 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1430 //\r
1431 Status = AtaNonDataCommandIn (\r
1432 IdeDev,\r
1e23bd8d 1433 ATA_CMD_SET_FEATURES,\r
ead42efc 1434 DeviceSelect,\r
1435 0x03,\r
1436 SectorCount,\r
1437 0,\r
1438 0,\r
1439 0\r
1440 );\r
1441\r
1442 return Status;\r
1443}\r
1444\r
1445/**\r
1446 Send ATA command into device with NON_DATA protocol\r
1447\r
1448 @param IdeDev Standard IDE device private data structure\r
1449 @param AtaCommand The ATA command to be sent\r
1450 @param Device The value in Device register\r
1451 @param Feature The value in Feature register\r
1452 @param SectorCount The value in SectorCount register\r
1453 @param LbaLow The value in LBA_LOW register\r
1454 @param LbaMiddle The value in LBA_MIDDLE register\r
1455 @param LbaHigh The value in LBA_HIGH register\r
1456\r
1457 @retval EFI_SUCCESS Reading succeed\r
1458 @retval EFI_ABORTED Command failed\r
97404058 1459 @retval EFI_DEVICE_ERROR Device status error.\r
ead42efc 1460\r
1461**/\r
1462EFI_STATUS\r
1463AtaNonDataCommandIn (\r
1464 IN IDE_BLK_IO_DEV *IdeDev,\r
1465 IN UINT8 AtaCommand,\r
1466 IN UINT8 Device,\r
1467 IN UINT8 Feature,\r
1468 IN UINT8 SectorCount,\r
1469 IN UINT8 LbaLow,\r
1470 IN UINT8 LbaMiddle,\r
1471 IN UINT8 LbaHigh\r
1472 )\r
1473{\r
1474 EFI_STATUS Status;\r
1475 UINT8 StatusRegister;\r
1476\r
1477 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1478 if (EFI_ERROR (Status)) {\r
1479 return EFI_DEVICE_ERROR;\r
1480 }\r
1481\r
1482 //\r
1483 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1484 //\r
1485 IDEWritePortB (\r
1486 IdeDev->PciIo,\r
1487 IdeDev->IoPort->Head,\r
1488 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1489 );\r
1490\r
1491 //\r
1492 // ATA commands for ATA device must be issued when DRDY is set\r
1493 //\r
1494 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1495 if (EFI_ERROR (Status)) {\r
1496 return EFI_DEVICE_ERROR;\r
1497 }\r
1498\r
1499 //\r
1500 // Pass parameter into device register block\r
1501 //\r
1502 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1503 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);\r
1504 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);\r
1505 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1506 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);\r
1507 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1508\r
1509 //\r
1510 // Send command via Command Register\r
1511 //\r
1512 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1513\r
1514 //\r
1515 // Wait for command completion\r
1e23bd8d 1516 // For ATAPI_SMART_CMD, we may need more timeout to let device\r
ead42efc 1517 // adjust internal states.\r
1518 //\r
1e23bd8d 1519 if (AtaCommand == ATA_CMD_SMART) {\r
ead42efc 1520 Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);\r
1521 } else {\r
1522 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1523 }\r
1524 if (EFI_ERROR (Status)) {\r
1525 return EFI_DEVICE_ERROR;\r
1526 }\r
1527\r
1528 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1529 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
ead42efc 1530 //\r
1531 // Failed to execute command, abort operation\r
1532 //\r
1533 return EFI_ABORTED;\r
1534 }\r
1535\r
1536 return EFI_SUCCESS;\r
1537}\r
1538\r
1539/**\r
1540 Send ATA Ext command into device with NON_DATA protocol\r
1541\r
1542 @param IdeDev Standard IDE device private data structure\r
1543 @param AtaCommand The ATA command to be sent\r
1544 @param Device The value in Device register\r
1545 @param Feature The value in Feature register\r
1546 @param SectorCount The value in SectorCount register\r
1547 @param LbaAddress The LBA address in 48-bit mode\r
1548\r
1549 @retval EFI_SUCCESS Reading succeed\r
1550 @retval EFI_ABORTED Command failed\r
97404058 1551 @retval EFI_DEVICE_ERROR Device status error.\r
ead42efc 1552\r
1553**/\r
1554EFI_STATUS\r
1555AtaNonDataCommandInExt (\r
1556 IN IDE_BLK_IO_DEV *IdeDev,\r
1557 IN UINT8 AtaCommand,\r
1558 IN UINT8 Device,\r
1559 IN UINT16 Feature,\r
1560 IN UINT16 SectorCount,\r
1561 IN EFI_LBA LbaAddress\r
1562 )\r
1563{\r
1564 EFI_STATUS Status;\r
1565 UINT8 StatusRegister;\r
1566 UINT8 SectorCount8;\r
1567 UINT8 Feature8;\r
1568 UINT8 LbaLow;\r
1569 UINT8 LbaMid;\r
1570 UINT8 LbaHigh;\r
1571\r
1572 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1573 if (EFI_ERROR (Status)) {\r
1574 return EFI_DEVICE_ERROR;\r
1575 }\r
1576\r
1577 //\r
1578 // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)\r
1579 //\r
1580 IDEWritePortB (\r
1581 IdeDev->PciIo,\r
1582 IdeDev->IoPort->Head,\r
1583 (UINT8) ((IdeDev->Device << 4) | 0xe0)\r
1584 );\r
1585\r
1586 //\r
1587 // ATA commands for ATA device must be issued when DRDY is set\r
1588 //\r
1589 Status = DRDYReady (IdeDev, ATATIMEOUT);\r
1590 if (EFI_ERROR (Status)) {\r
1591 return EFI_DEVICE_ERROR;\r
1592 }\r
1593\r
1594 //\r
1595 // Pass parameter into device register block\r
1596 //\r
1597 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);\r
1598\r
1599 //\r
1600 // Fill the feature register, which is a two-byte FIFO. Need write twice.\r
1601 //\r
1602 Feature8 = (UINT8) (Feature >> 8);\r
1603 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1604\r
1605 Feature8 = (UINT8) Feature;\r
1606 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);\r
1607\r
1608 //\r
1609 // Fill the sector count register, which is a two-byte FIFO. Need write twice.\r
1610 //\r
1611 SectorCount8 = (UINT8) (SectorCount >> 8);\r
1612 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1613\r
1614 SectorCount8 = (UINT8) SectorCount;\r
1615 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);\r
1616\r
1617 //\r
1618 // Fill the start LBA registers, which are also two-byte FIFO\r
1619 //\r
1620 LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);\r
1621 LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);\r
1622 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);\r
1623 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1624 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1625 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1626\r
1627 LbaLow = (UINT8) LbaAddress;\r
1628 LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);\r
1629 LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);\r
1630 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);\r
1631 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);\r
1632 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);\r
1633\r
1634 //\r
1635 // Send command via Command Register\r
1636 //\r
1637 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);\r
1638\r
1639 //\r
1640 // Wait for command completion\r
1641 //\r
1642 Status = WaitForBSYClear (IdeDev, ATATIMEOUT);\r
1643 if (EFI_ERROR (Status)) {\r
1644 return EFI_DEVICE_ERROR;\r
1645 }\r
1646\r
1647 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1e23bd8d 1648 if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {\r
ead42efc 1649 //\r
1650 // Failed to execute command, abort operation\r
1651 //\r
1652 return EFI_ABORTED;\r
1653 }\r
1654\r
1655 return EFI_SUCCESS;\r
1656}\r
1657\r
1658//\r
1659// SetDriveParameters\r
1660//\r
1661/**\r
1662 Set drive parameters for devices not support PACKETS command\r
1663\r
1664 @param[in] IdeDev Standard IDE device private data structure\r
1665 @param[in] DriveParameters The device parameters to be set into the disk\r
1666\r
97404058 1667 @return SetParameters Command execute status.\r
ead42efc 1668\r
1669**/\r
1670EFI_STATUS\r
1671SetDriveParameters (\r
1672 IN IDE_BLK_IO_DEV *IdeDev,\r
1673 IN ATA_DRIVE_PARMS *DriveParameters\r
1674 )\r
1675{\r
1676 EFI_STATUS Status;\r
1677 UINT8 DeviceSelect;\r
1678\r
1679 DeviceSelect = 0;\r
1680 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1681\r
1682 //\r
1683 // Send Init drive parameters\r
1684 //\r
1685 Status = AtaNonDataCommandIn (\r
1686 IdeDev,\r
1e23bd8d 1687 ATA_CMD_INIT_DRIVE_PARAM,\r
ead42efc 1688 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1689 0,\r
1690 DriveParameters->Sector,\r
1691 0,\r
1692 0,\r
1693 0\r
1694 );\r
1695\r
1696 //\r
1697 // Send Set Multiple parameters\r
1698 //\r
1699 Status = AtaNonDataCommandIn (\r
1700 IdeDev,\r
1e23bd8d 1701 ATA_CMD_SET_MULTIPLE_MODE,\r
ead42efc 1702 DeviceSelect,\r
1703 0,\r
1704 DriveParameters->MultipleSector,\r
1705 0,\r
1706 0,\r
1707 0\r
1708 );\r
1709 return Status;\r
1710}\r
1711\r
1712/**\r
1713 TODO: Add function description\r
1714\r
1715 @param IdeDev TODO: add argument description\r
1716\r
97404058 1717 @retval EFI_SUCCESS TODO: Add description for return value.\r
ead42efc 1718\r
1719**/\r
1720EFI_STATUS\r
1721EnableInterrupt (\r
1722 IN IDE_BLK_IO_DEV *IdeDev\r
1723 )\r
1724{\r
1725 UINT8 DeviceControl;\r
1726\r
1727 //\r
1728 // Enable interrupt for DMA operation\r
1729 //\r
1730 DeviceControl = 0;\r
1731 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1732\r
1733 return EFI_SUCCESS;\r
1734}\r
1735\r
1736/**\r
1737 Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.\r
1738\r
1739 @param[in] Event Pointer to this event\r
1740 @param[in] Context Event hanlder private data\r
1741\r
1742**/\r
1743VOID\r
1744EFIAPI\r
1745ClearInterrupt (\r
1746 IN EFI_EVENT Event,\r
1747 IN VOID *Context\r
1748 )\r
1749{\r
1750 EFI_STATUS Status;\r
1751 UINT64 IoPortForBmis;\r
1752 UINT8 RegisterValue;\r
1753 IDE_BLK_IO_DEV *IdeDev;\r
1754\r
1755 //\r
1756 // Get our context\r
1757 //\r
1758 IdeDev = (IDE_BLK_IO_DEV *) Context;\r
1759\r
1760 //\r
1761 // Obtain IDE IO port registers' base addresses\r
1762 //\r
1763 Status = ReassignIdeResources (IdeDev);\r
1764 if (EFI_ERROR (Status)) {\r
1765 return;\r
1766 }\r
1767\r
1768 //\r
1769 // Check whether interrupt is pending\r
1770 //\r
1771\r
1772 //\r
1773 // Reset IDE device to force it de-assert interrupt pin\r
1774 // Note: this will reset all devices on this IDE channel\r
1775 //\r
1776 AtaSoftReset (IdeDev);\r
1777 if (EFI_ERROR (Status)) {\r
1778 return;\r
1779 }\r
1780\r
1781 //\r
1782 // Get base address of IDE Bus Master Status Regsiter\r
1783 //\r
1784 if (IdePrimary == IdeDev->Channel) {\r
1785 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;\r
1786 } else {\r
1787 if (IdeSecondary == IdeDev->Channel) {\r
1788 IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;\r
1789 } else {\r
1790 return;\r
1791 }\r
1792 }\r
1793 //\r
1794 // Read BMIS register and clear ERROR and INTR bit\r
1795 //\r
1796 IdeDev->PciIo->Io.Read (\r
1797 IdeDev->PciIo,\r
1798 EfiPciIoWidthUint8,\r
1799 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1800 IoPortForBmis,\r
1801 1,\r
1802 &RegisterValue\r
1803 );\r
1804\r
1805 RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);\r
1806\r
1807 IdeDev->PciIo->Io.Write (\r
1808 IdeDev->PciIo,\r
1809 EfiPciIoWidthUint8,\r
1810 EFI_PCI_IO_PASS_THROUGH_BAR,\r
1811 IoPortForBmis,\r
1812 1,\r
1813 &RegisterValue\r
1814 );\r
1815\r
1816 //\r
1817 // Select the other device on this channel to ensure this device to release the interrupt pin\r
1818 //\r
1819 if (IdeDev->Device == 0) {\r
1820 RegisterValue = (1 << 4) | 0xe0;\r
1821 } else {\r
1822 RegisterValue = (0 << 4) | 0xe0;\r
1823 }\r
1824 IDEWritePortB (\r
1825 IdeDev->PciIo,\r
1826 IdeDev->IoPort->Head,\r
1827 RegisterValue\r
1828 );\r
1829\r
1830}\r