/*++
Copyright (c) 1998-2001  Microsoft Corporation

Module Name:

    ohci1394.c

Abstract:

    1394 Kernel Debugger DLL

Author:

    Peter Binder (pbinder)

Revision   History:
Date       Who       What
---------- --------- ------------------------------------------------------------
06/21/2001 pbinder   having fun...
--*/

#define _OHCI1394_C
#include "pch.h"
#undef _OHCI1394_C

ULONG
FASTCALL
Dbg1394_ByteSwap(
    IN ULONG Source
    )
/*++

Routine Description:

    The RtlUlongByteSwap function exchanges byte pairs 0:3 and 1:2 of
    Source and returns the resulting ULONG.

Arguments:

    Source - 32-bit value to byteswap.

Return Value:

    Swapped 32-bit value.

--*/
{
    ULONG swapped;

    swapped = ((Source)              << (8 * 3)) |
              ((Source & 0x0000FF00) << (8 * 1)) |
              ((Source & 0x00FF0000) >> (8 * 1)) |
              ((Source)              >> (8 * 3));

    return swapped;
} // Dbg1394_ByteSwap

ULONG
Dbg1394_CalculateCrc(
    IN PULONG Quadlet,
    IN ULONG length
    )
/*++

Routine Description:

    This routine calculates a CRC for the pointer to the Quadlet data.

Arguments:

    Quadlet - Pointer to data to CRC

    length - length of data to CRC

Return Value:

    returns the CRC

--*/
{
    LONG temp;
    ULONG index;

    temp = index = 0;

    while (index < length) {

        temp = Dbg1394_Crc16(Quadlet[index++], temp);
    }

    return (temp);
} // Dbg1394_CalculateCrc

ULONG
Dbg1394_Crc16(
    IN ULONG data,
    IN ULONG check
    )
/*++

Routine Description:

    This routine derives the 16 bit CRC as defined by IEEE 1212
    clause 8.1.5.  (ISO/IEC 13213) First edition 1994-10-05.

Arguments:

    data - ULONG data to derive CRC from

    check - check value

Return Value:

    Returns CRC.

--*/
{
    LONG shift, sum, next;

    for (next = check, shift = 28; shift >= 0; shift -= 4) {

        sum = ((next >> 12) ^ (data >> shift)) & 0xf;
        next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ (sum);
    }

    return(next & 0xFFFF);
} // Dbg1394_Crc16

NTSTATUS
Dbg1394_ReadPhyRegister(
    PDEBUG_1394_DATA    DebugData,
    ULONG               Offset,
    PUCHAR              pData
    )
{
    union {
        ULONG                   AsUlong;
        PHY_CONTROL_REGISTER    PhyControl;
    } u;

    ULONG   retry = 0;

    u.AsUlong = 0;
    u.PhyControl.RdReg = TRUE;
    u.PhyControl.RegAddr = Offset;

    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyControl, u.AsUlong);

    retry = MAX_REGISTER_READS;

    do {

        u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyControl);

    } while ((!u.PhyControl.RdDone) && --retry);


    if (!retry) {

        return(STATUS_UNSUCCESSFUL);
    }

    *pData = (UCHAR)u.PhyControl.RdData;
    return(STATUS_SUCCESS);
} // Dbg1394_ReadPhyRegister

NTSTATUS
Dbg1394_WritePhyRegister(
    PDEBUG_1394_DATA    DebugData,
    ULONG               Offset,
    UCHAR               Data
    )
{
    union {
        ULONG                   AsUlong;
        PHY_CONTROL_REGISTER    PhyControl;
    } u;

    ULONG   retry = 0;

    u.AsUlong = 0;
    u.PhyControl.WrReg = TRUE;
    u.PhyControl.RegAddr = Offset;
    u.PhyControl.WrData = Data;

    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyControl, u.AsUlong);

    retry = MAX_REGISTER_READS;

    do {

        u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyControl);

    } while (u.PhyControl.WrReg && --retry);

    if (!retry) {

        return(STATUS_UNSUCCESSFUL);
    }

    return(STATUS_SUCCESS);
} // Dbg1394_WritePhyRegister

