[FREELDR] Add ATA/ATAPI driver. (#2167)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / xboxdisk.c
1 /*
2 * PROJECT: FreeLoader
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Xbox specific disk access routines
5 * COPYRIGHT: Copyright 2004 Gé van Geldorp (gvg@reactos.com)
6 * Copyright 2019 Dmitry Borisov (di.sean@protonmail.com)
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <freeldr.h>
12 #include <hwide.h>
13
14 #include <debug.h>
15 DBG_DEFAULT_CHANNEL(DISK);
16
17 /* GLOBALS ********************************************************************/
18
19 static PDEVICE_UNIT HardDrive = NULL;
20 static PDEVICE_UNIT CdDrive = NULL;
21 static BOOLEAN AtaInitialized = FALSE;
22
23 /* FUNCTIONS ******************************************************************/
24
25 VOID
26 XboxDiskInit(BOOLEAN Init)
27 {
28 UCHAR DetectedCount;
29 UCHAR UnitNumber;
30 PDEVICE_UNIT DeviceUnit = NULL;
31
32 if (Init & !AtaInitialized)
33 {
34 /* Find first HDD and CD */
35 AtaInit(&DetectedCount);
36 for (UnitNumber = 0; UnitNumber <= DetectedCount; UnitNumber++)
37 {
38 DeviceUnit = AtaGetDevice(UnitNumber);
39 if (DeviceUnit)
40 {
41 if (DeviceUnit->Flags & ATA_DEVICE_ATAPI)
42 {
43 if (!CdDrive)
44 CdDrive = DeviceUnit;
45 }
46 else
47 {
48 if (!HardDrive)
49 HardDrive = DeviceUnit;
50 }
51 }
52 }
53 AtaInitialized = TRUE;
54 }
55 else
56 {
57 AtaFree();
58 }
59 }
60
61 static
62 inline
63 BOOLEAN
64 XboxDiskDriveNumberToDeviceUnit(UCHAR DriveNumber, PDEVICE_UNIT *DeviceUnit)
65 {
66 /* Xbox has only 1 IDE controller and no floppy */
67 if (DriveNumber < 0x80 || (DriveNumber & 0x0F) >= 2)
68 return FALSE;
69
70 if (!AtaInitialized)
71 XboxDiskInit(TRUE);
72
73 /* HDD */
74 if ((DriveNumber == 0x80) && HardDrive)
75 {
76 *DeviceUnit = HardDrive;
77 return TRUE;
78 }
79
80 /* CD */
81 if ((DriveNumber & 0xF0) > 0x80 && CdDrive)
82 {
83 *DeviceUnit = CdDrive;
84 return TRUE;
85 }
86
87 return FALSE;
88 }
89
90 BOOLEAN
91 XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
92 {
93 PDEVICE_UNIT DeviceUnit = NULL;
94
95 TRACE("XboxDiskReadLogicalSectors() DriveNumber: 0x%x SectorNumber: %I64d SectorCount: %d Buffer: 0x%x\n",
96 DriveNumber, SectorNumber, SectorCount, Buffer);
97
98 if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
99 return FALSE;
100
101 return AtaAtapiReadLogicalSectorsLBA(DeviceUnit, SectorNumber, SectorCount, Buffer);
102 }
103
104 BOOLEAN
105 XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
106 {
107 PDEVICE_UNIT DeviceUnit = NULL;
108
109 TRACE("XboxDiskGetDriveGeometry(0x%x)\n", DriveNumber);
110
111 if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
112 return FALSE;
113
114 Geometry->Cylinders = DeviceUnit->Cylinders;
115 Geometry->Heads = DeviceUnit->Heads;
116 Geometry->Sectors = DeviceUnit->Sectors;
117 Geometry->BytesPerSector = DeviceUnit->SectorSize;
118
119 return TRUE;
120 }
121
122 ULONG
123 XboxDiskGetCacheableBlockCount(UCHAR DriveNumber)
124 {
125 PDEVICE_UNIT DeviceUnit = NULL;
126
127 TRACE("XboxDiskGetCacheableBlockCount(0x%x)\n", DriveNumber);
128
129 if (!XboxDiskDriveNumberToDeviceUnit(DriveNumber, &DeviceUnit))
130 return 0;
131
132 /*
133 * If LBA is supported then the block size will be 64 sectors (32k)
134 * If not then the block size is the size of one track.
135 */
136 if (DeviceUnit->Flags & ATA_DEVICE_LBA)
137 return 64;
138 else
139 return DeviceUnit->Sectors;
140 }