[PATCH 5/5] In verbose mode, display contents of VPD if possible

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux