diff options
Diffstat (limited to 'private/ntos/fw/alpha/jxfboot.c')
-rw-r--r-- | private/ntos/fw/alpha/jxfboot.c | 2273 |
1 files changed, 2273 insertions, 0 deletions
diff --git a/private/ntos/fw/alpha/jxfboot.c b/private/ntos/fw/alpha/jxfboot.c new file mode 100644 index 000000000..039b56ee7 --- /dev/null +++ b/private/ntos/fw/alpha/jxfboot.c @@ -0,0 +1,2273 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation +Copyright (c) 1993 Digital Equipment Corporation + +Module Name: + + jxfboot.c + +Abstract: + + This module implements the floppy disk boot driver for the Jazz system. + +Author: + + Darryl E. Havens (darrylh) 28-Aug-1989 + +Environment: + + Kernel mode only, raised IRQL, generally self-contained. + + +Revision History: + + 31-August-1992 John DeRosa [DEC] + + Made Alpha/Jensen modifications. This file is now Alpha-specific. + +--*/ + +#include "fwp.h" +#include "jnsnprom.h" +#include "ntdddisk.h" +#include "flo_data.h" +#include "xxstring.h" + +// +// Define local static data. +// + +UCHAR DebugByte[8]; +ULONG MotorStatus; +PDRIVE_MEDIA_CONSTANTS CurrentDriveMediaConstants; + +// +// Define timeout constants. +// + +#define MICROSECONDS_10 10 +#define MICROSECONDS_20 20 +#define MICROSECONDS_250 250 +#define MICROSECONDS_500 500 +#define MILLISECONDS_15 (15 * 1000) +#define MILLISECONDS_30 (30 * 1000) +#define MILLISECONDS_500 (500 * 1000) +#define SECONDS_2 (2 * 1000 * 1000) +#define FW_FLOPPY_TIMEOUT 2 + +// +// Define the number of times an operation is retried before it is considered +// to be a hard error. +// + +#define RETRY_COUNT 8 + +// +// Define the MINIMUM macro. +// + +#define MINIMUM( x, y ) ( x <= y ? x : y ) + +// +// Define floppy device register structure. +// + +typedef struct _FLOPPY_REGISTERS { + UCHAR StatusRegisterA; + UCHAR StatusRegisterB; + UCHAR DigitalOutput; + UCHAR Reserved1; + union { + UCHAR MainStatus; + UCHAR DataRateSelect; + } MsrDsr; + UCHAR Fifo; + UCHAR Reserved2; + union { + UCHAR DigitalInput; + UCHAR ConfigurationControl; + } DirCcr; +} FLOPPY_REGISTERS, *PFLOPPY_REGISTERS; + +// +// Define pointer to the floppy registers. +// + +#define FLOPPY_CONTROL ((volatile PFLOPPY_REGISTERS)FLOPPY_VIRTUAL_BASE) + + + +// +// Define bits in some of the floppy registers. The existing Microsoft +// code uses constants (e.g. 0xC0) for register masking. These defines +// will be used in Digital Equipment Corporation code. +// + +#define FLOPPY_SRA_INTPENDING 0x80 +#define FLOPPY_MSR_DRV0BUSY 0x1 +#define FLOPPY_MSR_DRV1BUSY 0x2 +#define FLOPPY_MSR_CMDBUSY 0x10 +#define FLOPPY_MSR_NONDMA 0x20 +#define FLOPPY_MSR_DIO 0x40 +#define FLOPPY_MSR_RQM 0x80 + +ARC_STATUS +FloppyClose ( + IN ULONG FileId + ); + +ARC_STATUS +FloppyMount ( + IN PCHAR MountPath, + IN MOUNT_OPERATION Operation + ); + +ARC_STATUS +FloppyOpen ( + IN PCHAR OpenPath, + IN OPEN_MODE OpenMode, + OUT PULONG FileId + ); + +ARC_STATUS +FloppyRead ( + IN ULONG FileId, + IN PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ); + +ARC_STATUS +FloppyGetReadStatus ( + IN ULONG FileId + ); + +ARC_STATUS +FloppySeek ( + IN ULONG FileId, + IN PLARGE_INTEGER Offset, + IN SEEK_MODE SeekMode + ); + +ARC_STATUS +FloppyWrite ( + IN ULONG FileId, + IN PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ); + +ARC_STATUS +FloppyGetFileInformation ( + IN ULONG FileId, + OUT PFILE_INFORMATION Finfo + ); + +ARC_STATUS +FloppyBootIO( + IN PMDL MdlAddress, + IN ULONG StartingBlock, + IN ULONG FileId, + IN BOOLEAN ReadWrite + ); + +VOID +ClearFloppyFifo ( + IN VOID + ); + +ULONG +ReadFloppyFifo ( + IN PUCHAR Buffer + ); + +VOID +WriteFloppyFifo( + IN PUCHAR Buffer, + IN ULONG Size + ); + +// +// Declare and Initialize the floppy disk device entry table. +// + +BL_DEVICE_ENTRY_TABLE FloppyEntryTable = { + FloppyClose, + FloppyMount, + FloppyOpen, + FloppyRead, + FloppyGetReadStatus, + FloppySeek, + FloppyWrite, + FloppyGetFileInformation, + (PARC_SET_FILE_INFO_ROUTINE)NULL + }; + +// +// Define prototypes for all routines used by this module. +// + + +ARC_STATUS +WaitForFloppyInterrupt( + ULONG Timeout + ); + +ARC_STATUS +FloppyBootClose( + ); + +BOOLEAN +Recalibrate ( + UCHAR DriveNumber + ); + +VOID +FloppyBootSetup( + VOID + ); + +UCHAR +ReceiveByte ( + ); + +BOOLEAN +SendByte( + IN UCHAR SourceByte + ); + +ARC_STATUS +FloppyDetermineMediaType( + IN OUT PFLOPPY_CONTEXT FloppyContext, + OUT PMEDIA_TYPE mediaType + ); + +ARC_STATUS +FloppyDatarateSpecifyConfigure( + IN DRIVE_MEDIA_TYPE DriveMediaType, + IN UCHAR DriveNumber + ); + + +ARC_STATUS +FloppyClose ( + IN ULONG FileId + ) + +/*++ + +Routine Description: + + This function closes the file table entry specified by the file id. + +Arguments: + + FileId - Supplies the file table index. + +Return Value: + + ESUCCESS is returned + +--*/ + +{ + FloppyBootClose(); + BlFileTable[FileId].Flags.Open = 0; + return ESUCCESS; +} + +ARC_STATUS +FloppyMount ( + IN PCHAR MountPath, + IN MOUNT_OPERATION Operation + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + return ESUCCESS; +} + +ARC_STATUS +FloppyOpen ( + IN PCHAR OpenPath, + IN OPEN_MODE OpenMode, + IN OUT PULONG FileId + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + PCONFIGURATION_COMPONENT FloppyComponent, FloppyController; + UCHAR Data[sizeof(CM_PARTIAL_RESOURCE_LIST) + + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 8 + + sizeof(CM_FLOPPY_DEVICE_DATA)]; + PCM_PARTIAL_RESOURCE_LIST List = (PCM_PARTIAL_RESOURCE_LIST)Data; + PCM_FLOPPY_DEVICE_DATA FloppyData; + ULONG DriveNumber; + ULONG Index; + ARC_STATUS ArcStatus; + CHAR TempBuffer[SECTOR_SIZE + 32]; + PCHAR TempPointer; + ULONG Count; + UCHAR mediaDescriptor; + MEDIA_TYPE mediaType = Unknown; + DRIVE_MEDIA_TYPE driveMediaType; + ULONG DriveType; + ULONG ConfigDriveType; + + // + // Get the drive number from the pathname. + // + + if (JzGetPathMnemonicKey(OpenPath, "fdisk", &DriveNumber)) { + return ENODEV; + } + + // + // If the ARC CDS data is invalid, default to 2.88MB floppy + // + + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_2880; + + // + // Look in the configuration database for the floppy device data to + // determine the size of the floppy drive. + // + + FloppyComponent = FwGetComponent(OpenPath); + if ((FloppyComponent != NULL) && + (FloppyComponent->Type == FloppyDiskPeripheral)) { + if (FwGetConfigurationData(List, FloppyComponent) == ESUCCESS) { + FloppyData = (PCM_FLOPPY_DEVICE_DATA)&List->PartialDescriptors[List->Count]; + if (strcmp(FloppyData->Size,"5.25")==0) { + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200; + } else { + if (strcmp(FloppyData->Size,"3.5")==0) { + if (FloppyData->MaxDensity == 2880) { + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_2880; + } else { + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440; + } + } + } + } + } + + ConfigDriveType = BlFileTable[*FileId].u.FloppyContext.DriveType; + BlFileTable[*FileId].u.FloppyContext.DiskId = DriveNumber; + BlFileTable[*FileId].Position.LowPart=0; + BlFileTable[*FileId].Position.HighPart=0; + + // + // Enable the drive and start the motor via the DOR. + // + + if (MotorStatus != DriveNumber) { + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->DigitalOutput, + ((0xc + DriveNumber) + (1 << (DriveNumber + 4)))); + MotorStatus = DriveNumber; + + // + // Wait for at least 500ms to ensure that the motor really is running. + // + + FwStallExecution(MILLISECONDS_500); + } + + // + // Determine the disk density. + // + + ClearFloppyFifo(); + ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext, + &mediaType); + if (ArcStatus == EIO) { + + FloppyClose(*FileId); + + // + // Reset the floppy, it seems to get in a bad state. + // + + FloppyBootSetup(); + return(ArcStatus); + + } else if (ArcStatus != ESUCCESS) { + + // + // The floppy was not readable, so try next lowest floppy type. + // + + DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType; + + if (DriveType == DRIVE_TYPE_2880) { + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440; + } else if (DriveType == DRIVE_TYPE_1440) { + BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200; + } + + ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext, + &mediaType); + + if (ArcStatus != ESUCCESS) { +// FwPrint("Unrecognized floppy format\r\n"); + FloppyClose(*FileId); + return(ArcStatus); + } + } + + // + // Read the first sector to get the media descriptor byte. + // + + TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) + & ~(KeGetDcacheFillSize() - 1)); + ArcStatus = FloppyRead(*FileId, TempPointer, SECTOR_SIZE, &Count); + + if (ArcStatus != ESUCCESS) { +// FwPrint("Error opening floppy\r\n"); + FloppyClose(*FileId); + return(ArcStatus); + } + + // + // Check the media descriptor byte to verify that we have the right + // drive and media type. + // + + DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType; + mediaDescriptor = *( TempPointer + MEDIA_DESCRIPTOR_OFFSET ); + + switch ( mediaDescriptor ) { + + case MEDIA_DESCRIPTOR_160K: + mediaType = F5_160_512; + DriveType = DRIVE_TYPE_1200; + break; + + case MEDIA_DESCRIPTOR_180K: + mediaType = F5_180_512; + DriveType = DRIVE_TYPE_1200; + break; + + case MEDIA_DESCRIPTOR_320K: + mediaType = F5_320_512; + DriveType = DRIVE_TYPE_1200; + break; + + case MEDIA_DESCRIPTOR_360K: + mediaType = F5_360_512; + DriveType = DRIVE_TYPE_1200; + break; + + case MEDIA_DESCRIPTOR_720K_OR_1220K: + + // + // The following code tries to take care of the case when the floppy + // is really a 5 1/4" drive but the firmware thinks its 3 1/2". A + // 1.2 MByte floppy can be read with the 1.44 MByte parameters, but + // the descriptor byte will be MEDIA_DESCRIPTOR_720K_OR_1220K. Check + // if the parameters are really for 720 K, otherwise default to + // 1.2 MByte. + // + + if ((DriveType == DRIVE_TYPE_1440) && + (BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack == 9)) { + mediaType = F3_720_512; + } else { + mediaType = F5_1Pt2_512; + DriveType = DRIVE_TYPE_1200; + } + break; + + + case MEDIA_DESCRIPTOR_1440K_OR_2880K: + default: + + // + // FloppyDetermineMediaType did the right thing for this case, + // so no additional verification is needed. + // + + break; + } + + + if ( mediaType != 0 ) { + + // + // Find the constants for this media type. + // + + driveMediaType = DriveMediaLimits[DriveType].HighestDriveMediaType; + while ( ( DriveMediaConstants[driveMediaType].MediaType != mediaType ) && + ( driveMediaType > DriveMediaLimits[DriveType].LowestDriveMediaType ) ) { + + driveMediaType--; + } + + // + // Set the sectors per track and the drive type in the floppy + // context record. + // + + BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack = + DriveMediaConstants[driveMediaType].SectorsPerTrack; + BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType; + } + + // + // If the floppy drive type has changed, update the configuration database + // with the correct drive type. + // + + if (DriveType != ConfigDriveType) { + + switch (DriveType) { + + case DRIVE_TYPE_1200: + + strcpy(FloppyData->Size,"5.25"); + FloppyData->MaxDensity = 1200; + break; + + case DRIVE_TYPE_1440: + + strcpy(FloppyData->Size,"3.5"); + FloppyData->MaxDensity = 1440; + break; + + default: + + strcpy(FloppyData->Size,"3.5"); + FloppyData->MaxDensity = 2880; + break; + } + + // + // Get a pointer to the floppy controller component. + // + + if ((FloppyController = FwGetParent(FloppyComponent)) != NULL) { + + // + // Delete the old entry, note that this does not actually delete the + // data in the database, it only changes the pointers, so that the + // AddChild call can still use the old component data structure. + // + + if (FwDeleteComponent(FloppyComponent) == ESUCCESS) { + + // + // Add back the modified floppy structure. + // + + FwAddChild(FloppyController, FloppyComponent, List); + } + } + } + + return ESUCCESS; +} + +ARC_STATUS +FloppyRead ( + IN ULONG FileId, + IN PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ) + +/*++ + +Routine Description: + + This function reads data from the floppy starting at the position + specified in the file table. + + +Arguments: + + FileId - Supplies the file table index. + + Buffer - Supplies a poiner to the buffer that receives the data + read. + + Length - Supplies the number of bytes to be read. + + Count - Supplies a pointer to a variable that receives the number of + bytes actually read. + +Return Value: + + + The read completion status is returned. + +--*/ + +{ + + ARC_STATUS ArcStatus; + ULONG FrameNumber; + ULONG Index; + ULONG Limit; + PMDL MdlAddress; + UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)]; + ULONG NumberOfPages; + ULONG Offset; + PULONG PageFrame; + ULONG Position; + CHAR TempBuffer[SECTOR_SIZE + 32]; + PCHAR TempPointer; + + // + // If the requested size of the transfer is zero return ESUCCESS + // + if (Length==0) { + return ESUCCESS; + } + // + // If the current position is not at a sector boundary , then + // read the first and/or last sector separately and copy the data. + // + + Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1); + if (Offset != 0) { + // + // Adjust position to the sector boundary, align the transfer address + // and read that first sector. + // + BlFileTable[FileId].Position.LowPart -= Offset; + TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) + & ~(KeGetDcacheFillSize() - 1)); + + ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); + + // + // If the transfer was not successful, then reset the position + // and return the completion status. + // + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart += Offset; + return ArcStatus; + } + + // + // If the length of read is less than the number of bytes from + // the offset to the end of the sector, then copy only the number + // of bytes required to fulfil the request. Otherwise copy to the end + // of the sector and, read the remaining data. + // + + if ((SECTOR_SIZE - Offset) > Length) { + Limit = Offset + Length; + } else { + Limit = SECTOR_SIZE; + } + + // + // Copy the data to the specified buffer. + // + for (Index = Offset; Index < Limit; Index += 1) { + *((PCHAR)Buffer)++ = *(TempPointer + Index); + } + + // + // Adjust the current position and + // Read the remaining part of the specified transfer. + // + + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit; + Position = BlFileTable[FileId].Position.LowPart; + ArcStatus = FloppyRead(FileId, + Buffer, + Length - (Limit - Offset), + Count); + + // + // If the transfer was not successful, then reset the device + // position and return the completion status. + // + + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart = Position; + return ArcStatus; + } else { + *Count = Length; + return ESUCCESS; + } + } else { + // + // if the size of requested data is not a multiple of the sector + // size then read the last sector separately. + // + if (Length & (SECTOR_SIZE - 1)) { + Position = BlFileTable[FileId].Position.LowPart; + ArcStatus = FloppyRead(FileId, + Buffer, + Length & (~(SECTOR_SIZE - 1)), + Count); + + // + // If the transfer was not successful, then reset the device + // position and return the completion status. + // + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart = Position; + return ArcStatus; + } + + // + // Read the last sector and copy the requested data. + // + TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) + & ~(KeGetDcacheFillSize() - 1)); + + ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); + + // + // If the transfer was not successful return the completion status. + // + if (ArcStatus != ESUCCESS) { + return ArcStatus; + } + + // + // Copy the data to the specified buffer. + // + (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1)); + Limit = Length & (SECTOR_SIZE - 1); + for (Index = 0; Index < Limit; Index += 1) { + *((PCHAR)Buffer)++ = *(TempPointer + Index); + } + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit; + *Count = Length; + return ESUCCESS; + + + + } else { + + // + // Build the memory descriptor list. + // + + MdlAddress = (PMDL)&MdlBuffer[0]; + MdlAddress->Next = NULL; + MdlAddress->Size = sizeof(MDL) + + ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG); + MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer); + MdlAddress->ByteCount = Length; + MdlAddress->ByteOffset = BYTE_OFFSET(Buffer); + PageFrame = (PULONG)(MdlAddress + 1); + FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT; + NumberOfPages = (MdlAddress->ByteCount + + MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT; + for (Index = 0; Index < NumberOfPages; Index += 1) { + *PageFrame++ = FrameNumber++; + } + + // + // Flush I/O buffers and read from the boot device. + // + + HalFlushIoBuffers(MdlAddress, TRUE, TRUE); + ArcStatus = FloppyBootIO(MdlAddress, + BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT, + FileId, + FALSE); + + if (ArcStatus == ESUCCESS) { + BlFileTable[FileId].Position.LowPart += Length; + *Count = Length; + return ESUCCESS; + } else { + *Count = 0; + return EIO; + } + } + } +} + +ARC_STATUS +FloppyWrite ( + IN ULONG FileId, + IN PVOID Buffer, + IN ULONG Length, + OUT PULONG Count + ) + +/*++ + +Routine Description: + + This function writes data to the floppy starting at the position + specified in the file table. + + +Arguments: + + FileId - Supplies the file table index. + + Buffer - Supplies a poiner to the buffer that contains the data + to be written. + + Length - Supplies the number of bytes to be writtes. + + Count - Supplies a pointer to a variable that receives the number of + bytes actually written. + +Return Value: + + + The write completion status is returned. + +--*/ + +{ + + ARC_STATUS ArcStatus; + ULONG FrameNumber; + ULONG Index; + ULONG Limit; + PMDL MdlAddress; + UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)]; + ULONG NumberOfPages; + ULONG Offset; + PULONG PageFrame; + ULONG Position; + CHAR TempBuffer[SECTOR_SIZE + 32]; + PCHAR TempPointer; + + // + // If the requested size of the transfer is zero return ESUCCESS + // + if (Length==0) { + return ESUCCESS; + } + // + // If the current position is not at a sector boundary , then + // read the first and/or last sector separately and copy the data. + // + + Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1); + if (Offset != 0) { + // + // Adjust position to the sector boundary, align the transfer address + // and read that first sector. + // + BlFileTable[FileId].Position.LowPart -= Offset; + TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) + & ~(KeGetDcacheFillSize() - 1)); + + ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); + + // + // If the transfer was not successful, then reset the position + // and return the completion status. + // + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart += Offset; + return ArcStatus; + } else { + // + // Reset the position as it was before the read. + // + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE; + } + + // + // If the length of write is less than the number of bytes from + // the offset to the end of the sector, then copy only the number + // of bytes required to fulfil the request. Otherwise copy to the end + // of the sector and, read the remaining data. + // + + if ((SECTOR_SIZE - Offset) > Length) { + Limit = Offset + Length; + } else { + Limit = SECTOR_SIZE; + } + + // + // Merge the data from the specified buffer. + // + for (Index = Offset; Index < Limit; Index += 1) { + *(TempPointer + Index) = *((PCHAR)Buffer)++; + } + + // + // Write the modified sector. + // + ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count); + + if (ArcStatus != ESUCCESS) { + return ArcStatus; + } + + // + // Adjust the current position and + // Write the remaining part of the specified transfer. + // + + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit; + Position = BlFileTable[FileId].Position.LowPart; + ArcStatus = FloppyWrite(FileId, + Buffer, + Length - (Limit - Offset), + Count); + + // + // If the transfer was not successful, then reset the device + // position and return the completion status. + // + + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart = Position; + return ArcStatus; + } else { + *Count = Length; + return ESUCCESS; + } + } else { + // + // if the size of requested data is not a multiple of the sector + // size then write the last sector separately. + // + if (Length & (SECTOR_SIZE - 1)) { + + // + // Do the transfer of the complete sectors in the middle + // + Position = BlFileTable[FileId].Position.LowPart; + ArcStatus = FloppyWrite(FileId, + Buffer, + Length & (~(SECTOR_SIZE - 1)), + Count); + + // + // If the transfer was not successful, then reset the device + // position and return the completion status. + // + if (ArcStatus != ESUCCESS) { + BlFileTable[FileId].Position.LowPart = Position; + return ArcStatus; + } + + // + // Read the last sector and copy the requested data. + // + TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1) + & ~(KeGetDcacheFillSize() - 1)); + + ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count); + + // + // If the transfer was not successful return the completion status. + // + if (ArcStatus != ESUCCESS) { + return ArcStatus; + } + + // + // Copy the data to the specified buffer. + // + (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1)); + Limit = Length & (SECTOR_SIZE - 1); + for (Index = 0; Index < Limit; Index += 1) { + *(TempPointer + Index) = *((PCHAR)Buffer)++; + } + // + // Adjust the position and write the data. + // + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE; + ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count); + + // + // Set the position for the requested transfer + // + BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit; + + *Count = Length; + return ArcStatus; + + } else { + + // + // Build the memory descriptor list. + // + + MdlAddress = (PMDL)&MdlBuffer[0]; + MdlAddress->Next = NULL; + MdlAddress->Size = sizeof(MDL) + + ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG); + MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer); + MdlAddress->ByteCount = Length; + MdlAddress->ByteOffset = BYTE_OFFSET(Buffer); + PageFrame = (PULONG)(MdlAddress + 1); + FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT; + NumberOfPages = (MdlAddress->ByteCount + + MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT; + for (Index = 0; Index < NumberOfPages; Index += 1) { + *PageFrame++ = FrameNumber++; + } + + // + // Flush I/O buffers and write to the boot device. + // + + HalFlushIoBuffers(MdlAddress, FALSE, TRUE); + ArcStatus = FloppyBootIO(MdlAddress, + BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT, + FileId, + TRUE); + + if (ArcStatus == ESUCCESS) { + BlFileTable[FileId].Position.LowPart += Length; + *Count = Length; + return ESUCCESS; + } else { + *Count = 0; + return EIO; + } + } + } +} + +ARC_STATUS +FloppyGetReadStatus ( + IN ULONG FileId + ) + +/*++ + +Routine Description: + + +Arguments: + + +Return Value: + + +--*/ + +{ + return ESUCCESS; +} + +ARC_STATUS +FloppySeek ( + IN ULONG FileId, + IN PLARGE_INTEGER Offset, + IN SEEK_MODE SeekMode + ) + +/*++ + +Routine Description: + + This function sets the device position to the specified offset for + the specified file id. + +Arguments: + + FileId - Supplies the file table index. + + Offset - Supplies to new device position. + + SeekMode - Supplies the mode for the position. + +Return Value: + + ESUCCESS is returned. + +--*/ + +{ + + // + // Set the current device position as specifed by the seek mode. + // + + if (SeekMode == SeekAbsolute) { + BlFileTable[FileId].Position.LowPart = Offset->LowPart; + + } else if (SeekMode == SeekRelative) { + BlFileTable[FileId].Position.LowPart += Offset->LowPart; + } + + return ESUCCESS; +} + +ARC_STATUS +FloppyGetFileInformation ( + IN ULONG FileId, + OUT PFILE_INFORMATION Finfo + ) + +/*++ + +Routine Description: + + This routine returns the floppy size. + +Arguments: + + FileId - Supplies the file table index. + + Finfo - Supplies a pointer to where the File Information is stored. + +Return Value: + + ESUCCESS is returned. + +--*/ + +{ + + RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION)); + + switch (BlFileTable[FileId].u.FloppyContext.DriveType) { + + case DRIVE_TYPE_1200: Finfo->EndingAddress.LowPart = 1200 * 1024; + break; + case DRIVE_TYPE_1440: Finfo->EndingAddress.LowPart = 1440 * 1024; + break; + case DRIVE_TYPE_2880: Finfo->EndingAddress.LowPart = 2880 * 1024; + break; + + default : return EINVAL; + } + + Finfo->CurrentPosition = BlFileTable[FileId].Position; + Finfo->Type = FloppyDiskPeripheral; + return ESUCCESS; +} + + +VOID +FloppyBootSetup( + VOID + ) + +/*++ + +Routine Description: + + This routine is invoked to initialize the floppy boot device before any + other floppy operations are attempted. This routine performs the following + operations to initialize the device: + + o Clear the reset and DMA gate flags in the DOR + o Reset the floppy by writing the s/w reset in the DSR + o Set the program data rate in the CCR + o Issue a sense interrupt command and read the four statuses back + o Issue a configure command + o Issue a specify command + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + ULONG i,j; + // + // Begin by clearing the reset and DMA gate flags in the DOR. + // + + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->DigitalOutput, 0x0c); + FwStallExecution(MICROSECONDS_500); + + // + // Reset the floppy controller by setting the s/w reset bit in the DSR. + // + + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.DataRateSelect, 0x80); + FwStallExecution(MILLISECONDS_30); + + // + // Set the data rate in the CCR. + // + +// WRITE_PORT_UCHAR(&FLOPPY_CONTROL->DirCcr.ConfigurationControl, 0); + +// if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1), +// FW_FLOPPY_TIMEOUT)) { + if (WaitForFloppyInterrupt(FW_FLOPPY_TIMEOUT)) { +// FwPrint("Floppy setup timeout\r\n"); + return; + } + + FwStallExecution(MICROSECONDS_20); + + + // + // Issue the sense interrupt command and read back the status and + // relative cylinder number from the controller. This is done for + // each of the four possible devices. Note that the output is always + // ignored. + // + + for (i = j = 0; i <= 3; i++) { + SendByte(COMMND_SENSE_INTERRUPT); + DebugByte[j++] = ReceiveByte(); + DebugByte[j++] = ReceiveByte(); + } + + // + // Issue the configuration command. + // + + SendByte( COMMND_CONFIGURE ); // command + SendByte( 0x00 ); // required 0 + SendByte( 0x58 ); // implied seeks, disable polling & threshold = 8 + SendByte( 0x00 ); // precompensation track = 0 + + // + // Issue the specify command. + // + + SendByte( COMMND_SPECIFY ); // command + SendByte( 0xdf ); // step rate time=d, head unload=f + SendByte( 0x03 ); // head load=1, DMA disabled + + return; +} + +VOID +FloppyInitialize( + IN OUT PDRIVER_LOOKUP_ENTRY LookupTable, + IN ULONG Entries + ) + +/*++ + +Routine Description: + + This routine initializes the FloppyDriver. + +Arguments: + + LookupTable - Pointer to the driver lookup table where the pathnames + recognized by this driver will be stored. + + Entries - Number of entries in the table. + +Return Value: + + None. + +--*/ + +{ + PCONFIGURATION_COMPONENT FloppyComponent; + CHAR FloppyPath[32]; + ULONG Drive; + // + // Set motor status to all motors stopped. + // + + MotorStatus = MAXLONG; + + FloppyBootSetup(); + + // + // Default to floppy 0 in case no configuration is present in the NVRAM + // + LookupTable->DevicePath = FW_FLOPPY_0_DEVICE; + LookupTable->DispatchTable = &FloppyEntryTable; + + // + // Get the floppy configuration information. + // + FloppyComponent = FwGetComponent(FW_FLOPPY_0_DEVICE); + if ((FloppyComponent != NULL) && + (FloppyComponent->Type == FloppyDiskPeripheral)) { + + // + // Initialize the lookup table. + // + + LookupTable->DevicePath = FW_FLOPPY_0_DEVICE; + LookupTable->DispatchTable = &FloppyEntryTable; + LookupTable++; + + // + // Return if no more room in the lookup table. + // + + if (Entries == 1) { + return; + } + } + FloppyComponent = FwGetComponent(FW_FLOPPY_1_DEVICE); + if ((FloppyComponent != NULL) && + (FloppyComponent->Type == FloppyDiskPeripheral)) { + + // + // Initialize the lookup table. + // + LookupTable->DevicePath = FW_FLOPPY_1_DEVICE; + LookupTable->DispatchTable = &FloppyEntryTable; + } +} + +ARC_STATUS +FloppyBootClose( + ) + +/*++ + +Routine Description: + + This routine shuts down the floppy after the boot has taken place. + +Arguments: + + None. + +Return Value: + + Normal, successful completion status. + +--*/ + +{ + + // + // Turn the floppy drive's motor off and indicate that the + // motor has been shut off. + // + + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->DigitalOutput, 0xc); + MotorStatus = MAXLONG; + + + return ESUCCESS; +} + +ARC_STATUS +FloppyBootIO ( + IN PMDL Mdl, + IN ULONG StartingBlock, + IN ULONG FileId, + IN BOOLEAN ReadWrite + ) + +/*++ + +Routine Description: + + This routine reads or writes blocks from the floppy into the buffer described by + the MDL. The size of the read is the number of bytes mapped by the MDL + and the blocks read start at StartingBlock. + +Arguments: + + Mdl - Memory Descriptor List for buffer. + + StartingBlock - Block to begin the read operation. + + FileId - The file identifier of the floppy drive to access. + + ReadWrite - Specifies the kind of transfer to be done + TRUE = WRITE + FALSE = READ + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + + UCHAR Cylinder; + UCHAR Head = 0; + UCHAR Sector; + UCHAR EndSector; + ULONG BlockCount; + ULONG TransferSize; + ULONG TransferedBytes; + ULONG i,j,k; + PUCHAR Buffer; + BOOLEAN Success; + ARC_STATUS Status = ESUCCESS; + UCHAR DriveNumber; + ULONG SectorsPerTrack; + + DriveNumber = BlFileTable[FileId].u.FloppyContext.DiskId; + SectorsPerTrack = BlFileTable[FileId].u.FloppyContext.SectorsPerTrack; + + // + // Enable the drive and start the motor via the DOR. + // + + if (MotorStatus != DriveNumber) { + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->DigitalOutput, + ((0xc + DriveNumber) + (1 << (DriveNumber + 4)))); + MotorStatus = DriveNumber; + + // + // Wait for at least 500ms to ensure that the motor really is running. + // + + FwStallExecution(MILLISECONDS_500); + } + + // + // Get the number of blocks that need to be read in order to fulfill + // this request. Also set the base address of the caller's buffer. + // + + Buffer = ((PUCHAR) Mdl->StartVa) + Mdl->ByteOffset; + + // + // Get the parameters for the read command. + // + + Cylinder = StartingBlock / (SectorsPerTrack * 2); + Sector = (StartingBlock % SectorsPerTrack) + 1; + Head = (StartingBlock / SectorsPerTrack) % 2; + + ClearFloppyFifo(); + + // + // Loop reading blocks from the device until the request has been + // satisfied. + // + + for (BlockCount = Mdl->ByteCount >> 9; BlockCount > 0; ) { + + // + // Determine the size of this read based on the number of blocks + // required and where the current sector is on the current track. + // + + EndSector = MINIMUM( SectorsPerTrack, (Sector + (BlockCount - 1)) ); + TransferSize = (EndSector - Sector) + 1; + BlockCount -= TransferSize; + TransferSize <<= 9; + + // + // Attempt to read the block(s) up to RETRY_COUNT times. + // + + for (k = 0; k < RETRY_COUNT; k++) { + + // + // Assume that the operation will be successful. + // + + Success = TRUE; + + // + // Do an explicit seek if this is a 360 K disk in a 1.2 MB drive. + // + + if (CurrentDriveMediaConstants->CylinderShift != 0) { + if (!SendByte( COMMND_SEEK ) || + !SendByte( (Head << 2) + DriveNumber ) || // head select & drive + !SendByte( Cylinder << CurrentDriveMediaConstants->CylinderShift )) { + return(EIO); + } + +// if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1), +// FW_FLOPPY_TIMEOUT)) { + if (WaitForFloppyInterrupt(FW_FLOPPY_TIMEOUT)) { + return(EIO); + } + + // + // Send the sense interrupt command. + // + + if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command + return(EIO); + } + + // + // Read back the information from the drive and check the status of the + // recalibrate command. + // + + DebugByte[0] = ReceiveByte(); + DebugByte[1] = ReceiveByte(); + + if (DebugByte[1] != (Cylinder << CurrentDriveMediaConstants->CylinderShift)) { + return(EIO); + } + + // + // Now try to read the ID from wherever we're at. + // + + if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command + !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) { + return(EIO); + } + +// if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1), +// FW_FLOPPY_TIMEOUT)) { + if (WaitForFloppyInterrupt(FW_FLOPPY_TIMEOUT)) { + return(EIO); + } + + for (i = 0; i < 7; i++) { + DebugByte[i] = ReceiveByte(); + } + + if ( ( DebugByte[0] != + (UCHAR)(DriveNumber | + ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) || + ( DebugByte[1] != 0 ) || + ( DebugByte[2] != 0 ) ) { + + return(EIO); + } + + } + + // + // Send the command and parameters for the operation. + // + + if (ReadWrite == TRUE) { + if (!SendByte( COMMND_WRITE_DATA + COMMND_MFM )) { + return(EIO); + } + } else { + if (!SendByte( COMMND_READ_DATA + COMMND_MFM )) { + return(EIO); + } + } + if (!SendByte( (Head << 2) + DriveNumber ) || // head select & drive + !SendByte( Cylinder ) || // cylinder + !SendByte( Head ) || // head + !SendByte( Sector ) || // sector + !SendByte( 2 ) || // sector size; 2 => 512B/sec + !SendByte( EndSector ) || // end of track sector + !SendByte( CurrentDriveMediaConstants->ReadWriteGapLength ) || + !SendByte( 0xff )) { // special sector size + return(EIO); + } + + // + // Ensure that the floppy drive does not time-out. + // + + for (j = 0; j < SECONDS_2; j += MICROSECONDS_10) { + if (READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) + > 127) { + break; + } + + FwStallExecution(MICROSECONDS_10); + } + + // + // Check for time-out; if one occurred, then return unsuccessful + // status. + // + + if (j == SECONDS_2) { +// FwPrint("Floppy timeout\r\n"); + return EIO; + } + + // + // Read the data from the appropriate block(s) and check the number + // of bytes actually read. + // + + if (ReadWrite == TRUE) { + WriteFloppyFifo(Buffer,TransferSize); + } else { + TransferedBytes = ReadFloppyFifo(Buffer); + if (TransferedBytes != TransferSize) { + Success = FALSE; + } + } + + // + // Read the status information from the device. + // + + while (READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) + <= 127) { + } + + for (i = 0; i < 7; i++) { + DebugByte[i] = ReceiveByte(); + } + + if (((DebugByte[0] >> 4) == 2) && + (DebugByte[1] == 0) && + (DebugByte[2] == 0) && + Success) { + ; + + } else { + + if ((DebugByte[0] >> 4) != 4) { + Success = FALSE; + } + + if (DebugByte[1] != 0x80) { + Success = FALSE; + } + + if (DebugByte[2] != 0) { + Success = FALSE; + } + } + + // + // If the operation was successful, exit the loop. + // + + if (Success) { + Buffer += TransferSize; + break; + } + + // + // The operation did not work. Attempt to recalibrate the + // device and wait for everything to settle out, and then + // try the operation again. + // + + if (!Recalibrate(DriveNumber)) { +// FwPrint("Floppy recalibration error\r\n"); + return(EIO); + } + FwStallExecution(MILLISECONDS_15); + } + + // + // If the operation was not successful after RETRY_COUNT tries, get + // out now. + // + + if (!Success) { + Status = EIO; + break; + } + + // + // If more data is needed, get the next place to read from. Note + // that if there is more data to be read, then the last sector + // just read was the last sector on this head. + // + + if (BlockCount > 0) { + if (Head == 1) { + Cylinder += 1; + Head = 0; + } else { + Head = 1; + } + Sector = 1; + } + + if (Success) { + Status = ESUCCESS; + } + } + return Status; +} + +BOOLEAN +Recalibrate( + UCHAR DriveNumber + ) + +/*++ + +Routine Description: + + This routine issues a recalibrate command to the device, waits for it to + interrupt, sends it a sense interrupt command, and checks the result to + ensure that the recalibrate command worked properly. + +Arguments: + + DriveNumber - Supplies the Floppy drive to recalibrate. + +Return Value: + + Returns TRUE if the recalibrate was successful, FALSE if not. + +--*/ + +{ + + // + // Send the recalibrate command to the device. + // + + if (!SendByte( COMMND_RECALIBRATE ) || // command + !SendByte( DriveNumber )) { // drive select + return(FALSE); + } + +// if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1), +// FW_FLOPPY_TIMEOUT)) { + if (WaitForFloppyInterrupt(FW_FLOPPY_TIMEOUT)) { +// FwPrint("Floppy recalibrate timeout\r\n"); + return(FALSE); + } + + // + // Send the sense interrupt command. + // + + if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command + return(FALSE); + } + + // + // Read back the information from the drive and check the status of the + // recalibrate command. + // + + DebugByte[0] = ReceiveByte(); + if ((DebugByte[0] >> 4) != 2) { + return FALSE; + } + + DebugByte[1] = ReceiveByte(); + + if ((READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) & + STATUS_IO_READY_MASK) == STATUS_READ_READY) { + return FALSE; + } + + return TRUE; +} + +UCHAR +ReceiveByte( + ) + +/*++ + +Routine Description: + + This routine reads the next byte from the floppy FIFO register. + +Arguments: + + None. + +Return Value: + + The function value is the value of the byte read from the floppy FIFO. + +--*/ + +{ + + ULONG i; + + // + // Check status register for readiness to receive data. + // + + for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) { + if ((READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) & + STATUS_IO_READY_MASK) == STATUS_READ_READY) { + return READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->Fifo); + } + + FwStallExecution(MICROSECONDS_10); + } + + // + // A timeout occurred while attempting to read data from the floppy fifo. + // Output an error message and return. + // + +// FwPrint("Error reading from floppy fifo\r\n"); + return(0xFF); +} + +BOOLEAN +SendByte( + IN UCHAR SourceByte + ) + +/*++ + +Routine Description: + + This routine sends a specified byte to the floppy FIFO register. + +Arguments: + + SourceByte - Byte to be sent to the controller. + +Return Value: + + If the byte was successfully written to the floppy FIFO, TRUE is returned, + otherwise FALSE is returned. + +--*/ + +{ + + ULONG i; + + // + // Check status register for readiness to receive data. + // + + for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) { + if ((READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) & + STATUS_IO_READY_MASK) == STATUS_WRITE_READY) { + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->Fifo, SourceByte); + return(TRUE); + } + + FwStallExecution(MICROSECONDS_10); + } + + // + // A timeout occurred while attempting to write data to the floppy fifo. + // Output an error message and return. + // + +// FwPrint("Error writing to floppy fifo\r\n"); + return(FALSE); +} + +VOID +ClearFloppyFifo( + IN VOID + ) + +/*++ + +Routine Description: + + This routine empties the fifo. + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + + ULONG i; + + // + // Check status register for readiness to receive data. + // + while ((READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) & + STATUS_IO_READY_MASK) == STATUS_READ_READY) { + READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->Fifo); + FwStallExecution(MICROSECONDS_10); + } +} + + +ARC_STATUS +FloppyDatarateSpecifyConfigure( + IN DRIVE_MEDIA_TYPE DriveMediaType, + IN UCHAR DriveNumber + ) + +/*++ + +Routine Description: + + This routine is called to set up the controller every time a new type + of diskette is to be accessed. It issues the CONFIGURE command, + does a SPECIFY, sets the data rate, and RECALIBRATEs the drive. + +Arguments: + + DriveMediaType - supplies the drive type/media density combination. + + DriveNumber - supplies the drive number. + +Return Value: + + ESUCCESS if the controller is properly prepared; appropriate + error propogated otherwise. + +--*/ + +{ + UCHAR Configure; + + // + // Don't enable implied seeks when there is a 360K disk in a 1.2M drive. + // + + if (DriveMediaConstants[DriveMediaType].CylinderShift) { + Configure = 0x18; + } else { + Configure = 0x58; + } + + // + // Issue the configuration command. + // + + if (!SendByte( COMMND_CONFIGURE ) || // command + !SendByte( 0x00 ) || // required 0 + !SendByte( Configure ) || // implied seeks, disable polling & threshold = 8 + !SendByte( 0x00 ) || // precompensation track = 0 + + // + // Issue SPECIFY command to program the head load and unload + // rates, the drive step rate, and the DMA data transfer mode. + // + + !SendByte( COMMND_SPECIFY ) || // command + !SendByte( DriveMediaConstants[DriveMediaType].StepRateHeadUnloadTime) || + !SendByte( DriveMediaConstants[DriveMediaType].HeadLoadTime + 1)) { + return(EIO); + } + + // + // Program the data rate + // + + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.DataRateSelect, + DriveMediaConstants[DriveMediaType].DataTransferRate ); + + // + // Recalibrate the drive, now that we've changed all its + // parameters. + // + + if (Recalibrate(DriveNumber)) { + return(ESUCCESS); + } else { +// FwPrint("Floppy recalibration error\r\n"); + return(EIO); + } +} + +ARC_STATUS +FloppyDetermineMediaType( + IN OUT PFLOPPY_CONTEXT FloppyContext, + OUT PMEDIA_TYPE mediaType + ) + +/*++ + +Routine Description: + + This routine is called by FloppyBootIO() when the media type is + unknown. It assumes the largest media supported by the drive is + available, and keeps trying lower values until it finds one that + works. + +Arguments: + + FloppyContext - supplies a pointer to the floppy context structure. + + mediaType - supplies a pointer to a variable that receives the + type of the media in the drive. + +Return Value: + + ESUCCESS if the type of the media is determined; appropriate + error propogated otherwise. + +--*/ + +{ + ARC_STATUS Status; + BOOLEAN mediaTypesExhausted = FALSE; + DRIVE_MEDIA_TYPE DriveMediaType; + UCHAR DriveNumber; + ULONG i; + + // + // Assume that the largest supported media is in the drive. If that + // turns out to be untrue, we'll try successively smaller media types + // until we find what's really in there (or we run out and decide + // that the media isn't formatted). + // + + DriveMediaType = + DriveMediaLimits[FloppyContext->DriveType].HighestDriveMediaType; + + DriveNumber = FloppyContext->DiskId; + + do { + + Status = FloppyDatarateSpecifyConfigure( DriveMediaType, DriveNumber ); + + if ( Status != ESUCCESS ) { + + // + // The SPECIFY or CONFIGURE commands resulted in an error. + // Force ourselves out of this loop and return error. + // + + mediaTypesExhausted = TRUE; + + } else { + + CurrentDriveMediaConstants = &DriveMediaConstants[DriveMediaType]; + + // + // Now try to read the ID from wherever we're at. + // + + if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command + !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) { + return(EIO); + } + +// if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1), +// FW_FLOPPY_TIMEOUT)) { + if (WaitForFloppyInterrupt(FW_FLOPPY_TIMEOUT)) { +// FwPrint("Floppy determine media timeout\r\n"); + return(EIO); + } + + for (i = 0; i < 7; i++) { + DebugByte[i] = ReceiveByte(); + } + + if ( ( DebugByte[0] != + (UCHAR)(DriveNumber | + ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) || + ( DebugByte[1] != 0 ) || + ( DebugByte[2] != 0 ) ) { + + DriveMediaType--; + + Status = ENXIO; + + // + // Next comparison must be signed, for when + // LowestDriveMediaType = 0. + // + + if ( (CHAR)( DriveMediaType ) < + (CHAR)( DriveMediaLimits[FloppyContext->DriveType].LowestDriveMediaType )) { + + mediaTypesExhausted = TRUE; + + } + } + } + + } while ( ( ( Status != ESUCCESS ) ) && !( mediaTypesExhausted ) ); + + if ( Status == ESUCCESS ) { + + FloppyContext->SectorsPerTrack = + CurrentDriveMediaConstants->SectorsPerTrack; + + *mediaType = CurrentDriveMediaConstants->MediaType; + } + return Status; +} + +ULONG +ReadFloppyFifo ( + IN OUT PUCHAR Buffer + ) + +/*++ + +Routine Description: + + This reads data from the floppy fifo. + +Arguments: + + Buffer - Pointer to the buffer that receives the data read. + +Return Value: + + The number of bytes read. + +--*/ +{ + ULONG BytesRead = 0; + UCHAR MSR; + + while (TRUE) { + + // Loop until DIO and RQM are both set. + while ( + ((MSR = READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus)) + & (FLOPPY_MSR_DIO | FLOPPY_MSR_RQM)) + != (FLOPPY_MSR_DIO | FLOPPY_MSR_RQM) + ) { + } + + // If the non-DMA bit is clear, end of transfer. + if ((MSR & FLOPPY_MSR_NONDMA) == 0) { + return (BytesRead); + } + + // Read the byte, increment pointer and total, until done. + *Buffer++ = READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->Fifo); + BytesRead++; + } +} + +VOID +WriteFloppyFifo( + IN PUCHAR Buffer, + IN ULONG Size + ) + +/*++ + +Routine Description: + + This writes data to the floppy fifo. + +Arguments: + + Buffer - Pointer to the buffer that contains the data to be written. + + Size - The number of bytes to be written. + +Return Value: + + None. + +--*/ + +{ + while (Size) { + + // Loop until DIO is clear and RQM is set. + while ( + (READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) + & (FLOPPY_MSR_DIO | FLOPPY_MSR_RQM)) + != FLOPPY_MSR_RQM + ) { + } + + // + // Write the byte, increment pointer, decrement count, until done. + // Remember, C does call by value. + // + + WRITE_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->Fifo, *Buffer++); + --Size; + } + + // + // All bytes written to fifo. Wait until the floppy controller + // empties it. + // + + while ( + (READ_PORT_UCHAR((PUCHAR)&FLOPPY_CONTROL->MsrDsr.MainStatus) + & FLOPPY_MSR_NONDMA) + != 0 ) { + } + + + return; + +} + +ARC_STATUS +WaitForFloppyInterrupt( + ULONG Timeout + ) + +/*++ + +Routine Description: + + This waits until the floppy controller has an interrupt pending, + or the requested Timeout period has been reached. + + The Jazz code enables interrupts for the keyboard and individual + devices. In actuality, the only non-keyboard device it enables interrupts + for is the floppy controller. For Alpha we avoid dealing + with interrupts in the firmware code to keep the PALcode simple. So + every Jazz call to "FwWaitForDeviceInterrupt" has been changed to + this function. + +Arguments: + + Timeout - A timeout value in seconds. Note that a timeout of 0 gives + an actual timeout of between 0 and 1, a timeout of 1 gives + an actual timeout of between 1 and 2, and so on. + +Return Value: + + ESUCCESS if an interrupt is floppy interrupt is detected. + EIO if a timeout occurs. + +--*/ + +{ + ULONG Time1; + + + Time1 = FwGetRelativeTime(); + + // Ask for the interrupt wires + WRITE_PORT_UCHAR((PUCHAR)EISA_INT_OCW3, EISA_INT_OCW3_IRR); + + // + // 0x40 is irq6, which is the floppy controller. I should make this + // into a #define. + // + while ( + (READ_PORT_UCHAR((PUCHAR)EISA_INT_OCW3) & 0x40) + == 0) { + if ((FwGetRelativeTime() - Time1) > (Timeout + 1)) { + return(EIO); + } + } + + return(ESUCCESS); +} |