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>