VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxIdeBusDxe/Ide.c@ 48947

Last change on this file since 48947 was 48947, checked in by vboxsync, 11 years ago

Devices: Whitespace and svn:keyword cleanups by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette