/*++

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"
#if defined(NEC_98)
#include "string.h"
#else // PC98
#include <string.h>

#endif // PC98

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 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;

#if defined(NEC_98)
    USHORT  DiskEquips;
    USHORT  Disk2HC;
    UCHAR   Counter = 0;
    BOOLEAN FdIoLocked = FALSE;
    UCHAR   status;
    UCHAR   driveExchange;

    DiskEquips = DISK_EQUIPS_FD;
    Disk2HC    = DISK_2HC;

    if ( (COM_ID_L == 0x98) && (COM_ID_H == 0x21) &&
         (ROM_FLAG7 & LOCKED_FD) ){

        FdIoLocked = TRUE;

    }
#endif // PC98
    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;
#if defined(NEC_98)
    ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)0x90;
#else // PC98
    ControlData.DescriptorList[z].u.Port.Start.LowPart = (ULONG)0x3f0;
#endif // PC98
    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;
    }
#if defined(NEC_98)
    ControlData.DescriptorList[z].u.Interrupt.Level = 11;
    ControlData.DescriptorList[z].u.Interrupt.Vector = 0x13;
#else // PC98
    ControlData.DescriptorList[z].u.Interrupt.Level = 6;
    ControlData.DescriptorList[z].u.Interrupt.Vector = 6;
#endif // PC98
    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
                                              );

#if _GAMBIT_
    //
    // Supply the DriveTypeValue that is supplied by the following IA
    // assembly programs.
    //
    DriveType = 0;
    FloppyDataVersion = 0;
    ParameterTable = NULL;
    
    //
    // Collect disk peripheral data
    //

    while (1) {
#else
#if defined(NEC_98)

        DriveType = 0;
        FloppyDataVersion = 0;
        driveExchange = 0;

        if ( DiskEquips & 0x0F ) {

            //
            // Check drive exchange.
            //
            status = READ_PORT_UCHAR((PUCHAR)0x94) & 0x04;

            if ( status == 0 ) {

                //
                // internal drive is #3/#4.
                //
                driveExchange = 1;
            }
        }

        if ( !(FdIoLocked) && Counter < 4 ){

            if ( DiskEquips & (1 << Counter ) ){

                //
                // Check internal drive or extension drive.
                //

                if ( (Counter / (UCHAR)2) == driveExchange ) {
                    if (Disk2HC & (1 << Counter)) {
                        //
                        // 1.44MB drive
                        //
                        DriveType = 4;

                    } else {
                        //
                        // 1.2MB drive
                        //
                        DriveType = 2;
                    }

                } else {
                    //
                    // 1.2MB extension drive.
                    //
                    DriveType = 7;
                }

                Counter++;

            } else {
                Counter++;
                continue;
            }
        }

#else // PC98
        _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:

            ;
            ; if int 13 fails, we know that floppy drive is present.
            ; So, we try to get the Drive Type from CMOS.
            ;

            mov     al, CMOS_FLOPPY_CONFIG_BYTE
            mov     dx, CMOS_CONTROL_PORT   ; address port
            out     dx, al
            jmp     $ + 2                   ; I/O DELAY
            mov     dx, CMOS_DATA_PORT      ; READ IN REQUESTED CMOS DATA
            in      al, dx
            jmp     $ + 2                   ; I/O DELAY

            cmp     FloppyNumber, 0
            jne     short CmosTest1

            and     al, 0xf0
            shr     al, 4
            jmp     short CmosTest2

        CmosTest1:
            cmp     FloppyNumber, 1
            jne     short Exit

            and     al, 0xf
        CmosTest2:
            mov     DriveType, al
            mov     FloppyDataVersion, 0
        Exit:
            pop     es
        }
#endif // PC98
#endif // _GAMBIT_

        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;
            Component->AffinityMask = 0xffffffff;
            Component->ConfigurationDataLength = 0;

            //
            // Set up type string.
            //

            strcpy(DiskName, "FLOPPYx");
            DiskName[6] = FloppyNumber + (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;
#if defined(NEC_98)
            case 7:
                MaxDensity = 1201;
                break;
#endif
            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 == 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((USHORT)(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;

#if defined(NEC_98)
#else // PC98
#if !defined(_GAMBIT_)
                    //
                    // 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));
                        }
                    }
#endif // _GAMBIT_
#endif // PC98

                    if (PreviousEntry == NULL) {
                        FirstController->Child = CurrentEntry;
                    } else {
                        PreviousEntry->Sibling = CurrentEntry;
                    }
                    CurrentEntry->Parent = FirstController;
                    PreviousEntry = CurrentEntry;
                }
            }
            return(FirstController);
        }
    }
}

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.

--*/

