
#define PCI_FIND_CAP_TTL    48

static int __pci_find_next_cap_ttl(PCITAG pciTag, u8_t pos,
                                   int cap, int *ttl)
{
    u8_t id;

    while ((*ttl)--)
    {
        pos = pciReadByte(pciTag, pos);
		if (pos < 0x40)
			break;
		pos &= ~3;
        id = pciReadByte(pciTag, pos + PCI_CAP_LIST_ID);
		if (id == 0xff)
			break;
		if (id == cap)
			return pos;
		pos += PCI_CAP_LIST_NEXT;
	}
	return 0;
}

static int __pci_find_next_cap(PCITAG pciTag, u8_t pos, int cap)
{
	int ttl = PCI_FIND_CAP_TTL;

    return __pci_find_next_cap_ttl(pciTag, pos, cap, &ttl);
}

static int __pci_bus_find_cap_start(PCITAG pciTag)
{
    u16_t status;
    u8_t  hdr_type;

    status = pciReadWord(pciTag, PCI_STATUS);
	if (!(status & PCI_STATUS_CAP_LIST))
		return 0;

    hdr_type = pciReadByte(pciTag, 0x0E);
    switch (hdr_type)
    {
        case PCI_HEADER_TYPE_NORMAL:
        case PCI_HEADER_TYPE_BRIDGE:
            return PCI_CAPABILITY_LIST;
        case PCI_HEADER_TYPE_CARDBUS:
            return PCI_CB_CAPABILITY_LIST;
        default:
            return 0;
	}
	return 0;
}


int pci_find_capability(PCITAG pciTag, int cap)
{
	int pos;

    pos = __pci_bus_find_cap_start(pciTag);
	if (pos)
        pos = __pci_find_next_cap(pciTag, pos, cap);

	return pos;
}


PCITAG pci_find_class(u16_t class)
{
    u32_t bus, last_bus;
    PCITAG tag;

    if( (last_bus = PciApi(1))==-1)
        return -1;

    for(bus=0;bus<=last_bus;bus++)
    {
        u32_t devfn;

        for(devfn=0;devfn<256;devfn++)
        {
            u16_t devclass;

            devclass = PciRead16(bus,devfn, 0x0A);

            if( devclass != class)
                continue;

            return pciTag(bus,(devfn>>3)&0x1F,devfn&0x7);
        };
    };
    return -1;
};


PCITAG pci_get_device(u32_t vendor, u32_t device, PCITAG from)
{
    u32_t bus, last_bus;
    u32_t devfn;

    if( (last_bus = PciApi(1))==-1)
        return -1;

    bus   = PCI_BUS_FROM_TAG(from);
    devfn = PCI_DFN_FROM_TAG(from);

    devfn++;

    for(;bus<=last_bus; bus++)
    {
        for(;devfn < 256;devfn++)
        {
            u32_t tmp;
            u32_t dev_vendor;
            u32_t dev_id;

            tmp = PciRead32(bus,devfn, 0);

            dev_vendor = (u16_t)tmp;
            dev_id = tmp >> 16;

            if ((vendor == PCI_ANY_ID || dev_vendor == vendor))
                return pciTag(bus,(devfn>>3)&0x1F,devfn&0x7);
        };
    };
    return -1;
}

