]> mj.ucw.cz Git - pciutils.git/blobdiff - ls-vpd.c
lib: fixup DOE status register bit
[pciutils.git] / ls-vpd.c
index 36c34c9176903a57f2910a9be19b9b1cb3c44efb..fcb80ae030eabdc2d61378103349908cc58f4f0e 100644 (file)
--- a/ls-vpd.c
+++ b/ls-vpd.c
@@ -4,14 +4,56 @@
  *     Copyright (c) 2008 Solarflare Communications
  *
  *     Written by Ben Hutchings <bhutchings@solarflare.com>
+ *     Improved by Martin Mares <mj@ucw.cz>
  *
- *     Can be freely distributed and used under the terms of the GNU GPL.
+ *     Can be freely distributed and used under the terms of the GNU GPL v2+.
+ *
+ *     SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 #include <stdio.h>
+#include <string.h>
 
 #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)
 {
@@ -20,6 +62,8 @@ print_vpd_string(const byte *buf, word 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
@@ -27,6 +71,18 @@ print_vpd_string(const byte *buf, word len)
     }
 }
 
+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)
 {
@@ -41,7 +97,7 @@ void
 cap_vpd(struct device *d)
 {
   word res_addr = 0, res_len, part_pos, part_len;
-  byte key[2], buf[256];
+  byte buf[256];
   byte tag;
   byte csum = 0;
 
@@ -102,52 +158,50 @@ cap_vpd(struct device *d)
          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;
-             key[0] = buf[0];
-             key[1] = buf[1];
+             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 = (key[0] == 'R' && key[1] == 'V') ? 1 : part_len;
+             read_len = (item->format == F_RESVD) ? 1 : part_len;
              if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
                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: ", key[0], key[1]);
+             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");
-               }
-             else if (key[0] == 'R' && key[1] == 'V')
-               {
-                 /* Reserved and checksum */
-                 printf("\t\t\tRV: checksum %s, %d byte(s) reserved\n",
-                        csum ? "bad" : "good", part_len - 1);
-               }
-             else if (key[0] == 'R' && key[1] == 'W')
-               {
-                 /* Read-write area */
-                 printf("\t\t\tRW: %d byte(s) 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]);
+                 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;
@@ -155,9 +209,9 @@ cap_vpd(struct device *d)
          break;
 
        default:
-         printf("\t\tUnknown %s resource type %02x\n",
+         printf("\t\tUnknown %s resource type %02x, will not decode more.\n",
                 (tag & 0x80) ? "large" : "small", tag & ~0x80);
-         break;
+         return;
        }
 
       res_addr += res_len;