]> mj.ucw.cz Git - pciutils.git/blob - ls-vpd.c
Decode VPD fully only with -vv or higher.
[pciutils.git] / ls-vpd.c
1 /*
2  *      The PCI Utilities -- Show Vital Product Data
3  *
4  *      Copyright (c) 2008 Ben Hutchings <bhutchings@solarflare.com>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <stdio.h>
10
11 #include "lspci.h"
12
13 static void
14 print_vpd_string(const byte *buf, word len)
15 {
16   while (len--)
17     {
18       byte ch = *buf++;
19       if (ch == '\\')
20         printf("\\\\");
21       else if (ch < 32 || ch == 127)
22         printf("\\x%02x", ch);
23       else
24         putchar(ch);
25     }
26 }
27
28 static int
29 read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum)
30 {
31   if (!pci_read_vpd(d->dev, pos, buf, len))
32     return 0;
33   while (len--)
34     *csum += *buf++;
35   return 1;
36 }
37
38 void
39 cap_vpd(struct device *d)
40 {
41   word res_addr = 0, res_len, part_pos, part_len;
42   byte key[2], buf[256];
43   byte tag;
44   byte csum = 0;
45
46   printf("Vital Product Data\n");
47   if (verbose < 2)
48     return;
49
50   while (res_addr <= PCI_VPD_ADDR_MASK)
51     {
52       if (!read_vpd(d, res_addr, &tag, 1, &csum))
53         break;
54       if (tag & 0x80)
55         {
56           if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3)
57             break;
58           if (!read_vpd(d, res_addr + 1, buf, 2, &csum))
59             break;
60           res_len = buf[0] + (buf[1] << 8);
61           res_addr += 3;
62         }
63       else
64         {
65           res_len = tag & 7;
66           tag >>= 3;
67           res_addr += 1;
68         }
69       if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr)
70         break;
71
72       part_pos = 0;
73
74       switch (tag)
75         {
76         case 0x0f:
77           printf("\t\tEnd\n");
78           return;
79
80         case 0x82:
81           printf("\t\tProduct Name: ");
82           while (part_pos < res_len)
83             {
84               part_len = res_len - part_pos;
85               if (part_len > sizeof(buf))
86                 part_len = sizeof(buf);
87               if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum))
88                 break;
89               print_vpd_string(buf, part_len);
90               part_pos += part_len;
91             }
92           printf("\n");
93           break;
94
95         case 0x90:
96         case 0x91:
97           printf("\t\t%s fields:\n",
98                  (tag == 0x90) ? "Read-only" : "Read/write");
99
100           while (part_pos + 3 <= res_len)
101             {
102               word read_len;
103
104               if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
105                 break;
106               part_pos += 3;
107               key[0] = buf[0];
108               key[1] = buf[1];
109               part_len = buf[2];
110               if (part_len > res_len - part_pos)
111                 break;
112
113               /* Only read the first byte of the RV field because the
114                * remaining bytes are not included in the checksum. */
115               read_len = (key[0] == 'R' && key[1] == 'V') ? 1 : part_len;
116               if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
117                 break;
118
119               if ((key[0] == 'E' && key[1] == 'C') ||
120                   (key[0] == 'P' && key[1] == 'N') ||
121                   (key[0] == 'S' && key[1] == 'N') ||
122                   key[0] == 'V' ||
123                   key[0] == 'Y')
124                 {
125                   /* Alphanumeric content */
126                   printf("\t\t\t%c%c: ", key[0], key[1]);
127                   print_vpd_string(buf, part_len);
128                   printf("\n");
129                 }
130               else if (key[0] == 'R' && key[1] == 'V')
131                 {
132                   /* Reserved and checksum */
133                   printf("\t\t\tRV: checksum %s, %d byte(s) reserved\n",
134                          csum ? "bad" : "good", part_len - 1);
135                 }
136               else if (key[0] == 'R' && key[1] == 'W')
137                 {
138                   /* Read-write area */
139                   printf("\t\t\tRW: %d byte(s) free\n", part_len);
140                 }
141               else
142                 {
143                   /* Binary or unknown content */
144                   int i;
145                   printf("\t\t\t%c%c:", key[0], key[1]);
146                   for (i = 0; i < part_len; i++)
147                     printf(" %02x", buf[i]);
148                   printf("\n");
149                 }
150
151               part_pos += part_len;
152             }
153           break;
154
155         default:
156           printf("\t\tUnknown %s resource type %02x\n",
157                  (tag & 0x80) ? "large" : "small", tag & ~0x80);
158           break;
159         }
160
161       res_addr += res_len;
162     }
163
164   if (res_addr == 0)
165     printf("\t\tNot readable\n");
166   else
167     printf("\t\tNo end tag found\n");
168 }