⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 威盛 wince5.0 bsp 包 for x86 系统, 支持 VT8601 等北桥
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
// -----------------------------------------------------------------------------
//
//      THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//      ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//      THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//      PARTICULAR PURPOSE.
//  
// -----------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <PCIReg.h>
#include <ddkmacro.h>

// -------------------------------------
UCHAR   ucPCIConfigMechanism = 0;

UCHAR   ucPCIMaxDeviceNumber = PCI_MAX_DEVICES;

#define PCI_TYPE1_ADDRESS       0x0CF8
#define PCI_TYPE1_DATA          0x0CFC

// -------------------------------------
typedef struct  _TYPE1_PCI_ADDRESS {
    union {
        struct {
            ULONG   Reserved:2;
            ULONG   Register:6;
            ULONG   Function:3;
            ULONG   Device:5;
            ULONG   Bus:8;
            ULONG   Reserved2:7;
            ULONG   ConfigurationAccess:1;
        } bits;
        ULONG   AsULONG;
    } u;
} TYPE1_PCI_ADDRESS, *PTYPE1_PCI_ADDRESS;

#define PCI_TYPE2_FORWARD       0x0CFA
#define PCI_TYPE2_CSE           0x0CF8

typedef struct  _TYPE2_PCI_CSE {
    union {
        struct {
            UCHAR   SCE:1;
            UCHAR   Function:3;
            UCHAR   Key:4;
        } bits;
        UCHAR   AsUCHAR;
    } u;
} TYPE2_PCI_CSE, *PTYPE2_PCI_CSE;

typedef struct  _TYPE2_PCI_ADDRESS {
    union {
        struct {
            USHORT  Reserved:2;
            USHORT  Register:6;
            USHORT  Device:4;
            USHORT  PCIConfigSpace:4;   // Must be 0xC
        } bits;
        USHORT  AsUSHORT;
    } u;
} TYPE2_PCI_ADDRESS, *PTYPE2_PCI_ADDRESS;

#define	HW_ACCESS_SIZE  (sizeof _inpd ((USHORT) PCI_TYPE1_DATA))	// 32-bit access only
#define	HW_ODD_BITS     (HW_ACCESS_SIZE - 1U)
#define	BITS_PER_BYTE   8U
#define	BYTE_MASK       0xffU

