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