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