]> git.ipfire.org Git - thirdparty/pciutils.git/blob - ls-vpd.c
Merge remote-tracking branch 'pali/win32-cfgmgr32'
[thirdparty/pciutils.git] / ls-vpd.c
1 /*
2 * The PCI Utilities -- Show Vital Product Data
3 *
4 * Copyright (c) 2008 Solarflare Communications
5 *
6 * Written by Ben Hutchings <bhutchings@solarflare.com>
7 * Improved by Martin Mares <mj@ucw.cz>
8 *
9 * Can be freely distributed and used under the terms of the GNU GPL.
10 */
11
12 #include <stdio.h>
13 #include <string.h>
14
15 #include "lspci.h"
16
17 /*
18 * The list of all known VPD items and their formats.
19 * Technically, this belongs to the pci.ids file, but the VPD does not seem
20 * to be developed any longer, so we have chosen the easier way.
21 */
22
23 enum vpd_format {
24 F_BINARY,
25 F_TEXT,
26 F_RESVD,
27 F_RDWR,
28 };
29
30 static const struct vpd_item {
31 byte id1, id2;
32 byte format;
33 const char *name;
34 } vpd_items[] = {
35 { 'C','P', F_BINARY, "Extended capability" },
36 { 'E','C', F_TEXT, "Engineering changes" },
37 { 'M','N', F_TEXT, "Manufacture ID" },
38 { 'P','N', F_TEXT, "Part number" },
39 { 'R','V', F_RESVD, "Reserved" },
40 { 'R','W', F_RDWR, "Read-write area" },
41 { 'S','N', F_TEXT, "Serial number" },
42 { 'Y','A', F_TEXT, "Asset tag" },
43 { 'V', 0 , F_TEXT, "Vendor specific" },
44 { 'Y', 0 , F_TEXT, "System specific" },
45 /* Non-standard extensions */
46 { 'C','C', F_TEXT, "CCIN" },
47 { 'F','C', F_TEXT, "Feature code" },
48 { 'F','N', F_TEXT, "FRU" },
49 { 'N','A', F_TEXT, "Network address" },
50 { 'R','M', F_TEXT, "Firmware version" },
51 { 'Z', 0 , F_TEXT, "Product specific" },
52 { 0, 0 , F_BINARY, "Unknown" }
53 };
54
55 static void
56 print_vpd_string(const byte *buf, word len)
57 {
58 while (len--)
59 {
60 byte ch = *buf++;
61 if (ch == '\\')
62 printf("\\\\");
63 else if (!ch && !len)
64 ; /* Cards with null-terminated strings have been observed */
65 else if (ch < 32 || ch == 127)
66 printf("\\x%02x", ch);
67 else
68 putchar(ch);
69 }
70 }
71
72 static void
73 print_vpd_binary(const byte *buf, word len)
74 {
75 int i;
76 for (i = 0; i < len; i++)
77 {
78 if (i)
79 putchar(' ');
80 printf("%02x", buf[i]);
81 }
82 }
83
84 static int
85 read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum)
86 {
87 if (!pci_read_vpd(d->dev, pos, buf, len))
88 return 0;
89 while (len--)
90 *csum += *buf++;
91 return 1;
92 }
93
94 void
95 cap_vpd(struct device *d)
96 {
97 word res_addr = 0, res_len, part_pos, part_len;
98 byte buf[256];
99 byte tag;
100 byte csum = 0;
101
102 printf("Vital Product Data\n");
103 if (verbose < 2)
104 return;
105
106 while (res_addr <= PCI_VPD_ADDR_MASK)
107 {
108 if (!read_vpd(d, res_addr, &tag, 1, &csum))
109 break;
110 if (tag & 0x80)
111 {
112 if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3)
113 break;
114 if (!read_vpd(d, res_addr + 1, buf, 2, &csum))
115 break;
116 res_len = buf[0] + (buf[1] << 8);
117 res_addr += 3;
118 }
119 else
120 {
121 res_len = tag & 7;
122 tag >>= 3;
123 res_addr += 1;
124 }
125 if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr)
126 break;
127
128 part_pos = 0;
129
130 switch (tag)
131 {
132 case 0x0f:
133 printf("\t\tEnd\n");
134 return;
135
136 case 0x82:
137 printf("\t\tProduct Name: ");
138 while (part_pos < res_len)
139 {
140 part_len = res_len - part_pos;
141 if (part_len > sizeof(buf))
142 part_len = sizeof(buf);
143 if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum))
144 break;
145 print_vpd_string(buf, part_len);
146 part_pos += part_len;
147 }
148 printf("\n");
149 break;
150
151 case 0x90:
152 case 0x91:
153 printf("\t\t%s fields:\n",
154 (tag == 0x90) ? "Read-only" : "Read/write");
155
156 while (part_pos + 3 <= res_len)
157 {
158 word read_len;
159 const struct vpd_item *item;
160 byte id[2], id1, id2;
161
162 if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
163 break;
164 part_pos += 3;
165 memcpy(id, buf, 2);
166 id1 = id[0];
167 id2 = id[1];
168 part_len = buf[2];
169 if (part_len > res_len - part_pos)
170 break;
171
172 /* Is this item known? */
173 for (item=vpd_items; item->id1 && item->id1 != id1 ||
174 item->id2 && item->id2 != id2; item++)
175 ;
176
177 /* Only read the first byte of the RV field because the
178 * remaining bytes are not included in the checksum. */
179 read_len = (item->format == F_RESVD) ? 1 : part_len;
180 if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
181 break;
182
183 printf("\t\t\t[");
184 print_vpd_string(id, 2);
185 printf("] %s: ", item->name);
186
187 switch (item->format)
188 {
189 case F_TEXT:
190 print_vpd_string(buf, part_len);
191 printf("\n");
192 break;
193 case F_BINARY:
194 print_vpd_binary(buf, part_len);
195 printf("\n");
196 break;
197 case F_RESVD:
198 printf("checksum %s, %d byte(s) reserved\n", csum ? "bad" : "good", part_len - 1);
199 break;
200 case F_RDWR:
201 printf("%d byte(s) free\n", part_len);
202 break;
203 }
204
205 part_pos += part_len;
206 }
207 break;
208
209 default:
210 printf("\t\tUnknown %s resource type %02x, will not decode more.\n",
211 (tag & 0x80) ? "large" : "small", tag & ~0x80);
212 return;
213 }
214
215 res_addr += res_len;
216 }
217
218 if (res_addr == 0)
219 printf("\t\tNot readable\n");
220 else
221 printf("\t\tNo end tag found\n");
222 }