]> git.ipfire.org Git - thirdparty/pciutils.git/blame - ls-vpd.c
lspci: Print names of capabilities even if we can't decode the rest
[thirdparty/pciutils.git] / ls-vpd.c
CommitLineData
c7a34993
MM
1/*
2 * The PCI Utilities -- Show Vital Product Data
3 *
2ba49657
MM
4 * Copyright (c) 2008 Solarflare Communications
5 *
6 * Written by Ben Hutchings <bhutchings@solarflare.com>
01f4caed 7 * Improved by Martin Mares <mj@ucw.cz>
c7a34993
MM
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
01f4caed
MM
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
22enum vpd_format {
23 F_BINARY,
24 F_TEXT,
25 F_RESVD,
26 F_RDWR,
27};
28
29static 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" },
b7ffb971 36 { 'M','N', F_TEXT, "Manufacture ID" },
01f4caed
MM
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" },
7f9d3023 44 { 0, 0 , F_BINARY, "Unknown" }
01f4caed
MM
45};
46
c7a34993
MM
47static void
48print_vpd_string(const byte *buf, word len)
49{
50 while (len--)
51 {
52 byte ch = *buf++;
53 if (ch == '\\')
54 printf("\\\\");
db2a16f4
MM
55 else if (!ch && !len)
56 ; /* Cards with null-terminated strings have been observed */
c7a34993
MM
57 else if (ch < 32 || ch == 127)
58 printf("\\x%02x", ch);
59 else
60 putchar(ch);
61 }
62}
63
01f4caed
MM
64static void
65print_vpd_binary(const byte *buf, word len)
66{
67 int i;
68 for (i = 0; i < len; i++)
69 {
70 if (i)
71 putchar(' ');
72 printf("%02x", buf[i]);
73 }
74}
75
c7a34993
MM
76static int
77read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum)
78{
79 if (!pci_read_vpd(d->dev, pos, buf, len))
80 return 0;
81 while (len--)
82 *csum += *buf++;
83 return 1;
84}
85
86void
87cap_vpd(struct device *d)
88{
89 word res_addr = 0, res_len, part_pos, part_len;
01f4caed 90 byte buf[256];
c7a34993
MM
91 byte tag;
92 byte csum = 0;
93
94 printf("Vital Product Data\n");
746c9057
MM
95 if (verbose < 2)
96 return;
c7a34993
MM
97
98 while (res_addr <= PCI_VPD_ADDR_MASK)
99 {
100 if (!read_vpd(d, res_addr, &tag, 1, &csum))
101 break;
102 if (tag & 0x80)
103 {
104 if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3)
105 break;
106 if (!read_vpd(d, res_addr + 1, buf, 2, &csum))
107 break;
108 res_len = buf[0] + (buf[1] << 8);
109 res_addr += 3;
110 }
111 else
112 {
113 res_len = tag & 7;
114 tag >>= 3;
115 res_addr += 1;
116 }
117 if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr)
118 break;
119
120 part_pos = 0;
121
122 switch (tag)
123 {
124 case 0x0f:
125 printf("\t\tEnd\n");
126 return;
127
128 case 0x82:
129 printf("\t\tProduct Name: ");
130 while (part_pos < res_len)
131 {
132 part_len = res_len - part_pos;
133 if (part_len > sizeof(buf))
134 part_len = sizeof(buf);
135 if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum))
136 break;
137 print_vpd_string(buf, part_len);
138 part_pos += part_len;
139 }
140 printf("\n");
141 break;
142
143 case 0x90:
144 case 0x91:
145 printf("\t\t%s fields:\n",
146 (tag == 0x90) ? "Read-only" : "Read/write");
147
148 while (part_pos + 3 <= res_len)
149 {
150 word read_len;
01f4caed 151 const struct vpd_item *item;
7f9d3023 152 byte id1, id2;
c7a34993
MM
153
154 if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
155 break;
156 part_pos += 3;
7f9d3023
BH
157 id1 = buf[0];
158 id2 = buf[1];
c7a34993
MM
159 part_len = buf[2];
160 if (part_len > res_len - part_pos)
161 break;
162
01f4caed 163 /* Is this item known? */
7f9d3023
BH
164 for (item=vpd_items; item->id1 && item->id1 != id1 ||
165 item->id2 && item->id2 != id2; item++)
01f4caed 166 ;
01f4caed 167
c7a34993
MM
168 /* Only read the first byte of the RV field because the
169 * remaining bytes are not included in the checksum. */
01f4caed 170 read_len = (item->format == F_RESVD) ? 1 : part_len;
c7a34993
MM
171 if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
172 break;
173
7f9d3023 174 printf("\t\t\t[%c%c] %s: ", id1, id2, item->name);
01f4caed
MM
175
176 switch (item->format)
177 {
178 case F_TEXT:
c7a34993
MM
179 print_vpd_string(buf, part_len);
180 printf("\n");
01f4caed
MM
181 break;
182 case F_BINARY:
183 print_vpd_binary(buf, part_len);
c7a34993 184 printf("\n");
01f4caed
MM
185 break;
186 case F_RESVD:
187 printf("checksum %s, %d byte(s) reserved\n", csum ? "bad" : "good", part_len - 1);
188 break;
189 case F_RDWR:
190 printf("%d byte(s) free\n", part_len);
191 break;
c7a34993
MM
192 }
193
194 part_pos += part_len;
195 }
196 break;
197
198 default:
169bfd45 199 printf("\t\tUnknown %s resource type %02x, will not decode more.\n",
c7a34993 200 (tag & 0x80) ? "large" : "small", tag & ~0x80);
9eaaf5c7 201 return;
c7a34993
MM
202 }
203
204 res_addr += res_len;
205 }
206
207 if (res_addr == 0)
208 printf("\t\tNot readable\n");
209 else
210 printf("\t\tNo end tag found\n");
211}