pciconfig.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,063 行 · 第 1/3 页

C
1,063
字号
    }

    /* work out the interrupt number from the slot/pin */
    interrupt = uHALir_PCIMapInterrupt(pin, curr->slot);

    /*
     * write it to the device (this will be read later by a
     * device driver
     */
    OEM_WriteConfigByte(device->bus, device->slot, device->func,
                       PCI_INTERRUPT_LINE, interrupt);
#endif
}


/*
 *  Routine:     PCI_AllocateIOSpace
 *
 *  Description: Allocate space in PCI IO memory
 *
 *  Returns:     Base address of allocated PCI I/O space
 *
 *  Note:        Calling this code has a side effect of moving the global
 *               IO base on.
 */
static DWORD PCI_AllocateIOSpace(DWORD size)
{
    DWORD base;

    /*
     * 20000329 KWelton
     *
     * I don't see why we need to align to DEFAULT_IO_ALIGNMENT at
     * all - according to the spec we only need to align to the requested
     * size
     */
#ifdef OldCode
    DWORD alignto;

    /* align in minimum sized chunks of DEFAULT_IO_ALIGNMENT */
    alignto = MAX(size, DEFAULT_IO_ALIGNMENT);

    base = ALIGN(PCI_IOBase, alignto);
#else /* OldCode */
    base = ALIGN(PCI_IOBase, size);
#endif /* !def OldCode */

    PCI_IOBase = base + size;

    return base;
}

/*
 *  Routine:     PCI_AllocatePCIDevice
 *
 *  Description: Allocate new PCIDevice structure.
 *
 *  Returns:     Pointer to new structure, or NULL if it fails.
 */
static PCIDevice_t *PCI_AllocatePCIDevice(void)
{
    PCIDevice_t *newDev;

    newDev = freePCIDevices;

    if (newDev != NULL)
    {
        freePCIDevices = newDev->next;

        newDev->flags.bridge = 0;
        newDev->next = NULL;
        newDev->sibling = NULL;
        newDev->parent = NULL;
        newDev->bridge.children = NULL;
    }

    return newDev;
}

/*
 *  Routine:     PCI_InitDevices
 *
 *  Description: Initializes the devNode data structures.
 *
 *  Returns:     Nothing
 *
 */
static void PCI_InitDevices(void)
{
    int i;
    PCIDevice_t *newDev;

    for (i = 0; i < MAX_PCIDEVICES; i++)
    {
        newDev = &StaticPCIDevices[i];
        newDev->next = freePCIDevices;
        freePCIDevices = newDev;
    }

    PCIDevicesInitialised = TRUE;
}

/*
 *  Routine:     PCI_AddPCIDevice
 *
 *  Description: This routine will insert this device into the devNode tree. 
 *               It will keep track of available devNodes. 
 *
 *  returns:     Pointer to new device, NULL if it failed
 */
static PCIDevice_t *PCI_AddPCIDevice(PCIDevice_t *bridge, BYTE bus,
                                     BYTE slot, BYTE func,
                                     WORD vendor, WORD device)
{
    PCIDevice_t *newDev;

    /* first allocate a new one */
    newDev = PCI_AllocatePCIDevice();

    if (newDev != NULL)
    {
        newDev->bus = bus;
        newDev->slot = slot;
        newDev->func = func;
        newDev->vendor = vendor;
        newDev->device = device;

        // enqueue it [1]
        newDev->next = PCIDeviceList;
        PCIDeviceList = newDev;

        // enqueue it [2]
        newDev->sibling = bridge->bridge.children;
        bridge->bridge.children = newDev;
        newDev->parent = bridge;
    }

    return newDev;
}

/*
 *  Routine:     PCI_ScanPCI
 *
 *  Description: This routine will insert all known fixed devices into the
 *               device node tree. It will then scan the PCI buses looking
 *               for valid devices.
 *
 *  Returns:     Number of maximum subordinate bus
 *
 */
