File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pciutils / ls-vpd.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:18:43 2012 UTC (12 years, 3 months ago) by misho
Branches: pciutils, MAIN
CVS tags: v3_1_9, HEAD
pciutils

    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>