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