static unsigned char PCI_ScanPCI(PCIDevice_t *bus)
{
    UCHAR slot, maxsub;
    UCHAR thisbus = bus->bridge.secondary;
    DWORD maxSlot;

    /* maximum subordinate bus number (used in PCI bus numbering) */
    maxsub = bus->bridge.secondary;

    /*
     * how many slots we scan depends on whether this is the primary
     * PCI bus or we're going through one or more bridges
     */
    maxSlot = (thisbus == 0) ? 20 : 31;

    /* scan all possible buses and slots looking for devices */
    for (slot = 0; slot <= maxSlot; slot++)
    {
        BOOL is_a_multi_function_device = FALSE;
        UCHAR func;

        /* now scan all functions */
        for (func = 0; func < 8; func++)
        {
            WORD vendor, device;
            DWORD devClass;

            /*
             * if it is not a multi-function device, do not
             * treat it as one
             */
            if ((func != 0) && !is_a_multi_function_device)
                break;

            /* read the device configuration space */
            vendor = OEM_ReadConfigWord(thisbus, slot, func, PCI_VENDOR_ID);

            /* check if it responds */
            if (vendor != PCI_NOTFITTED)
            {
                UCHAR header_type;
                PCIDevice_t *newDev;

                /*
                 * read the header type (this may be a multi-function
                 * device)
                 */
                header_type = OEM_ReadConfigByte(thisbus, slot, func,
                                                 PCI_HEADER_TYPE);

                if (func == 0)
                    is_a_multi_function_device = ((header_type & 0x80) != 0);

                /*
                 * get the device and create PCI device data structure
                 */
                device = OEM_ReadConfigWord(thisbus, slot, func,
                                            PCI_DEVICE_ID);

                VDPF("PCI_ScanPCI: Device %x, Vendor %x on %d:%d:%d\n",
                     device, vendor, thisbus, slot, func);

                newDev = PCI_AddPCIDevice(bus, thisbus, slot, func,
                                          vendor, device);

                /*
                 * is it a PCI-PCI bridge (make this a naturally aligned
                 * read)?
                 */
                devClass = (OEM_ReadConfigDword(thisbus, slot, func,
                                                PCI_REV_ID) & 0xFFFFFF00) >> 8;

                if ((devClass >> 16) == PCI_BRIDGE_CLASS)
                {
                    if (((devClass & 0xFF00) >> 8) == 4)
                    {
                        unsigned int buses, command;

                        VDPF( "PCI_ScanPCI found a Bridge.\n" );

                        /* initialise it */
                        newDev->flags.bridge = TRUE;
                        newDev->bridge.secondary =
                            ++maxsub;

                        newDev->bridge.primary = bus->bridge.secondary;

                        /*
                         * temporary subordinate bus number until we
                         * know better
                         */
                        newDev->bridge.subordinate = 0xFF;

                        /*
                         * Clear all status bits, turn of memory, IO and
                         * master enables
                         */
                        command = OEM_ReadConfigDword(thisbus, slot, func,
                                                      PCI_COMMAND);

                        OEM_WriteConfigWord(thisbus, slot, func,
                                            PCI_COMMAND, 0x0000);
                        OEM_WriteConfigWord(thisbus, slot, func,
                                            PCI_STATUS, 0xffff);
                        
                        /* configure the bus numbers for this bridge */

                        /*
                         * 20000329 KWelton
                         *
                         * assign to buses, don't modify an unintialised
                         * variable
                         */
#ifdef OldCode
                        buses &= 0xFF000000;
                        buses |= ((newDev->bridge.primary << 0) |
                                  (newDev->bridge.secondary << 8) |
                                  (newDev->bridge.subordinate << 16));
#else
                        /*
                         * TRACE
                         *
                         * should we set the secondary latency timer?
                         */
                        buses = (newDev->bridge.primary << 0) |
                            (newDev->bridge.secondary << 8) |
                            (newDev->bridge.subordinate << 16);
#endif /* def OldCode */

                        OEM_WriteConfigDword(thisbus, slot, func,
                                             PCI_BUSES_AND_LATENCY, buses);

                        /*
                         * scan all subordinate buses with a recursive
                         * call to this routine
                         */
                        maxsub = PCI_ScanPCI(newDev);

                        /*
                         * set subordinate bus number to its (now
                         * known) value
                         */
                        newDev->bridge.subordinate = maxsub;
                        buses = (buses & 0xff00ffff) | (maxsub << 16);
                        OEM_WriteConfigDword(thisbus, slot, func,
                                             PCI_BUSES_AND_LATENCY, buses);
                    }
                }
            }
        }
    }

    /* all done */
    return maxsub;
}

/*
 * Routine:     PCI_AssignResources
 *
 * Description: This routine will attempt to glean resource requirements
 *              from the device pointed to by handle
 *
 * Returns:     Nothing
 */
static void PCI_AssignResources(PCIDevice_t *device)
{
    unsigned int offset = PCI_MEM_BAR;
    DWORD base, mask, size;
    WORD barFlag = 0;
    int i;
    unsigned int bus, slot, func;

    /* set up the bus, slot and func */
    bus = device->bus;
    slot = device->slot;
    func = device->func;

    /* Disable PCI IO and memory accesses */
    OEM_WriteConfigWord(bus, slot, func, PCI_COMMAND, 0);

    /* allocate an irq number */
    PCI_AllocateInterrupt (device);

    /* Scan each of the BARS for this device */
    for (i = 0; i < PCI_MAX_BAR; i++)
    {
        /*
         * write PCI_INVALID to BAR to get size, then read it back
         */
        OEM_WriteConfigDword(bus, slot, func, offset, PCI_INVALID);
        base = OEM_ReadConfigDword(bus, slot, func, offset);

        /* check if this is an implemented BAR (size != 0) */
        if (base != 0)
        {
            VDPF("    [%d] base: %x\n", i, base);

            /*
             * Assign some PCI memory (IO or Memory) space to this BAR
             */
            if (base & PCI_IO_ENABLE)
            {
                /*
                 * I/O Space BAR
                 *

⌨️ 快捷键说明

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