]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
IntelFrameworkModulePkg: Convert non DOS format files to DOS format
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / IdeBusDxe / Ide.c
... / ...
CommitLineData
1/** @file\r
2 The file ontaining the helper functions implement of the Ide Bus driver\r
3 \r
4 Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "IdeBus.h"\r
16\r
17BOOLEAN ChannelDeviceDetected = FALSE;\r
18BOOLEAN SlaveDeviceExist = FALSE;\r
19UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;\r
20BOOLEAN MasterDeviceExist = FALSE;\r
21UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;\r
22\r
23/**\r
24 read a one-byte data from a IDE port.\r
25\r
26 @param PciIo The PCI IO protocol instance\r
27 @param Port the IDE Port number \r
28\r
29 @return the one-byte data read from IDE port\r
30**/\r
31UINT8\r
32IDEReadPortB (\r
33 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
34 IN UINT16 Port\r
35 )\r
36{\r
37 UINT8 Data;\r
38\r
39 Data = 0;\r
40 //\r
41 // perform 1-byte data read from register\r
42 //\r
43 PciIo->Io.Read (\r
44 PciIo,\r
45 EfiPciIoWidthUint8,\r
46 EFI_PCI_IO_PASS_THROUGH_BAR,\r
47 (UINT64) Port,\r
48 1,\r
49 &Data\r
50 );\r
51 return Data;\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 OUT 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 write a 1-byte data to a specific IDE port.\r
113\r
114 @param PciIo PCI IO protocol instance\r
115 @param Port The IDE port to be writen\r
116 @param Data The data to write to the port\r
117**/\r
118VOID\r
119IDEWritePortB (\r
120 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
121 IN UINT16 Port,\r
122 IN UINT8 Data\r
123 )\r
124{\r
125 //\r
126 // perform 1-byte data write to register\r
127 //\r
128 PciIo->Io.Write (\r
129 PciIo,\r
130 EfiPciIoWidthUint8,\r
131 EFI_PCI_IO_PASS_THROUGH_BAR,\r
132 (UINT64) Port,\r
133 1,\r
134 &Data\r
135 );\r
136\r
137}\r
138\r
139/**\r
140 write a 1-word data to a specific IDE port.\r
141\r
142 @param PciIo PCI IO protocol instance\r
143 @param Port The IDE port to be writen\r
144 @param Data The data to write to the port\r
145**/\r
146VOID\r
147IDEWritePortW (\r
148 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
149 IN UINT16 Port,\r
150 IN UINT16 Data\r
151 )\r
152{\r
153 //\r
154 // perform 1-word data write to register\r
155 //\r
156 PciIo->Io.Write (\r
157 PciIo,\r
158 EfiPciIoWidthUint16,\r
159 EFI_PCI_IO_PASS_THROUGH_BAR,\r
160 (UINT64) Port,\r
161 1,\r
162 &Data\r
163 );\r
164}\r
165\r
166/**\r
167 Write multiple words of data to the IDE data port.\r
168 Call the IO abstraction once to do the complete read,\r
169 not one word at a time\r
170\r
171 @param PciIo Pointer to the EFI_PCI_IO instance\r
172 @param Port IO port to read\r
173 @param Count No. of UINT16's to read\r
174 @param Buffer Pointer to the data buffer for read\r
175\r
176**/\r
177VOID\r
178IDEWritePortWMultiple (\r
179 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
180 IN UINT16 Port,\r
181 IN UINTN Count,\r
182 IN VOID *Buffer\r
183 )\r
184{\r
185 UINT16 *AlignedBuffer;\r
186 UINT32 *WorkingBuffer;\r
187 UINTN Size;\r
188\r
189 //\r
190 // Prepare an 16-bit alligned working buffer. CpuIo will return failure and\r
191 // not perform actual I/O operations if buffer pointer passed in is not at\r
192 // natural boundary. The "Buffer" argument is passed in by user and may not\r
193 // at 16-bit natural boundary.\r
194 //\r
195 Size = sizeof (UINT16) * Count;\r
196\r
197 gBS->AllocatePool (\r
198 EfiBootServicesData,\r
199 Size + 1,\r
200 (VOID **) &WorkingBuffer\r
201 );\r
202\r
203 AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));\r
204\r
205 //\r
206 // Copy data from user buffer to working buffer\r
207 //\r
208 CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);\r
209\r
210 //\r
211 // perform UINT16 data write to the FIFO\r
212 //\r
213 PciIo->Io.Write (\r
214 PciIo,\r
215 EfiPciIoWidthFifoUint16,\r
216 EFI_PCI_IO_PASS_THROUGH_BAR,\r
217 (UINT64) Port,\r
218 Count,\r
219 (UINT16 *) AlignedBuffer\r
220 );\r
221\r
222 gBS->FreePool (WorkingBuffer);\r
223}\r
224/**\r
225 Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,\r
226 use fixed addresses. In Native-PCI mode, get base addresses from BARs in\r
227 the PCI IDE controller's Configuration Space.\r
228\r
229 The steps to get IDE IO port registers' base addresses for each channel\r
230 as follows:\r
231\r
232 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE\r
233 controller's Configuration Space to determine the operating mode.\r
234\r
235 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.\r
236 <pre>\r
237 ___________________________________________\r
238 | | Command Block | Control Block |\r
239 | Channel | Registers | Registers |\r
240 |___________|_______________|_______________|\r
241 | Primary | 1F0h - 1F7h | 3F6h - 3F7h |\r
242 |___________|_______________|_______________|\r
243 | Secondary | 170h - 177h | 376h - 377h |\r
244 |___________|_______________|_______________|\r
245\r
246 Table 1. Compatibility resource mappings\r
247 </pre>\r
248\r
249 b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs\r
250 in IDE controller's PCI Configuration Space, shown in the Table 2 below.\r
251 <pre>\r
252 ___________________________________________________\r
253 | | Command Block | Control Block |\r
254 | Channel | Registers | Registers |\r
255 |___________|___________________|___________________|\r
256 | Primary | BAR at offset 0x10| BAR at offset 0x14|\r
257 |___________|___________________|___________________|\r
258 | Secondary | BAR at offset 0x18| BAR at offset 0x1C|\r
259 |___________|___________________|___________________|\r
260\r
261 Table 2. BARs for Register Mapping\r
262 </pre>\r
263 @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for\r
264 primary, 0374h for secondary. So 2 bytes extra offset should be\r
265 added to the base addresses read from BARs.\r
266\r
267 For more details, please refer to PCI IDE Controller Specification and Intel\r
268 ICH4 Datasheet.\r
269\r
270 @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance\r
271 @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to\r
272 receive IDE IO port registers' base addresses\r
273 \r
274 @retval EFI_UNSUPPORTED return this value when the BARs is not IO type\r
275 @retval EFI_SUCCESS Get the Base address successfully\r
276 @retval other read the pci configureation data error\r
277\r
278**/\r
279EFI_STATUS\r
280GetIdeRegistersBaseAddr (\r
281 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
282 OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr\r
283 )\r
284{\r
285 EFI_STATUS Status;\r
286 PCI_TYPE00 PciData;\r
287\r
288 Status = PciIo->Pci.Read (\r
289 PciIo,\r
290 EfiPciIoWidthUint8,\r
291 0,\r
292 sizeof (PciData),\r
293 &PciData\r
294 );\r
295\r
296 if (EFI_ERROR (Status)) {\r
297 return Status;\r
298 }\r
299\r
300 if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {\r
301 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;\r
302 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;\r
303 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
304 (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));\r
305 } else {\r
306 //\r
307 // The BARs should be of IO type\r
308 //\r
309 if ((PciData.Device.Bar[0] & BIT0) == 0 ||\r
310 (PciData.Device.Bar[1] & BIT0) == 0) {\r
311 return EFI_UNSUPPORTED;\r
312 }\r
313\r
314 IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =\r
315 (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);\r
316 IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =\r
317 (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);\r
318 IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =\r
319 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
320 }\r
321\r
322 if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {\r
323 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;\r
324 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;\r
325 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
326 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
327 } else {\r
328 //\r
329 // The BARs should be of IO type\r
330 //\r
331 if ((PciData.Device.Bar[2] & BIT0) == 0 ||\r
332 (PciData.Device.Bar[3] & BIT0) == 0) {\r
333 return EFI_UNSUPPORTED;\r
334 }\r
335\r
336 IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =\r
337 (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);\r
338 IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =\r
339 (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);\r
340 IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =\r
341 (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));\r
342 }\r
343\r
344 return EFI_SUCCESS;\r
345}\r
346\r
347/**\r
348 This function is used to requery IDE resources. The IDE controller will\r
349 probably switch between native and legacy modes during the EFI->CSM->OS\r
350 transfer. We do this everytime before an BlkIo operation to ensure its\r
351 succeess.\r
352\r
353 @param IdeDev The BLK_IO private data which specifies the IDE device\r
354 \r
355 @retval EFI_INVALID_PARAMETER return this value when the channel is invalid\r
356 @retval EFI_SUCCESS reassign the IDE IO resource successfully\r
357 @retval other get the IDE current base address effor\r
358\r
359**/\r
360EFI_STATUS\r
361ReassignIdeResources (\r
362 IN IDE_BLK_IO_DEV *IdeDev\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366 IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];\r
367 UINT16 CommandBlockBaseAddr;\r
368 UINT16 ControlBlockBaseAddr;\r
369\r
370 if (IdeDev->Channel >= IdeMaxChannel) {\r
371 return EFI_INVALID_PARAMETER;\r
372 }\r
373 \r
374 //\r
375 // Requery IDE IO port registers' base addresses in case of the switch of\r
376 // native and legacy modes\r
377 //\r
378 Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);\r
379 if (EFI_ERROR (Status)) {\r
380 return Status;\r
381 }\r
382\r
383 ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));\r
384 CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;\r
385 ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;\r
386\r
387 IdeDev->IoPort->Data = CommandBlockBaseAddr;\r
388 (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);\r
389 IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);\r
390 IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);\r
391 IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);\r
392 IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);\r
393 IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);\r
394\r
395 (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);\r
396 (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;\r
397 IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);\r
398 IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);\r
399\r
400 IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;\r
401 return EFI_SUCCESS;\r
402}\r
403\r
404/**\r
405 This function is called by DiscoverIdeDevice(). It is used for detect\r
406 whether the IDE device exists in the specified Channel as the specified\r
407 Device Number.\r
408\r
409 There is two IDE channels: one is Primary Channel, the other is\r
410 Secondary Channel.(Channel is the logical name for the physical "Cable".)\r
411 Different channel has different register group.\r
412\r
413 On each IDE channel, at most two IDE devices attach,\r
414 one is called Device 0 (Master device), the other is called Device 1\r
415 (Slave device). The devices on the same channel co-use the same register\r
416 group, so before sending out a command for a specified device via command\r
417 register, it is a must to select the current device to accept the command\r
418 by set the device number in the Head/Device Register.\r
419\r
420 @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the\r
421 information of the IDE device.\r
422\r
423 @retval EFI_SUCCESS successfully detects device.\r
424\r
425 @retval other any failure during detection process will return this value.\r
426\r
427**/\r
428EFI_STATUS\r
429DetectIDEController (\r
430 IN IDE_BLK_IO_DEV *IdeDev\r
431 )\r
432{\r
433 EFI_STATUS Status;\r
434 UINT8 SectorCountReg;\r
435 UINT8 LBALowReg;\r
436 UINT8 LBAMidReg;\r
437 UINT8 LBAHighReg;\r
438 UINT8 InitStatusReg;\r
439 UINT8 StatusReg;\r
440\r
441 //\r
442 // Select slave device\r
443 //\r
444 IDEWritePortB (\r
445 IdeDev->PciIo,\r
446 IdeDev->IoPort->Head,\r
447 (UINT8) ((1 << 4) | 0xe0)\r
448 );\r
449 gBS->Stall (100);\r
450\r
451 //\r
452 // Save the init slave status register\r
453 //\r
454 InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
455\r
456 //\r
457 // Select Master back\r
458 //\r
459 IDEWritePortB (\r
460 IdeDev->PciIo,\r
461 IdeDev->IoPort->Head,\r
462 (UINT8) ((0 << 4) | 0xe0)\r
463 );\r
464 gBS->Stall (100);\r
465\r
466 //\r
467 // Send ATA Device Execut Diagnostic command.\r
468 // This command should work no matter DRDY is ready or not\r
469 //\r
470 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);\r
471\r
472 Status = WaitForBSYClear (IdeDev, 3500);\r
473 if (EFI_ERROR (Status)) {\r
474 DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));\r
475 return Status;\r
476 }\r
477 //\r
478 // Read device signature\r
479 //\r
480 //\r
481 // Select Master\r
482 //\r
483 IDEWritePortB (\r
484 IdeDev->PciIo,\r
485 IdeDev->IoPort->Head,\r
486 (UINT8) ((0 << 4) | 0xe0)\r
487 );\r
488 gBS->Stall (100);\r
489 SectorCountReg = IDEReadPortB (\r
490 IdeDev->PciIo,\r
491 IdeDev->IoPort->SectorCount\r
492 );\r
493 LBALowReg = IDEReadPortB (\r
494 IdeDev->PciIo,\r
495 IdeDev->IoPort->SectorNumber\r
496 );\r
497 LBAMidReg = IDEReadPortB (\r
498 IdeDev->PciIo,\r
499 IdeDev->IoPort->CylinderLsb\r
500 );\r
501 LBAHighReg = IDEReadPortB (\r
502 IdeDev->PciIo,\r
503 IdeDev->IoPort->CylinderMsb\r
504 );\r
505 if ((SectorCountReg == 0x1) &&\r
506 (LBALowReg == 0x1) &&\r
507 (LBAMidReg == 0x0) &&\r
508 (LBAHighReg == 0x0)) {\r
509 MasterDeviceExist = TRUE;\r
510 MasterDeviceType = ATA_DEVICE_TYPE;\r
511 } else {\r
512 if ((LBAMidReg == 0x14) &&\r
513 (LBAHighReg == 0xeb)) {\r
514 MasterDeviceExist = TRUE;\r
515 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
516 }\r
517 }\r
518\r
519 //\r
520 // For some Hard Drive, it takes some time to get\r
521 // the right signature when operating in single slave mode.\r
522 // We stall 20ms to work around this.\r
523 //\r
524 if (!MasterDeviceExist) {\r
525 gBS->Stall (20000);\r
526 }\r
527\r
528 //\r
529 // Select Slave\r
530 //\r
531 IDEWritePortB (\r
532 IdeDev->PciIo,\r
533 IdeDev->IoPort->Head,\r
534 (UINT8) ((1 << 4) | 0xe0)\r
535 );\r
536 gBS->Stall (100);\r
537 SectorCountReg = IDEReadPortB (\r
538 IdeDev->PciIo,\r
539 IdeDev->IoPort->SectorCount\r
540 );\r
541 LBALowReg = IDEReadPortB (\r
542 IdeDev->PciIo,\r
543 IdeDev->IoPort->SectorNumber\r
544 );\r
545 LBAMidReg = IDEReadPortB (\r
546 IdeDev->PciIo,\r
547 IdeDev->IoPort->CylinderLsb\r
548 );\r
549 LBAHighReg = IDEReadPortB (\r
550 IdeDev->PciIo,\r
551 IdeDev->IoPort->CylinderMsb\r
552 );\r
553 StatusReg = IDEReadPortB (\r
554 IdeDev->PciIo,\r
555 IdeDev->IoPort->Reg.Status\r
556 );\r
557 if ((SectorCountReg == 0x1) &&\r
558 (LBALowReg == 0x1) &&\r
559 (LBAMidReg == 0x0) &&\r
560 (LBAHighReg == 0x0)) {\r
561 SlaveDeviceExist = TRUE;\r
562 SlaveDeviceType = ATA_DEVICE_TYPE;\r
563 } else {\r
564 if ((LBAMidReg == 0x14) &&\r
565 (LBAHighReg == 0xeb)) {\r
566 SlaveDeviceExist = TRUE;\r
567 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
568 }\r
569 }\r
570\r
571 //\r
572 // When single master is plugged, slave device\r
573 // will be wrongly detected. Here's the workaround\r
574 // for ATA devices by detecting DRY bit in status\r
575 // register.\r
576 // NOTE: This workaround doesn't apply to ATAPI.\r
577 //\r
578 if (MasterDeviceExist && SlaveDeviceExist &&\r
579 (StatusReg & ATA_STSREG_DRDY) == 0 &&\r
580 (InitStatusReg & ATA_STSREG_DRDY) == 0 &&\r
581 MasterDeviceType == SlaveDeviceType &&\r
582 SlaveDeviceType != ATAPI_DEVICE_TYPE) {\r
583 SlaveDeviceExist = FALSE;\r
584 }\r
585\r
586 //\r
587 // Indicate this channel has been detected\r
588 //\r
589 ChannelDeviceDetected = TRUE;\r
590 return EFI_SUCCESS;\r
591}\r
592/**\r
593 Detect if there is disk attached to this port\r
594\r
595 @param IdeDev The BLK_IO private data which specifies the IDE device.\r
596 \r
597 @retval EFI_NOT_FOUND The device or channel is not found\r
598 @retval EFI_SUCCESS The device is found\r
599\r
600**/\r
601EFI_STATUS\r
602DiscoverIdeDevice (\r
603 IN IDE_BLK_IO_DEV *IdeDev\r
604 )\r
605{\r
606 EFI_STATUS Status;\r
607 EFI_STATUS LongPhyStatus;\r
608\r
609 //\r
610 // If a channel has not been checked, check it now. Then set it to "checked" state\r
611 // After this step, all devices in this channel have been checked.\r
612 //\r
613 if (!ChannelDeviceDetected) {\r
614 Status = DetectIDEController (IdeDev);\r
615 if (EFI_ERROR (Status)) {\r
616 return EFI_NOT_FOUND;\r
617 }\r
618 }\r
619\r
620 Status = EFI_NOT_FOUND;\r
621\r
622 //\r
623 // Device exists. test if it is an ATA device.\r
624 // Prefer the result from DetectIDEController,\r
625 // if failed, try another device type to handle\r
626 // devices that not follow the spec.\r
627 //\r
628 if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {\r
629 if (MasterDeviceType == ATA_DEVICE_TYPE) {\r
630 Status = ATAIdentify (IdeDev);\r
631 if (EFI_ERROR (Status)) {\r
632 Status = ATAPIIdentify (IdeDev);\r
633 if (!EFI_ERROR (Status)) {\r
634 MasterDeviceType = ATAPI_DEVICE_TYPE;\r
635 }\r
636 }\r
637 } else {\r
638 Status = ATAPIIdentify (IdeDev);\r
639 if (EFI_ERROR (Status)) {\r
640 Status = ATAIdentify (IdeDev);\r
641 if (!EFI_ERROR (Status)) {\r
642 MasterDeviceType = ATA_DEVICE_TYPE;\r
643 }\r
644 }\r
645 }\r
646 }\r
647 if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {\r
648 if (SlaveDeviceType == ATA_DEVICE_TYPE) {\r
649 Status = ATAIdentify (IdeDev);\r
650 if (EFI_ERROR (Status)) {\r
651 Status = ATAPIIdentify (IdeDev);\r
652 if (!EFI_ERROR (Status)) {\r
653 SlaveDeviceType = ATAPI_DEVICE_TYPE;\r
654 }\r
655 }\r
656 } else {\r
657 Status = ATAPIIdentify (IdeDev);\r
658 if (EFI_ERROR (Status)) {\r
659 Status = ATAIdentify (IdeDev);\r
660 if (!EFI_ERROR (Status)) {\r
661 SlaveDeviceType = ATA_DEVICE_TYPE;\r
662 }\r
663 }\r
664 }\r
665 }\r
666 if (EFI_ERROR (Status)) {\r
667 return EFI_NOT_FOUND;\r
668 }\r
669 //\r
670 // Init Block I/O interface\r
671 //\r
672 LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);\r
673 if (!EFI_ERROR (LongPhyStatus)) {\r
674 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;\r
675 } else {\r
676 IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;\r
677 }\r
678 IdeDev->BlkIo.Reset = IDEBlkIoReset;\r
679 IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;\r
680 IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;\r
681 IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;\r
682\r
683 IdeDev->BlkMedia.LogicalPartition = FALSE;\r
684 IdeDev->BlkMedia.WriteCaching = FALSE;\r
685\r
686 //\r
687 // Init Disk Info interface\r
688 //\r
689 gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));\r
690 IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;\r
691 IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;\r
692 IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;\r
693 IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;\r
694\r
695 return EFI_SUCCESS;\r
696}\r
697\r
698/**\r
699 This interface is used to initialize all state data related to the detection of one\r
700 channel.\r
701**/\r
702VOID\r
703InitializeIDEChannelData (\r
704 VOID\r
705 )\r
706{\r
707 ChannelDeviceDetected = FALSE;\r
708 MasterDeviceExist = FALSE;\r
709 MasterDeviceType = 0xff;\r
710 SlaveDeviceExist = FALSE;\r
711 SlaveDeviceType = 0xff;\r
712}\r
713/**\r
714 This function is used to poll for the DRQ bit clear in the Status\r
715 Register. DRQ is cleared when the device is finished transferring data.\r
716 So this function is called after data transfer is finished.\r
717\r
718 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
719 to record all the information of the IDE device.\r
720 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
721\r
722 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
723\r
724 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
725\r
726 @note\r
727 Read Status Register will clear interrupt status.\r
728\r
729**/\r
730EFI_STATUS\r
731DRQClear (\r
732 IN IDE_BLK_IO_DEV *IdeDev,\r
733 IN UINTN TimeoutInMilliSeconds\r
734 )\r
735{\r
736 UINT32 Delay;\r
737 UINT8 StatusRegister;\r
738 UINT8 ErrorRegister;\r
739\r
740 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
741 do {\r
742\r
743 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
744\r
745 //\r
746 // wait for BSY == 0 and DRQ == 0\r
747 //\r
748 if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
749 break;\r
750 }\r
751\r
752 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
753\r
754 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
755 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
756 return EFI_ABORTED;\r
757 }\r
758 }\r
759\r
760 //\r
761 // Stall for 30 us\r
762 //\r
763 gBS->Stall (30);\r
764\r
765 Delay--;\r
766\r
767 } while (Delay > 0);\r
768\r
769 if (Delay == 0) {\r
770 return EFI_TIMEOUT;\r
771 }\r
772\r
773 return EFI_SUCCESS;\r
774}\r
775/**\r
776 This function is used to poll for the DRQ bit clear in the Alternate\r
777 Status Register. DRQ is cleared when the device is finished\r
778 transferring data. So this function is called after data transfer\r
779 is finished.\r
780\r
781 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
782 to record all the information of the IDE device.\r
783\r
784 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.\r
785\r
786 @retval EFI_SUCCESS DRQ bit clear within the time out.\r
787\r
788 @retval EFI_TIMEOUT DRQ bit not clear within the time out.\r
789 @note Read Alternate Status Register will not clear interrupt status.\r
790\r
791**/\r
792EFI_STATUS\r
793DRQClear2 (\r
794 IN IDE_BLK_IO_DEV *IdeDev,\r
795 IN UINTN TimeoutInMilliSeconds\r
796 )\r
797{\r
798 UINT32 Delay;\r
799 UINT8 AltRegister;\r
800 UINT8 ErrorRegister;\r
801\r
802 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
803 do {\r
804\r
805 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
806\r
807 //\r
808 // wait for BSY == 0 and DRQ == 0\r
809 //\r
810 if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {\r
811 break;\r
812 }\r
813\r
814 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
815\r
816 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
817 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
818 return EFI_ABORTED;\r
819 }\r
820 }\r
821\r
822 //\r
823 // Stall for 30 us\r
824 //\r
825 gBS->Stall (30);\r
826\r
827 Delay--;\r
828\r
829 } while (Delay > 0);\r
830\r
831 if (Delay == 0) {\r
832 return EFI_TIMEOUT;\r
833 }\r
834\r
835 return EFI_SUCCESS;\r
836}\r
837\r
838/**\r
839 This function is used to poll for the DRQ bit set in the\r
840 Status Register.\r
841 DRQ is set when the device is ready to transfer data. So this function\r
842 is called after the command is sent to the device and before required\r
843 data is transferred.\r
844\r
845 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to\r
846 record all the information of the IDE device.\r
847 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
848\r
849 @retval EFI_SUCCESS DRQ bit set within the time out.\r
850 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
851 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
852\r
853 @note Read Status Register will clear interrupt status.\r
854\r
855**/\r
856EFI_STATUS\r
857DRQReady (\r
858 IN IDE_BLK_IO_DEV *IdeDev,\r
859 IN UINTN TimeoutInMilliSeconds\r
860 )\r
861{\r
862 UINT32 Delay;\r
863 UINT8 StatusRegister;\r
864 UINT8 ErrorRegister;\r
865\r
866 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
867 do {\r
868 //\r
869 // read Status Register will clear interrupt\r
870 //\r
871 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
872\r
873 //\r
874 // BSY==0,DRQ==1\r
875 //\r
876 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
877 break;\r
878 }\r
879\r
880 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
881\r
882 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
883 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
884 return EFI_ABORTED;\r
885 }\r
886 }\r
887\r
888 //\r
889 // Stall for 30 us\r
890 //\r
891 gBS->Stall (30);\r
892\r
893 Delay--;\r
894 } while (Delay > 0);\r
895\r
896 if (Delay == 0) {\r
897 return EFI_TIMEOUT;\r
898 }\r
899\r
900 return EFI_SUCCESS;\r
901}\r
902/**\r
903 This function is used to poll for the DRQ bit set in the Alternate Status Register.\r
904 DRQ is set when the device is ready to transfer data. So this function is called after \r
905 the command is sent to the device and before required data is transferred.\r
906\r
907 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to \r
908 record all the information of the IDE device.\r
909\r
910 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
911\r
912 @retval EFI_SUCCESS DRQ bit set within the time out.\r
913 @retval EFI_TIMEOUT DRQ bit not set within the time out.\r
914 @retval EFI_ABORTED DRQ bit not set caused by the command abort.\r
915 @note Read Alternate Status Register will not clear interrupt status.\r
916\r
917**/\r
918EFI_STATUS\r
919DRQReady2 (\r
920 IN IDE_BLK_IO_DEV *IdeDev,\r
921 IN UINTN TimeoutInMilliSeconds\r
922 )\r
923{\r
924 UINT32 Delay;\r
925 UINT8 AltRegister;\r
926 UINT8 ErrorRegister;\r
927\r
928 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
929\r
930 do {\r
931 //\r
932 // Read Alternate Status Register will not clear interrupt status\r
933 //\r
934 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
935 //\r
936 // BSY == 0 , DRQ == 1\r
937 //\r
938 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {\r
939 break;\r
940 }\r
941\r
942 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
943\r
944 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
945 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
946 return EFI_ABORTED;\r
947 }\r
948 }\r
949\r
950 //\r
951 // Stall for 30 us\r
952 //\r
953 gBS->Stall (30);\r
954\r
955 Delay--;\r
956 } while (Delay > 0);\r
957\r
958 if (Delay == 0) {\r
959 return EFI_TIMEOUT;\r
960 }\r
961\r
962 return EFI_SUCCESS;\r
963}\r
964\r
965/**\r
966 This function is used to poll for the BSY bit clear in the Status Register. BSY\r
967 is clear when the device is not busy. Every command must be sent after device is not busy.\r
968\r
969 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used \r
970 to record all the information of the IDE device.\r
971 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
972\r
973 @retval EFI_SUCCESS BSY bit clear within the time out.\r
974 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
975\r
976 @note Read Status Register will clear interrupt status.\r
977**/\r
978EFI_STATUS\r
979WaitForBSYClear (\r
980 IN IDE_BLK_IO_DEV *IdeDev,\r
981 IN UINTN TimeoutInMilliSeconds\r
982 )\r
983{\r
984 UINT32 Delay;\r
985 UINT8 StatusRegister;\r
986\r
987 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
988 do {\r
989\r
990 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
991 if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {\r
992 break;\r
993 }\r
994\r
995 //\r
996 // Stall for 30 us\r
997 //\r
998 gBS->Stall (30);\r
999\r
1000 Delay--;\r
1001\r
1002 } while (Delay > 0);\r
1003\r
1004 if (Delay == 0) {\r
1005 return EFI_TIMEOUT;\r
1006 }\r
1007\r
1008 return EFI_SUCCESS;\r
1009}\r
1010/**\r
1011 This function is used to poll for the BSY bit clear in the Alternate Status Register. \r
1012 BSY is clear when the device is not busy. Every command must be sent after device is \r
1013 not busy.\r
1014\r
1015 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record \r
1016 all the information of the IDE device.\r
1017 @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.\r
1018\r
1019 @retval EFI_SUCCESS BSY bit clear within the time out.\r
1020 @retval EFI_TIMEOUT BSY bit not clear within the time out.\r
1021 @note Read Alternate Status Register will not clear interrupt status.\r
1022\r
1023**/\r
1024EFI_STATUS\r
1025WaitForBSYClear2 (\r
1026 IN IDE_BLK_IO_DEV *IdeDev,\r
1027 IN UINTN TimeoutInMilliSeconds\r
1028 )\r
1029{\r
1030 UINT32 Delay;\r
1031 UINT8 AltRegister;\r
1032\r
1033 Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1034 do {\r
1035 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1036 if ((AltRegister & ATA_STSREG_BSY) == 0x00) {\r
1037 break;\r
1038 }\r
1039\r
1040 gBS->Stall (30);\r
1041\r
1042 Delay--;\r
1043\r
1044 } while (Delay > 0);\r
1045\r
1046 if (Delay == 0) {\r
1047 return EFI_TIMEOUT;\r
1048 }\r
1049\r
1050 return EFI_SUCCESS;\r
1051}\r
1052/**\r
1053 This function is used to poll for the DRDY bit set in the Status Register. DRDY\r
1054 bit is set when the device is ready to accept command. Most ATA commands must be \r
1055 sent after DRDY set except the ATAPI Packet Command.\r
1056\r
1057 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1058 to record all the information of the IDE device.\r
1059 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
1060\r
1061 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1062 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
1063\r
1064 @note Read Status Register will clear interrupt status.\r
1065**/\r
1066EFI_STATUS\r
1067DRDYReady (\r
1068 IN IDE_BLK_IO_DEV *IdeDev,\r
1069 IN UINTN DelayInMilliSeconds\r
1070 )\r
1071{\r
1072 UINT32 Delay;\r
1073 UINT8 StatusRegister;\r
1074 UINT8 ErrorRegister;\r
1075\r
1076 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1077 do {\r
1078 StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);\r
1079 //\r
1080 // BSY == 0 , DRDY == 1\r
1081 //\r
1082 if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
1083 break;\r
1084 }\r
1085\r
1086 if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1087\r
1088 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1089 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1090 return EFI_ABORTED;\r
1091 }\r
1092 }\r
1093\r
1094 gBS->Stall (30);\r
1095\r
1096 Delay--;\r
1097 } while (Delay > 0);\r
1098\r
1099 if (Delay == 0) {\r
1100 return EFI_TIMEOUT;\r
1101 }\r
1102\r
1103 return EFI_SUCCESS;\r
1104}\r
1105/**\r
1106 This function is used to poll for the DRDY bit set in the Alternate Status Register. \r
1107 DRDY bit is set when the device is ready to accept command. Most ATA commands must \r
1108 be sent after DRDY set except the ATAPI Packet Command.\r
1109\r
1110 @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used\r
1111 to record all the information of the IDE device.\r
1112 @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.\r
1113\r
1114 @retval EFI_SUCCESS DRDY bit set within the time out.\r
1115 @retval EFI_TIMEOUT DRDY bit not set within the time out.\r
1116\r
1117 @note Read Alternate Status Register will clear interrupt status.\r
1118\r
1119**/\r
1120EFI_STATUS\r
1121DRDYReady2 (\r
1122 IN IDE_BLK_IO_DEV *IdeDev,\r
1123 IN UINTN DelayInMilliSeconds\r
1124 )\r
1125{\r
1126 UINT32 Delay;\r
1127 UINT8 AltRegister;\r
1128 UINT8 ErrorRegister;\r
1129\r
1130 Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);\r
1131 do {\r
1132 AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);\r
1133 //\r
1134 // BSY == 0 , DRDY == 1\r
1135 //\r
1136 if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {\r
1137 break;\r
1138 }\r
1139\r
1140 if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {\r
1141\r
1142 ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);\r
1143 if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {\r
1144 return EFI_ABORTED;\r
1145 }\r
1146 }\r
1147\r
1148 gBS->Stall (30);\r
1149\r
1150 Delay--;\r
1151 } while (Delay > 0);\r
1152\r
1153 if (Delay == 0) {\r
1154 return EFI_TIMEOUT;\r
1155 }\r
1156\r
1157 return EFI_SUCCESS;\r
1158}\r
1159/**\r
1160 Release resources of an IDE device before stopping it.\r
1161\r
1162 @param IdeBlkIoDevice Standard IDE device private data structure\r
1163\r
1164**/\r
1165VOID\r
1166ReleaseIdeResources (\r
1167 IN IDE_BLK_IO_DEV *IdeBlkIoDevice\r
1168 )\r
1169{\r
1170 if (IdeBlkIoDevice == NULL) {\r
1171 return ;\r
1172 }\r
1173\r
1174 //\r
1175 // Release all the resourses occupied by the IDE_BLK_IO_DEV\r
1176 //\r
1177\r
1178 if (IdeBlkIoDevice->SenseData != NULL) {\r
1179 gBS->FreePool (IdeBlkIoDevice->SenseData);\r
1180 IdeBlkIoDevice->SenseData = NULL;\r
1181 }\r
1182\r
1183 if (IdeBlkIoDevice->Cache != NULL) {\r
1184 gBS->FreePool (IdeBlkIoDevice->Cache);\r
1185 IdeBlkIoDevice->Cache = NULL;\r
1186 }\r
1187\r
1188 if (IdeBlkIoDevice->IdData != NULL) {\r
1189 gBS->FreePool (IdeBlkIoDevice->IdData);\r
1190 IdeBlkIoDevice->IdData = NULL;\r
1191 }\r
1192\r
1193 if (IdeBlkIoDevice->InquiryData != NULL) {\r
1194 gBS->FreePool (IdeBlkIoDevice->InquiryData);\r
1195 IdeBlkIoDevice->InquiryData = NULL;\r
1196 }\r
1197\r
1198 if (IdeBlkIoDevice->ControllerNameTable != NULL) {\r
1199 FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);\r
1200 IdeBlkIoDevice->ControllerNameTable = NULL;\r
1201 }\r
1202\r
1203 if (IdeBlkIoDevice->IoPort != NULL) {\r
1204 gBS->FreePool (IdeBlkIoDevice->IoPort);\r
1205 }\r
1206\r
1207 if (IdeBlkIoDevice->DevicePath != NULL) {\r
1208 gBS->FreePool (IdeBlkIoDevice->DevicePath);\r
1209 }\r
1210\r
1211 if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {\r
1212 gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);\r
1213 IdeBlkIoDevice->ExitBootServiceEvent = NULL;\r
1214 }\r
1215\r
1216 gBS->FreePool (IdeBlkIoDevice);\r
1217 IdeBlkIoDevice = NULL;\r
1218\r
1219 return ;\r
1220}\r
1221/**\r
1222 Set the calculated Best transfer mode to a detected device.\r
1223\r
1224 @param IdeDev Standard IDE device private data structure\r
1225 @param TransferMode The device transfer mode to be set\r
1226 @return Set transfer mode Command execute status.\r
1227\r
1228**/\r
1229EFI_STATUS\r
1230SetDeviceTransferMode (\r
1231 IN IDE_BLK_IO_DEV *IdeDev,\r
1232 IN ATA_TRANSFER_MODE *TransferMode\r
1233 )\r
1234{\r
1235 EFI_STATUS Status;\r
1236 UINT8 DeviceSelect;\r
1237 UINT8 SectorCount;\r
1238\r
1239 DeviceSelect = 0;\r
1240 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1241 SectorCount = *((UINT8 *) TransferMode);\r
1242\r
1243 //\r
1244 // Send SET FEATURE command (sub command 0x03) to set pio mode.\r
1245 //\r
1246 Status = AtaNonDataCommandIn (\r
1247 IdeDev,\r
1248 ATA_CMD_SET_FEATURES,\r
1249 DeviceSelect,\r
1250 0x03,\r
1251 SectorCount,\r
1252 0,\r
1253 0,\r
1254 0\r
1255 );\r
1256\r
1257 return Status;\r
1258}\r
1259/**\r
1260 Set drive parameters for devices not support PACKETS command.\r
1261\r
1262 @param IdeDev Standard IDE device private data structure\r
1263 @param DriveParameters The device parameters to be set into the disk\r
1264 @return SetParameters Command execute status.\r
1265\r
1266**/\r
1267EFI_STATUS\r
1268SetDriveParameters (\r
1269 IN IDE_BLK_IO_DEV *IdeDev,\r
1270 IN ATA_DRIVE_PARMS *DriveParameters\r
1271 )\r
1272{\r
1273 EFI_STATUS Status;\r
1274 UINT8 DeviceSelect;\r
1275\r
1276 DeviceSelect = 0;\r
1277 DeviceSelect = (UINT8) ((IdeDev->Device) << 4);\r
1278\r
1279 //\r
1280 // Send Init drive parameters\r
1281 //\r
1282 Status = AtaNonDataCommandIn (\r
1283 IdeDev,\r
1284 ATA_CMD_INIT_DRIVE_PARAM,\r
1285 (UINT8) (DeviceSelect + DriveParameters->Heads),\r
1286 0,\r
1287 DriveParameters->Sector,\r
1288 0,\r
1289 0,\r
1290 0\r
1291 );\r
1292\r
1293 //\r
1294 // Send Set Multiple parameters\r
1295 //\r
1296 Status = AtaNonDataCommandIn (\r
1297 IdeDev,\r
1298 ATA_CMD_SET_MULTIPLE_MODE,\r
1299 DeviceSelect,\r
1300 0,\r
1301 DriveParameters->MultipleSector,\r
1302 0,\r
1303 0,\r
1304 0\r
1305 );\r
1306 return Status;\r
1307}\r
1308\r
1309/**\r
1310 Enable Interrupt on IDE controller.\r
1311\r
1312 @param IdeDev Standard IDE device private data structure\r
1313\r
1314 @retval EFI_SUCCESS Enable Interrupt successfully\r
1315**/\r
1316EFI_STATUS\r
1317EnableInterrupt (\r
1318 IN IDE_BLK_IO_DEV *IdeDev\r
1319 )\r
1320{\r
1321 UINT8 DeviceControl;\r
1322\r
1323 //\r
1324 // Enable interrupt for DMA operation\r
1325 //\r
1326 DeviceControl = 0;\r
1327 IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);\r
1328\r
1329 return EFI_SUCCESS;\r
1330}\r