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