Signed-off-by: Ben Hutchings <bhutchings@xxxxxxxxxxxxxx> --- lspci.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 106 insertions(+), 1 deletions(-) diff --git a/lspci.c b/lspci.c index ddedb42..eb5117d 100644 --- a/lspci.c +++ b/lspci.c @@ -458,6 +458,111 @@ cap_agp(struct device *d, int where, int cap) } static void +cap_vpd(struct device *d) +{ + word res_addr = 0, res_len, part_pos, part_len; + byte key[2], buf[256]; + byte tag; + + printf("Vital Product Data\n"); + + while (res_addr <= PCI_VPD_ADDR_MASK) { + if (!pci_read_vpd(d->dev, res_addr, &tag, 1)) + break; + if (tag & 0x80) { + if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3) + break; + if (!pci_read_vpd(d->dev, res_addr + 1, buf, 2)) + break; + res_len = buf[0] + (buf[1] << 8); + res_addr += 3; + } else { + res_len = tag & 7; + tag >>= 3; + res_addr += 1; + } + if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr) + break; + + part_pos = 0; + + switch (tag) { + case 0x0f: + printf("\t\tEnd\n"); + return; + + case 0x82: + printf("\t\tProduct Name: "); + while (part_pos < res_len) { + part_len = res_len - part_pos; + if (part_len > sizeof(buf)) + part_len = sizeof(buf); + if (!pci_read_vpd(d->dev, res_addr + part_pos, buf, part_len)) + break; + fwrite(buf, 1, part_len, stdout); + part_pos += part_len; + } + printf("\n"); + break; + + case 0x90: + case 0x91: + printf("\t\t%s fields:\n", (tag == 0x90) ? "Read-only" : "Read/write"); + + while (part_pos + 3 <= res_len) { + if (!pci_read_vpd(d->dev, res_addr + part_pos, buf, 3)) + break; + part_pos += 3; + key[0] = buf[0]; + key[1] = buf[1]; + part_len = buf[2]; + if (part_len > res_len - part_pos) + break; + if (!pci_read_vpd(d->dev, res_addr + part_pos, buf, part_len)) + break; + + if ((key[0] == 'E' && key[1] == 'C') || + (key[0] == 'P' && key[1] == 'N') || + (key[0] == 'S' && key[1] == 'N') || + key[0] == 'V' || + key[0] == 'Y') { + /* Alphanumeric content */ + printf("\t\t\t%c%c: %.*s\n", key[0], key[1], part_len, buf); + } else if (key[0] == 'R' && key[1] == 'V') { + /* Reserved and checksum */ + /* XXX should verify checksum? */ + } else if (key[0] == 'R' && key[1] == 'W') { + /* Read-write area */ + printf("\t\t\tRW: %d bytes free\n", part_len); + } else { + /* Binary or unknown content */ + int i; + printf("\t\t\t%c%c:", key[0], key[1]); + for (i = 0; i < part_len; i++) + printf(" %02x", buf[i]); + printf("\n"); + } + + part_pos += part_len; + } + break; + + default: + printf("\t\tUnknown %s resource type %02x\n", + (tag & 0x80) ? "large" : "small", tag & ~0x80); + break; + } + + res_addr += res_len; + } + + if (res_addr == 0) + printf("\t\tNot readable\n"); + else + printf("\t\tNo end tag found\n"); +} + +static void cap_pcix_nobridge(struct device *d, int where) { u16 command; @@ -1747,7 +1852,7 @@ show_caps(struct device *d) cap_agp(d, where, cap); break; case PCI_CAP_ID_VPD: - printf("Vital Product Data <?>\n"); + cap_vpd(d); break; case PCI_CAP_ID_SLOTID: cap_slotid(cap); -- Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked. -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html