]> mj.ucw.cz Git - pciutils.git/blob - ls-vpd.c
36c34c9176903a57f2910a9be19b9b1cb3c44efb
[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  *
8  *      Can be freely distributed and used under the terms of the GNU GPL.
9  */
10
11 #include <stdio.h>
12
13 #include "lspci.h"
14
15 static void
16 print_vpd_string(const byte *buf, word len)
17 {
18   while (len--)
19     {
20       byte ch = *buf++;
21       if (ch == '\\')
22         printf("\\\\");
23       else if (ch < 32 || ch == 127)
24         printf("\\x%02x", ch);
25       else
26         putchar(ch);
27     }
28 }
29
30 static int
31 read_vpd(struct device *d, int pos, byte *buf, int len, byte *csum)
32 {
33   if (!pci_read_vpd(d->dev, pos, buf, len))
34     return 0;
35   while (len--)
36     *csum += *buf++;
37   return 1;
38 }
39
40 void
41 cap_vpd(struct device *d)
42 {
43   word res_addr = 0, res_len, part_pos, part_len;
44   byte key[2], buf[256];
45   byte tag;
46   byte csum = 0;
47
48   printf("Vital Product Data\n");
49   if (verbose < 2)
50     return;
51
52   while (res_addr <= PCI_VPD_ADDR_MASK)
53     {
54       if (!read_vpd(d, res_addr, &tag, 1, &csum))
55         break;
56       if (tag & 0x80)
57         {
58           if (res_addr > PCI_VPD_ADDR_MASK + 1 - 3)
59             break;
60           if (!read_vpd(d, res_addr + 1, buf, 2, &csum))
61             break;
62           res_len = buf[0] + (buf[1] << 8);
63           res_addr += 3;
64         }
65       else
66         {
67           res_len = tag & 7;
68           tag >>= 3;
69           res_addr += 1;
70         }
71       if (res_len > PCI_VPD_ADDR_MASK + 1 - res_addr)
72         break;
73
74       part_pos = 0;
75
76       switch (tag)
77         {
78         case 0x0f:
79           printf("\t\tEnd\n");
80           return;
81
82         case 0x82:
83           printf("\t\tProduct Name: ");
84           while (part_pos < res_len)
85             {
86               part_len = res_len - part_pos;
87               if (part_len > sizeof(buf))
88                 part_len = sizeof(buf);
89               if (!read_vpd(d, res_addr + part_pos, buf, part_len, &csum))
90                 break;
91               print_vpd_string(buf, part_len);
92               part_pos += part_len;
93             }
94           printf("\n");
95           break;
96
97         case 0x90:
98         case 0x91:
99           printf("\t\t%s fields:\n",
100                  (tag == 0x90) ? "Read-only" : "Read/write");
101
102           while (part_pos + 3 <= res_len)
103             {
104               word read_len;
105
106               if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
107                 break;
108               part_pos += 3;
109               key[0] = buf[0];
110               key[1] = buf[1];
111               part_len = buf[2];
112               if (part_len > res_len - part_pos)
113                 break;
114
115               /* Only read the first byte of the RV field because the
116                * remaining bytes are not included in the checksum. */
117               read_len = (key[0] == 'R' && key[1] == 'V') ? 1 : part_len;
118               if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
119                 break;
120
121               if ((key[0] == 'E' && key[1] == 'C') ||
122                   (key[0] == 'P' && key[1] == 'N') ||
123                   (key[0] == 'S' && key[1] == 'N') ||
124                   key[0] == 'V' ||
125                   key[0] == 'Y')
126                 {
127                   /* Alphanumeric content */
128                   printf("\t\t\t%c%c: ", key[0], key[1]);
129                   print_vpd_string(buf, part_len);
130                   printf("\n");
131                 }
132               else if (key[0] == 'R' && key[1] == 'V')
133                 {
134                   /* Reserved and checksum */
135                   printf("\t\t\tRV: checksum %s, %d byte(s) reserved\n",
136                          csum ? "bad" : "good", part_len - 1);
137                 }
138               else if (key[0] == 'R' && key[1] == 'W')
139                 {
140                   /* Read-write area */
141                   printf("\t\t\tRW: %d byte(s) free\n", part_len);
142                 }
143               else
144                 {
145                   /* Binary or unknown content */
146                   int i;
147                   printf("\t\t\t%c%c:", key[0], key[1]);
148                   for (i = 0; i < part_len; i++)
149                     printf(" %02x", buf[i]);
150                   printf("\n");
151                 }
152
153               part_pos += part_len;
154             }
155           break;
156
157         default:
158           printf("\t\tUnknown %s resource type %02x\n",
159                  (tag & 0x80) ? "large" : "small", tag & ~0x80);
160           break;
161         }
162
163       res_addr += res_len;
164     }
165
166   if (res_addr == 0)
167     printf("\t\tNot readable\n");
168   else
169     printf("\t\tNo end tag found\n");
170 }