]> mj.ucw.cz Git - pciutils.git/blob - ls-vpd.c
HWDB: Handle NULL returned by udev_list_entry_get_*
[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 }