/*++
Copyright (c) 1991 Microsoft Corporation
Copyright (c) 1993 Digital Equipment Corporation
Module Name:
fwio.c
Abstract:
This module implements the ARC firmware I/O operations for a MIPS
R3000 or R3000 Jazz system, or for the DEC Alpha/Jensen system.
Author:
David N. Cutler (davec) 14-May-1991
Revision History:
Lluis Abello (lluis) 20-Jun-1991
15-April-1992 John DeRosa [DEC]
Added Alpha/Jensen hooks.
--*/
#include "fwp.h"
#include "string.h"
#include "fwstring.h"
//
// Needed to fix a bug in the bldr\scsiboot.c file where repeated reboots
// would cause a crash due to walking off the end of an array.
//
ULONG ScsiPortCount;
PDEVICE_OBJECT ScsiPortDeviceObject[10];
//
// Define file table.
//
BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
#define DEVICE_DEVICE 0xDEAD
extern PADAPTER_OBJECT MasterAdapterObject;
extern PADAPTER_OBJECT HalpEisaAdapter[8];
#if !defined(FAILSAFE_BOOTER) && defined(EISA_PLATFORM)
extern BL_DEVICE_ENTRY_TABLE OmfEntryTable;
extern BL_DEVICE_ENTRY_TABLE OmfFileEntryTable;
#endif
//
// Declare the table of opened devices.
//
OPENED_PATHNAME_ENTRY OpenedPathTable[SIZE_OF_OPENED_PATHNAME_TABLE];
//
// Declare the table of opened drivers.
//
DRIVER_LOOKUP_ENTRY DeviceLookupTable[SIZE_OF_LOOKUP_TABLE];
//
// Define data structure for the file system structure context.
//
typedef union _FILE_SYSTEM_STRUCTURE {
FAT_STRUCTURE_CONTEXT FatContext;
NTFS_STRUCTURE_CONTEXT NtfsContext;
ULONG Tmp;
} FILE_SYSTEM_STRUCTURE, *PFILE_SYSTEM_STRUCTURE;
typedef struct _FS_POOL_ENTRY {
BOOLEAN InUse;
FILE_SYSTEM_STRUCTURE Fs;
} FS_POOL_ENTRY, *PFS_POOL_ENTRY;
//
// The pool size was reduced from eight to five as an easy way to include
// NTFS booting without radically changing the manipulation of the firmware
// file system pool.
//
//#define FS_POOL_SIZE 8
//
#define FS_POOL_SIZE 5
PFS_POOL_ENTRY FileSystemStructurePool;
//
// Declare local procedures
//
VOID
FiFreeFsStructure(
IN PFILE_SYSTEM_STRUCTURE PFs
);
PVOID
FiAllocateFsStructure(
VOID
);
ARC_STATUS
FiGetFileTableEntry(
OUT PULONG Entry
);
PFAT_STRUCTURE_CONTEXT
FiAllocateFatStructure(
VOID
);
ARC_STATUS
FwGetFileInformation (
IN ULONG FileId,
OUT PFILE_INFORMATION Finfo
)
/*++
Routine Description:
This function gets the file information for the specified FileId.
Arguments:
FileId - Supplies the file table index.
Finfo - Supplies a pointer to where the File Informatino is stored.
Return Value:
If the specified file is open then this routine dispatches to the
File routine.
Otherwise, returns an unsuccessful status.
--*/
{
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->GetFileInformation)(FileId,
Finfo);
} else {
return EACCES;
}
}
ARC_STATUS
FwSetFileInformation (
IN ULONG FileId,
IN ULONG AttributeFlags,
IN ULONG AttributeMask
)
/*++
Routine Description:
This function sets the file attributes for the specified FileId.
Arguments:
FileId - Supplies the file table index.
AttributeFlags - Supply the attributes to be set for the file.
AttributeMask
Return Value:
If the specified file is open and is not a device then this routine
dispatches to the file system routine.
Otherwise, returns an unsuccessful status.
--*/
{
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].DeviceId != DEVICE_DEVICE)) {
return (BlFileTable[FileId].DeviceEntryTable->SetFileInformation)(FileId,
AttributeFlags,
AttributeMask);
} else {
return EACCES;
}
}
ARC_STATUS
FwMount (
IN PCHAR MountPath,
IN MOUNT_OPERATION Operation
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return ESUCCESS;
}
ARC_STATUS
FwRead (
IN ULONG FileId,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
/*++
Routine Description:
This function reads from a file or a device that is open.
Alpha/Jensen cannot do DMA in the .5MB -- 1MB memory space, so
transfers within that space are done through another buffer. This is
transparent to the code that called this function. \TBD\: whether
other Alpha PC's need this fix too. We will leave the fix in for
now as Alpha-generic.
Arguments:
FileId - Supplies the file table index.
Buffer - Supplies a pointer to the buffer that receives the data
read.
Length - Supplies the number of bytes that are to be read.
Count - Supplies a pointer to a variable that receives the number of
bytes actually transfered.
Return Value:
If the specified file is open for read, then a read is attempted
and the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
#ifdef ALPHA
// These are for buffering DMA data destined for .5MB -- 1MB addresses.
ARC_STATUS Status;
UCHAR LocalSectorBuffer[SECTOR_SIZE];
PUCHAR LocalBuffer = Buffer;
ULONG LocalLengthRemaining = Length;
ULONG LocalCountSum = 0;
ULONG LocalLength;
ULONG LocalCount;
PUCHAR P_512KB;
PUCHAR P_1MB;
#endif
//
// If the file is open for read, then attempt to read from it. Otherwise
// return an access error.
//
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Read == 1)) {
#ifdef ALPHA
//
// These pointers are used to compare buffer addresses to the
// Alpha/Jensen missing memory DMA section of .5MB -- 1MB.
// The KSEG0_BASE bit is set if the incoming Buffer address has it
// set.
//
P_512KB = (PUCHAR)(_512_KB | ((ULONG)Buffer & KSEG0_BASE));
P_1MB = (PUCHAR)(ONE_MB | ((ULONG)Buffer & KSEG0_BASE));
//
// LocalBuffer and LocalLengthRemaining are bumped along by each
// section of the JENSEN code to simplify the comparisons.
//
// LocalCountSum will keep a running total of the bytes actually
// transferred. This is initialized to zero.
//
//
// Read the part below .5MB.
//
if (LocalBuffer < P_512KB) {
LocalLength = ((LocalBuffer + LocalLengthRemaining) > P_512KB) ?
(P_512KB - LocalBuffer) : LocalLengthRemaining;
Status = (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
LocalBuffer,
LocalLength,
&LocalCount);
LocalBuffer += LocalLength;
LocalLengthRemaining -= LocalLength;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
//
// Read the part between .5MB and 1MB.
//
if ((LocalBuffer >= P_512KB) &&
(LocalBuffer < P_1MB) &&
(LocalLengthRemaining > 0)) {
// Calculate amount to read
LocalLength = LocalLengthRemaining > _512_KB ?
_512_KB : LocalLengthRemaining;
//
// Now read the data into this region via LocalSectorBuffer.
//
// First read in data in chunks of SECTOR_SIZE size, and then
// read in any remaining bytes. Note: C integer division
// truncates any fractional part.
//
while (LocalLength / SECTOR_SIZE) {
Status = (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
LocalSectorBuffer,
SECTOR_SIZE,
&LocalCount);
RtlMoveMemory ( LocalBuffer, LocalSectorBuffer, SECTOR_SIZE );
LocalBuffer += SECTOR_SIZE;
LocalLengthRemaining -= SECTOR_SIZE;
LocalLength -= SECTOR_SIZE;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
//
// Now read in any remaining bytes.
//
if (LocalLength) {
Status = (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
LocalSectorBuffer,
LocalLength,
&LocalCount);
RtlMoveMemory ( LocalBuffer, LocalSectorBuffer, LocalLength );
LocalBuffer += LocalLength;
LocalLengthRemaining -= LocalLength;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
}
//
// Read the part above 1MB.
//
if ((LocalBuffer >= P_1MB) &&
(LocalLengthRemaining > 0)) {
Status = (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
LocalBuffer,
LocalLengthRemaining,
&LocalCount);
LocalCountSum += LocalCount;
}
//
// The read must have succeeded. Return Status and Count.
//
*Count = LocalCountSum;
return (ESUCCESS);
#else
// Non-JENSEN code.
return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
Buffer,
Length,
Count);
#endif
} else {
return EACCES;
}
}
ARC_STATUS
FwGetReadStatus (
IN ULONG FileId
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// If the file is open for read, then call the call the specific routine.
// Otherwise return an access error.
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Read == 1)) {
//
// Make sure there is a valid GetReadStatus entry.
//
if (BlFileTable[FileId].DeviceEntryTable->GetReadStatus != NULL) {
return(BlFileTable[FileId].DeviceEntryTable->GetReadStatus)(FileId);
} else {
return(EACCES);
}
} else {
return EACCES;
}
return ESUCCESS;
}
ARC_STATUS
FwSeek (
IN ULONG FileId,
IN PLARGE_INTEGER Offset,
IN SEEK_MODE SeekMode
)
/*++
Routine Description:
Arguments:
Return Value:
If the specified file is open, then a seek is attempted and
the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
//
// If the file is open, then attempt to seek on it. Otherwise return an
// access error.
//
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
Offset,
SeekMode);
} else {
return EACCES;
}
}
ARC_STATUS
FwWrite (
IN ULONG FileId,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
/*++
Routine Description:
This function writes to a file or a device that is open.
Alpha/Jensen cannot do DMA in the .5MB -- 1MB memory space, so
transfers within that space are done through another buffer. This is
transparent to the code that called this function.
Arguments:
FileId - Supplies the file table index.
Buffer - Supplies a pointer to the buffer that contains the data
to write.
Length - Supplies the number of bytes that are to be written.
Count - Supplies a pointer to a variable that receives the number of
bytes actually transfered.
Return Value:
If the specified file is open for write, then a write is attempted
and the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
#ifdef ALPHA
// These are for buffering DMA data from .5MB -- 1MB addresses.
ARC_STATUS Status;
UCHAR LocalSectorBuffer[SECTOR_SIZE];
PUCHAR LocalBuffer = Buffer;
ULONG LocalLengthRemaining = Length;
ULONG LocalCountSum = 0;
ULONG LocalLength;
ULONG LocalCount;
PUCHAR P_512KB;
PUCHAR P_1MB;
#endif
//
// If the file is open for write, then attempt to write to it. Otherwise
// return an access error.
//
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Write == 1)) {
#ifdef ALPHA
//
// These pointers are used to compare buffer addresses to the
// Alpha/Jensen missing memory DMA section of .5MB -- 1MB.
// The KSEG0_BASE bit is set if the incoming Buffer address has it
// set.
//
P_512KB = (PUCHAR)(_512_KB | ((ULONG)Buffer & KSEG0_BASE));
P_1MB = (PUCHAR)(ONE_MB | ((ULONG)Buffer & KSEG0_BASE));
//
// LocalBuffer and LocalLengthRemaining are bumped along by each
// section of the JENSEN code to simplify the comparisons.
//
// LocalCountSum will keep a running total of the bytes actually
// transferred. This is initialized to zero.
//
//
// Write the part below .5MB.
//
if (LocalBuffer < P_512KB) {
LocalLength = ((LocalBuffer + LocalLengthRemaining) > P_512KB) ?
(P_512KB - LocalBuffer) : LocalLengthRemaining;
Status = (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
LocalBuffer,
LocalLength,
&LocalCount);
LocalBuffer += LocalLength;
LocalLengthRemaining -= LocalLength;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
//
// Write the part between .5MB and 1MB.
//
if ((LocalBuffer >= P_512KB) &&
(LocalBuffer < P_1MB) &&
(LocalLengthRemaining > 0)) {
// Calculate amount to write
LocalLength = LocalLengthRemaining > _512_KB ?
_512_KB : LocalLengthRemaining;
//
// Now write the data into this region via LocalSectorBuffer.
//
// First write data in chunks of SECTOR_SIZE size, and then
// write any remaining bytes. Note: C integer division
// truncates any fractional part.
//
while (LocalLength / SECTOR_SIZE) {
RtlMoveMemory ( LocalSectorBuffer, LocalBuffer, SECTOR_SIZE );
Status = (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
LocalSectorBuffer,
SECTOR_SIZE,
&LocalCount);
LocalBuffer += SECTOR_SIZE;
LocalLengthRemaining -= SECTOR_SIZE;
LocalLength -= SECTOR_SIZE;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
//
// Now write any remaining bytes.
//
if (LocalLength) {
RtlMoveMemory ( LocalSectorBuffer, LocalBuffer, LocalLength );
Status = (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
LocalSectorBuffer,
LocalLength,
&LocalCount);
LocalBuffer += LocalLength;
LocalLengthRemaining -= LocalLength;
LocalCountSum += LocalCount;
if (Status != ESUCCESS) {
*Count = LocalCountSum;
return (Status);
}
}
}
//
// Write the part above 1MB.
//
if ((LocalBuffer >= P_1MB) &&
(LocalLengthRemaining > 0)) {
Status = (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
LocalBuffer,
LocalLengthRemaining,
&LocalCount);
LocalCountSum += LocalCount;
}
//
// The write must have succeeded. Return Status and Count.
//
*Count = LocalCountSum;
return (ESUCCESS);
#else
// Non-JENSEN code.
return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
Buffer,
Length,
Count);
#endif
} else {
return EACCES;
}
}
ARC_STATUS
FwGetDirectoryEntry (
IN ULONG FileId,
OUT PDIRECTORY_ENTRY Buffer,
IN ULONG Length,
OUT PULONG Count
)
/*++
Routine Description:
This function reads from a file the requested number of directory entries.
Arguments:
FileId - Supplies the file table index.
Buffer - Supplies a pointer to the buffer to receive the directory
entries.
Length - Supplies the number of directory entries to be read.
Count - Supplies a pointer to a variable that receives the number of
directory entries actually read..
Return Value:
If the specified file is open for read, then a read is attempted
and the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
//
// If the file is open for read, then call the specific routine.
// Otherwise return an access error.
//
if ((FileId < BL_FILE_TABLE_SIZE) &&
(BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Read == 1) &&
(BlFileTable[FileId].DeviceId != DEVICE_DEVICE)) {
//
// Check to make sure a GetDirectoryEntry routine exists
//
if (BlFileTable[FileId].DeviceEntryTable->GetDirectoryEntry != NULL) {
return (BlFileTable[FileId].DeviceEntryTable->GetDirectoryEntry)
(FileId, Buffer, Length, Count);
}
} else {
return EBADF;
}
}
ARC_STATUS
FwClose (
IN ULONG FileId
)
/*++
Routine Description:
This function closes a file or a device if it's open.
The DeviceId field indicates if the FileId is a device
(it has the value DEVICE_DEVICE) or is a file.
When closing a file, after the file is closed the
reference counter for the device is decremented and if zero
the device is also closed and the device name removed from
the table of opened devices.
If FileId specifies a device, the reference counter is
decremented and if zero the device is closed and the device
name removed from the table of opened devices.
Arguments:
FileId - Supplies the file table index.
Return Value:
If the specified file is open, then a close is attempted and
the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
ULONG DeviceId;
ARC_STATUS Status;
if (BlFileTable[FileId].Flags.Open == 1) {
//
// Check if closing a file or a device
//
if (BlFileTable[FileId].DeviceId == DEVICE_DEVICE) {
//
// Decrement reference counter, if it's zero call the device
// close routine.
//
OpenedPathTable[FileId].ReferenceCounter--;
if (OpenedPathTable[FileId].ReferenceCounter == 0) {
//
// Remove the name of the device from the table of opened devices.
//
OpenedPathTable[FileId].DeviceName[0] = '\0';
//
// Call the device specific close routine.
//
Status = (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
//
// If the device has a file system, free the memory used for
// the STRUCTURE_CONTEXT.
//
if (BlFileTable[FileId].StructureContext != NULL) {
FiFreeFsStructure(BlFileTable[FileId].StructureContext);
}
return Status;
} else {
return ESUCCESS;
}
} else {
//
// Close the file
//
DeviceId= BlFileTable[FileId].DeviceId;
Status = (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
if (Status) {
return Status;
}
//
// Close also the device
//
return FwClose(DeviceId);
}
} else {
return EACCES;
}
}
ARC_STATUS
FwOpen (
IN PCHAR OpenPath,
IN OPEN_MODE OpenMode,
OUT PULONG FileId
)
/*++
Routine Description:
This function opens the file specified by OpenPath.
If the device portion of the pathanme is already opened, it reuses
the fid. Otherwise it looks for a driver able to handle this
device and logs the opened device so that it can be reused.
Arguments:
OpenPath - ARC compliant pathname of the device/file to be opened.
OpenMode - Supplies the mode in wich the file is opened.
FileId - Pointer to a variable that receives the fid for this
pathname.
Return Value:
If the file is successfully opened returns ESUCCESS otherwise
returns an unsuccessfull status.
--*/
{
ULONG i;
ULONG DeviceId;
PCHAR FileName ;
PCHAR TempString1;
PCHAR TempString2;
ARC_STATUS Status;
CHAR DeviceName[80];
PVOID TmpStructureContext;
OPEN_MODE DeviceOpenMode;
#if !defined(FAILSAFE_BOOTER) && defined(EISA_PLATFORM)
BOOLEAN OmfProtocol;
#endif
//
// Split OpenPath into DeviceName and FileName.
// Search for the last ')'
//
FileName = OpenPath;
for (TempString1 = OpenPath; *TempString1; TempString1++) {
if ( *TempString1 == ')') {
FileName = TempString1+1;
}
}
if (FileName == OpenPath) {
return ENODEV;
}
//
// Extract the device pathname, convert it to lower case and
// put zeros where the "key" is not specified.
//
TempString1=DeviceName;
for (TempString2=OpenPath;TempString2 != FileName ;TempString2++) {
//
// If about to copy ')' and previous char was '('
// put a zero in between.
//
if (((*TempString2 == ')') && (*(TempString1-1)) == '(')){
*TempString1++ = '0';
}
*TempString1++ = tolower(*TempString2);
}
*TempString1 = '\0';
//
// Translate the open mode to its equivalent for devices.
//
DeviceOpenMode = OpenMode;
if (FileName[0] == '\0') {
//
// On an attempt to open a device with an invalid OpenMode
// return an error.
//
if (OpenMode > ArcOpenReadWrite) {
return EINVAL;
}
} else {
//
// A file is being opened, set the right Open Mode for the device.
//
if (OpenMode > ArcOpenReadOnly) {
DeviceOpenMode = ArcOpenReadWrite;
}
}
#if !defined(FAILSAFE_BOOTER) && defined(EISA_PLATFORM)
//
// Check for OMF protocol.
//
if ( strstr(DeviceName, ")omf(0)" ) != NULL ) {
OmfProtocol = TRUE;
} else {
OmfProtocol = FALSE;
}
#endif
//
// Search for a matching entry in the table of opened devices.
//
for (DeviceId = 0;DeviceId < SIZE_OF_OPENED_PATHNAME_TABLE;DeviceId++) {
if (strcmp(DeviceName,OpenedPathTable[DeviceId].DeviceName)==0) {
//
// device already opened. Check that it is also opened in
// the same mode.
//
if ((DeviceOpenMode != ArcOpenWriteOnly) && (BlFileTable[DeviceId].Flags.Read != 1)) {
continue;
}
if ((DeviceOpenMode != ArcOpenReadOnly) && (BlFileTable[DeviceId].Flags.Write != 1)) {
continue;
}
//
// If opened for the same Mode then just increment reference counter.
//
OpenedPathTable[DeviceId].ReferenceCounter++;
Status = ESUCCESS;
break;
}
}
if (DeviceId == SIZE_OF_OPENED_PATHNAME_TABLE) {
//
// Device not opened. Look for a driver that handles this device.
//
#if !defined(FAILSAFE_BOOTER) && defined(EISA_PLATFORM)
if ( OmfProtocol ) {
//
// omf protocol, let the omf software layer validate the path.
// Get a free entry in the file table for the device.
//
if ( Status = FiGetFileTableEntry( &DeviceId ) ) {
return Status;
}
BlFileTable[DeviceId].DeviceEntryTable = &OmfEntryTable;
} else {
#else
{
#endif
for (i=0;i < SIZE_OF_LOOKUP_TABLE; i++) {
if (DeviceLookupTable[i].DevicePath == NULL) {
//
// Driver not found
//
return ENODEV;
}
if (strstr(DeviceName,DeviceLookupTable[i].DevicePath) == DeviceName) {
//
// Get a free entry in the file table for the device.
//
if (Status = FiGetFileTableEntry(&DeviceId)) {
return Status;
}
//
// Set the dispatch table in the file table.
//
BlFileTable[DeviceId].DeviceEntryTable = DeviceLookupTable[i].DispatchTable;
break;
}
}
//
// if end of table, drive not found
//
if ( i == SIZE_OF_LOOKUP_TABLE )
{
return ENODEV;
}
}
//
// Call the device specific open routine. Use the DeviceName instead of
// the OpenPath so that the drivers always see a lowercase name.
//
Status = (BlFileTable[DeviceId].DeviceEntryTable->Open)(DeviceName,
DeviceOpenMode,
&DeviceId);
if (Status != ESUCCESS) {
return Status;
}
//
// if the device was successfully opened. Log this device name
// and initialize the file table.
//
strcpy(OpenedPathTable[DeviceId].DeviceName,DeviceName);
OpenedPathTable[DeviceId].ReferenceCounter = 1;
//
// Set flags in file table.
//
BlFileTable[DeviceId].Flags.Open = 1;
if (DeviceOpenMode != ArcOpenWriteOnly) {
BlFileTable[DeviceId].Flags.Read = 1;
}
if (DeviceOpenMode != ArcOpenReadOnly) {
BlFileTable[DeviceId].Flags.Write = 1;
}
//
// Mark this entry in the file table as a device itself.
//
BlFileTable[DeviceId].DeviceId = DEVICE_DEVICE;
BlFileTable[DeviceId].StructureContext = NULL;
}
//
// If we get here the device was successfully open and DeviceId contains
// the entry in the file table for this device.
//
if (FileName[0]) {
//
// Get an entry for the file.
//
if (Status=FiGetFileTableEntry(FileId)) {
FwClose( DeviceId );
return Status;
#if !defined(FAILSAFE_BOOTER) && defined(EISA_PLATFORM)
//
// check if "omf" file system
//
} else if ( OmfProtocol ) {
BlFileTable[ *FileId ].DeviceEntryTable = &OmfFileEntryTable;
#endif
//
// Check if the device has a recognized file system on it. If not
// present, allocate a structure context.
//
} else if (((TmpStructureContext = BlFileTable[DeviceId].StructureContext) == NULL) &&
((TmpStructureContext = FiAllocateFsStructure()) == NULL)) {
FwClose( DeviceId );
return EMFILE;
//
// Check for FAT filesystem.
//
} else if ((BlFileTable[*FileId].DeviceEntryTable =
IsFatFileStructure(DeviceId,TmpStructureContext))
!= NULL) {
BlFileTable[DeviceId].StructureContext = TmpStructureContext;
//
// Check for CD filesystem.
//
} else if ((BlFileTable[*FileId].DeviceEntryTable =
IsCdfsFileStructure(DeviceId,TmpStructureContext))
!= NULL) {
BlFileTable[DeviceId].StructureContext = TmpStructureContext;
#if !defined(FAILSAFE_BOOTER) && !defined(ALPHA_FW_KDHOOKS)
//
// Do not build in this clause if this is a FailSafe Booter build, or
// if we are building in the kernel debugger stub.
//
//
// Check for NTFS filesystem.
//
} else if ((BlFileTable[*FileId].DeviceEntryTable =
IsNtfsFileStructure(DeviceId,TmpStructureContext))
!= NULL) {
BlFileTable[DeviceId].StructureContext = TmpStructureContext;
#endif
} else {
FiFreeFsStructure(TmpStructureContext);
FwClose(DeviceId);
FwPrint(FW_FILESYSTEM_NOT_REQ_MSG);
return EIO;
}
//
// Set the DeviceId in the file table.
//
BlFileTable[*FileId].DeviceId = DeviceId;
//
// Copy the pointer to FatStructureContext from the device entry
// to the file entry.
//
BlFileTable[*FileId].StructureContext = BlFileTable[DeviceId].StructureContext;
Status = (BlFileTable[*FileId].DeviceEntryTable->Open)(FileName,
OpenMode,
FileId);
//
// If the file could not be opened. Then close the device and
// return the error
//
if (Status != ESUCCESS) {
FiFreeFsStructure(TmpStructureContext);
FwClose(DeviceId);
}
return Status;
} else {
//
// No file specified return the fid for the device.
//
*FileId = DeviceId;
return Status;
}
}
ARC_STATUS
FiGetFileTableEntry(
OUT PULONG Entry
)
/*++
Routine Description:
This function looks for an unused entry in the FileTable.
Arguments:
Entry - Pointer to the variable that gets an index for the file table.
Return Value:
Returns ESUCCESS if a free entry is found
or EMFILE if no entry is available.
--*/
{
ULONG Index;
for (Index=0;Index < BL_FILE_TABLE_SIZE;Index++) {
if (BlFileTable[Index].Flags.Open == 0) {
*Entry = Index;
return ESUCCESS;
}
}
return EMFILE;
}
ULONG
FiGetFreeLookupEntry (
VOID
)
/*++
Routine Description:
This routine looks for the first available entry in the device
lookup table, that is the entry where DevicePath is NULL.
Arguments:
None.
Return Value:
Returns the Index of the first free entry of the DeviceLookupTable
or SIZE_OF_LOOKUP_TABLE is the table is full.
--*/
{
ULONG Index;
//
// Search for the first free entry in the Lookup table
//
for (Index=0;Index < SIZE_OF_LOOKUP_TABLE;Index++) {
if (DeviceLookupTable[Index].DevicePath == NULL) {
break;
}
}
return Index;
}
VOID
FwIoInitialize1(
VOID
)
/*++
Routine Description:
This routine initializes the file table used by the firmware to
export I/O functions to client programs loaded from the system
partition, initializes the I/O entry points in the firmware
transfer vector and initializes the display driver.
Note: This routine is called at phase 1 initialization.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Index;
//
// Initialize the I/O entry points in the firmware transfer vector.
//
(PARC_CLOSE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = FwClose;
(PARC_MOUNT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[MountRoutine] = FwMount;
(PARC_OPEN_ROUTINE)SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = FwOpen;
(PARC_READ_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = FwRead;
(PARC_READ_STATUS_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] =
FwGetReadStatus;
(PARC_SEEK_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = FwSeek;
(PARC_WRITE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = FwWrite;
(PARC_GET_FILE_INFO_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetFileInformationRoutine] = FwGetFileInformation;
(PARC_SET_FILE_INFO_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SetFileInformationRoutine] = FwSetFileInformation;
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDirectoryEntryRoutine] = FwGetDirectoryEntry;
//
// Initialize the file table.
//
for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
BlFileTable[Index].Flags.Open = 0;
}
//
// Initialize the driver lookup table.
//
for (Index=0;Index < SIZE_OF_LOOKUP_TABLE;Index++) {
DeviceLookupTable[Index].DevicePath = NULL;
}
//
// Initialize the table of opened devices.
//
for (Index = 0;Index < SIZE_OF_OPENED_PATHNAME_TABLE;Index++) {
OpenedPathTable[Index].DeviceName[0]='\0';
}
//
// Call the Display driver initialization routine
//
DisplayInitialize(&DeviceLookupTable[0],
SIZE_OF_LOOKUP_TABLE);
return;
}
VOID
FwIoInitialize2(
VOID
)
/*++
Routine Description:
This routine calls the device driver initialization routines.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Index;
//
// Call the Keyboard driver initialization routine
//
if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
} else {
KeyboardInitialize(&DeviceLookupTable[Index],
SIZE_OF_LOOKUP_TABLE-Index);
}
//
// Look for first free entry and call
// floppy driver initialization routine
//
if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
} else {
FloppyInitialize(&DeviceLookupTable[Index],
SIZE_OF_LOOKUP_TABLE-Index);
}
//
// Initialize the MasterAdapterObject for the pseudo-Hal support
// functions in jxhwsup.c.
//
MasterAdapterObject = NULL;
for (Index = 0; Index < 8; Index++) {
HalpEisaAdapter[Index] = 0;
}
//
// Initialize global variables. This fixes a bug where the firmware
// will crash after (10/number of SCSI busses) reboots.
// Init is done here since aha154x driver calls scsiportinitialize
// twice (for isa then mca) so can't init this there.
//
for (ScsiPortCount = 0; ScsiPortCount < 10; ScsiPortCount++) {
ScsiPortDeviceObject[ScsiPortCount] = 0;
}
ScsiPortCount = 0;
//
// Call the mini-port driver initialization routine.
//
DriverEntry(NULL, NULL);
//
// Call the scsi driver initialization routine
//
{
//
// This is a temporary bugfix for the FwAddChild failure bug in
// scsidisk.c
//
CHAR ComponentPath[10];
PCONFIGURATION_COMPONENT ControllerComponent;
PCONFIGURATION_COMPONENT ScsiComponent;
PCONFIGURATION_COMPONENT NextComponent;
PCONFIGURATION_COMPONENT PeripheralComponent;
//
// Search the configuration database for scsi disk and cdrom devices and
// delete them.
//
sprintf(ComponentPath,"scsi(%1d)", 0);
ScsiComponent = FwGetComponent(ComponentPath);
if (ScsiComponent != NULL) {
if (ScsiComponent->Type == ScsiAdapter) {
ControllerComponent = FwGetChild(ScsiComponent);
while (ControllerComponent != NULL) {
NextComponent = FwGetPeer(ControllerComponent);
if ((ControllerComponent->Type == DiskController) ||
(ControllerComponent->Type == CdromController)) {
PeripheralComponent = FwGetChild(ControllerComponent);
if (FwDeleteComponent(PeripheralComponent) == ESUCCESS) {
FwDeleteComponent(ControllerComponent);
}
}
ControllerComponent = NextComponent;
}
}
}
FwPrint(FW_DO_NOT_POWER_OFF_MSG);
FwSaveConfiguration();
FwPrint(FW_OK_MSG);
FwPrint(FW_CRLF_MSG);
}
if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
} else {
HardDiskInitialize(&DeviceLookupTable[Index],
SIZE_OF_LOOKUP_TABLE-Index,
NULL);
}
//
// Call the serial port driver initialization routine
//
if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
} else {
SerialInitialize(&DeviceLookupTable[Index],
SIZE_OF_LOOKUP_TABLE-Index);
}
//
// Pre allocate memory for the File system structures.
//
FileSystemStructurePool =
FwAllocatePool(sizeof(FS_POOL_ENTRY) * FS_POOL_SIZE);
return;
}
PVOID
FiAllocateFsStructure(
VOID
)
/*++
Routine Description:
This routine allocates a File System structure
Arguments:
None.
Return Value:
Returns a pointer to the Allocated File System structure or NULL.
--*/
{
PFS_POOL_ENTRY TmpPointer,Last;
if (FileSystemStructurePool == NULL) {
return NULL;
}
TmpPointer = FileSystemStructurePool;
Last = FileSystemStructurePool+FS_POOL_SIZE;
do {
if (TmpPointer->InUse == FALSE) {
TmpPointer->InUse = TRUE;
return &TmpPointer->Fs;
}
TmpPointer++;
} while (TmpPointer != Last);
return NULL;
}
VOID
FiFreeFsStructure(
IN PFILE_SYSTEM_STRUCTURE PFs
)
/*++
Routine Description:
This routine frees a File System structure previously allocated.
Arguments:
PFs pointer to the file system structure to free.
Return Value:
None.
--*/
{
CONTAINING_RECORD(PFs, FS_POOL_ENTRY, Fs)->InUse = FALSE;
return;
}