567 lines
17 KiB
C
567 lines
17 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
diskc.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This is the NEC PD756 (aka AT, aka ISA, aka ix86) and Intel 82077
|
|||
|
(aka MIPS) floppy diskette detection code for NT. This file also
|
|||
|
collect BIOS disk drive parameters.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Shie-Lin Tzong (shielint) Dec-26-1991.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
x86 real mode.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
//
|
|||
|
// Include files.
|
|||
|
//
|
|||
|
|
|||
|
#include "hwdetect.h"
|
|||
|
#include "disk.h"
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
|
|||
|
FPFWCONFIGURATION_COMPONENT_DATA
|
|||
|
GetFloppyInformation(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine tries to get floppy configuration information.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to a FPCONFIGURATION_COMPONENT_DATA is returned. It is
|
|||
|
the head of floppy component tree root.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR DriveType;
|
|||
|
FPUCHAR ParameterTable;
|
|||
|
FPFWCONFIGURATION_COMPONENT_DATA CurrentEntry, PreviousEntry = NULL;
|
|||
|
FPFWCONFIGURATION_COMPONENT_DATA FirstController = NULL;
|
|||
|
FPFWCONFIGURATION_COMPONENT Component;
|
|||
|
HWCONTROLLER_DATA ControlData;
|
|||
|
UCHAR FloppyNumber = 0;
|
|||
|
UCHAR FloppySkipped = 0;
|
|||
|
UCHAR DiskName[30];
|
|||
|
UCHAR FloppyParmTable[FLOPPY_PARAMETER_TABLE_LENGTH];
|
|||
|
FPUCHAR fpString;
|
|||
|
USHORT Length, z;
|
|||
|
ULONG MaxDensity = 0;
|
|||
|
CM_FLOPPY_DEVICE_DATA far *FloppyData;
|
|||
|
FPHWRESOURCE_DESCRIPTOR_LIST DescriptorList;
|
|||
|
USHORT FloppyDataVersion;
|
|||
|
|
|||
|
for (z = 0; z < FLOPPY_PARAMETER_TABLE_LENGTH; z++ ) {
|
|||
|
FloppyParmTable[z] = 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize Controller data
|
|||
|
//
|
|||
|
|
|||
|
ControlData.NumberPortEntries = 0;
|
|||
|
ControlData.NumberIrqEntries = 0;
|
|||
|
ControlData.NumberMemoryEntries = 0;
|
|||
|
ControlData.NumberDmaEntries = 0;
|
|||
|
z = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for Controller component and initialize it.
|
|||
|
//
|
|||
|
|
|||
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|||
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|||
|
FirstController = CurrentEntry;
|
|||
|
Component = &CurrentEntry->ComponentEntry;
|
|||
|
|
|||
|
Component->Class = ControllerClass;
|
|||
|
Component->Type = DiskController;
|
|||
|
Component->Flags.Removable = 1;
|
|||
|
Component->Flags.Input = 1;
|
|||
|
Component->Flags.Output = 1;
|
|||
|
Component->Version = 0;
|
|||
|
Component->Key = 0;
|
|||
|
Component->AffinityMask = 0xffffffff;
|
|||
|
|
|||
|
//
|
|||
|
// Set up Port information
|
|||
|
//
|
|||
|
|
|||
|
ControlData.NumberPortEntries = 1;
|
|||
|
ControlData.DescriptorList[z].Type = RESOURCE_PORT;
|
|||
|
ControlData.DescriptorList[z].ShareDisposition =
|
|||
|
CmResourceShareDeviceExclusive;
|
|||
|
ControlData.DescriptorList[z].Flags = CM_RESOURCE_PORT_IO;
|
|||
|
ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)0x3f0;
|
|||
|
ControlData.DescriptorList[z].u.Port.Start.HighPart = (ULONG)0;
|
|||
|
ControlData.DescriptorList[z].u.Port.Length = 8;
|
|||
|
z++;
|
|||
|
|
|||
|
//
|
|||
|
// Set up Irq information
|
|||
|
//
|
|||
|
|
|||
|
ControlData.NumberIrqEntries = 1;
|
|||
|
ControlData.DescriptorList[z].Type = RESOURCE_INTERRUPT;
|
|||
|
ControlData.DescriptorList[z].ShareDisposition =
|
|||
|
CmResourceShareUndetermined;
|
|||
|
if (HwBusType == MACHINE_TYPE_MCA) {
|
|||
|
ControlData.DescriptorList[z].Flags = LEVEL_SENSITIVE;
|
|||
|
} else {
|
|||
|
ControlData.DescriptorList[z].Flags = EDGE_TRIGGERED;
|
|||
|
}
|
|||
|
ControlData.DescriptorList[z].u.Interrupt.Level = 6;
|
|||
|
ControlData.DescriptorList[z].u.Interrupt.Vector = 6;
|
|||
|
ControlData.DescriptorList[z].u.Interrupt.Affinity = ALL_PROCESSORS;
|
|||
|
z++;
|
|||
|
|
|||
|
//
|
|||
|
// Set up DMA information. Only set channel number. Timming and
|
|||
|
// transferSize are defaulted - 8 bits and ISA compatible.
|
|||
|
//
|
|||
|
|
|||
|
ControlData.NumberDmaEntries = 1;
|
|||
|
ControlData.DescriptorList[z].Type = RESOURCE_DMA;
|
|||
|
ControlData.DescriptorList[z].ShareDisposition =
|
|||
|
CmResourceShareUndetermined;
|
|||
|
ControlData.DescriptorList[z].Flags = 0;
|
|||
|
ControlData.DescriptorList[z].u.Dma.Channel = (ULONG)2;
|
|||
|
ControlData.DescriptorList[z].u.Dma.Port = 0;
|
|||
|
z++;
|
|||
|
|
|||
|
CurrentEntry->ConfigurationData =
|
|||
|
HwSetUpResourceDescriptor(Component,
|
|||
|
NULL,
|
|||
|
&ControlData,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Collect disk peripheral data
|
|||
|
//
|
|||
|
while (1) {
|
|||
|
_asm {
|
|||
|
push es
|
|||
|
|
|||
|
mov DriveType, 0
|
|||
|
mov FloppyDataVersion, CURRENT_FLOPPY_DATA_VERSION
|
|||
|
|
|||
|
mov ah, 15h
|
|||
|
mov dl, FloppyNumber
|
|||
|
int 13h
|
|||
|
jc short CmosTest
|
|||
|
|
|||
|
cmp ah, 0
|
|||
|
je short Exit
|
|||
|
|
|||
|
cmp ah, 2 ; make sure this is floppy
|
|||
|
ja short Exit
|
|||
|
|
|||
|
mov ah, 8
|
|||
|
mov dl, FloppyNumber
|
|||
|
lea di, word ptr FloppyParmTable ; use 'word ptr' to quiet compiler
|
|||
|
push ds
|
|||
|
pop es ; (es:di)->dummy FloppyParmTable
|
|||
|
int 13h
|
|||
|
jc short CmosTest
|
|||
|
|
|||
|
mov DriveType, bl
|
|||
|
mov ax, es
|
|||
|
mov word ptr ParameterTable + 2, ax
|
|||
|
mov word ptr ParameterTable, di
|
|||
|
jmp short Exit
|
|||
|
|
|||
|
CmosTest:
|
|||
|
|
|||
|
;
|
|||
|
; ifint 13 fails, we know that floppy drive is present.
|
|||
|
;So, we tryto get the Drive Type from CMOS.
|
|||
|
;
|
|||
|
|
|||
|
mov al, CMOS_FLOPPY_CONFIG_BYTE
|
|||
|
mov dx, CMOS_CONTROL_PORT ; address port
|
|||
|
out dx, al
|
|||
|
jmp short delay1 ; I/O DELAY
|
|||
|
delay1:
|
|||
|
mov dx, CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
|
|||
|
in al, dx
|
|||
|
jmp short delay2 ; I/O DELAY
|
|||
|
delay2:
|
|||
|
cmp FloppyNumber, 0
|
|||
|
jne short CmosTest1
|
|||
|
|
|||
|
and al, 0xf0
|
|||
|
shr al, 4
|
|||
|
jmp short Test2Cmos
|
|||
|
|
|||
|
CmosTest1:
|
|||
|
cmp FloppyNumber, 1
|
|||
|
jne short Exit
|
|||
|
|
|||
|
and al, 0xf
|
|||
|
Test2Cmos:
|
|||
|
mov DriveType, al
|
|||
|
mov FloppyDataVersion, 0
|
|||
|
|
|||
|
Exit:
|
|||
|
pop es
|
|||
|
}
|
|||
|
|
|||
|
if (DriveType) {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for first pripheral component and initialize it.
|
|||
|
//
|
|||
|
|
|||
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|||
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|||
|
|
|||
|
Component = &CurrentEntry->ComponentEntry;
|
|||
|
|
|||
|
Component->Class = PeripheralClass;
|
|||
|
Component->Type = FloppyDiskPeripheral;
|
|||
|
Component->Version = 0;
|
|||
|
Component->Key = FloppyNumber - FloppySkipped;
|
|||
|
Component->AffinityMask = 0xffffffff;
|
|||
|
Component->ConfigurationDataLength = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Set up type string.
|
|||
|
//
|
|||
|
|
|||
|
strcpy(DiskName, "FLOPPYx");
|
|||
|
DiskName[6] = FloppyNumber - FloppySkipped + (UCHAR)'1';
|
|||
|
Length = strlen(DiskName) + 1;
|
|||
|
fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
|
|||
|
_fstrcpy(fpString, DiskName);
|
|||
|
Component->IdentifierLength = Length;
|
|||
|
Component->Identifier = fpString;
|
|||
|
|
|||
|
//
|
|||
|
// Set up floppy device specific data
|
|||
|
//
|
|||
|
|
|||
|
switch (DriveType) {
|
|||
|
case 1:
|
|||
|
MaxDensity = 360;
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
MaxDensity = 1200;
|
|||
|
break;
|
|||
|
case 3:
|
|||
|
MaxDensity = 720;
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
MaxDensity = 1440;
|
|||
|
break;
|
|||
|
case 5:
|
|||
|
case 6:
|
|||
|
MaxDensity = 2880;
|
|||
|
break;
|
|||
|
case 0x10:
|
|||
|
//
|
|||
|
// Mark a removable atapi as a super floppy.
|
|||
|
// Enable it to work around the problem of not having
|
|||
|
// a floppy but only a LS-120
|
|||
|
//
|
|||
|
//N.B we can ONLY get away with using the high bit on the
|
|||
|
// superfloppy. SFLOPPY doesn't use this field
|
|||
|
// fdc does, but isn't loaded on these devices!
|
|||
|
//
|
|||
|
MaxDensity=(2880 | 0x80000000);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
MaxDensity = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
|
|||
|
Length = sizeof(CM_FLOPPY_DEVICE_DATA);
|
|||
|
} else {
|
|||
|
Length = (SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime);
|
|||
|
}
|
|||
|
DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
|
|||
|
Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST),
|
|||
|
TRUE);
|
|||
|
CurrentEntry->ConfigurationData = DescriptorList;
|
|||
|
Component->ConfigurationDataLength =
|
|||
|
Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
|
|||
|
DescriptorList->Count = 1;
|
|||
|
DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
|
|||
|
DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
|
|||
|
Length;
|
|||
|
FloppyData = (CM_FLOPPY_DEVICE_DATA far *)(DescriptorList + 1);
|
|||
|
FloppyData->MaxDensity = MaxDensity;
|
|||
|
FloppyData->Version = FloppyDataVersion;
|
|||
|
if (FloppyDataVersion == CURRENT_FLOPPY_DATA_VERSION) {
|
|||
|
_fmemcpy((FPCHAR)&FloppyData->StepRateHeadUnloadTime,
|
|||
|
ParameterTable,
|
|||
|
sizeof(CM_FLOPPY_DEVICE_DATA) -
|
|||
|
(SHORT)&(((CM_FLOPPY_DEVICE_DATA*)0)->StepRateHeadUnloadTime)
|
|||
|
);
|
|||
|
}
|
|||
|
if ((FloppyNumber - FloppySkipped) == 0) {
|
|||
|
FirstController->Child = CurrentEntry;
|
|||
|
} else {
|
|||
|
PreviousEntry->Sibling = CurrentEntry;
|
|||
|
}
|
|||
|
CurrentEntry->Parent = FirstController;
|
|||
|
PreviousEntry = CurrentEntry;
|
|||
|
FloppyNumber++;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// This is a *hack* for ntldr. Here we create a arc name for
|
|||
|
// each bios disks such that ntldr can open them.
|
|||
|
//
|
|||
|
|
|||
|
if (NumberBiosDisks != 0) {
|
|||
|
|
|||
|
for (z = 0; z < NumberBiosDisks; z++) {
|
|||
|
|
|||
|
//
|
|||
|
// Allocate space for disk peripheral component
|
|||
|
//
|
|||
|
|
|||
|
CurrentEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
|
|||
|
sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
|
|||
|
|
|||
|
Component = &CurrentEntry->ComponentEntry;
|
|||
|
|
|||
|
Component->Class = PeripheralClass;
|
|||
|
Component->Type = DiskPeripheral;
|
|||
|
Component->Flags.Input = 1;
|
|||
|
Component->Flags.Output = 1;
|
|||
|
Component->Version = 0;
|
|||
|
Component->Key = z;
|
|||
|
Component->AffinityMask = 0xffffffff;
|
|||
|
|
|||
|
//
|
|||
|
// Set up identifier string = 8 digit signature - 8 digit checksum
|
|||
|
// for example: 00fe964d-005467dd
|
|||
|
//
|
|||
|
|
|||
|
GetDiskId(0x80 + z, DiskName);
|
|||
|
|
|||
|
if (DiskName[0] == (UCHAR)NULL) {
|
|||
|
strcpy(DiskName, "BIOSDISKx");
|
|||
|
DiskName[8] = (UCHAR)z + (UCHAR)'1';
|
|||
|
}
|
|||
|
|
|||
|
Length = strlen(DiskName) + 1;
|
|||
|
fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
|
|||
|
_fstrcpy(fpString, DiskName);
|
|||
|
Component->IdentifierLength = Length;
|
|||
|
Component->Identifier = fpString;
|
|||
|
|
|||
|
//
|
|||
|
// Set up BIOS disk device specific data.
|
|||
|
// (If extended int 13 drive parameters are supported by
|
|||
|
// BIOS, we will collect them and store them here.)
|
|||
|
//
|
|||
|
|
|||
|
if (IsExtendedInt13Available(0x80+z)) {
|
|||
|
DescriptorList = (FPHWRESOURCE_DESCRIPTOR_LIST)HwAllocateHeap(
|
|||
|
sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
|
|||
|
sizeof(CM_DISK_GEOMETRY_DEVICE_DATA),
|
|||
|
TRUE);
|
|||
|
Length = GetExtendedDriveParameters(
|
|||
|
0x80 + z,
|
|||
|
(CM_DISK_GEOMETRY_DEVICE_DATA far *)(DescriptorList + 1)
|
|||
|
);
|
|||
|
if (Length) {
|
|||
|
CurrentEntry->ConfigurationData = DescriptorList;
|
|||
|
Component->ConfigurationDataLength =
|
|||
|
Length + sizeof(HWRESOURCE_DESCRIPTOR_LIST);
|
|||
|
DescriptorList->Count = 1;
|
|||
|
DescriptorList->PartialDescriptors[0].Type = RESOURCE_DEVICE_DATA;
|
|||
|
DescriptorList->PartialDescriptors[0].u.DeviceSpecificData.DataSize =
|
|||
|
Length;
|
|||
|
} else {
|
|||
|
HwFreeHeap(sizeof(HWRESOURCE_DESCRIPTOR_LIST) +
|
|||
|
sizeof(CM_DISK_GEOMETRY_DEVICE_DATA));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (PreviousEntry == NULL) {
|
|||
|
FirstController->Child = CurrentEntry;
|
|||
|
} else {
|
|||
|
PreviousEntry->Sibling = CurrentEntry;
|
|||
|
}
|
|||
|
CurrentEntry->Parent = FirstController;
|
|||
|
PreviousEntry = CurrentEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
return (FirstController);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
#pragma warning(4:4146) // unary minus operator applied to unsigned type (checksum on line 733)
|
|||
|
VOID
|
|||
|
GetDiskId(
|
|||
|
USHORT Disk,
|
|||
|
PUCHAR Identifier
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine reads the master boot sector of the specified harddisk drive,
|
|||
|
compute the checksum of the sector to form a drive identifier.
|
|||
|
|
|||
|
The identifier will be set to "8-digit-checksum"+"-"+"8-digit-signature"
|
|||
|
For example: 00ff6396-6549071f
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Disk - supplies the BIOS drive number, i.e. 80h - 87h
|
|||
|
|
|||
|
Identifier - Supplies a buffer to receive the disk id.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None. In the worst case, the Identifier will be empty.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UCHAR Sector[512];
|
|||
|
ULONG Signature, Checksum;
|
|||
|
USHORT i, Length;
|
|||
|
PUCHAR BufferAddress;
|
|||
|
BOOLEAN Fail;
|
|||
|
|
|||
|
Identifier[0] = 0;
|
|||
|
BufferAddress = &Sector[0];
|
|||
|
Fail = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// Read in the first sector
|
|||
|
//
|
|||
|
|
|||
|
_asm {
|
|||
|
push es
|
|||
|
mov ax, 0x201
|
|||
|
mov cx, 1
|
|||
|
mov dx, Disk
|
|||
|
push ss
|
|||
|
pop es
|
|||
|
mov bx, BufferAddress
|
|||
|
int 0x13
|
|||
|
pop es
|
|||
|
jnc Gdixxx
|
|||
|
|
|||
|
mov Fail, 1
|
|||
|
Gdixxx:
|
|||
|
}
|
|||
|
|
|||
|
if (Fail) {
|
|||
|
#if DBG
|
|||
|
// could not get the sector, so return NULL DiskID
|
|||
|
BlPrint("Failed to read sector -- returning NULL DiskId\n");
|
|||
|
#endif
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
|
|||
|
|
|||
|
//
|
|||
|
// compute the checksum
|
|||
|
//
|
|||
|
|
|||
|
Checksum = 0;
|
|||
|
for (i = 0; i < 128; i++) {
|
|||
|
Checksum += ((PULONG)Sector)[i];
|
|||
|
}
|
|||
|
Checksum = -Checksum;
|
|||
|
|
|||
|
//
|
|||
|
// Zero the identifier
|
|||
|
//
|
|||
|
|
|||
|
for (i=0; i < 30; i++) {
|
|||
|
Identifier[i]='0';
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Put the dashes in the right places.
|
|||
|
//
|
|||
|
|
|||
|
Identifier[8] = '-';
|
|||
|
Identifier[17] = '-';
|
|||
|
|
|||
|
//
|
|||
|
// If the boot sector has a valid partition table signature,
|
|||
|
// attach an 'A.' Otherwise we use 'X.'
|
|||
|
//
|
|||
|
|
|||
|
if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
|
|||
|
Identifier[18]='X';
|
|||
|
} else {
|
|||
|
Identifier[18]='A';
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reuse sector buffer to build checksum string.
|
|||
|
//
|
|||
|
|
|||
|
ultoa(Checksum, Sector, 16);
|
|||
|
Length = strlen(Sector);
|
|||
|
|
|||
|
for (i=0; i<Length; i++) {
|
|||
|
Identifier[7-i] = Sector[Length-i-1];
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reuse sector buffer to build signature string.
|
|||
|
//
|
|||
|
|
|||
|
ultoa(Signature, Sector, 16);
|
|||
|
Length = strlen(Sector);
|
|||
|
|
|||
|
for (i=0; i<Length; i++) {
|
|||
|
Identifier[16-i] = Sector[Length-i-1];
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Terminate string.
|
|||
|
//
|
|||
|
|
|||
|
Identifier[19] = 0;
|
|||
|
|
|||
|
#if DBG
|
|||
|
BlPrint("%s\n", Identifier);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
|