]> git.ipfire.org Git - thirdparty/pciutils.git/blame - ls-vpd.c
Decode VPD fully only with -vv or higher.
[thirdparty/pciutils.git] / ls-vpd.c
CommitLineData
c7a34993
MM
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
13static void
14print_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
28static int
29read_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
38void
39cap_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");
746c9057
MM
47 if (verbose < 2)
48 return;
c7a34993
MM
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}