From 7a19c99f661602b67db95fd1d8aca5fe3a387441 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 28 Apr 2024 11:24:33 +0200 Subject: Adding upstream version 1:3.9.0. Signed-off-by: Daniel Baumann --- ls-vpd.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 ls-vpd.c (limited to 'ls-vpd.c') diff --git a/ls-vpd.c b/ls-vpd.c new file mode 100644 index 0000000..92627e4 --- /dev/null +++ b/ls-vpd.c @@ -0,0 +1,222 @@ +/* + * The PCI Utilities -- Show Vital Product Data + * + * Copyright (c) 2008 Solarflare Communications + * + * Written by Ben Hutchings + * Improved by Martin Mares + * + * Can be freely distributed and used under the terms of the GNU GPL. + */ + +#include +#include + +#include "lspci.h" + +/* + * The list of all known VPD items and their formats. + * Technically, this belongs to the pci.ids file, but the VPD does not seem + * to be developed any longer, so we have chosen the easier way. + */ + +enum vpd_format { + F_BINARY, + F_TEXT, + F_RESVD, + F_RDWR, +}; + +static const struct vpd_item { + byte id1, id2; + byte format; + const char *name; +} vpd_items[] = { + { 'C','P', F_BINARY, "Extended capability" }, + { 'E','C', F_TEXT, "Engineering changes" }, + { 'M','N', F_TEXT, "Manufacture ID" }, + { 'P','N', F_TEXT, "Part number" }, + { 'R','V', F_RESVD, "Reserved" }, + { 'R','W', F_RDWR, "Read-write area" }, + { 'S','N', F_TEXT, "Serial number" }, + { 'Y','A', F_TEXT, "Asset tag" }, + { 'V', 0 , F_TEXT, "Vendor specific" }, + { 'Y', 0 , F_TEXT, "System specific" }, + /* Non-standard extensions */ + { 'C','C', F_TEXT, "CCIN" }, + { 'F','C', F_TEXT, "Feature code" }, + { 'F','N', F_TEXT, "FRU" }, + { 'N','A', F_TEXT, "Network address" }, + { 'R','M', F_TEXT, "Firmware version" }, + { 'Z', 0 , F_TEXT, "Product specific" }, + { 0, 0 , F_BINARY, "Unknown" } +}; + +static void +print_vpd_string(const byte *buf, word len) +{ + while (len--) + { + byte ch = *buf++; + if (ch == '\\') + printf("\\\\"); + else if (!ch && !len) + ; /* Cards with null-terminated strings have been observed */ + else if (ch < 32 || ch == 127) + printf("\\x%02x", ch); + else + putchar(ch); + } +} + +static void +print_vpd_binary(const byte *buf, word len) +{ + int i; + for (i = 0; i < len; i++) + { + if (i) + putchar(' '); + printf("%02x", buf[i]); + } +} + +static int +read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum) +{ + if (!pci_read_vpd(d->dev, pos, buf, len)) + return 0; + while (len--) + *csum += *buf++; + return 1; +} + +void +cap_vpd(struct device *d) +{ + word res_addr = 0, res_len, part_pos, part_len; + byte buf[256]; + byte tag; + byte csum = 0; + + printf("Vital Product Data\n"); + if (verbose < 2) + return; + + while (res_addr <= PCI_VPD_ADDR_MASK) + { + if (!read_vpd(d, res_addr, &tag, 1, &csum)) + break; + if (tag & 0x80) + { + if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3) + break; + if (!read_vpd(d, res_addr + 1, buf, 2, &csum)) + 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 (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum)) + break; + print_vpd_string(buf, part_len); + 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) + { + word read_len; + const struct vpd_item *item; + byte id[2], id1, id2; + + if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum)) + break; + part_pos += 3; + memcpy(id, buf, 2); + id1 = id[0]; + id2 = id[1]; + part_len = buf[2]; + if (part_len > res_len - part_pos) + break; + + /* Is this item known? */ + for (item=vpd_items; item->id1 && item->id1 != id1 || + item->id2 && item->id2 != id2; item++) + ; + + /* Only read the first byte of the RV field because the + * remaining bytes are not included in the checksum. */ + read_len = (item->format == F_RESVD) ? 1 : part_len; + if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum)) + break; + + printf("\t\t\t["); + print_vpd_string(id, 2); + printf("] %s: ", item->name); + + switch (item->format) + { + case F_TEXT: + print_vpd_string(buf, part_len); + printf("\n"); + break; + case F_BINARY: + print_vpd_binary(buf, part_len); + printf("\n"); + break; + case F_RESVD: + printf("checksum %s, %d byte(s) reserved\n", csum ? "bad" : "good", part_len - 1); + break; + case F_RDWR: + printf("%d byte(s) free\n", part_len); + break; + } + + part_pos += part_len; + } + break; + + default: + printf("\t\tUnknown %s resource type %02x, will not decode more.\n", + (tag & 0x80) ? "large" : "small", tag & ~0x80); + return; + } + + res_addr += res_len; + } + + if (res_addr == 0) + printf("\t\tNot readable\n"); + else + printf("\t\tNo end tag found\n"); +} -- cgit v1.2.3