BOOLEAN
Dbg1394_InitializeController(
    IN PDEBUG_1394_DATA         DebugData,
    IN PDEBUG_1394_PARAMETERS   DebugParameters
    )
{
    BOOLEAN             bReturn = TRUE;

    ULONG               ulVersion;
    UCHAR               MajorVersion;
    UCHAR               MinorVersion;

    ULONG               ReadRetry;

    PHYSICAL_ADDRESS    physAddr;

    UCHAR               Data;
    NTSTATUS            ntStatus;

    union {
        ULONG                       AsUlong;
        HC_CONTROL_REGISTER         HCControl;
        LINK_CONTROL_REGISTER       LinkControl;
        NODE_ID_REGISTER            NodeId;
        CONFIG_ROM_INFO             ConfigRomHeader;
        BUS_OPTIONS_REGISTER        BusOptions;
        IMMEDIATE_ENTRY             CromEntry;
        DIRECTORY_INFO              DirectoryInfo;
    } u;

    // initialize our bus info
    DebugData->Config.Tag = DEBUG_1394_CONFIG_TAG;
    DebugData->Config.MajorVersion = DEBUG_1394_MAJOR_VERSION;
    DebugData->Config.MinorVersion = DEBUG_1394_MINOR_VERSION;
    DebugData->Config.Id = DebugParameters->Id;
    DebugData->Config.BusPresent = FALSE;
    DebugData->Config.SendPacket = MmGetPhysicalAddress(&DebugData->SendPacket);
    DebugData->Config.ReceivePacket = MmGetPhysicalAddress(&DebugData->ReceivePacket);

    // get our base address
    DebugData->BaseAddress = \
        (POHCI_REGISTER_MAP)DebugParameters->DbgDeviceDescriptor.BaseAddress[0].TranslatedAddress;

    // get our version
    ulVersion = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->Version);

    MajorVersion = (UCHAR)(ulVersion >> 16);
    MinorVersion = (UCHAR)ulVersion;

    // make sure we have a valid version
    if (MajorVersion != 1) { // INVESTIGATE

        bReturn = FALSE;
        goto Exit_Dbg1394_InitializeController;
    }

    // soft reset to initialize the controller
    u.AsUlong = 0;
    u.HCControl.SoftReset = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet, u.AsUlong);

    // wait until reset complete - ??
    ReadRetry = 1000; // ??

    do {

        u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet);
        Dbg1394_StallExecution(1);

    } while ((u.HCControl.SoftReset) && (--ReadRetry));

    // see if reset succeeded
    if (ReadRetry == 0) {

        bReturn = FALSE;
        goto Exit_Dbg1394_InitializeController;
    }

    // what's this do???
    u.AsUlong = 0;
    u.HCControl.Lps = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet, u.AsUlong);

    Dbg1394_StallExecution(20);

    // initialize HCControl register
    u.AsUlong = 0;
    u.HCControl.NoByteSwapData = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlClear, u.AsUlong);

    u.AsUlong = 0;
    u.HCControl.PostedWriteEnable = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet, u.AsUlong);

    // setup the link control
    u.AsUlong = 0x0;
    u.LinkControl.CycleTimerEnable = TRUE;
    u.LinkControl.CycleMaster = TRUE;
    u.LinkControl.RcvPhyPkt = TRUE;
    u.LinkControl.RcvSelfId = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->LinkControlClear, u.AsUlong);

    u.AsUlong = 0;
    u.LinkControl.CycleTimerEnable = TRUE;
    u.LinkControl.CycleMaster = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->LinkControlSet, u.AsUlong);

    // set the bus number (hardcoded to 0x3FF) - ??? what about node id??
    u.AsUlong = 0;
    u.NodeId.BusId = (USHORT)0x3FF;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->NodeId, u.AsUlong);

    // ???????????????
    // IA64 BUGBUG assumes that our global buffers, that were loaded with our 
    // image are placed < 32bit memory
    // ???????????????

    // do something with the crom...

    // 0xf0000404 - bus id register
    DebugData->CromBuffer[1] = 0x31333934;

    // 0xf0000408 - bus options register
    u.AsUlong = Dbg1394_ByteSwap(READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->BusOptions));
    u.BusOptions.Pmc = FALSE;
    u.BusOptions.Bmc = FALSE;
    u.BusOptions.Isc = FALSE;
    u.BusOptions.Cmc = FALSE;
    u.BusOptions.Irmc = FALSE;
    u.BusOptions.g = 1;
    DebugData->CromBuffer[2] = Dbg1394_ByteSwap(u.AsUlong);

    // 0xf000040c - global unique id hi
    u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->GuidHi);
    DebugData->CromBuffer[3] = u.AsUlong;

    // 0xf0000410 - global unique id lo
    u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->GuidLo);
    DebugData->CromBuffer[4] = u.AsUlong;

    // 0xf0000400 - config rom header - set last to calculate CRC!
    u.AsUlong = 0;
    u.ConfigRomHeader.CRI_Info_Length = 4;
    u.ConfigRomHeader.CRI_CRC_Length = 4;
    u.ConfigRomHeader.u.CRI_CRC_Value = (USHORT)Dbg1394_CalculateCrc( &DebugData->CromBuffer[1],
                                                                      u.ConfigRomHeader.CRI_CRC_Length
                                                                      );
    DebugData->CromBuffer[0] = u.AsUlong;

    // 0xf0000418 - node capabilities
    DebugData->CromBuffer[6] = 0xC083000C;

    // 0xf000041C - module vendor id
    DebugData->CromBuffer[7] = 0xF2500003;

    // 0xf0000420 - extended key
    DebugData->CromBuffer[8] = 0xF250001C;

    // 0xf0000424 - debug key
    DebugData->CromBuffer[9] = 0x0200001D;

    // 0xf0000428 - debug value
    physAddr = MmGetPhysicalAddress(&DebugData->Config);
    u.AsUlong = (ULONG)physAddr.LowPart;
    u.CromEntry.IE_Key = 0x1E;
    DebugData->CromBuffer[10] = Dbg1394_ByteSwap(u.AsUlong);

    // 0xf0000414 - root directory header - set last to calculate CRC!
    u.AsUlong = 0;
    u.DirectoryInfo.DI_Length = 5;
    u.DirectoryInfo.u.DI_CRC = (USHORT)Dbg1394_CalculateCrc( &DebugData->CromBuffer[6],
                                                             u.DirectoryInfo.DI_Length
                                                             );
    DebugData->CromBuffer[5] = Dbg1394_ByteSwap(u.AsUlong);

    // write the first few registers
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->ConfigRomHeader, DebugData->CromBuffer[0]);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->BusId, DebugData->CromBuffer[1]);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->BusOptions, DebugData->CromBuffer[2]);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->GuidHi, DebugData->CromBuffer[3]);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->GuidLo, DebugData->CromBuffer[4]);

    // set our crom
    physAddr = MmGetPhysicalAddress(&DebugData->CromBuffer);

    u.AsUlong = (ULONG)physAddr.LowPart; // FIXFIX quadpart to ulong??
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->ConfigRomMap, u.AsUlong);

    // disable all interrupts. wdm driver will enable them later - ??
    u.AsUlong = 0xFFFFFFFF;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->IntMaskClear, u.AsUlong);

    // enable the link
    u.AsUlong = 0;
    u.HCControl.LinkEnable = TRUE;
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet, u.AsUlong);

    Dbg1394_StallExecution(1000);

    // enable access filters to all nodes
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->AsynchReqFilterLoSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->AsynchReqFilterHiSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyReqFilterHiSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyReqFilterLoSet, 0xFFFFFFFF);

    // hard reset on the bus
    ntStatus = Dbg1394_ReadPhyRegister(DebugData, 1, &Data);

    if (NT_SUCCESS(ntStatus)) {

        Data |= PHY_INITIATE_BUS_RESET;
        Dbg1394_WritePhyRegister(DebugData, 1, Data);

        Dbg1394_StallExecution(1000);
    }
    else {

        bReturn = FALSE;
    }