{
#if defined(_GAMBIT_)
    Identifier = NULL;
#else
#if defined(NEC_98)
    USHORT BootRecordSignature;    // Boot Record Signature (0x55aa)
    UCHAR  diskNumber;
    UCHAR Sector[1024];
#else // PC98
    UCHAR Sector[512];
#endif // PC98
    ULONG Signature, Checksum;
    USHORT i, Length;
    PUCHAR BufferAddress;
    BOOLEAN Fail;

    Identifier[0] = 0;
    BufferAddress = &Sector[0];
    Fail = FALSE;

    //
    // Read in the first sector
    //

#if defined(NEC_98)
    //
    // We can't access over 4GB except relative access.
    // Therefore we use a relative(Sequential) access.
    //
    Disk &= 0x7F;
    diskNumber = (UCHAR)Disk;

    //
    //   Read sectors (NTFS Signature)
    //
    _asm {
          push    es
          mov     ah, 0x06             //  Disk read command
          mov     al, diskNumber       //  Disk No (00,01)
          mov     bx, 512              //  Data length
          mov     cx, 0x10             //  Sector LSW
          mov     dx, 0x00             //  Sector HSW
          push    ss
          pop     es
          push    bp
          mov     bp, BufferAddress    // ES:BP Buffer address
          int     0x1b
          pop     bp
          pop     es
          jnc     Gdi000

          mov     Fail, 1
    Gdi000:
    }
#else // PC98
    _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:
    }
#endif // PC98

    if (Fail) {
#if DBG
        // could not get the sector, so return NULL DiskID
        BlPrint("Failed to read sector -- returning NULL DiskId\n");
#endif        
        return;
    }

#if defined(NEC_98)
    //
    //  Get the NTFS Sinature
    //
    if (((PUSHORT)Sector)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE) {
        Signature = 0;
    } else {
        Signature = ((PULONG)Sector)[0];
    }
#else // PC98
    Signature = ((PULONG)Sector)[PARTITION_TABLE_OFFSET/2-1];
#endif // PC98

    //
    // compute the checksum
    //
#if defined(NEC_98)
    //
    //  Read No 0 and 1 sectors. (for Check Sum)
    //
    _asm {
        push    es
        mov     ah, 0x06              //  Disk read command
        mov     al, diskNumber        //  Disk No (00,01)
        mov     bx, 512 * 2           //  Data length
        mov     cx, 0x00              //  Sector LSW
        mov     dx, 0x00              //  Sector HSW
        push    ss
        pop     es
        push    bp
        mov     bp, BufferAddress     // ES:BP Buffer address
        int     1bh
        pop     bp
        pop     es
        jnc     Gdi001

        mov     Fail, 1
    Gdi001:
    }


    if (Fail) {
        return;
    }
#endif // PC98


    Checksum = 0;
    for (i = 0; i < 128; i++) {
#if defined(NEC_98)
        Checksum += ((PULONG)Sector)[ i + 512/4 ];
#else // PC98
        Checksum += ((PULONG)Sector)[i];
#endif // PC98
    }
    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

#endif // _GAMBIT_
}


#if defined(NEC_98)
//
//  This section was used to get some SCSI disks' information connecting to
//  SCSI board that is includeing boot up disk.
//
//  These information was very important when do FD-less setup.
//
//  When the HIPER SCSI BIOS for array disk is abailable, it is useing a
//  trick to show two scsi board as one scsi board accessing through BIOS
//  functions.
//
//  We must separete information per board from the two boards' information.
//

BOOLEAN
BootedFromScsiDisk(
    PUSHORT     pFakeScsiId,
    PUSHORT     pNumberScsiDisks,
    PUSHORT     pScsiDisksMap
    )
{

    USHORT      DauaBootedFrom;
    USHORT      StartPosition = 0;
    USHORT      EndPosition = SCSI_MAX_ID;
    USHORT      tmp, i;


    DauaBootedFrom = DAUA_BOOTED_FROM;

    *pFakeScsiId = 0;
    *pNumberScsiDisks = 0;
    *pScsiDisksMap = DISK_EQUIPS_SCSI;

    if (!(DauaBootedFrom & DASCSI)){
        return (FALSE);
    }


    if ((EQUIPS_47Ch == (USHORT)0) && ((*pScsiDisksMap & 0x80) == 0)) {
        //
        //  Array SCSI BIOS was available.
        //

        if (H_DISK_EQUIPS_L != (USHORT)0){      // we do not need high byte.

            tmp = H_EQUIPS;
            for ( i = 0; i < SCSI_MAX_ID; i++ ){
              if ( tmp & (1 << i)) (*pFakeScsiId)++;
            }

            if ( (DauaBootedFrom & UA_MASK) >= *pFakeScsiId ){
                //
                //  System was booted from disk connected array scsi card.
                //

                StartPosition = *pFakeScsiId;
                EndPosition = SCSI_MAX_ID;

            } else {
                //
                //  System was booted from disk connected normal scsi card.
                //

                StartPosition = 0;
                EndPosition = *pFakeScsiId;
                *pFakeScsiId = 0;       // Reset

            }
        }
    }

    for ( i = StartPosition; i < EndPosition; i++ ){
        if ( *pScsiDisksMap & (1 << i)) (*pNumberScsiDisks)++;
    }

    *pFakeScsiId |= 0xA0;

    return(TRUE);
}