// -----------------------------------------------------------------------------
// Type 1 Configuration:
// Given the bus number, device number, and function number, read or write
// based on the "fWriting" flag "Length" bytes at "ByteOffset" in PCI space.
// Note that on this platform the PCI space exists in X86 IO space and can
// only be accessed as long-words. This routine is responsible for managing
// accesses that are not on long-word boundaries.
// -----------------------------------------------------------------------------
ULONG
PCI_Type1_Configuration(
    IN ULONG     BusNumber,
    IN ULONG     DeviceNumber,
    IN ULONG     FunctionNumber,
    IN OUT PVOID Buffer,
    IN ULONG     ByteOffset,
    IN ULONG     Length,        // Length in bytes to read or write
    IN BOOL      fWriting       // False for read, true for write
    )
{
    TYPE1_PCI_ADDRESS type1Address;
    ULONG             longOffset;	// Hardware can only access longs
    ULONG             value;
    int               bitPosition;
    union {
        ULONG *Long;	// Aligned accesses
        UCHAR *Char;	// Unaligned
    }                 ptr;

    ptr.Long = Buffer;
    longOffset = ByteOffset / HW_ACCESS_SIZE;

    // Construct a PCI address from the various fields.
    type1Address.u.AsULONG = 0UL;
    type1Address.u.bits.ConfigurationAccess = 1UL;
    type1Address.u.bits.Bus = BusNumber;
    type1Address.u.bits.Device = DeviceNumber;
    type1Address.u.bits.Function = FunctionNumber;
    type1Address.u.bits.Register = longOffset;

    //
    // If the offset is not on a long-word boundary,
    // operate on bytes until it is.
    //
    if (ByteOffset & HW_ODD_BITS)
    {
        // Set the PCI address latch in x86 IO space.
        _outpd ((USHORT) PCI_TYPE1_ADDRESS, type1Address.u.AsULONG);

        // Read the long-word from this aligned address.
        value = _inpd ((USHORT) PCI_TYPE1_DATA);

        if (!fWriting)
            value >>= (ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;	// Discard odd bytes read.

        // Operate on the unaligned bytes.
        while ((ByteOffset & HW_ODD_BITS) && (Length > 0UL))
        {
            if (fWriting)
            {
                bitPosition = (int)(ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;
                value &= ~(BYTE_MASK << bitPosition);
                value |= *ptr.Char++ << bitPosition;
            } else {
                *ptr.Char++ = (UCHAR)value;
                value >>= BITS_PER_BYTE;
            }
            ++ByteOffset;
            --Length;
        }
        if (fWriting)
        {
	    // Now write back the full long-word that has the odd bytes.
            _outpd ((USHORT) PCI_TYPE1_DATA, value);
        }
        ++longOffset;
    }

    //
    // Long alignment has been established. Operate on longs now.
    //
    while (Length >= sizeof *ptr.Long)
    {
        // Set the PCI address latch in x86 IO space.
        type1Address.u.bits.Register = longOffset++;
        _outpd ((USHORT) PCI_TYPE1_ADDRESS, type1Address.u.AsULONG);
        if (fWriting)
        {
            _outpd ((USHORT) PCI_TYPE1_DATA, *ptr.Long++);
        } else {
            *ptr.Long++ = _inpd ((USHORT) PCI_TYPE1_DATA);
        }
        Length -= sizeof *ptr.Long;
    }

    //
    // Operate on remaining bytes if the length was not long aligned.
    //
    if (Length > 0UL)
    {
        // Set the PCI address latch in x86 IO space.
        type1Address.u.bits.Register = longOffset;
        _outpd ((USHORT) PCI_TYPE1_ADDRESS, type1Address.u.AsULONG);

        // Read the aligned long-word to operate on the odd bytes.
        value = _inpd ((USHORT) PCI_TYPE1_DATA);

        for (ByteOffset = 0UL; Length > 0UL; ++ByteOffset)
        {
            if (fWriting)
            {
                bitPosition = (int)(ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;
                value &= ~(BYTE_MASK << bitPosition);
                value |= (ULONG)(*ptr.Char++ << bitPosition);
            } else {
                *ptr.Char++ = (UCHAR)(value & BYTE_MASK);
                value >>= BITS_PER_BYTE;
            }
            Length -= sizeof *ptr.Char;
        }
        if (fWriting)
        {
	    // Now write back the full long-word that has the remaining bytes.
            _outpd ((USHORT) PCI_TYPE1_DATA, value);
        }
    }

    return ((ULONG)(ptr.Char - (UCHAR *)Buffer));
}


// -----------------------------------------------------------------------------
// Type 2 Configuration:
// Given the bus number, device number, and function number, read or write
// based on the "fWriting" flag "Length" bytes at "ByteOffset" in PCI space.
// Note that on this platform the PCI space exists in X86 IO space and can
// only be accessed as long-words. This routine is responsible for managing
// accesses that are not on long-word boundaries.
// -----------------------------------------------------------------------------
ULONG
PCI_Type2_Configuration (
    IN ULONG     BusNumber,
    IN ULONG     DeviceNumber,
    IN ULONG     FunctionNumber,
    IN OUT PVOID Buffer,
    IN ULONG     ByteOffset,
    IN ULONG     Length,        // Length in bytes to read or write
    IN BOOL      fWriting       // False for read, true for write
    )
{
    TYPE2_PCI_ADDRESS type2Address;
    TYPE2_PCI_CSE     type2CSE;
    USHORT            longOffset;	// Hardware can only access longs
    ULONG             value;
    int               bitPosition;
    union {
        ULONG *Long;	// Aligned accesses
        UCHAR *Char;	// Unaligned
    }                 ptr;

    ptr.Long = Buffer;
    longOffset = (USHORT)(ByteOffset / HW_ACCESS_SIZE);

    // Construct a PCI address from the various fields.
    type2CSE.u.bits.Key = type2CSE.u.bits.SCE = 0xffU;
    type2CSE.u.bits.Function = (UCHAR)FunctionNumber;

    type2Address.u.AsUSHORT = 0U;
    type2Address.u.bits.PCIConfigSpace = 0xcU;
    type2Address.u.bits.Device = (USHORT)DeviceNumber;
    type2Address.u.bits.Register = longOffset;

    _outp ((USHORT) PCI_TYPE2_FORWARD, (UCHAR) BusNumber);
    _outp ((USHORT) PCI_TYPE2_CSE, type2CSE.u.AsUCHAR);

    //
    // If the offset is not on a long-word boundary,
    // operate on bytes until it is.
    //
    if (ByteOffset & HW_ODD_BITS)
    {
        // Read the long-word from this aligned address.
        value = _inpd (type2Address.u.AsUSHORT);

        if (!fWriting)
            value >>= (ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;	// Discard odd bytes read.

        // Operate on the unaligned bytes.
        while ((ByteOffset & HW_ODD_BITS) && (Length > 0UL))
        {
            if (fWriting)
            {
                bitPosition = (int)(ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;
                value &= ~(BYTE_MASK << bitPosition);
                value |= *ptr.Char++ << bitPosition;
            } else {
                *ptr.Char++ = (UCHAR)value;
                value >>= BITS_PER_BYTE;
            }
            ++ByteOffset;
            --Length;
        }
        if (fWriting)
        {
	    // Now write back the full long-word that has the odd bytes.
          _outpd (type2Address.u.AsUSHORT, value);
        }
        ++longOffset;
    }

    //
    // Long alignment has been established. Operate on longs now.
    //
    while (Length >= sizeof *ptr.Long)
    {
        type2Address.u.bits.Register = longOffset++;
        if (fWriting)
        {
            _outpd (type2Address.u.AsUSHORT, *ptr.Long++);
        } else {
            *ptr.Long++ = _inpd (type2Address.u.AsUSHORT);
        }
        Length -= sizeof *ptr.Long;
    }

    //
    // Operate on remaining bytes if the length was not long aligned.
    //
    if (Length > 0UL)
    {
        // Read the aligned long-word to operate on the odd bytes.
        type2Address.u.bits.Register = longOffset;
        value = _inpd (type2Address.u.AsUSHORT);

        for (ByteOffset = 0UL; Length > 0UL; ++ByteOffset)
        {
            if (fWriting)
            {
                bitPosition = (int)(ByteOffset & HW_ODD_BITS) * BITS_PER_BYTE;
                value &= ~(BYTE_MASK << bitPosition);
                value |= (ULONG)(*ptr.Char++ << bitPosition);
            } else {
                *ptr.Char++ = (UCHAR)(value & BYTE_MASK);
                value >>= BITS_PER_BYTE;
            }
            Length -= sizeof *ptr.Char;
        }
        if (fWriting)
        {
	    // Now write back the full long-word that has the remaining bytes.
            _outpd (type2Address.u.AsUSHORT, value);
        }
    }

    _outp ((USHORT)PCI_TYPE2_CSE, 0);
    _outp ((USHORT)PCI_TYPE2_FORWARD, 0);

    return ((ULONG)(ptr.Char - (UCHAR *)Buffer));
}


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
ULONG
PCIReadBusData(
              IN ULONG BusNumber,
              IN ULONG DeviceNumber,
              IN ULONG FunctionNumber,
              OUT PVOID Buffer,
              IN ULONG Offset,
              IN ULONG Length
              )
{
    BOOL bIntEnable = INTERRUPTS_ENABLE (FALSE);
    switch (ucPCIConfigMechanism) {
    case 1:
        Length = PCI_Type1_Configuration (BusNumber,
            DeviceNumber, FunctionNumber, Buffer, Offset, Length, FALSE);
        break;
    case 2:
        Length = PCI_Type2_Configuration (BusNumber,
            DeviceNumber, FunctionNumber, Buffer, Offset, Length, FALSE);
        break;
    default:
        Length = 0;
    }
    INTERRUPTS_ENABLE(bIntEnable);

    return (Length);
}


ULONG
PCIWriteBusData(
              IN ULONG BusNumber,
              IN ULONG DeviceNumber,
              IN ULONG FunctionNumber,
              IN PVOID Buffer,
              IN ULONG Offset,
              IN ULONG Length
              )
{
    BOOL bIntEnable = INTERRUPTS_ENABLE (FALSE);
    switch (ucPCIConfigMechanism) {
    case 1:
        Length = PCI_Type1_Configuration (BusNumber,
            DeviceNumber, FunctionNumber, Buffer, Offset, Length, TRUE);
        break;
    case 2:
        Length = PCI_Type2_Configuration (BusNumber,
            DeviceNumber, FunctionNumber, Buffer, Offset, Length, TRUE);
        break;
    default:
        Length = 0;
    }
    INTERRUPTS_ENABLE(bIntEnable);

    return (Length);
}


// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
ULONG
PCIGetBusDataByOffset(
                     IN ULONG BusNumber,
                     IN ULONG SlotNumber,
                     IN PVOID Buffer,
                     IN ULONG Offset,
                     IN ULONG Length
                     )
{
    PCI_SLOT_NUMBER     slotNumber;
    
    slotNumber.u.AsULONG = SlotNumber;

    // Since we turn interrupts off in PCIReadBusData/PCIWriteBusData, 
    // we don't need to use CS to serialize the call.

    return (slotNumber.u.bits.DeviceNumber >= ucPCIMaxDeviceNumber)
        ? 0
        : PCIReadBusData (BusNumber, slotNumber.u.bits.DeviceNumber,
                          slotNumber.u.bits.FunctionNumber, Buffer, Offset, Length);
}



// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
ULONG
PCISetBusDataByOffset(
                     IN ULONG BusNumber,
                     IN ULONG SlotNumber,
                     IN PVOID Buffer,
                     IN ULONG Offset,
                     IN ULONG Length
                     )
{
    PCI_SLOT_NUMBER     slotNumber;

    slotNumber.u.AsULONG = SlotNumber;

    // Since we turn interrupts off in PCIReadBusData/PCIWriteBusData, 
    // we don't need to use CS to serialize the call.

    return (slotNumber.u.bits.DeviceNumber >= ucPCIMaxDeviceNumber)
        ? 0
        : PCIWriteBusData (BusNumber, slotNumber.u.bits.DeviceNumber,
                          slotNumber.u.bits.FunctionNumber, Buffer, Offset, Length);
}

BOOL PCIInitConfigMechanism (UCHAR ucConfigMechanism)
{
    ucPCIConfigMechanism = ucConfigMechanism;

    if (ucPCIConfigMechanism == 2) {
        ucPCIMaxDeviceNumber = 16;
    }

    return 0 != ucPCIConfigMechanism;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -