dcdf319909269415cefd40cfaa029c21c758f1f1
[reactos.git] / boot / freeldr / freeldr / arch / i386 / xboxdisk.c
1 /*
2 * FreeLoader
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Note: mostly ripped from atapi.c
19 * Some of this code was based on knowledge and/or code developed
20 * by the Xbox Linux group: http://www.xbox-linux.org
21 *
22 */
23
24 #include <freeldr.h>
25
26 #include <debug.h>
27
28 DBG_DEFAULT_CHANNEL(DISK);
29
30 #define XBOX_IDE_COMMAND_PORT 0x1f0
31 #define XBOX_IDE_CONTROL_PORT 0x170
32
33 #define XBOX_SIGNATURE_SECTOR 3
34 #define XBOX_SIGNATURE ('B' | ('R' << 8) | ('F' << 16) | ('R' << 24))
35
36 static struct
37 {
38 ULONG SectorCountBeforePartition;
39 ULONG PartitionSectorCount;
40 UCHAR SystemIndicator;
41 } XboxPartitions[] =
42 {
43 /* This is in the \Device\Harddisk0\Partition.. order used by the Xbox kernel */
44 { 0x0055F400, 0x0098f800, PARTITION_FAT32 }, /* Store , E: */
45 { 0x00465400, 0x000FA000, PARTITION_FAT_16 }, /* System, C: */
46 { 0x00000400, 0x00177000, PARTITION_FAT_16 }, /* Cache1, X: */
47 { 0x00177400, 0x00177000, PARTITION_FAT_16 }, /* Cache2, Y: */
48 { 0x002EE400, 0x00177000, PARTITION_FAT_16 } /* Cache3, Z: */
49 };
50
51 #define IDE_SECTOR_BUF_SZ 512
52 #define IDE_MAX_POLL_RETRIES 100000
53 #define IDE_MAX_BUSY_RETRIES 50000
54
55 /* Control Block offsets and masks */
56 #define IDE_REG_ALT_STATUS 0x0000
57 #define IDE_REG_DEV_CNTRL 0x0000 /* device control register */
58 #define IDE_DC_SRST 0x04 /* drive reset (both drives) */
59 #define IDE_DC_nIEN 0x02 /* IRQ enable (active low) */
60 #define IDE_REG_DRV_ADDR 0x0001
61
62 /* Command Block offsets and masks */
63 #define IDE_REG_DATA_PORT 0x0000
64 #define IDE_REG_ERROR 0x0001 /* error register */
65 #define IDE_ER_AMNF 0x01 /* addr mark not found */
66 #define IDE_ER_TK0NF 0x02 /* track 0 not found */
67 #define IDE_ER_ABRT 0x04 /* command aborted */
68 #define IDE_ER_MCR 0x08 /* media change requested */
69 #define IDE_ER_IDNF 0x10 /* ID not found */
70 #define IDE_ER_MC 0x20 /* Media changed */
71 #define IDE_ER_UNC 0x40 /* Uncorrectable data error */
72 #define IDE_REG_PRECOMP 0x0001
73 #define IDE_REG_SECTOR_CNT 0x0002
74 #define IDE_REG_SECTOR_NUM 0x0003
75 #define IDE_REG_CYL_LOW 0x0004
76 #define IDE_REG_CYL_HIGH 0x0005
77 #define IDE_REG_DRV_HEAD 0x0006
78 #define IDE_DH_FIXED 0xA0
79 #define IDE_DH_LBA 0x40
80 #define IDE_DH_HDMASK 0x0F
81 #define IDE_DH_DRV0 0x00
82 #define IDE_DH_DRV1 0x10
83 #define IDE_REG_STATUS 0x0007
84 #define IDE_SR_BUSY 0x80
85 #define IDE_SR_DRDY 0x40
86 #define IDE_SR_WERR 0x20
87 #define IDE_SR_DRQ 0x08
88 #define IDE_SR_ERR 0x01
89 #define IDE_REG_COMMAND 0x0007
90
91 /* IDE/ATA commands */
92 #define IDE_CMD_RESET 0x08
93 #define IDE_CMD_READ 0x20
94 #define IDE_CMD_READ_RETRY 0x21
95 #define IDE_CMD_WRITE 0x30
96 #define IDE_CMD_WRITE_RETRY 0x31
97 #define IDE_CMD_PACKET 0xA0
98 #define IDE_CMD_READ_MULTIPLE 0xC4
99 #define IDE_CMD_WRITE_MULTIPLE 0xC5
100 #define IDE_CMD_READ_DMA 0xC8
101 #define IDE_CMD_WRITE_DMA 0xCA
102 #define IDE_CMD_FLUSH_CACHE 0xE7
103 #define IDE_CMD_FLUSH_CACHE_EXT 0xEA
104 #define IDE_CMD_IDENT_ATA_DRV 0xEC
105 #define IDE_CMD_IDENT_ATAPI_DRV 0xA1
106 #define IDE_CMD_GET_MEDIA_STATUS 0xDA
107
108 /*
109 * Access macros for command registers
110 * Each macro takes an address of the command port block, and data
111 */
112 #define IDEReadError(Address) \
113 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ERROR)))
114 #define IDEWritePrecomp(Address, Data) \
115 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_PRECOMP), (Data)))
116 #define IDEReadSectorCount(Address) \
117 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT)))
118 #define IDEWriteSectorCount(Address, Data) \
119 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_CNT), (Data)))
120 #define IDEReadSectorNum(Address) \
121 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM)))
122 #define IDEWriteSectorNum(Address, Data) \
123 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_SECTOR_NUM), (Data)))
124 #define IDEReadCylinderLow(Address) \
125 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW)))
126 #define IDEWriteCylinderLow(Address, Data) \
127 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_LOW), (Data)))
128 #define IDEReadCylinderHigh(Address) \
129 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH)))
130 #define IDEWriteCylinderHigh(Address, Data) \
131 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_CYL_HIGH), (Data)))
132 #define IDEReadDriveHead(Address) \
133 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD)))
134 #define IDEWriteDriveHead(Address, Data) \
135 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DRV_HEAD), (Data)))
136 #define IDEReadStatus(Address) \
137 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_STATUS)))
138 #define IDEWriteCommand(Address, Data) \
139 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_COMMAND), (Data)))
140 #define IDEReadDMACommand(Address) \
141 (READ_PORT_UCHAR((PUCHAR)((Address))))
142 #define IDEWriteDMACommand(Address, Data) \
143 (WRITE_PORT_UCHAR((PUCHAR)((Address)), (Data)))
144 #define IDEReadDMAStatus(Address) \
145 (READ_PORT_UCHAR((PUCHAR)((Address) + 2)))
146 #define IDEWriteDMAStatus(Address, Data) \
147 (WRITE_PORT_UCHAR((PUCHAR)((Address) + 2), (Data)))
148 #define IDEWritePRDTable(Address, Data) \
149 (WRITE_PORT_ULONG((PULONG)((Address) + 4), (Data)))
150
151 /*
152 * Data block read and write commands
153 */
154 #define IDEReadBlock(Address, Buffer, Count) \
155 (READ_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
156 #define IDEWriteBlock(Address, Buffer, Count) \
157 (WRITE_PORT_BUFFER_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT), (PUSHORT)(Buffer), (Count) / 2))
158
159 #define IDEReadBlock32(Address, Buffer, Count) \
160 (READ_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
161 #define IDEWriteBlock32(Address, Buffer, Count) \
162 (WRITE_PORT_BUFFER_ULONG((PULONG)((Address) + IDE_REG_DATA_PORT), (PULONG)(Buffer), (Count) / 4))
163
164 #define IDEReadWord(Address) \
165 (READ_PORT_USHORT((PUSHORT)((Address) + IDE_REG_DATA_PORT)))
166
167 /*
168 * Access macros for control registers
169 * Each macro takes an address of the control port blank and data
170 */
171 #define IDEReadAltStatus(Address) \
172 (READ_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_ALT_STATUS)))
173 #define IDEWriteDriveControl(Address, Data) \
174 (WRITE_PORT_UCHAR((PUCHAR)((Address) + IDE_REG_DEV_CNTRL), (Data)))
175
176 /* IDE_DRIVE_IDENTIFY */
177 typedef struct _IDE_DRIVE_IDENTIFY
178 {
179 USHORT ConfigBits; /*00*/
180 USHORT LogicalCyls; /*01*/
181 USHORT Reserved02; /*02*/
182 USHORT LogicalHeads; /*03*/
183 USHORT BytesPerTrack; /*04*/
184 USHORT BytesPerSector; /*05*/
185 USHORT SectorsPerTrack; /*06*/
186 UCHAR InterSectorGap; /*07*/
187 UCHAR InterSectorGapSize;
188 UCHAR Reserved08H; /*08*/
189 UCHAR BytesInPLO;
190 USHORT VendorUniqueCnt; /*09*/
191 UCHAR SerialNumber[20]; /*10*/
192 USHORT ControllerType; /*20*/
193 USHORT BufferSize; /*21*/
194 USHORT ECCByteCnt; /*22*/
195 UCHAR FirmwareRev[8]; /*23*/
196 UCHAR ModelNumber[40]; /*27*/
197 USHORT RWMultImplemented; /*47*/
198 USHORT DWordIo; /*48*/
199 USHORT Capabilities; /*49*/
200 #define IDE_DRID_STBY_SUPPORTED 0x2000
201 #define IDE_DRID_IORDY_SUPPORTED 0x0800
202 #define IDE_DRID_IORDY_DISABLE 0x0400
203 #define IDE_DRID_LBA_SUPPORTED 0x0200
204 #define IDE_DRID_DMA_SUPPORTED 0x0100
205 USHORT Reserved50; /*50*/
206 USHORT MinPIOTransTime; /*51*/
207 USHORT MinDMATransTime; /*52*/
208 USHORT TMFieldsValid; /*53*/
209 USHORT TMCylinders; /*54*/
210 USHORT TMHeads; /*55*/
211 USHORT TMSectorsPerTrk; /*56*/
212 USHORT TMCapacityLo; /*57*/
213 USHORT TMCapacityHi; /*58*/
214 USHORT RWMultCurrent; /*59*/
215 USHORT TMSectorCountLo; /*60*/
216 USHORT TMSectorCountHi; /*61*/
217 USHORT DmaModes; /*62*/
218 USHORT MultiDmaModes; /*63*/
219 USHORT Reserved64[5]; /*64*/
220 USHORT Reserved69[2]; /*69*/
221 USHORT Reserved71[4]; /*71*/
222 USHORT MaxQueueDepth; /*75*/
223 USHORT Reserved76[4]; /*76*/
224 USHORT MajorRevision; /*80*/
225 USHORT MinorRevision; /*81*/
226 USHORT SupportedFeatures82; /*82*/
227 USHORT SupportedFeatures83; /*83*/
228 USHORT SupportedFeatures84; /*84*/
229 USHORT EnabledFeatures85; /*85*/
230 USHORT EnabledFeatures86; /*86*/
231 USHORT EnabledFeatures87; /*87*/
232 USHORT UltraDmaModes; /*88*/
233 USHORT Reserved89[11]; /*89*/
234 USHORT Max48BitAddress[4]; /*100*/
235 USHORT Reserved104[151]; /*104*/
236 USHORT Checksum; /*255*/
237 } IDE_DRIVE_IDENTIFY, *PIDE_DRIVE_IDENTIFY;
238
239 /* XboxDiskPolledRead
240 *
241 * DESCRIPTION:
242 * Read a sector of data from the drive in a polled fashion.
243 *
244 * RUN LEVEL:
245 * PASSIVE_LEVEL
246 *
247 * ARGUMENTS:
248 * ULONG CommandPort Address of command port for drive
249 * ULONG ControlPort Address of control port for drive
250 * UCHAR PreComp Value to write to precomp register
251 * UCHAR SectorCnt Value to write to sectorCnt register
252 * UCHAR SectorNum Value to write to sectorNum register
253 * UCHAR CylinderLow Value to write to CylinderLow register
254 * UCHAR CylinderHigh Value to write to CylinderHigh register
255 * UCHAR DrvHead Value to write to Drive/Head register
256 * UCHAR Command Value to write to Command register
257 * PVOID Buffer Buffer for output data
258 *
259 * RETURNS:
260 * BOOLEAN: TRUE success, FALSE error
261 */
262 static BOOLEAN
263 XboxDiskPolledRead(ULONG CommandPort,
264 ULONG ControlPort,
265 UCHAR PreComp,
266 UCHAR SectorCnt,
267 UCHAR SectorNum,
268 UCHAR CylinderLow,
269 UCHAR CylinderHigh,
270 UCHAR DrvHead,
271 UCHAR Command,
272 PVOID Buffer)
273 {
274 ULONG SectorCount = 0;
275 ULONG RetryCount;
276 BOOLEAN Junk = FALSE;
277 UCHAR Status;
278
279 /* Wait for BUSY to clear */
280 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
281 {
282 Status = IDEReadStatus(CommandPort);
283 if (!(Status & IDE_SR_BUSY))
284 break;
285
286 StallExecutionProcessor(10);
287 }
288 TRACE("status=0x%x\n", Status);
289 TRACE("waited %d usecs for busy to clear\n", RetryCount * 10);
290 if (RetryCount >= IDE_MAX_BUSY_RETRIES)
291 {
292 WARN("Drive is BUSY for too long\n");
293 return FALSE;
294 }
295
296 /* Write Drive/Head to select drive */
297 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
298 StallExecutionProcessor(500);
299
300 /* Disable interrupts */
301 IDEWriteDriveControl(ControlPort, IDE_DC_nIEN);
302 StallExecutionProcessor(500);
303
304 /* Issue command to drive */
305 if (DrvHead & IDE_DH_LBA)
306 {
307 TRACE("READ:DRV=%d:LBA=1:BLK=%d:SC=0x%x:CM=0x%x\n",
308 DrvHead & IDE_DH_DRV1 ? 1 : 0,
309 ((DrvHead & 0x0f) << 24) + (CylinderHigh << 16) + (CylinderLow << 8) + SectorNum,
310 SectorCnt,
311 Command);
312 }
313 else
314 {
315 TRACE("READ:DRV=%d:LBA=0:CH=0x%x:CL=0x%x:HD=0x%x:SN=0x%x:SC=0x%x:CM=0x%x\n",
316 DrvHead & IDE_DH_DRV1 ? 1 : 0,
317 CylinderHigh,
318 CylinderLow,
319 DrvHead & 0x0f,
320 SectorNum,
321 SectorCnt,
322 Command);
323 }
324
325 /* Setup command parameters */
326 IDEWritePrecomp(CommandPort, PreComp);
327 IDEWriteSectorCount(CommandPort, SectorCnt);
328 IDEWriteSectorNum(CommandPort, SectorNum);
329 IDEWriteCylinderHigh(CommandPort, CylinderHigh);
330 IDEWriteCylinderLow(CommandPort, CylinderLow);
331 IDEWriteDriveHead(CommandPort, IDE_DH_FIXED | DrvHead);
332
333 /* Issue the command */
334 IDEWriteCommand(CommandPort, Command);
335 StallExecutionProcessor(50);
336
337 /* Wait for DRQ or error */
338 for (RetryCount = 0; RetryCount < IDE_MAX_POLL_RETRIES; RetryCount++)
339 {
340 Status = IDEReadStatus(CommandPort);
341 if (!(Status & IDE_SR_BUSY))
342 {
343 if (Status & IDE_SR_ERR)
344 {
345 IDEWriteDriveControl(ControlPort, 0);
346 StallExecutionProcessor(50);
347 IDEReadStatus(CommandPort);
348 return FALSE;
349 }
350
351 if (Status & IDE_SR_DRQ)
352 {
353 break;
354 }
355 else
356 {
357 IDEWriteDriveControl(ControlPort, 0);
358 StallExecutionProcessor(50);
359 IDEReadStatus(CommandPort);
360 return FALSE;
361 }
362 }
363 StallExecutionProcessor(10);
364 }
365
366 /* Timed out */
367 if (RetryCount >= IDE_MAX_POLL_RETRIES)
368 {
369 IDEWriteDriveControl(ControlPort, 0);
370 StallExecutionProcessor(50);
371 IDEReadStatus(CommandPort);
372 return FALSE;
373 }
374
375 while (1)
376 {
377 /* Read data into buffer */
378 if (Junk == FALSE)
379 {
380 IDEReadBlock(CommandPort, Buffer, IDE_SECTOR_BUF_SZ);
381 Buffer = (PVOID)((ULONG_PTR)Buffer + IDE_SECTOR_BUF_SZ);
382 }
383 else
384 {
385 UCHAR JunkBuffer[IDE_SECTOR_BUF_SZ];
386 IDEReadBlock(CommandPort, JunkBuffer, IDE_SECTOR_BUF_SZ);
387 }
388 SectorCount++;
389
390 /* Check for error or more sectors to read */
391 for (RetryCount = 0; RetryCount < IDE_MAX_BUSY_RETRIES; RetryCount++)
392 {
393 Status = IDEReadStatus(CommandPort);
394 if (!(Status & IDE_SR_BUSY))
395 {
396 if (Status & IDE_SR_ERR)
397 {
398 IDEWriteDriveControl(ControlPort, 0);
399 StallExecutionProcessor(50);
400 IDEReadStatus(CommandPort);
401 return FALSE;
402 }
403 if (Status & IDE_SR_DRQ)
404 {
405 if (SectorCount >= SectorCnt)
406 {
407 TRACE("Buffer size exceeded!\n");
408 Junk = TRUE;
409 }
410 break;
411 }
412 else
413 {
414 if (SectorCount > SectorCnt)
415 {
416 TRACE("Read %lu sectors of junk!\n",
417 SectorCount - SectorCnt);
418 }
419
420 IDEWriteDriveControl(ControlPort, 0);
421 StallExecutionProcessor(50);
422 IDEReadStatus(CommandPort);
423 return TRUE;
424 }
425 }
426 }
427 }
428 }
429
430 BOOLEAN
431 XboxDiskReadLogicalSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
432 {
433 ULONG StartSector;
434 UCHAR Count;
435
436 if (DriveNumber < 0x80 || 2 <= (DriveNumber & 0x0f))
437 {
438 /* Xbox has only 1 IDE controller and no floppy */
439 WARN("Invalid drive number\n");
440 return FALSE;
441 }
442
443 if (UINT64_C(0) != ((SectorNumber + SectorCount) & UINT64_C(0xfffffffff0000000)))
444 {
445 FIXME("48bit LBA required but not implemented\n");
446 return FALSE;
447 }
448
449 StartSector = (ULONG) SectorNumber;
450 while (0 < SectorCount)
451 {
452 Count = (SectorCount <= 255 ? (UCHAR)SectorCount : 255);
453 if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
454 XBOX_IDE_CONTROL_PORT,
455 0, Count,
456 StartSector & 0xff,
457 (StartSector >> 8) & 0xff,
458 (StartSector >> 16) & 0xff,
459 ((StartSector >> 24) & 0x0f) | IDE_DH_LBA |
460 (0 == (DriveNumber & 0x0f) ? IDE_DH_DRV0 : IDE_DH_DRV1),
461 IDE_CMD_READ,
462 Buffer))
463 {
464 return FALSE;
465 }
466 SectorCount -= Count;
467 Buffer = (PVOID) ((PCHAR) Buffer + Count * IDE_SECTOR_BUF_SZ);
468 }
469
470 return TRUE;
471 }
472
473 BOOLEAN
474 XboxDiskGetPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
475 {
476 UCHAR SectorData[IDE_SECTOR_BUF_SZ];
477
478 /*
479 * This is the Xbox, chances are that there is a Xbox-standard
480 * partitionless disk in it so let's check that first.
481 */
482 if (1 <= PartitionNumber && PartitionNumber <= sizeof(XboxPartitions) / sizeof(XboxPartitions[0]) &&
483 MachDiskReadLogicalSectors(DriveNumber, XBOX_SIGNATURE_SECTOR, 1, SectorData))
484 {
485 if (*((PULONG) SectorData) == XBOX_SIGNATURE)
486 {
487 memset(PartitionTableEntry, 0, sizeof(PARTITION_TABLE_ENTRY));
488 PartitionTableEntry->SystemIndicator = XboxPartitions[PartitionNumber - 1].SystemIndicator;
489 PartitionTableEntry->SectorCountBeforePartition = XboxPartitions[PartitionNumber - 1].SectorCountBeforePartition;
490 PartitionTableEntry->PartitionSectorCount = XboxPartitions[PartitionNumber - 1].PartitionSectorCount;
491 return TRUE;
492 }
493 }
494
495 /* No magic Xbox partitions, maybe there's a MBR */
496 return DiskGetMbrPartitionEntry(DriveNumber, PartitionNumber, PartitionTableEntry);
497 }
498
499 BOOLEAN
500 XboxDiskGetDriveGeometry(UCHAR DriveNumber, PGEOMETRY Geometry)
501 {
502 IDE_DRIVE_IDENTIFY DrvParms;
503 ULONG i;
504 BOOLEAN Atapi;
505
506 Atapi = FALSE; /* FIXME */
507 /* Get the Drive Identify block from drive or die */
508 if (!XboxDiskPolledRead(XBOX_IDE_COMMAND_PORT,
509 XBOX_IDE_CONTROL_PORT,
510 0,
511 1,
512 0,
513 0,
514 0,
515 (0 == (DriveNumber & 0x0f) ? IDE_DH_DRV0 : IDE_DH_DRV1),
516 (Atapi ? IDE_CMD_IDENT_ATAPI_DRV : IDE_CMD_IDENT_ATA_DRV),
517 (PUCHAR) &DrvParms))
518 {
519 ERR("XboxDiskPolledRead() failed\n");
520 return FALSE;
521 }
522
523 Geometry->Cylinders = DrvParms.LogicalCyls;
524 Geometry->Heads = DrvParms.LogicalHeads;
525 Geometry->Sectors = DrvParms.SectorsPerTrack;
526
527 if (! Atapi && 0 != (DrvParms.Capabilities & IDE_DRID_LBA_SUPPORTED))
528 {
529 /* LBA ATA drives always have a sector size of 512 */
530 Geometry->BytesPerSector = 512;
531 }
532 else
533 {
534 TRACE("BytesPerSector %d\n", DrvParms.BytesPerSector);
535 if (DrvParms.BytesPerSector == 0)
536 {
537 Geometry->BytesPerSector = 512;
538 }
539 else
540 {
541 for (i = 1 << 15; i; i /= 2)
542 {
543 if ((DrvParms.BytesPerSector & i) != 0)
544 {
545 Geometry->BytesPerSector = i;
546 break;
547 }
548 }
549 }
550 }
551 TRACE("Cylinders %d\n", Geometry->Cylinders);
552 TRACE("Heads %d\n", Geometry->Heads);
553 TRACE("Sectors %d\n", Geometry->Sectors);
554 TRACE("BytesPerSector %d\n", Geometry->BytesPerSector);
555
556 return TRUE;
557 }
558
559 ULONG
560 XboxDiskGetCacheableBlockCount(UCHAR DriveNumber)
561 {
562 /* 64 seems a nice number, it is used by the machpc code for LBA devices */
563 return 64;
564 }
565
566 /* EOF */