FPFWCONFIGURATION_COMPONENT_DATA
GetScsiDiskInformation(
    VOID
    )

/*++

Routine Description:

    This routine tries to get SCSI Disk configuration information.

Arguments:

    None.

Return Value:

    A pointer to a FPCONFIGURATION_COMPONENT_DATA is returned.  It is
    the head of floppy component tree root.

--*/

{
    FPFWCONFIGURATION_COMPONENT_DATA ControllerEntry, PreviousEntry = NULL;
    FPFWCONFIGURATION_COMPONENT_DATA PeripheralEntry;
    FPFWCONFIGURATION_COMPONENT_DATA FirstController = NULL;
    FPFWCONFIGURATION_COMPONENT_DATA AdapterEntry;
    FPFWCONFIGURATION_COMPONENT Component;
    CHAR Identifier[256];
    UCHAR DiskName[30];
    FPUCHAR fpString;
    USHORT Length;
    FPCHAR IdentifierString;

    USHORT  DiskCount, Id;

    USHORT  FakeScsiId;
    USHORT  NumberScsiDisks;
    USHORT  ScsiDisksMap;


    if (!BootedFromScsiDisk( &FakeScsiId, &NumberScsiDisks, &ScsiDisksMap )){
        return (NULL);
    }

    //
    // Allocate space for Controller component and initialize it.
    //

    AdapterEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
                   sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);
    FirstController = AdapterEntry;

    Component = &AdapterEntry->ComponentEntry;
    Component->Class = AdapterClass;
    Component->Type = ScsiAdapter;

    strcpy (Identifier, "SCSI");
    Length = strlen(Identifier) + 1;
    IdentifierString = (FPCHAR)HwAllocateHeap(Length, FALSE);
    _fstrcpy(IdentifierString, Identifier);

    Component->Version = 0;
    Component->Key = 0;
    Component->AffinityMask = 0xffffffff;
    Component->IdentifierLength = Length;
    Component->Identifier = IdentifierString;

    AdapterEntry->ConfigurationData = NULL;
    Component->ConfigurationDataLength = 0;

    for ( DiskCount = 0, Id = 0; DiskCount < NumberScsiDisks && Id < 7 ; Id++ ) {

        if ( !(ScsiDisksMap & (1 << (FakeScsiId + Id)))){
            continue;
        }

        //
        // Allocate space for disk peripheral component
        //

        ControllerEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
                        sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);

        Component = &ControllerEntry->ComponentEntry;

        Component->Class = ControllerClass;
        Component->Type = DiskController;
        Component->Flags.Input = 1;
        Component->Flags.Output = 1;
        Component->Version = 0;
        Component->Key = Id;
        Component->AffinityMask = 0xffffffff;

        ControllerEntry->ConfigurationData = NULL;

        //
        // Set up identifier string = 8 digit signature - 8 digit checksum
        // for example: 00fe964d-005467dd
        //

        GetDiskId(FakeScsiId + Id, DiskName);
        if (DiskName[0] == (UCHAR)NULL) {
            strcpy(DiskName, "BIOSDISKx");
            DiskName[8] = (UCHAR)DiskCount + (UCHAR)'1';
        }
        Length = strlen(DiskName) + 1;
        fpString = (FPUCHAR)HwAllocateHeap(Length, FALSE);
        _fstrcpy(fpString, DiskName);
        Component->IdentifierLength = Length;
        Component->Identifier = fpString;


        //
        // Create Peripheral Entry
        //

        PeripheralEntry = (FPFWCONFIGURATION_COMPONENT_DATA)HwAllocateHeap (
                          sizeof(FWCONFIGURATION_COMPONENT_DATA), TRUE);

        Component = &PeripheralEntry->ComponentEntry;
        Component->Class = PeripheralClass;
        Component->Type = DiskPeripheral;
        Component->Flags.Input = 1;
        Component->Flags.Output = 1;
        Component->Version = 0;
        Component->Key = 0;
        Component->AffinityMask = 0xffffffff;

        PeripheralEntry->ConfigurationData = NULL;

        Component->IdentifierLength = Length;
        Component->Identifier = fpString;

        PeripheralEntry->Parent = ControllerEntry;
        ControllerEntry->Child = PeripheralEntry;


        if (PreviousEntry == NULL) {
            FirstController->Child = ControllerEntry;
        } else {
            PreviousEntry->Sibling = ControllerEntry;
        }

        ControllerEntry->Parent = FirstController;
        PreviousEntry = ControllerEntry;

        DiskCount++;
    }

    return(FirstController);
}

#endif // PC98