summaryrefslogtreecommitdiff
path: root/lib/sysfs.c
diff options
context:
space:
mode:
authorAlex Chiang <achiang@hp.com>2008-12-03 12:30:21 -0700
committerMartin Mares <mj@ucw.cz>2008-12-13 00:13:15 +0100
commit2849a16541917b641d861bac8dfadd1056231c12 (patch)
treeb01d9fa4637b8a29a8063d7fc2f702e98e84384b /lib/sysfs.c
parent1d03d3414810f1d1f114e037a0f9b4ba2c993dea (diff)
downloadpciutils-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.c64
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,