Exit_Dbg1394_InitializeController:

    return(bReturn);
} // Dbg1394_InitializeController

ULONG // ?? need to look into this
Dbg1394_StallExecution(
    ULONG   LoopCount
    )
{
    ULONG i,j,b,k,l;

    b = 1;

    for (k=0;k<LoopCount;k++) {

        for (i=1;i<100000;i++) {

            PAUSE_PROCESSOR
            b=b* (i>>k);
        }
    };

    return(b);
} // Dbg1394_StallExecution

void
Dbg1394_EnablePhysicalAccess(
    IN PDEBUG_1394_DATA     DebugData
    )
{
    union {
        ULONG                       AsUlong;
        INT_EVENT_MASK_REGISTER     IntEvent;
        HC_CONTROL_REGISTER         HCControl;
    } u;

    // see if ohci1394 is being loaded...
    u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->HCControlSet);

    if (!u.HCControl.LinkEnable || !u.HCControl.Lps || u.HCControl.SoftReset) {

        return;
    }

    // only clear the bus reset interrupt if ohci1394 isn't loaded...
//    if (DebugData->Config.BusPresent == FALSE) {

        // if the bus reset interrupt is not cleared, we have to clear it...
        u.AsUlong = READ_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->IntEventSet);

        if (u.IntEvent.BusReset) {

            WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->IntEventClear, PHY_BUS_RESET_INT);
        }
