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