Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2057 lines
50 KiB

4 years ago
  1. #if defined(JAZZ) && !defined(DUO)
  2. /*++
  3. Copyright (c) 1989 Microsoft Corporation
  4. Module Name:
  5. jxfboot.c
  6. Abstract:
  7. This module implements the floppy disk boot driver for the Jazz system.
  8. Author:
  9. Darryl E. Havens (darrylh) 28-Aug-1989
  10. Environment:
  11. Kernel mode only, raised IRQL, generally self-contained.
  12. Revision History:
  13. --*/
  14. #include "fwp.h"
  15. #include "jazzprom.h"
  16. #include "jazzint.h"
  17. #include "ntdddisk.h"
  18. #include "flo_data.h"
  19. #include "fwstring.h"
  20. //
  21. // Define local static data.
  22. //
  23. UCHAR DebugByte[8];
  24. ULONG MotorStatus;
  25. PDRIVE_MEDIA_CONSTANTS CurrentDriveMediaConstants;
  26. //
  27. // Define timeout constants.
  28. //
  29. #define MICROSECONDS_10 10
  30. #define MICROSECONDS_250 250
  31. #define MILLISECONDS_15 (15 * 1000)
  32. #define MILLISECONDS_500 (500 * 1000)
  33. #define SECONDS_2 (2 * 1000 * 1000)
  34. #define FW_FLOPPY_TIMEOUT 2
  35. //
  36. // Define the number of times an operation is retried before it is considered
  37. // to be a hard error.
  38. //
  39. #define RETRY_COUNT 8
  40. //
  41. // Define the MINIMUM macro.
  42. //
  43. #define MINIMUM( x, y ) ( x <= y ? x : y )
  44. //
  45. // Define floppy device register structure.
  46. //
  47. typedef struct _FLOPPY_REGISTERS {
  48. UCHAR StatusRegisterA;
  49. UCHAR StatusRegisterB;
  50. UCHAR DigitalOutput;
  51. UCHAR Reserved1;
  52. union {
  53. UCHAR MainStatus;
  54. UCHAR DataRateSelect;
  55. } MsrDsr;
  56. UCHAR Fifo;
  57. UCHAR Reserved2;
  58. union {
  59. UCHAR DigitalInput;
  60. UCHAR ConfigurationControl;
  61. } DirCcr;
  62. } FLOPPY_REGISTERS, *PFLOPPY_REGISTERS;
  63. //
  64. // Define pointer to the floppy registers.
  65. //
  66. #define FLOPPY_CONTROL ((volatile PFLOPPY_REGISTERS)FLOPPY_VIRTUAL_BASE)
  67. PUCHAR Floppy0Path = "multi(0)disk(0)fdisk(0)";
  68. PUCHAR Floppy1Path = "multi(0)disk(0)fdisk(1)";
  69. ARC_STATUS
  70. FloppyClose (
  71. IN ULONG FileId
  72. );
  73. ARC_STATUS
  74. FloppyMount (
  75. IN PCHAR MountPath,
  76. IN MOUNT_OPERATION Operation
  77. );
  78. ARC_STATUS
  79. FloppyOpen (
  80. IN PCHAR OpenPath,
  81. IN OPEN_MODE OpenMode,
  82. OUT PULONG FileId
  83. );
  84. ARC_STATUS
  85. FloppyRead (
  86. IN ULONG FileId,
  87. IN PVOID Buffer,
  88. IN ULONG Length,
  89. OUT PULONG Count
  90. );
  91. ARC_STATUS
  92. FloppyGetReadStatus (
  93. IN ULONG FileId
  94. );
  95. ARC_STATUS
  96. FloppySeek (
  97. IN ULONG FileId,
  98. IN PLARGE_INTEGER Offset,
  99. IN SEEK_MODE SeekMode
  100. );
  101. ARC_STATUS
  102. FloppyWrite (
  103. IN ULONG FileId,
  104. IN PVOID Buffer,
  105. IN ULONG Length,
  106. OUT PULONG Count
  107. );
  108. ARC_STATUS
  109. FloppyGetFileInformation (
  110. IN ULONG FileId,
  111. OUT PFILE_INFORMATION Finfo
  112. );
  113. ARC_STATUS
  114. FloppyBootIO(
  115. IN PMDL MdlAddress,
  116. IN ULONG StartingBlock,
  117. IN ULONG FileId,
  118. IN BOOLEAN ReadWrite
  119. );
  120. VOID
  121. ClearFloppyFifo (
  122. IN VOID
  123. );
  124. ULONG
  125. ReadFloppyFifo (
  126. IN PUCHAR Buffer
  127. );
  128. VOID
  129. WriteFloppyFifo(
  130. IN PUCHAR Buffer,
  131. IN ULONG Size
  132. );
  133. //
  134. // Declare and Initialize the floppy disk device entry table.
  135. //
  136. BL_DEVICE_ENTRY_TABLE FloppyEntryTable = {
  137. FloppyClose,
  138. FloppyMount,
  139. FloppyOpen,
  140. FloppyRead,
  141. FloppyGetReadStatus,
  142. FloppySeek,
  143. FloppyWrite,
  144. FloppyGetFileInformation,
  145. (PARC_SET_FILE_INFO_ROUTINE)NULL
  146. };
  147. //
  148. // Define prototypes for all routines used by this module.
  149. //
  150. ARC_STATUS
  151. FloppyBootClose(
  152. );
  153. BOOLEAN
  154. Recalibrate (
  155. UCHAR DriveNumber
  156. );
  157. VOID
  158. FloppyBootSetup(
  159. VOID
  160. );
  161. UCHAR
  162. ReceiveByte (
  163. );
  164. BOOLEAN
  165. SendByte(
  166. IN UCHAR SourceByte
  167. );
  168. ARC_STATUS
  169. FloppyDetermineMediaType(
  170. IN OUT PFLOPPY_CONTEXT FloppyContext
  171. );
  172. ARC_STATUS
  173. FloppyDatarateSpecifyConfigure(
  174. IN DRIVE_MEDIA_TYPE DriveMediaType,
  175. IN UCHAR DriveNumber
  176. );
  177. ARC_STATUS
  178. FloppyClose (
  179. IN ULONG FileId
  180. )
  181. /*++
  182. Routine Description:
  183. This function closes the file table entry specified by the file id.
  184. Arguments:
  185. FileId - Supplies the file table index.
  186. Return Value:
  187. ESUCCESS is returned
  188. --*/
  189. {
  190. FloppyBootClose();
  191. BlFileTable[FileId].Flags.Open = 0;
  192. return ESUCCESS;
  193. }
  194. ARC_STATUS
  195. FloppyMount (
  196. IN PCHAR MountPath,
  197. IN MOUNT_OPERATION Operation
  198. )
  199. /*++
  200. Routine Description:
  201. Arguments:
  202. Return Value:
  203. --*/
  204. {
  205. return ESUCCESS;
  206. }
  207. ARC_STATUS
  208. FloppyOpen (
  209. IN PCHAR OpenPath,
  210. IN OPEN_MODE OpenMode,
  211. IN OUT PULONG FileId
  212. )
  213. /*++
  214. Routine Description:
  215. Arguments:
  216. Return Value:
  217. --*/
  218. {
  219. PCONFIGURATION_COMPONENT FloppyComponent, FloppyController;
  220. UCHAR Data[sizeof(CM_PARTIAL_RESOURCE_LIST) +
  221. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 8 +
  222. sizeof(CM_FLOPPY_DEVICE_DATA)];
  223. PCM_PARTIAL_RESOURCE_LIST List = (PCM_PARTIAL_RESOURCE_LIST)Data;
  224. PCM_FLOPPY_DEVICE_DATA FloppyData;
  225. ULONG DriveNumber;
  226. ULONG Index;
  227. ARC_STATUS ArcStatus;
  228. CHAR TempBuffer[SECTOR_SIZE + 32];
  229. PCHAR TempPointer;
  230. ULONG Count;
  231. UCHAR mediaDescriptor;
  232. MEDIA_TYPE mediaType;
  233. DRIVE_MEDIA_TYPE driveMediaType;
  234. ULONG DriveType;
  235. ULONG ConfigDriveType;
  236. //
  237. // Get the drive number from the pathname.
  238. //
  239. if (FwGetPathMnemonicKey(OpenPath, "fdisk", &DriveNumber)) {
  240. return ENODEV;
  241. }
  242. //
  243. // Default to 1.44MB floppy
  244. //
  245. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
  246. //
  247. // Look in the configuration database for the floppy device data to
  248. // determine the size of the floppy drive.
  249. //
  250. FloppyComponent = FwGetComponent(OpenPath);
  251. if ((FloppyComponent != NULL) &&
  252. (FloppyComponent->Type == FloppyDiskPeripheral)) {
  253. if (FwGetConfigurationData(List, FloppyComponent) == ESUCCESS) {
  254. FloppyData = (PCM_FLOPPY_DEVICE_DATA)&List->PartialDescriptors[List->Count];
  255. if (strcmp(FloppyData->Size,"5.25")==0) {
  256. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200;
  257. } else {
  258. if (strcmp(FloppyData->Size,"3.5")==0) {
  259. if (FloppyData->MaxDensity == 2880) {
  260. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_2880;
  261. } else {
  262. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
  263. }
  264. }
  265. }
  266. }
  267. }
  268. ConfigDriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
  269. BlFileTable[*FileId].u.FloppyContext.DiskId = DriveNumber;
  270. BlFileTable[*FileId].Position.LowPart=0;
  271. BlFileTable[*FileId].Position.HighPart=0;
  272. //
  273. // Enable the drive and start the motor via the DOR.
  274. //
  275. if (MotorStatus != DriveNumber) {
  276. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput,
  277. ((0xc + DriveNumber) + (1 << (DriveNumber + 4))));
  278. MotorStatus = DriveNumber;
  279. //
  280. // Wait for at least 500ms to ensure that the motor really is running.
  281. //
  282. FwStallExecution(MILLISECONDS_500);
  283. }
  284. //
  285. // Determine the disk density.
  286. //
  287. ClearFloppyFifo();
  288. ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext);
  289. if (ArcStatus == EIO) {
  290. FloppyClose(*FileId);
  291. //
  292. // Reset the floppy, it seems to get in a bad state.
  293. //
  294. FloppyBootSetup();
  295. return(ArcStatus);
  296. } else if (ArcStatus != ESUCCESS) {
  297. //
  298. // The floppy was not readable, so try the other floppy type.
  299. //
  300. DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
  301. if ((DriveType == DRIVE_TYPE_1440) || (DriveType == DRIVE_TYPE_2880)) {
  302. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200;
  303. } else {
  304. BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
  305. }
  306. ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext);
  307. if (ArcStatus == EIO) {
  308. FloppyClose(*FileId);
  309. return(ArcStatus);
  310. } else if (ArcStatus != ESUCCESS) {
  311. BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType;
  312. // FwPrint("Unrecognized floppy format\r\n");
  313. FloppyClose(*FileId);
  314. return(ArcStatus);
  315. }
  316. }
  317. //
  318. // Read the first sector to get the media descriptor byte.
  319. //
  320. TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
  321. & ~(KeGetDcacheFillSize() - 1));
  322. ArcStatus = FloppyRead(*FileId, TempPointer, SECTOR_SIZE, &Count);
  323. if (ArcStatus != ESUCCESS) {
  324. // FwPrint("Error opening floppy\r\n");
  325. FloppyClose(*FileId);
  326. return(ArcStatus);
  327. }
  328. //
  329. // Check the media descriptor byte to verify that we have the right
  330. // drive and media type.
  331. //
  332. DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
  333. mediaDescriptor = *( TempPointer + MEDIA_DESCRIPTOR_OFFSET );
  334. mediaType = 0;
  335. switch ( mediaDescriptor ) {
  336. case MEDIA_DESCRIPTOR_160K:
  337. mediaType = F5_160_512;
  338. DriveType = DRIVE_TYPE_1200;
  339. break;
  340. case MEDIA_DESCRIPTOR_180K:
  341. mediaType = F5_180_512;
  342. DriveType = DRIVE_TYPE_1200;
  343. break;
  344. case MEDIA_DESCRIPTOR_320K:
  345. mediaType = F5_320_512;
  346. DriveType = DRIVE_TYPE_1200;
  347. break;
  348. case MEDIA_DESCRIPTOR_360K:
  349. mediaType = F5_360_512;
  350. DriveType = DRIVE_TYPE_1200;
  351. break;
  352. case MEDIA_DESCRIPTOR_720K_OR_1220K:
  353. //
  354. // The following code tries to take care of the case when the floppy
  355. // is really a 5 1/4" drive but the firmware thinks its 3 1/2". A
  356. // 1.2 MByte floppy can be read with the 1.44 MByte parameters, but
  357. // the descriptor byte will be MEDIA_DESCRIPTOR_720K_OR_1220K. Check
  358. // if the parameters are really for 720 K, otherwise default to
  359. // 1.2 MByte.
  360. //
  361. if ((DriveType == DRIVE_TYPE_1440) &&
  362. (BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack == 9)) {
  363. mediaType = F3_720_512;
  364. } else {
  365. mediaType = F5_1Pt2_512;
  366. DriveType = DRIVE_TYPE_1200;
  367. }
  368. break;
  369. case MEDIA_DESCRIPTOR_1440K_OR_2880K:
  370. mediaType = F3_1Pt44_512;
  371. DriveType = DRIVE_TYPE_1440;
  372. break;
  373. default:
  374. break;
  375. }
  376. if ( mediaType != 0 ) {
  377. //
  378. // Find the constants for this media type.
  379. //
  380. driveMediaType = DriveMediaLimits[DriveType].HighestDriveMediaType;
  381. while ( ( DriveMediaConstants[driveMediaType].MediaType != mediaType ) &&
  382. ( driveMediaType > DriveMediaLimits[DriveType].LowestDriveMediaType ) ) {
  383. driveMediaType--;
  384. }
  385. //
  386. // Set the sectors per track and the drive type in the floppy
  387. // context record.
  388. //
  389. BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack =
  390. DriveMediaConstants[driveMediaType].SectorsPerTrack;
  391. BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType;
  392. }
  393. //
  394. // If the floppy drive type has changed, update the configuration database
  395. // with the correct drive type. NOTE Doesn't do 2.88 MByte floppies.
  396. //
  397. if (DriveType != ConfigDriveType) {
  398. if (DriveType == DRIVE_TYPE_1200) {
  399. strcpy(FloppyData->Size,"5.25");
  400. FloppyData->MaxDensity = 1200;
  401. } else {
  402. strcpy(FloppyData->Size,"3.5");
  403. FloppyData->MaxDensity = 1440;
  404. }
  405. //
  406. // Get a pointer to the floppy controller component.
  407. //
  408. if ((FloppyController = FwGetParent(FloppyComponent)) != NULL) {
  409. //
  410. // Delete the old entry, note that this does not actually delete the
  411. // data in the database, it only changes the pointers, so that the
  412. // AddChild call can still use the old component data structure.
  413. //
  414. if (FwDeleteComponent(FloppyComponent) == ESUCCESS) {
  415. //
  416. // Add back the modified floppy structure.
  417. //
  418. FwAddChild(FloppyController, FloppyComponent, List);
  419. }
  420. }
  421. }
  422. return ESUCCESS;
  423. }
  424. ARC_STATUS
  425. FloppyRead (
  426. IN ULONG FileId,
  427. IN PVOID Buffer,
  428. IN ULONG Length,
  429. OUT PULONG Count
  430. )
  431. /*++
  432. Routine Description:
  433. This function reads data from the floppy starting at the position
  434. specified in the file table.
  435. Arguments:
  436. FileId - Supplies the file table index.
  437. Buffer - Supplies a poiner to the buffer that receives the data
  438. read.
  439. Length - Supplies the number of bytes to be read.
  440. Count - Supplies a pointer to a variable that receives the number of
  441. bytes actually read.
  442. Return Value:
  443. The read completion status is returned.
  444. --*/
  445. {
  446. ARC_STATUS ArcStatus;
  447. ULONG FrameNumber;
  448. ULONG Index;
  449. ULONG Limit;
  450. PMDL MdlAddress;
  451. UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
  452. ULONG NumberOfPages;
  453. ULONG Offset;
  454. PULONG PageFrame;
  455. ULONG Position;
  456. CHAR TempBuffer[SECTOR_SIZE + 32];
  457. PCHAR TempPointer;
  458. //
  459. // If the requested size of the transfer is zero return ESUCCESS
  460. //
  461. if (Length==0) {
  462. return ESUCCESS;
  463. }
  464. //
  465. // If the current position is not at a sector boundary , then
  466. // read the first and/or last sector separately and copy the data.
  467. //
  468. Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1);
  469. if (Offset != 0) {
  470. //
  471. // Adjust position to the sector boundary, align the transfer address
  472. // and read that first sector.
  473. //
  474. BlFileTable[FileId].Position.LowPart -= Offset;
  475. TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
  476. & ~(KeGetDcacheFillSize() - 1));
  477. ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
  478. //
  479. // If the transfer was not successful, then reset the position
  480. // and return the completion status.
  481. //
  482. if (ArcStatus != ESUCCESS) {
  483. BlFileTable[FileId].Position.LowPart += Offset;
  484. return ArcStatus;
  485. }
  486. //
  487. // If the length of read is less than the number of bytes from
  488. // the offset to the end of the sector, then copy only the number
  489. // of bytes required to fulfil the request. Otherwise copy to the end
  490. // of the sector and, read the remaining data.
  491. //
  492. if ((SECTOR_SIZE - Offset) > Length) {
  493. Limit = Offset + Length;
  494. } else {
  495. Limit = SECTOR_SIZE;
  496. }
  497. //
  498. // Copy the data to the specified buffer.
  499. //
  500. for (Index = Offset; Index < Limit; Index += 1) {
  501. *((PCHAR)Buffer)++ = *(TempPointer + Index);
  502. }
  503. //
  504. // Adjust the current position and
  505. // Read the remaining part of the specified transfer.
  506. //
  507. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit;
  508. Position = BlFileTable[FileId].Position.LowPart;
  509. ArcStatus = FloppyRead(FileId,
  510. Buffer,
  511. Length - (Limit - Offset),
  512. Count);
  513. //
  514. // If the transfer was not successful, then reset the device
  515. // position and return the completion status.
  516. //
  517. if (ArcStatus != ESUCCESS) {
  518. BlFileTable[FileId].Position.LowPart = Position;
  519. return ArcStatus;
  520. } else {
  521. *Count = Length;
  522. return ESUCCESS;
  523. }
  524. } else {
  525. //
  526. // if the size of requested data is not a multiple of the sector
  527. // size then read the last sector separately.
  528. //
  529. if (Length & (SECTOR_SIZE - 1)) {
  530. Position = BlFileTable[FileId].Position.LowPart;
  531. ArcStatus = FloppyRead(FileId,
  532. Buffer,
  533. Length & (~(SECTOR_SIZE - 1)),
  534. Count);
  535. //
  536. // If the transfer was not successful, then reset the device
  537. // position and return the completion status.
  538. //
  539. if (ArcStatus != ESUCCESS) {
  540. BlFileTable[FileId].Position.LowPart = Position;
  541. return ArcStatus;
  542. }
  543. //
  544. // Read the last sector and copy the requested data.
  545. //
  546. TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
  547. & ~(KeGetDcacheFillSize() - 1));
  548. ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
  549. //
  550. // If the transfer was not successful return the completion status.
  551. //
  552. if (ArcStatus != ESUCCESS) {
  553. return ArcStatus;
  554. }
  555. //
  556. // Copy the data to the specified buffer.
  557. //
  558. (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1));
  559. Limit = Length & (SECTOR_SIZE - 1);
  560. for (Index = 0; Index < Limit; Index += 1) {
  561. *((PCHAR)Buffer)++ = *(TempPointer + Index);
  562. }
  563. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit;
  564. *Count = Length;
  565. return ESUCCESS;
  566. } else {
  567. //
  568. // Build the memory descriptor list.
  569. //
  570. MdlAddress = (PMDL)&MdlBuffer[0];
  571. MdlAddress->Next = NULL;
  572. MdlAddress->Size = sizeof(MDL) +
  573. ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
  574. MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
  575. MdlAddress->ByteCount = Length;
  576. MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
  577. PageFrame = (PULONG)(MdlAddress + 1);
  578. FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
  579. NumberOfPages = (MdlAddress->ByteCount +
  580. MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
  581. for (Index = 0; Index < NumberOfPages; Index += 1) {
  582. *PageFrame++ = FrameNumber++;
  583. }
  584. //
  585. // Flush I/O buffers and read from the boot device.
  586. //
  587. HalFlushIoBuffers(MdlAddress, TRUE, TRUE);
  588. ArcStatus = FloppyBootIO(MdlAddress,
  589. BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT,
  590. FileId,
  591. FALSE);
  592. if (ArcStatus == ESUCCESS) {
  593. BlFileTable[FileId].Position.LowPart += Length;
  594. *Count = Length;
  595. return ESUCCESS;
  596. } else {
  597. *Count = 0;
  598. return EIO;
  599. }
  600. }
  601. }
  602. }
  603. ARC_STATUS
  604. FloppyWrite (
  605. IN ULONG FileId,
  606. IN PVOID Buffer,
  607. IN ULONG Length,
  608. OUT PULONG Count
  609. )
  610. /*++
  611. Routine Description:
  612. This function writes data to the floppy starting at the position
  613. specified in the file table.
  614. Arguments:
  615. FileId - Supplies the file table index.
  616. Buffer - Supplies a poiner to the buffer that contains the data
  617. to be written.
  618. Length - Supplies the number of bytes to be writtes.
  619. Count - Supplies a pointer to a variable that receives the number of
  620. bytes actually written.
  621. Return Value:
  622. The write completion status is returned.
  623. --*/
  624. {
  625. ARC_STATUS ArcStatus;
  626. ULONG FrameNumber;
  627. ULONG Index;
  628. ULONG Limit;
  629. PMDL MdlAddress;
  630. UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
  631. ULONG NumberOfPages;
  632. ULONG Offset;
  633. PULONG PageFrame;
  634. ULONG Position;
  635. CHAR TempBuffer[SECTOR_SIZE + 32];
  636. PCHAR TempPointer;
  637. //
  638. // If the requested size of the transfer is zero return ESUCCESS
  639. //
  640. if (Length==0) {
  641. return ESUCCESS;
  642. }
  643. //
  644. // If the current position is not at a sector boundary , then
  645. // read the first and/or last sector separately and copy the data.
  646. //
  647. Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1);
  648. if (Offset != 0) {
  649. //
  650. // Adjust position to the sector boundary, align the transfer address
  651. // and read that first sector.
  652. //
  653. BlFileTable[FileId].Position.LowPart -= Offset;
  654. TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
  655. & ~(KeGetDcacheFillSize() - 1));
  656. ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
  657. //
  658. // If the transfer was not successful, then reset the position
  659. // and return the completion status.
  660. //
  661. if (ArcStatus != ESUCCESS) {
  662. BlFileTable[FileId].Position.LowPart += Offset;
  663. return ArcStatus;
  664. } else {
  665. //
  666. // Reset the position as it was before the read.
  667. //
  668. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE;
  669. }
  670. //
  671. // If the length of write is less than the number of bytes from
  672. // the offset to the end of the sector, then copy only the number
  673. // of bytes required to fulfil the request. Otherwise copy to the end
  674. // of the sector and, read the remaining data.
  675. //
  676. if ((SECTOR_SIZE - Offset) > Length) {
  677. Limit = Offset + Length;
  678. } else {
  679. Limit = SECTOR_SIZE;
  680. }
  681. //
  682. // Merge the data from the specified buffer.
  683. //
  684. for (Index = Offset; Index < Limit; Index += 1) {
  685. *(TempPointer + Index) = *((PCHAR)Buffer)++;
  686. }
  687. //
  688. // Write the modified sector.
  689. //
  690. ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count);
  691. if (ArcStatus != ESUCCESS) {
  692. return ArcStatus;
  693. }
  694. //
  695. // Adjust the current position and
  696. // Write the remaining part of the specified transfer.
  697. //
  698. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit;
  699. Position = BlFileTable[FileId].Position.LowPart;
  700. ArcStatus = FloppyWrite(FileId,
  701. Buffer,
  702. Length - (Limit - Offset),
  703. Count);
  704. //
  705. // If the transfer was not successful, then reset the device
  706. // position and return the completion status.
  707. //
  708. if (ArcStatus != ESUCCESS) {
  709. BlFileTable[FileId].Position.LowPart = Position;
  710. return ArcStatus;
  711. } else {
  712. *Count = Length;
  713. return ESUCCESS;
  714. }
  715. } else {
  716. //
  717. // if the size of requested data is not a multiple of the sector
  718. // size then write the last sector separately.
  719. //
  720. if (Length & (SECTOR_SIZE - 1)) {
  721. //
  722. // Do the transfer of the complete sectors in the middle
  723. //
  724. Position = BlFileTable[FileId].Position.LowPart;
  725. ArcStatus = FloppyWrite(FileId,
  726. Buffer,
  727. Length & (~(SECTOR_SIZE - 1)),
  728. Count);
  729. //
  730. // If the transfer was not successful, then reset the device
  731. // position and return the completion status.
  732. //
  733. if (ArcStatus != ESUCCESS) {
  734. BlFileTable[FileId].Position.LowPart = Position;
  735. return ArcStatus;
  736. }
  737. //
  738. // Read the last sector and copy the requested data.
  739. //
  740. TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
  741. & ~(KeGetDcacheFillSize() - 1));
  742. ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
  743. //
  744. // If the transfer was not successful return the completion status.
  745. //
  746. if (ArcStatus != ESUCCESS) {
  747. return ArcStatus;
  748. }
  749. //
  750. // Copy the data to the specified buffer.
  751. //
  752. (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1));
  753. Limit = Length & (SECTOR_SIZE - 1);
  754. for (Index = 0; Index < Limit; Index += 1) {
  755. *(TempPointer + Index) = *((PCHAR)Buffer)++;
  756. }
  757. //
  758. // Adjust the position and write the data.
  759. //
  760. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE;
  761. ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count);
  762. //
  763. // Set the position for the requested transfer
  764. //
  765. BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit;
  766. *Count = Length;
  767. return ArcStatus;
  768. } else {
  769. //
  770. // Build the memory descriptor list.
  771. //
  772. MdlAddress = (PMDL)&MdlBuffer[0];
  773. MdlAddress->Next = NULL;
  774. MdlAddress->Size = sizeof(MDL) +
  775. ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
  776. MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
  777. MdlAddress->ByteCount = Length;
  778. MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
  779. PageFrame = (PULONG)(MdlAddress + 1);
  780. FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
  781. NumberOfPages = (MdlAddress->ByteCount +
  782. MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
  783. for (Index = 0; Index < NumberOfPages; Index += 1) {
  784. *PageFrame++ = FrameNumber++;
  785. }
  786. //
  787. // Flush I/O buffers and write to the boot device.
  788. //
  789. HalFlushIoBuffers(MdlAddress, FALSE, TRUE);
  790. ArcStatus = FloppyBootIO(MdlAddress,
  791. BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT,
  792. FileId,
  793. TRUE);
  794. if (ArcStatus == ESUCCESS) {
  795. BlFileTable[FileId].Position.LowPart += Length;
  796. *Count = Length;
  797. return ESUCCESS;
  798. } else {
  799. *Count = 0;
  800. return EIO;
  801. }
  802. }
  803. }
  804. }
  805. ARC_STATUS
  806. FloppyGetReadStatus (
  807. IN ULONG FileId
  808. )
  809. /*++
  810. Routine Description:
  811. Arguments:
  812. Return Value:
  813. --*/
  814. {
  815. return ESUCCESS;
  816. }
  817. ARC_STATUS
  818. FloppySeek (
  819. IN ULONG FileId,
  820. IN PLARGE_INTEGER Offset,
  821. IN SEEK_MODE SeekMode
  822. )
  823. /*++
  824. Routine Description:
  825. This function sets the device position to the specified offset for
  826. the specified file id.
  827. Arguments:
  828. FileId - Supplies the file table index.
  829. Offset - Supplies to new device position.
  830. SeekMode - Supplies the mode for the position.
  831. Return Value:
  832. ESUCCESS is returned.
  833. --*/
  834. {
  835. //
  836. // Set the current device position as specifed by the seek mode.
  837. //
  838. if (SeekMode == SeekAbsolute) {
  839. BlFileTable[FileId].Position.LowPart = Offset->LowPart;
  840. } else if (SeekMode == SeekRelative) {
  841. BlFileTable[FileId].Position.LowPart += Offset->LowPart;
  842. }
  843. return ESUCCESS;
  844. }
  845. ARC_STATUS
  846. FloppyGetFileInformation (
  847. IN ULONG FileId,
  848. OUT PFILE_INFORMATION Finfo
  849. )
  850. /*++
  851. Routine Description:
  852. This routine returns the floppy size.
  853. Arguments:
  854. FileId - Supplies the file table index.
  855. Finfo - Supplies a pointer to where the File Information is stored.
  856. Return Value:
  857. ESUCCESS is returned.
  858. --*/
  859. {
  860. RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
  861. switch (BlFileTable[FileId].u.FloppyContext.DriveType) {
  862. case DRIVE_TYPE_1200: Finfo->EndingAddress.LowPart = 1200 * 1024;
  863. break;
  864. case DRIVE_TYPE_1440: Finfo->EndingAddress.LowPart = 1440 * 1024;
  865. break;
  866. case DRIVE_TYPE_2880: Finfo->EndingAddress.LowPart = 2880 * 1024;
  867. break;
  868. default : return EINVAL;
  869. }
  870. Finfo->CurrentPosition = BlFileTable[FileId].Position;
  871. Finfo->Type = FloppyDiskPeripheral;
  872. return ESUCCESS;
  873. }
  874. VOID
  875. FloppyBootSetup(
  876. VOID
  877. )
  878. /*++
  879. Routine Description:
  880. This routine is invoked to initialize the floppy boot device before any
  881. other floppy operations are attempted. This routine performs the following
  882. operations to initialize the device:
  883. o Clear the reset and DMA gate flags in the DOR
  884. o Reset the floppy by writing the s/w reset in the DSR
  885. o Set the program data rate in the CCR
  886. o Issue a sense interrupt command and read the four statuses back
  887. o Issue a configure command
  888. o Issue a specify command
  889. Arguments:
  890. None.
  891. Return Value:
  892. None.
  893. --*/
  894. {
  895. ULONG i,j;
  896. //
  897. // Begin by clearing the reset and DMA gate flags in the DOR.
  898. //
  899. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput, 0x0c);
  900. //
  901. // Reset the floppy controller by setting the s/w reset bit in the DSR.
  902. //
  903. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.DataRateSelect, 0x80);
  904. //
  905. // Set the data rate in the CCR.
  906. //
  907. // WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DirCcr.ConfigurationControl, 0);
  908. if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
  909. FW_FLOPPY_TIMEOUT)) {
  910. // FwPrint("Floppy setup timeout\r\n");
  911. return;
  912. }
  913. //
  914. // Issue the sense interrupt command and read back the status and
  915. // relative cylinder number from the controller. This is done for
  916. // each of the four possible devices. Note that the output is always
  917. // ignored.
  918. //
  919. for (i = j = 0; i <= 3; i++) {
  920. SendByte(COMMND_SENSE_INTERRUPT);
  921. DebugByte[j++] = ReceiveByte();
  922. DebugByte[j++] = ReceiveByte();
  923. }
  924. //
  925. // Issue the configuration command.
  926. //
  927. SendByte( COMMND_CONFIGURE ); // command
  928. SendByte( 0x00 ); // required 0
  929. SendByte( 0x58 ); // implied seeks, disable polling & threshold = 8
  930. SendByte( 0x00 ); // precompensation track = 0
  931. //
  932. // Issue the specify command.
  933. //
  934. SendByte( COMMND_SPECIFY ); // command
  935. SendByte( 0xdf ); // step rate time=d, head unload=f
  936. SendByte( 0x03 ); // head load=1, DMA disabled
  937. return;
  938. }
  939. VOID
  940. FloppyInitialize(
  941. IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
  942. IN ULONG Entries
  943. )
  944. /*++
  945. Routine Description:
  946. This routine initializes the FloppyDriver.
  947. Arguments:
  948. LookupTable - Pointer to the driver lookup table where the pathnames
  949. recognized by this driver will be stored.
  950. Entries - Number of entries in the table.
  951. Return Value:
  952. None.
  953. --*/
  954. {
  955. PCONFIGURATION_COMPONENT FloppyComponent;
  956. CHAR FloppyPath[32];
  957. ULONG Drive;
  958. //
  959. // Set motor status to all motors stopped.
  960. //
  961. MotorStatus = MAXLONG;
  962. FloppyBootSetup();
  963. //
  964. // Default to floppy 0 in case no configuration is present in the NVRAM
  965. //
  966. LookupTable->DevicePath = Floppy0Path;
  967. LookupTable->DispatchTable = &FloppyEntryTable;
  968. //
  969. // Get the floppy configuration information.
  970. //
  971. FloppyComponent = FwGetComponent(Floppy0Path);
  972. if ((FloppyComponent != NULL) &&
  973. (FloppyComponent->Type == FloppyDiskPeripheral)) {
  974. //
  975. // Initialize the lookup table.
  976. //
  977. LookupTable->DevicePath = Floppy0Path;
  978. LookupTable->DispatchTable = &FloppyEntryTable;
  979. LookupTable++;
  980. //
  981. // Return if no more room in the lookup table.
  982. //
  983. if (Entries == 1) {
  984. return;
  985. }
  986. }
  987. FloppyComponent = FwGetComponent(Floppy1Path);
  988. if ((FloppyComponent != NULL) &&
  989. (FloppyComponent->Type == FloppyDiskPeripheral)) {
  990. //
  991. // Initialize the lookup table.
  992. //
  993. LookupTable->DevicePath = Floppy1Path;
  994. LookupTable->DispatchTable = &FloppyEntryTable;
  995. }
  996. }
  997. ARC_STATUS
  998. FloppyBootClose(
  999. )
  1000. /*++
  1001. Routine Description:
  1002. This routine shuts down the floppy after the boot has taken place.
  1003. Arguments:
  1004. None.
  1005. Return Value:
  1006. Normal, successful completion status.
  1007. --*/
  1008. {
  1009. //
  1010. // Turn the floppy drive's motor off and indicate that the
  1011. // motor has been shut off.
  1012. //
  1013. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput, 0xc);
  1014. MotorStatus = MAXLONG;
  1015. return ESUCCESS;
  1016. }
  1017. ARC_STATUS
  1018. FloppyBootIO (
  1019. IN PMDL Mdl,
  1020. IN ULONG StartingBlock,
  1021. IN ULONG FileId,
  1022. IN BOOLEAN ReadWrite
  1023. )
  1024. /*++
  1025. Routine Description:
  1026. This routine reads or writes blocks from the floppy into the buffer described by
  1027. the MDL. The size of the read is the number of bytes mapped by the MDL
  1028. and the blocks read start at StartingBlock.
  1029. Arguments:
  1030. Mdl - Memory Descriptor List for buffer.
  1031. StartingBlock - Block to begin the read operation.
  1032. FileId - The file identifier of the floppy drive to access.
  1033. ReadWrite - Specifies the kind of transfer to be done
  1034. TRUE = WRITE
  1035. FALSE = READ
  1036. Return Value:
  1037. The function value is the status of the operation.
  1038. --*/
  1039. {
  1040. UCHAR Cylinder;
  1041. UCHAR Head = 0;
  1042. UCHAR Sector;
  1043. UCHAR EndSector;
  1044. ULONG BlockCount;
  1045. ULONG TransferSize;
  1046. ULONG TransferedBytes;
  1047. ULONG i,j,k;
  1048. PUCHAR Buffer;
  1049. BOOLEAN Success;
  1050. ARC_STATUS Status = ESUCCESS;
  1051. UCHAR DriveNumber;
  1052. ULONG SectorsPerTrack;
  1053. DriveNumber = BlFileTable[FileId].u.FloppyContext.DiskId;
  1054. SectorsPerTrack = BlFileTable[FileId].u.FloppyContext.SectorsPerTrack;
  1055. //
  1056. // Enable the drive and start the motor via the DOR.
  1057. //
  1058. if (MotorStatus != DriveNumber) {
  1059. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput,
  1060. ((0xc + DriveNumber) + (1 << (DriveNumber + 4))));
  1061. MotorStatus = DriveNumber;
  1062. //
  1063. // Wait for at least 500ms to ensure that the motor really is running.
  1064. //
  1065. FwStallExecution(MILLISECONDS_500);
  1066. }
  1067. //
  1068. // Get the number of blocks that need to be read in order to fulfill
  1069. // this request. Also set the base address of the caller's buffer.
  1070. //
  1071. Buffer = ((PUCHAR) Mdl->StartVa) + Mdl->ByteOffset;
  1072. //
  1073. // Get the parameters for the read command.
  1074. //
  1075. Cylinder = StartingBlock / (SectorsPerTrack * 2);
  1076. Sector = (StartingBlock % SectorsPerTrack) + 1;
  1077. Head = (StartingBlock / SectorsPerTrack) % 2;
  1078. ClearFloppyFifo();
  1079. //
  1080. // Loop reading blocks from the device until the request has been
  1081. // satisfied.
  1082. //
  1083. for (BlockCount = Mdl->ByteCount >> 9; BlockCount > 0; ) {
  1084. //
  1085. // Determine the size of this read based on the number of blocks
  1086. // required and where the current sector is on the current track.
  1087. //
  1088. EndSector = MINIMUM( SectorsPerTrack, (Sector + (BlockCount - 1)) );
  1089. TransferSize = (EndSector - Sector) + 1;
  1090. BlockCount -= TransferSize;
  1091. TransferSize <<= 9;
  1092. //
  1093. // Attempt to read the block(s) up to RETRY_COUNT times.
  1094. //
  1095. for (k = 0; k < RETRY_COUNT; k++) {
  1096. //
  1097. // Assume that the operation will be successful.
  1098. //
  1099. Success = TRUE;
  1100. //
  1101. // Do an explicit seek if this is a 360 K disk in a 1.2 MB drive.
  1102. //
  1103. if (CurrentDriveMediaConstants->CylinderShift != 0) {
  1104. if (!SendByte( COMMND_SEEK ) ||
  1105. !SendByte( (Head << 2) + DriveNumber ) || // head select & drive
  1106. !SendByte( Cylinder << CurrentDriveMediaConstants->CylinderShift )) {
  1107. return(EIO);
  1108. }
  1109. if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
  1110. FW_FLOPPY_TIMEOUT)) {
  1111. return(EIO);
  1112. }
  1113. //
  1114. // Send the sense interrupt command.
  1115. //
  1116. if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command
  1117. return(EIO);
  1118. }
  1119. //
  1120. // Read back the information from the drive and check the status of the
  1121. // recalibrate command.
  1122. //
  1123. DebugByte[0] = ReceiveByte();
  1124. DebugByte[1] = ReceiveByte();
  1125. if (DebugByte[1] != (Cylinder << CurrentDriveMediaConstants->CylinderShift)) {
  1126. return(EIO);
  1127. }
  1128. //
  1129. // Now try to read the ID from wherever we're at.
  1130. //
  1131. if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command
  1132. !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) {
  1133. return(EIO);
  1134. }
  1135. if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
  1136. FW_FLOPPY_TIMEOUT)) {
  1137. return(EIO);
  1138. }
  1139. for (i = 0; i < 7; i++) {
  1140. DebugByte[i] = ReceiveByte();
  1141. }
  1142. if ( ( DebugByte[0] !=
  1143. (UCHAR)(DriveNumber |
  1144. ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) ||
  1145. ( DebugByte[1] != 0 ) ||
  1146. ( DebugByte[2] != 0 ) ) {
  1147. return(EIO);
  1148. }
  1149. }
  1150. //
  1151. // Send the command and parameters for the operation.
  1152. //
  1153. if (ReadWrite == TRUE) {
  1154. if (!SendByte( COMMND_WRITE_DATA + COMMND_MFM )) {
  1155. return(EIO);
  1156. }
  1157. } else {
  1158. if (!SendByte( COMMND_READ_DATA + COMMND_MFM )) {
  1159. return(EIO);
  1160. }
  1161. }
  1162. if (!SendByte( (Head << 2) + DriveNumber ) || // head select & drive
  1163. !SendByte( Cylinder ) || // cylinder
  1164. !SendByte( Head ) || // head
  1165. !SendByte( Sector ) || // sector
  1166. !SendByte( 2 ) || // sector size; 2 => 512B/sec
  1167. !SendByte( EndSector ) || // end of track sector
  1168. !SendByte( CurrentDriveMediaConstants->ReadWriteGapLength ) ||
  1169. !SendByte( 0xff )) { // special sector size
  1170. return(EIO);
  1171. }
  1172. //
  1173. // Ensure that the floppy drive does not time-out.
  1174. //
  1175. for (j = 0; j < SECONDS_2; j += MICROSECONDS_10) {
  1176. if (READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) > 127) {
  1177. break;
  1178. }
  1179. FwStallExecution(MICROSECONDS_10);
  1180. }
  1181. //
  1182. // Check for time-out; if one occurred, then return unsuccessful
  1183. // status.
  1184. //
  1185. if (j == SECONDS_2) {
  1186. // FwPrint("Floppy timeout\r\n");
  1187. return EIO;
  1188. }
  1189. //
  1190. // Read the data from the appropriate block(s) and check the number
  1191. // of bytes actually read.
  1192. //
  1193. if (ReadWrite == TRUE) {
  1194. WriteFloppyFifo(Buffer,TransferSize);
  1195. } else {
  1196. TransferedBytes = ReadFloppyFifo(Buffer);
  1197. if (TransferedBytes != TransferSize) {
  1198. Success = FALSE;
  1199. }
  1200. }
  1201. //
  1202. // Read the status information from the device.
  1203. //
  1204. while (READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) <= 127) {
  1205. }
  1206. for (i = 0; i < 7; i++) {
  1207. DebugByte[i] = ReceiveByte();
  1208. }
  1209. if (((DebugByte[0] >> 4) == 2) &&
  1210. (DebugByte[1] == 0) &&
  1211. (DebugByte[2] == 0) &&
  1212. Success) {
  1213. ;
  1214. } else {
  1215. if ((DebugByte[0] >> 4) != 4) {
  1216. Success = FALSE;
  1217. }
  1218. if (DebugByte[1] != 0x80) {
  1219. Success = FALSE;
  1220. }
  1221. if (DebugByte[2] != 0) {
  1222. Success = FALSE;
  1223. }
  1224. }
  1225. //
  1226. // If the operation was successful, exit the loop.
  1227. //
  1228. if (Success) {
  1229. Buffer += TransferSize;
  1230. break;
  1231. }
  1232. //
  1233. // The operation did not work. Attempt to recalibrate the
  1234. // device and wait for everything to settle out, and then
  1235. // try the operation again.
  1236. //
  1237. if (!Recalibrate(DriveNumber)) {
  1238. // FwPrint("Floppy recalibration error\r\n");
  1239. return(EIO);
  1240. }
  1241. FwStallExecution(MILLISECONDS_15);
  1242. }
  1243. //
  1244. // If the operation was not successful after RETRY_COUNT tries, get
  1245. // out now.
  1246. //
  1247. if (!Success) {
  1248. Status = EIO;
  1249. break;
  1250. }
  1251. //
  1252. // If more data is needed, get the next place to read from. Note
  1253. // that if there is more data to be read, then the last sector
  1254. // just read was the last sector on this head.
  1255. //
  1256. if (BlockCount > 0) {
  1257. if (Head == 1) {
  1258. Cylinder += 1;
  1259. Head = 0;
  1260. } else {
  1261. Head = 1;
  1262. }
  1263. Sector = 1;
  1264. }
  1265. if (Success) {
  1266. Status = ESUCCESS;
  1267. }
  1268. }
  1269. return Status;
  1270. }
  1271. BOOLEAN
  1272. Recalibrate(
  1273. UCHAR DriveNumber
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This routine issues a recalibrate command to the device, waits for it to
  1278. interrupt, sends it a sense interrupt command, and checks the result to
  1279. ensure that the recalibrate command worked properly.
  1280. Arguments:
  1281. DriveNumber - Supplies the Floppy drive to recalibrate.
  1282. Return Value:
  1283. Returns TRUE if the recalibrate was successful, FALSE if not.
  1284. --*/
  1285. {
  1286. //
  1287. // Send the recalibrate command to the device.
  1288. //
  1289. if (!SendByte( COMMND_RECALIBRATE ) || // command
  1290. !SendByte( DriveNumber )) { // drive select
  1291. return(FALSE);
  1292. }
  1293. if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
  1294. FW_FLOPPY_TIMEOUT)) {
  1295. // FwPrint("Floppy recalibrate timeout\r\n");
  1296. return(FALSE);
  1297. }
  1298. //
  1299. // Send the sense interrupt command.
  1300. //
  1301. if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command
  1302. return(FALSE);
  1303. }
  1304. //
  1305. // Read back the information from the drive and check the status of the
  1306. // recalibrate command.
  1307. //
  1308. DebugByte[0] = ReceiveByte();
  1309. if ((DebugByte[0] >> 4) != 2) {
  1310. return FALSE;
  1311. }
  1312. DebugByte[1] = ReceiveByte();
  1313. if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
  1314. STATUS_IO_READY_MASK) == STATUS_READ_READY) {
  1315. return FALSE;
  1316. }
  1317. return TRUE;
  1318. }
  1319. UCHAR
  1320. ReceiveByte(
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. This routine reads the next byte from the floppy FIFO register.
  1325. Arguments:
  1326. None.
  1327. Return Value:
  1328. The function value is the value of the byte read from the floppy FIFO.
  1329. --*/
  1330. {
  1331. ULONG i;
  1332. //
  1333. // Check status register for readiness to receive data.
  1334. //
  1335. for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) {
  1336. if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
  1337. STATUS_IO_READY_MASK) == STATUS_READ_READY) {
  1338. return READ_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo);
  1339. }
  1340. FwStallExecution(MICROSECONDS_10);
  1341. }
  1342. //
  1343. // A timeout occurred while attempting to read data from the floppy fifo.
  1344. // Output an error message and return.
  1345. //
  1346. // FwPrint("Error reading from floppy fifo\r\n");
  1347. return(0xFF);
  1348. }
  1349. BOOLEAN
  1350. SendByte(
  1351. IN UCHAR SourceByte
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This routine sends a specified byte to the floppy FIFO register.
  1356. Arguments:
  1357. SourceByte - Byte to be sent to the controller.
  1358. Return Value:
  1359. If the byte was successfully written to the floppy FIFO, TRUE is returned,
  1360. otherwise FALSE is returned.
  1361. --*/
  1362. {
  1363. ULONG i;
  1364. //
  1365. // Check status register for readiness to receive data.
  1366. //
  1367. for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) {
  1368. if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
  1369. STATUS_IO_READY_MASK) == STATUS_WRITE_READY) {
  1370. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo, SourceByte);
  1371. return(TRUE);
  1372. }
  1373. FwStallExecution(MICROSECONDS_10);
  1374. }
  1375. //
  1376. // A timeout occurred while attempting to write data to the floppy fifo.
  1377. // Output an error message and return.
  1378. //
  1379. // FwPrint("Error writing to floppy fifo\r\n");
  1380. return(FALSE);
  1381. }
  1382. VOID
  1383. ClearFloppyFifo(
  1384. IN VOID
  1385. )
  1386. /*++
  1387. Routine Description:
  1388. This routine empties the fifo.
  1389. Arguments:
  1390. None.
  1391. Return Value:
  1392. None.
  1393. --*/
  1394. {
  1395. ULONG i;
  1396. //
  1397. // Check status register for readiness to receive data.
  1398. //
  1399. while ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
  1400. STATUS_IO_READY_MASK) == STATUS_READ_READY) {
  1401. READ_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo);
  1402. FwStallExecution(MICROSECONDS_10);
  1403. }
  1404. }
  1405. ARC_STATUS
  1406. FloppyDatarateSpecifyConfigure(
  1407. IN DRIVE_MEDIA_TYPE DriveMediaType,
  1408. IN UCHAR DriveNumber
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. This routine is called to set up the controller every time a new type
  1413. of diskette is to be accessed. It issues the CONFIGURE command,
  1414. does a SPECIFY, sets the data rate, and RECALIBRATEs the drive.
  1415. Arguments:
  1416. DriveMediaType - supplies the drive type/media density combination.
  1417. DriveNumber - supplies the drive number.
  1418. Return Value:
  1419. ESUCCESS if the controller is properly prepared; appropriate
  1420. error propogated otherwise.
  1421. --*/
  1422. {
  1423. UCHAR Configure;
  1424. //
  1425. // Don't enable implied seeks when there is a 360K disk in a 1.2M drive.
  1426. //
  1427. if (DriveMediaConstants[DriveMediaType].CylinderShift) {
  1428. Configure = 0x18;
  1429. } else {
  1430. Configure = 0x58;
  1431. }
  1432. //
  1433. // Issue the configuration command.
  1434. //
  1435. if (!SendByte( COMMND_CONFIGURE ) || // command
  1436. !SendByte( 0x00 ) || // required 0
  1437. !SendByte( Configure ) || // implied seeks, disable polling & threshold = 8
  1438. !SendByte( 0x00 ) || // precompensation track = 0
  1439. //
  1440. // Issue SPECIFY command to program the head load and unload
  1441. // rates, the drive step rate, and the DMA data transfer mode.
  1442. //
  1443. !SendByte( COMMND_SPECIFY ) || // command
  1444. !SendByte( DriveMediaConstants[DriveMediaType].StepRateHeadUnloadTime) ||
  1445. !SendByte( DriveMediaConstants[DriveMediaType].HeadLoadTime + 1)) {
  1446. return(EIO);
  1447. }
  1448. //
  1449. // Program the data rate
  1450. //
  1451. WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.DataRateSelect,
  1452. DriveMediaConstants[DriveMediaType].DataTransferRate );
  1453. //
  1454. // Recalibrate the drive, now that we've changed all its
  1455. // parameters.
  1456. //
  1457. if (Recalibrate(DriveNumber)) {
  1458. return(ESUCCESS);
  1459. } else {
  1460. // FwPrint("Floppy recalibration error\r\n");
  1461. return(EIO);
  1462. }
  1463. }
  1464. ARC_STATUS
  1465. FloppyDetermineMediaType(
  1466. IN OUT PFLOPPY_CONTEXT FloppyContext
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. This routine is called by FloppyBootIO() when the media type is
  1471. unknown. It assumes the largest media supported by the drive is
  1472. available, and keeps trying lower values until it finds one that
  1473. works.
  1474. Arguments:
  1475. FloppyContext - supplies a pointer to the floppy context structure.
  1476. Return Value:
  1477. ESUCCESS if the type of the media is determined; appropriate
  1478. error propogated otherwise.
  1479. --*/
  1480. {
  1481. ARC_STATUS Status;
  1482. BOOLEAN mediaTypesExhausted = FALSE;
  1483. DRIVE_MEDIA_TYPE DriveMediaType;
  1484. UCHAR DriveNumber;
  1485. ULONG i;
  1486. //
  1487. // Assume that the largest supported media is in the drive. If that
  1488. // turns out to be untrue, we'll try successively smaller media types
  1489. // until we find what's really in there (or we run out and decide
  1490. // that the media isn't formatted).
  1491. //
  1492. DriveMediaType =
  1493. DriveMediaLimits[FloppyContext->DriveType].HighestDriveMediaType;
  1494. DriveNumber = FloppyContext->DiskId;
  1495. do {
  1496. Status = FloppyDatarateSpecifyConfigure( DriveMediaType, DriveNumber );
  1497. if ( Status != ESUCCESS ) {
  1498. //
  1499. // The SPECIFY or CONFIGURE commands resulted in an error.
  1500. // Force ourselves out of this loop and return error.
  1501. //
  1502. mediaTypesExhausted = TRUE;
  1503. } else {
  1504. CurrentDriveMediaConstants = &DriveMediaConstants[DriveMediaType];
  1505. //
  1506. // Now try to read the ID from wherever we're at.
  1507. //
  1508. if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command
  1509. !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) {
  1510. return(EIO);
  1511. }
  1512. if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
  1513. FW_FLOPPY_TIMEOUT)) {
  1514. // FwPrint("Floppy determine media timeout\r\n");
  1515. return(EIO);
  1516. }
  1517. for (i = 0; i < 7; i++) {
  1518. DebugByte[i] = ReceiveByte();
  1519. }
  1520. if ( ( DebugByte[0] !=
  1521. (UCHAR)(DriveNumber |
  1522. ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) ||
  1523. ( DebugByte[1] != 0 ) ||
  1524. ( DebugByte[2] != 0 ) ) {
  1525. DriveMediaType--;
  1526. Status = ENXIO;
  1527. //
  1528. // Next comparison must be signed, for when
  1529. // LowestDriveMediaType = 0.
  1530. //
  1531. if ( (CHAR)( DriveMediaType ) <
  1532. (CHAR)( DriveMediaLimits[FloppyContext->DriveType].LowestDriveMediaType )) {
  1533. mediaTypesExhausted = TRUE;
  1534. }
  1535. }
  1536. }
  1537. } while ( ( ( Status != ESUCCESS ) ) && !( mediaTypesExhausted ) );
  1538. if ( Status == ESUCCESS ) {
  1539. FloppyContext->SectorsPerTrack =
  1540. CurrentDriveMediaConstants->SectorsPerTrack;
  1541. }
  1542. return Status;
  1543. }
  1544. #endif