//    }

    // we might need to reenable physical access, if so, do it.
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->AsynchReqFilterHiSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->AsynchReqFilterLoSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyReqFilterHiSet, 0xFFFFFFFF);
    WRITE_REGISTER_ULONG((PULONG)&DebugData->BaseAddress->PhyReqFilterLoSet, 0xFFFFFFFF);

    return;
} // Dbg1394_EnablePhysicalAccess

ULONG
Dbg1394_ReadPacket(
    PDEBUG_1394_DATA    DebugData,
    OUT PKD_PACKET      PacketHeader,
    OUT PSTRING         MessageHeader,
    OUT PSTRING         MessageData,
    BOOLEAN             Wait
    )
//    KDP_PACKET_RESEND - if resend is required.  = 2 = CP_GET_ERROR
//    KDP_PACKET_TIMEOUT - if timeout.            = 1 = CP_GET_NODATA
//    KDP_PACKET_RECEIVED - if packet received.   = 0 = CP_GET_SUCCESS
{
    ULONG   timeoutLimit = 0;

    do {

        // make sure our link is enabled..
        Dbg1394_EnablePhysicalAccess(Kd1394Data);

        if (DebugData->ReceivePacket.TransferStatus == STATUS_PENDING) {

            *KdDebuggerNotPresent = FALSE;
            SharedUserData->KdDebuggerEnabled |= 0x00000002;

            RtlCopyMemory( PacketHeader,
                           &DebugData->ReceivePacket.Packet[0],
                           sizeof(KD_PACKET)
                           );

            // make sure we have a valid PacketHeader
            if (DebugData->ReceivePacket.Length < sizeof(KD_PACKET)) {

                // short packet, we are done...
                DebugData->ReceivePacket.TransferStatus = STATUS_SUCCESS;
                return(KDP_PACKET_RESEND);
            }

            if (MessageHeader) {

                RtlCopyMemory( MessageHeader->Buffer,
                               &DebugData->ReceivePacket.Packet[sizeof(KD_PACKET)],
                               MessageHeader->MaximumLength
                               );

                if (DebugData->ReceivePacket.Length <= (USHORT)(sizeof(KD_PACKET)+MessageHeader->MaximumLength)) {

                    DebugData->ReceivePacket.TransferStatus = STATUS_SUCCESS;
                    return(KDP_PACKET_RECEIVED);
                }

                if (MessageData) {

                    RtlCopyMemory( MessageData->Buffer,
                                   &DebugData->ReceivePacket.Packet[sizeof(KD_PACKET) + MessageHeader->MaximumLength],
                                   DebugData->ReceivePacket.Length - (sizeof(KD_PACKET) + MessageHeader->MaximumLength)
                                   );
                }
            }

            DebugData->ReceivePacket.TransferStatus = STATUS_SUCCESS;
            return(KDP_PACKET_RECEIVED);
        }

        timeoutLimit++;

        if (Wait == FALSE) {

            return(KDP_PACKET_RESEND);
        }

    } while (timeoutLimit <= TIMEOUT_COUNT);

    return(KDP_PACKET_TIMEOUT);
} // Dbg1394_ReadPacket