2058 lines
50 KiB
C
2058 lines
50 KiB
C
#if defined(JAZZ) && !defined(DUO)
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1989 Microsoft 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:
|
||
|
||
--*/
|
||
|
||
#include "fwp.h"
|
||
#include "jazzprom.h"
|
||
#include "jazzint.h"
|
||
#include "ntdddisk.h"
|
||
#include "flo_data.h"
|
||
#include "fwstring.h"
|
||
|
||
|
||
//
|
||
// Define local static data.
|
||
//
|
||
|
||
UCHAR DebugByte[8];
|
||
ULONG MotorStatus;
|
||
PDRIVE_MEDIA_CONSTANTS CurrentDriveMediaConstants;
|
||
|
||
//
|
||
// Define timeout constants.
|
||
//
|
||
|
||
#define MICROSECONDS_10 10
|
||
#define MICROSECONDS_250 250
|
||
#define MILLISECONDS_15 (15 * 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)
|
||
|
||
PUCHAR Floppy0Path = "multi(0)disk(0)fdisk(0)";
|
||
PUCHAR Floppy1Path = "multi(0)disk(0)fdisk(1)";
|
||
|
||
|
||
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
|
||
FloppyBootClose(
|
||
);
|
||
|
||
BOOLEAN
|
||
Recalibrate (
|
||
UCHAR DriveNumber
|
||
);
|
||
|
||
VOID
|
||
FloppyBootSetup(
|
||
VOID
|
||
);
|
||
|
||
UCHAR
|
||
ReceiveByte (
|
||
);
|
||
|
||
BOOLEAN
|
||
SendByte(
|
||
IN UCHAR SourceByte
|
||
);
|
||
|
||
ARC_STATUS
|
||
FloppyDetermineMediaType(
|
||
IN OUT PFLOPPY_CONTEXT FloppyContext
|
||
);
|
||
|
||
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;
|
||
DRIVE_MEDIA_TYPE driveMediaType;
|
||
ULONG DriveType;
|
||
ULONG ConfigDriveType;
|
||
|
||
//
|
||
// Get the drive number from the pathname.
|
||
//
|
||
|
||
if (FwGetPathMnemonicKey(OpenPath, "fdisk", &DriveNumber)) {
|
||
return ENODEV;
|
||
}
|
||
|
||
//
|
||
// Default to 1.44MB floppy
|
||
//
|
||
|
||
BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
|
||
|
||
//
|
||
// 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_REGISTER_UCHAR(&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);
|
||
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 the other floppy type.
|
||
//
|
||
|
||
DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
|
||
if ((DriveType == DRIVE_TYPE_1440) || (DriveType == DRIVE_TYPE_2880)) {
|
||
BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200;
|
||
} else {
|
||
BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
|
||
}
|
||
|
||
ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext);
|
||
if (ArcStatus == EIO) {
|
||
FloppyClose(*FileId);
|
||
return(ArcStatus);
|
||
} else if (ArcStatus != ESUCCESS) {
|
||
BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType;
|
||
// 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 );
|
||
mediaType = 0;
|
||
|
||
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:
|
||
mediaType = F3_1Pt44_512;
|
||
DriveType = DRIVE_TYPE_1440;
|
||
break;
|
||
|
||
default:
|
||
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. NOTE Doesn't do 2.88 MByte floppies.
|
||
//
|
||
|
||
if (DriveType != ConfigDriveType) {
|
||
|
||
if (DriveType == DRIVE_TYPE_1200) {
|
||
strcpy(FloppyData->Size,"5.25");
|
||
FloppyData->MaxDensity = 1200;
|
||
} else {
|
||
strcpy(FloppyData->Size,"3.5");
|
||
FloppyData->MaxDensity = 1440;
|
||
}
|
||
|
||
//
|
||
// 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_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput, 0x0c);
|
||
|
||
//
|
||
// Reset the floppy controller by setting the s/w reset bit in the DSR.
|
||
//
|
||
|
||
WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.DataRateSelect, 0x80);
|
||
|
||
//
|
||
// Set the data rate in the CCR.
|
||
//
|
||
|
||
// WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DirCcr.ConfigurationControl, 0);
|
||
|
||
if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
|
||
FW_FLOPPY_TIMEOUT)) {
|
||
// FwPrint("Floppy setup timeout\r\n");
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// 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 = Floppy0Path;
|
||
LookupTable->DispatchTable = &FloppyEntryTable;
|
||
|
||
//
|
||
// Get the floppy configuration information.
|
||
//
|
||
FloppyComponent = FwGetComponent(Floppy0Path);
|
||
if ((FloppyComponent != NULL) &&
|
||
(FloppyComponent->Type == FloppyDiskPeripheral)) {
|
||
|
||
//
|
||
// Initialize the lookup table.
|
||
//
|
||
|
||
LookupTable->DevicePath = Floppy0Path;
|
||
LookupTable->DispatchTable = &FloppyEntryTable;
|
||
LookupTable++;
|
||
|
||
//
|
||
// Return if no more room in the lookup table.
|
||
//
|
||
|
||
if (Entries == 1) {
|
||
return;
|
||
}
|
||
}
|
||
FloppyComponent = FwGetComponent(Floppy1Path);
|
||
if ((FloppyComponent != NULL) &&
|
||
(FloppyComponent->Type == FloppyDiskPeripheral)) {
|
||
|
||
//
|
||
// Initialize the lookup table.
|
||
//
|
||
LookupTable->DevicePath = Floppy1Path;
|
||
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_REGISTER_UCHAR(&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_REGISTER_UCHAR(&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)) {
|
||
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)) {
|
||
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_REGISTER_UCHAR(&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_REGISTER_UCHAR(&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)) {
|
||
// 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_REGISTER_UCHAR(&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_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
|
||
STATUS_IO_READY_MASK) == STATUS_READ_READY) {
|
||
return READ_REGISTER_UCHAR(&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_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
|
||
STATUS_IO_READY_MASK) == STATUS_WRITE_READY) {
|
||
WRITE_REGISTER_UCHAR(&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_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
|
||
STATUS_IO_READY_MASK) == STATUS_READ_READY) {
|
||
READ_REGISTER_UCHAR(&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_REGISTER_UCHAR(&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
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
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)) {
|
||
// 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;
|
||
}
|
||
return Status;
|
||
}
|
||
#endif
|