void pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus) { int dev, multi, ht; struct pci_dev *t; a->debug("Scanning bus %02x for devices...\n", bus); if (busmap[bus]) { a->warning("Bus %02x seen twice (firmware bug). Ignored.", bus); return; } busmap[bus] = 1; t = pci_alloc_dev(a); t->bus = bus; for (dev=0; dev<32; dev++) { t->dev = dev; multi = 0; for (t->func=0; !t->func || multi && t->func<8; t->func++) { u32 vd = pci_read_long(t, PCI_VENDOR_ID); struct pci_dev *d; if (!vd || vd == 0xffffffff) continue; ht = pci_read_byte(t, PCI_HEADER_TYPE); if (!t->func) multi = ht & 0x80; ht &= 0x7f; d = pci_alloc_dev(a); d->bus = t->bus; d->dev = t->dev; d->func = t->func; d->vendor_id = vd & 0xffff; d->device_id = vd >> 16U; d->known_fields = PCI_FILL_IDENT; d->hdrtype = ht; pci_link_dev(a, d); switch (ht) { case PCI_HEADER_TYPE_NORMAL: break; case PCI_HEADER_TYPE_BRIDGE: case PCI_HEADER_TYPE_CARDBUS: pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS)); break; default: a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht); } } } pci_free_dev(t); }
static void proc_scan(struct pci_access *a) { FILE *f; char buf[512]; if (snprintf(buf, sizeof(buf), "%s/devices", pci_get_param(a, "proc.path")) == sizeof(buf)) a->error("File name too long"); f = fopen(buf, "r"); if (!f) a->error("Cannot open %s", buf); while (fgets(buf, sizeof(buf)-1, f)) { struct pci_dev *d = pci_alloc_dev(a); unsigned int dfn, vend, cnt, known; #define F " " PCIADDR_T_FMT cnt = sscanf(buf, "%x %x %x" F F F F F F F F F F F F F F, &dfn, &vend, &d->irq, &d->base_addr[0], &d->base_addr[1], &d->base_addr[2], &d->base_addr[3], &d->base_addr[4], &d->base_addr[5], &d->rom_base_addr, &d->size[0], &d->size[1], &d->size[2], &d->size[3], &d->size[4], &d->size[5], &d->rom_size); #undef F if (cnt != 9 && cnt != 10 && cnt != 17) a->error("proc: parse error (read only %d items)", cnt); d->bus = dfn >> 8U; d->dev = PCI_SLOT(dfn & 0xff); d->func = PCI_FUNC(dfn & 0xff); d->vendor_id = vend >> 16U; d->device_id = vend & 0xffff; known = PCI_FILL_IDENT; if (!a->buscentric) { known |= PCI_FILL_IRQ | PCI_FILL_BASES; if (cnt >= 10) known |= PCI_FILL_ROM_BASE; if (cnt >= 17) known |= PCI_FILL_SIZES; } d->known_fields = known; pci_link_dev(a, d); } fclose(f); }
struct pci_dev * pci_get_dev(struct pci_access *a, word bus, byte dev, byte func) { struct pci_dev *d = pci_alloc_dev(a); d->bus = bus; d->dev = dev; d->func = func; return d; }
struct pci_dev * pci_get_dev(struct pci_access *a, int bus, int dev, int func) { struct pci_dev *d = pci_alloc_dev(a); d->bus = bus; d->dev = dev; d->func = func; return d; }
static void sysfs_scan(struct pci_access *a) { char dirname[1024]; DIR *dir; struct dirent *entry; int n; n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a)); if (n < 0 || n >= (int) sizeof(dirname)) a->error("Directory name too long"); dir = opendir(dirname); if (!dir) a->error("Cannot open %s", dirname); while ((entry = readdir(dir))) { struct pci_dev *d; unsigned int dom, bus, dev, func; /* ".", ".." or a special non-device perhaps */ if (entry->d_name[0] == '.') continue; d = pci_alloc_dev(a); if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name); d->domain = dom; d->bus = bus; d->dev = dev; d->func = func; if (!a->buscentric) { sysfs_get_resources(d); d->irq = sysfs_get_value(d, "irq"); d->known_fields = PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES; #if 0 /* * We prefer reading these from the config registers, it's faster. * However, it would be possible and maybe even useful to hack the kernel * to believe that some device has a different ID. If you do it, just * enable this piece of code. --mj */ d->vendor_id = sysfs_get_value(d, "vendor"); d->device_id = sysfs_get_value(d, "device"); d->known_fields |= PCI_FILL_IDENT; #endif } pci_link_dev(a, d); } closedir(dir); }
static void sysfs_scan(struct pci_access *a) { char dirname[1024]; DIR *dir; struct dirent *entry; int n; n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a)); if (n < 0 || n >= (int) sizeof(dirname)) a->error("Directory name too long"); dir = opendir(dirname); if (!dir) a->error("Cannot open %s", dirname); while ((entry = readdir(dir))) { struct pci_dev *d; unsigned int dom, bus, dev, func; /* ".", ".." or a special non-device perhaps */ if (entry->d_name[0] == '.') continue; d = pci_alloc_dev(a); if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4) a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name); d->domain = dom; d->bus = bus; d->dev = dev; d->func = func; if (!a->buscentric) { sysfs_get_resources(d); d->irq = sysfs_get_value(d, "irq"); /* * We could read these faster from the config registers, but we want to give * the kernel a chance to fix up ID's and especially classes of broken devices. */ d->vendor_id = sysfs_get_value(d, "vendor"); d->device_id = sysfs_get_value(d, "device"); d->device_class = sysfs_get_value(d, "class") >> 8; d->known_fields = PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES; } pci_link_dev(a, d); }