diff options
author | Alex Chiang <achiang@hp.com> | 2008-12-03 12:30:21 -0700 |
---|---|---|
committer | Martin Mares <mj@ucw.cz> | 2008-12-13 00:13:15 +0100 |
commit | 2849a16541917b641d861bac8dfadd1056231c12 (patch) | |
tree | b01d9fa4637b8a29a8063d7fc2f702e98e84384b /lib/sysfs.c | |
parent | 1d03d3414810f1d1f114e037a0f9b4ba2c993dea (diff) | |
download | pciutils-2849a16541917b641d861bac8dfadd1056231c12.tar.gz |
Display physical slot information in lspci -v
We've been exposing slot information in /sys/bus/pci/slots for a
long time now (as long as a hotplug driver or slot detection
driver like pci_slot is loaded).
Let's make life better for our users and display that information
in lspci. If slot entries appear in /sys/bus/pci/slots/,
correlate them to PCI devices, and display the information when
lspci -v is issued.
If no slot entries appear in sysfs (due to no modules loaded), do
nothing.
Now you'll see sample output like the following:
23:01.1 Class 0c04: Device 10df:fd00 (rev 01)
Subsystem: Device 10df:fd00
Physical Slot: 3
Flags: bus master, 66MHz, medium devsel, latency 248, IRQ 60
...
Signed-off-by: Alex Chiang <achiang@hp.com>
Diffstat (limited to 'lib/sysfs.c')
-rw-r--r-- | lib/sysfs.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/lib/sysfs.c b/lib/sysfs.c index ca43562..5949ff1 100644 --- a/lib/sysfs.c +++ b/lib/sysfs.c @@ -177,6 +177,68 @@ static void sysfs_scan(struct pci_access *a) closedir(dir); } +static void +sysfs_fill_slots(struct pci_dev *d) +{ + struct pci_access *a = d->access; + char dirname[1024]; + DIR *dir; + struct dirent *entry; + int n; + + n = snprintf(dirname, sizeof(dirname), "%s/slots", 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))) + { + char namebuf[OBJNAMELEN], buf[16]; + FILE *file; + unsigned int dom, bus, dev; + struct pci_dev *pd; + int n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address"); + + /* ".", ".." or a special non-device perhaps */ + if (entry->d_name[0] == '.') + continue; + + if (n < 0 || n >= OBJNAMELEN) + d->access->error("File name too long"); + file = fopen(namebuf, "r"); + if (!file) + a->error("Cannot open %s: %s", namebuf, strerror(errno)); + if (!fgets(buf, sizeof(buf), file)) + break; + if (sscanf(buf, "%x:%x:%x", &dom, &bus, &dev) < 3) + a->error("sysfs_scan: Couldn't parse entry address %s", buf); + for (pd = a->devices; pd; pd = pd->next) + { + if (dom == pd->domain && bus == pd->bus && dev == pd->dev && !pd->phy_slot) + { + pd->phy_slot = pci_malloc(a, strlen(entry->d_name) + 1); + sprintf(pd->phy_slot, "%s", entry->d_name); + } + pd->known_fields |= PCI_FILL_PHYS_SLOT; + } + fclose(file); + } + closedir(dir); +} + +static int +sysfs_fill_info(struct pci_dev *d, int flags) +{ + int ret; + + ret = pci_generic_fill_info(d, flags); + if (flags & PCI_FILL_PHYS_SLOT && !(d->known_fields & PCI_FILL_PHYS_SLOT)) + sysfs_fill_slots(d); + + return ret; +} + /* Intent of the sysfs_setup() caller */ enum { @@ -306,7 +368,7 @@ struct pci_methods pm_linux_sysfs = { sysfs_init, sysfs_cleanup, sysfs_scan, - pci_generic_fill_info, + sysfs_fill_info, sysfs_read, sysfs_write, sysfs_read_vpd, |