Annotation of embedaddon/pciutils/ls-vpd.c, revision 1.1
1.1 ! misho 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_BINARY, "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: { 0, 0 , F_BINARY, "Unknown" }
! 45: };
! 46:
! 47: static void
! 48: print_vpd_string(const byte *buf, word len)
! 49: {
! 50: while (len--)
! 51: {
! 52: byte ch = *buf++;
! 53: if (ch == '\\')
! 54: printf("\\\\");
! 55: else if (!ch && !len)
! 56: ; /* Cards with null-terminated strings have been observed */
! 57: else if (ch < 32 || ch == 127)
! 58: printf("\\x%02x", ch);
! 59: else
! 60: putchar(ch);
! 61: }
! 62: }
! 63:
! 64: static void
! 65: print_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:
! 76: static int
! 77: read_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:
! 86: void
! 87: cap_vpd(struct device *d)
! 88: {
! 89: word res_addr = 0, res_len, part_pos, part_len;
! 90: byte buf[256];
! 91: byte tag;
! 92: byte csum = 0;
! 93:
! 94: printf("Vital Product Data\n");
! 95: if (verbose < 2)
! 96: return;
! 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;
! 151: const struct vpd_item *item;
! 152: byte id1, id2;
! 153:
! 154: if (!read_vpd(d, res_addr + part_pos, buf, 3, &csum))
! 155: break;
! 156: part_pos += 3;
! 157: id1 = buf[0];
! 158: id2 = buf[1];
! 159: part_len = buf[2];
! 160: if (part_len > res_len - part_pos)
! 161: break;
! 162:
! 163: /* Is this item known? */
! 164: for (item=vpd_items; item->id1 && item->id1 != id1 ||
! 165: item->id2 && item->id2 != id2; item++)
! 166: ;
! 167:
! 168: /* Only read the first byte of the RV field because the
! 169: * remaining bytes are not included in the checksum. */
! 170: read_len = (item->format == F_RESVD) ? 1 : part_len;
! 171: if (!read_vpd(d, res_addr + part_pos, buf, read_len, &csum))
! 172: break;
! 173:
! 174: printf("\t\t\t[%c%c] %s: ", id1, id2, item->name);
! 175:
! 176: switch (item->format)
! 177: {
! 178: case F_TEXT:
! 179: print_vpd_string(buf, part_len);
! 180: printf("\n");
! 181: break;
! 182: case F_BINARY:
! 183: print_vpd_binary(buf, part_len);
! 184: printf("\n");
! 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;
! 192: }
! 193:
! 194: part_pos += part_len;
! 195: }
! 196: break;
! 197:
! 198: default:
! 199: printf("\t\tUnknown %s resource type %02x, will not decode more.\n",
! 200: (tag & 0x80) ? "large" : "small", tag & ~0x80);
! 201: return;
! 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>