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

    1: /*
    2:  *	The PCI Utilities -- Manipulate PCI Configuration Registers
    3:  *
    4:  *	Copyright (c) 1998--2008 Martin Mares <mj@ucw.cz>
    5:  *
    6:  *	Can be freely distributed and used under the terms of the GNU GPL.
    7:  */
    8: 
    9: #include <stdio.h>
   10: #include <string.h>
   11: #include <stdlib.h>
   12: #include <stdarg.h>
   13: #include <errno.h>
   14: 
   15: #define PCIUTILS_SETPCI
   16: #include "pciutils.h"
   17: 
   18: static int force;			/* Don't complain if no devices match */
   19: static int verbose;			/* Verbosity level */
   20: static int demo_mode;			/* Only show */
   21: 
   22: const char program_name[] = "setpci";
   23: 
   24: static struct pci_access *pacc;
   25: 
   26: struct value {
   27:   unsigned int value;
   28:   unsigned int mask;
   29: };
   30: 
   31: struct op {
   32:   struct op *next;
   33:   struct pci_dev **dev_vector;
   34:   u16 cap_type;				/* PCI_CAP_xxx or 0 */
   35:   u16 cap_id;
   36:   unsigned int addr;
   37:   unsigned int width;			/* Byte width of the access */
   38:   unsigned int num_values;		/* Number of values to write; 0=read */
   39:   struct value values[0];
   40: };
   41: 
   42: static struct op *first_op, **last_op = &first_op;
   43: static unsigned int max_values[] = { 0, 0xff, 0xffff, 0, 0xffffffff };
   44: 
   45: static struct pci_dev **
   46: select_devices(struct pci_filter *filt)
   47: {
   48:   struct pci_dev *z, **a, **b;
   49:   int cnt = 1;
   50: 
   51:   for (z=pacc->devices; z; z=z->next)
   52:     if (pci_filter_match(filt, z))
   53:       cnt++;
   54:   a = b = xmalloc(sizeof(struct device *) * cnt);
   55:   for (z=pacc->devices; z; z=z->next)
   56:     if (pci_filter_match(filt, z))
   57:       *a++ = z;
   58:   *a = NULL;
   59:   return b;
   60: }
   61: 
   62: static void PCI_PRINTF(1,2)
   63: trace(const char *fmt, ...)
   64: {
   65:   va_list args;
   66:   va_start(args, fmt);
   67:   if (verbose)
   68:     vprintf(fmt, args);
   69:   va_end(args);
   70: }
   71: 
   72: static void
   73: exec_op(struct op *op, struct pci_dev *dev)
   74: {
   75:   const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x" };
   76:   const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x" };
   77:   unsigned int i, x, y;
   78:   int addr = 0;
   79:   int width = op->width;
   80:   char slot[16];
   81: 
   82:   sprintf(slot, "%04x:%02x:%02x.%x", dev->domain, dev->bus, dev->dev, dev->func);
   83:   trace("%s ", slot);
   84:   if (op->cap_type)
   85:     {
   86:       struct pci_cap *cap;
   87:       cap = pci_find_cap(dev, op->cap_id, op->cap_type);
   88:       if (cap)
   89: 	addr = cap->addr;
   90:       else
   91: 	die("%s: %s %04x not found", slot, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), op->cap_id);
   92:       trace(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x @%02x) " : "(ecap %04x @%03x) "), op->cap_id, addr);
   93:     }
   94:   addr += op->addr;
   95:   trace("@%02x", addr);
   96: 
   97:   /* We have already checked it when parsing, but addressing relative to capabilities can change the address. */
   98:   if (addr & (width-1))
   99:     die("%s: Unaligned access of width %d to register %04x", slot, width, addr);
  100:   if (addr + width > 0x1000)
  101:     die("%s: Access of width %d to register %04x out of range", slot, width, addr);
  102: 
  103:   if (op->num_values)
  104:     {
  105:       for (i=0; i<op->num_values; i++)
  106: 	{
  107: 	  if ((op->values[i].mask & max_values[width]) == max_values[width])
  108: 	    {
  109: 	      x = op->values[i].value;
  110: 	      trace(formats[width], op->values[i].value);
  111: 	    }
  112: 	  else
  113: 	    {
  114: 	      switch (width)
  115: 		{
  116: 		case 1:
  117: 		  y = pci_read_byte(dev, addr);
  118: 		  break;
  119: 		case 2:
  120: 		  y = pci_read_word(dev, addr);
  121: 		  break;
  122: 		default:
  123: 		  y = pci_read_long(dev, addr);
  124: 		  break;
  125: 		}
  126: 	      x = (y & ~op->values[i].mask) | op->values[i].value;
  127: 	      trace(mask_formats[width], y, op->values[i].value, op->values[i].mask, x);
  128: 	    }
  129: 	  if (!demo_mode)
  130: 	    {
  131: 	      switch (width)
  132: 		{
  133: 		case 1:
  134: 		  pci_write_byte(dev, addr, x);
  135: 		  break;
  136: 		case 2:
  137: 		  pci_write_word(dev, addr, x);
  138: 		  break;
  139: 		default:
  140: 		  pci_write_long(dev, addr, x);
  141: 		  break;
  142: 		}
  143: 	    }
  144: 	  addr += width;
  145: 	}
  146:       trace("\n");
  147:     }
  148:   else
  149:     {
  150:       trace(" = ");
  151:       switch (width)
  152: 	{
  153: 	case 1:
  154: 	  x = pci_read_byte(dev, addr);
  155: 	  break;
  156: 	case 2:
  157: 	  x = pci_read_word(dev, addr);
  158: 	  break;
  159: 	default:
  160: 	  x = pci_read_long(dev, addr);
  161: 	  break;
  162: 	}
  163:       printf(formats[width]+1, x);
  164:       putchar('\n');
  165:     }
  166: }
  167: 
  168: static void
  169: execute(struct op *op)
  170: {
  171:   struct pci_dev **vec = NULL;
  172:   struct pci_dev **pdev, *dev;
  173:   struct op *oops;
  174: 
  175:   while (op)
  176:     {
  177:       pdev = vec = op->dev_vector;
  178:       while (dev = *pdev++)
  179: 	for (oops=op; oops && oops->dev_vector == vec; oops=oops->next)
  180: 	  exec_op(oops, dev);
  181:       while (op && op->dev_vector == vec)
  182: 	op = op->next;
  183:     }
  184: }
  185: 
  186: static void
  187: scan_ops(struct op *op)
  188: {
  189:   if (demo_mode)
  190:     return;
  191:   while (op)
  192:     {
  193:       if (op->num_values)
  194: 	pacc->writeable = 1;
  195:       op = op->next;
  196:     }
  197: }
  198: 
  199: struct reg_name {
  200:   unsigned int cap;
  201:   unsigned int offset;
  202:   unsigned int width;
  203:   const char *name;
  204: };
  205: 
  206: static const struct reg_name pci_reg_names[] = {
  207:   {       0, 0x00, 2, "VENDOR_ID" },
  208:   {       0, 0x02, 2, "DEVICE_ID" },
  209:   {       0, 0x04, 2, "COMMAND" },
  210:   {       0, 0x06, 2, "STATUS" },
  211:   {       0, 0x08, 1, "REVISION" },
  212:   {       0, 0x09, 1, "CLASS_PROG" },
  213:   {       0, 0x0a, 2, "CLASS_DEVICE" },
  214:   {       0, 0x0c, 1, "CACHE_LINE_SIZE" },
  215:   {       0, 0x0d, 1, "LATENCY_TIMER" },
  216:   {       0, 0x0e, 1, "HEADER_TYPE" },
  217:   {       0, 0x0f, 1, "BIST" },
  218:   {       0, 0x10, 4, "BASE_ADDRESS_0" },
  219:   {       0, 0x14, 4, "BASE_ADDRESS_1" },
  220:   {       0, 0x18, 4, "BASE_ADDRESS_2" },
  221:   {       0, 0x1c, 4, "BASE_ADDRESS_3" },
  222:   {       0, 0x20, 4, "BASE_ADDRESS_4" },
  223:   {       0, 0x24, 4, "BASE_ADDRESS_5" },
  224:   {       0, 0x28, 4, "CARDBUS_CIS" },
  225:   {       0, 0x2c, 4, "SUBSYSTEM_VENDOR_ID" },
  226:   {       0, 0x2e, 2, "SUBSYSTEM_ID" },
  227:   {       0, 0x30, 4, "ROM_ADDRESS" },
  228:   {       0, 0x3c, 1, "INTERRUPT_LINE" },
  229:   {       0, 0x3d, 1, "INTERRUPT_PIN" },
  230:   {       0, 0x3e, 1, "MIN_GNT" },
  231:   {       0, 0x3f, 1, "MAX_LAT" },
  232:   {       0, 0x18, 1, "PRIMARY_BUS" },
  233:   {       0, 0x19, 1, "SECONDARY_BUS" },
  234:   {       0, 0x1a, 1, "SUBORDINATE_BUS" },
  235:   {       0, 0x1b, 1, "SEC_LATENCY_TIMER" },
  236:   {       0, 0x1c, 1, "IO_BASE" },
  237:   {       0, 0x1d, 1, "IO_LIMIT" },
  238:   {       0, 0x1e, 2, "SEC_STATUS" },
  239:   {       0, 0x20, 2, "MEMORY_BASE" },
  240:   {       0, 0x22, 2, "MEMORY_LIMIT" },
  241:   {       0, 0x24, 2, "PREF_MEMORY_BASE" },
  242:   {       0, 0x26, 2, "PREF_MEMORY_LIMIT" },
  243:   {       0, 0x28, 4, "PREF_BASE_UPPER32" },
  244:   {       0, 0x2c, 4, "PREF_LIMIT_UPPER32" },
  245:   {       0, 0x30, 2, "IO_BASE_UPPER16" },
  246:   {       0, 0x32, 2, "IO_LIMIT_UPPER16" },
  247:   {       0, 0x38, 4, "BRIDGE_ROM_ADDRESS" },
  248:   {       0, 0x3e, 2, "BRIDGE_CONTROL" },
  249:   {       0, 0x10, 4, "CB_CARDBUS_BASE" },
  250:   {       0, 0x14, 2, "CB_CAPABILITIES" },
  251:   {       0, 0x16, 2, "CB_SEC_STATUS" },
  252:   {       0, 0x18, 1, "CB_BUS_NUMBER" },
  253:   {       0, 0x19, 1, "CB_CARDBUS_NUMBER" },
  254:   {       0, 0x1a, 1, "CB_SUBORDINATE_BUS" },
  255:   {       0, 0x1b, 1, "CB_CARDBUS_LATENCY" },
  256:   {       0, 0x1c, 4, "CB_MEMORY_BASE_0" },
  257:   {       0, 0x20, 4, "CB_MEMORY_LIMIT_0" },
  258:   {       0, 0x24, 4, "CB_MEMORY_BASE_1" },
  259:   {       0, 0x28, 4, "CB_MEMORY_LIMIT_1" },
  260:   {       0, 0x2c, 2, "CB_IO_BASE_0" },
  261:   {       0, 0x2e, 2, "CB_IO_BASE_0_HI" },
  262:   {       0, 0x30, 2, "CB_IO_LIMIT_0" },
  263:   {       0, 0x32, 2, "CB_IO_LIMIT_0_HI" },
  264:   {       0, 0x34, 2, "CB_IO_BASE_1" },
  265:   {       0, 0x36, 2, "CB_IO_BASE_1_HI" },
  266:   {       0, 0x38, 2, "CB_IO_LIMIT_1" },
  267:   {       0, 0x3a, 2, "CB_IO_LIMIT_1_HI" },
  268:   {       0, 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID" },
  269:   {       0, 0x42, 2, "CB_SUBSYSTEM_ID" },
  270:   {       0, 0x44, 4, "CB_LEGACY_MODE_BASE" },
  271:   { 0x10001,    0, 0, "CAP_PM" },
  272:   { 0x10002,    0, 0, "CAP_AGP" },
  273:   { 0x10003,    0, 0, "CAP_VPD" },
  274:   { 0x10004,    0, 0, "CAP_SLOTID" },
  275:   { 0x10005,    0, 0, "CAP_MSI" },
  276:   { 0x10006,    0, 0, "CAP_CHSWP" },
  277:   { 0x10007,    0, 0, "CAP_PCIX" },
  278:   { 0x10008,    0, 0, "CAP_HT" },
  279:   { 0x10009,    0, 0, "CAP_VNDR" },
  280:   { 0x1000a,    0, 0, "CAP_DBG" },
  281:   { 0x1000b,    0, 0, "CAP_CCRC" },
  282:   { 0x1000c,    0, 0, "CAP_HOTPLUG" },
  283:   { 0x1000d,    0, 0, "CAP_SSVID" },
  284:   { 0x1000e,    0, 0, "CAP_AGP3" },
  285:   { 0x1000f,    0, 0, "CAP_SECURE" },
  286:   { 0x10010,    0, 0, "CAP_EXP" },
  287:   { 0x10011,    0, 0, "CAP_MSIX" },
  288:   { 0x10012,    0, 0, "CAP_SATA" },
  289:   { 0x10013,    0, 0, "CAP_AF" },
  290:   { 0x20001,	0, 0, "ECAP_AER" },
  291:   { 0x20002,	0, 0, "ECAP_VC" },
  292:   { 0x20003,	0, 0, "ECAP_DSN" },
  293:   { 0x20004,	0, 0, "ECAP_PB" },
  294:   { 0x20005,	0, 0, "ECAP_RCLINK" },
  295:   { 0x20006,	0, 0, "ECAP_RCILINK" },
  296:   { 0x20007,	0, 0, "ECAP_RCECOLL" },
  297:   { 0x20008,	0, 0, "ECAP_MFVC" },
  298:   { 0x2000a,	0, 0, "ECAP_RBCB" },
  299:   { 0x2000b,	0, 0, "ECAP_VNDR" },
  300:   { 0x2000d,	0, 0, "ECAP_ACS" },
  301:   { 0x2000e,	0, 0, "ECAP_ARI" },
  302:   { 0x2000f,	0, 0, "ECAP_ATS" },
  303:   { 0x20010,	0, 0, "ECAP_SRIOV" },
  304:   {       0,    0, 0, NULL }
  305: };
  306: 
  307: static void
  308: dump_registers(void)
  309: {
  310:   const struct reg_name *r;
  311: 
  312:   printf("cap pos w name\n");
  313:   for (r = pci_reg_names; r->name; r++)
  314:     {
  315:       if (r->cap >= 0x20000)
  316: 	printf("%04x", r->cap - 0x20000);
  317:       else if (r->cap)
  318: 	printf("  %02x", r->cap - 0x10000);
  319:       else
  320: 	printf("    ");
  321:       printf(" %02x %c %s\n", r->offset, "-BW?L"[r->width], r->name);
  322:     }
  323: }
  324: 
  325: static void NONRET
  326: usage(void)
  327: {
  328:   fprintf(stderr,
  329: "Usage: setpci [<options>] (<device>+ <reg>[=<values>]*)*\n"
  330: "\n"
  331: "General options:\n"
  332: "-f\t\tDon't complain if there's nothing to do\n"
  333: "-v\t\tBe verbose\n"
  334: "-D\t\tList changes, don't commit them\n"
  335: "--dumpregs\tDump all known register names and exit\n"
  336: "\n"
  337: "PCI access options:\n"
  338: GENERIC_HELP
  339: "\n"
  340: "Setting commands:\n"
  341: "<device>:\t-s [[[<domain>]:][<bus>]:][<slot>][.[<func>]]\n"
  342: "\t\t-d [<vendor>]:[<device>]\n"
  343: "<reg>:\t\t<base>[+<offset>][.(B|W|L)]\n"
  344: "<base>:\t\t<address>\n"
  345: "\t\t<named-register>\n"
  346: "\t\t[E]CAP_<capability-name>\n"
  347: "\t\t[E]CAP<capability-number>\n"
  348: "<values>:\t<value>[,<value>...]\n"
  349: "<value>:\t<hex>\n"
  350: "\t\t<hex>:<mask>\n");
  351:   exit(0);
  352: }
  353: 
  354: static void NONRET PCI_PRINTF(1,2)
  355: parse_err(const char *msg, ...)
  356: {
  357:   va_list args;
  358:   va_start(args, msg);
  359:   fprintf(stderr, "setpci: ");
  360:   vfprintf(stderr, msg, args);
  361:   fprintf(stderr, ".\nTry `setpci --help' for more information.\n");
  362:   exit(1);
  363: }
  364: 
  365: static int
  366: parse_options(int argc, char **argv)
  367: {
  368:   const char opts[] = GENERIC_OPTIONS;
  369:   int i=1;
  370: 
  371:   if (argc == 2)
  372:     {
  373:       if (!strcmp(argv[1], "--help"))
  374: 	usage();
  375:       if (!strcmp(argv[1], "--version"))
  376: 	{
  377: 	  puts("setpci version " PCIUTILS_VERSION);
  378: 	  exit(0);
  379: 	}
  380:       if (!strcmp(argv[1], "--dumpregs"))
  381: 	{
  382: 	  dump_registers();
  383: 	  exit(0);
  384: 	}
  385:     }
  386: 
  387:   while (i < argc && argv[i][0] == '-')
  388:     {
  389:       char *c = argv[i++] + 1;
  390:       char *d = c;
  391:       char *e;
  392:       while (*c)
  393: 	switch (*c)
  394: 	  {
  395: 	  case 0:
  396: 	    break;
  397: 	  case 'v':
  398: 	    verbose++;
  399: 	    c++;
  400: 	    break;
  401: 	  case 'f':
  402: 	    force++;
  403: 	    c++;
  404: 	    break;
  405: 	  case 'D':
  406: 	    demo_mode++;
  407: 	    c++;
  408: 	    break;
  409: 	  default:
  410: 	    if (e = strchr(opts, *c))
  411: 	      {
  412: 		char *arg;
  413: 		c++;
  414: 		if (e[1] == ':')
  415: 		  {
  416: 		    if (*c)
  417: 		      arg = c;
  418: 		    else if (i < argc)
  419: 		      arg = argv[i++];
  420: 		    else
  421: 		      parse_err("Option -%c requires an argument", *e);
  422: 		    c = "";
  423: 		  }
  424: 		else
  425: 		  arg = NULL;
  426: 		if (!parse_generic_option(*e, pacc, arg))
  427: 		  parse_err("Unable to parse option -%c", *e);
  428: 	      }
  429: 	    else
  430: 	      {
  431: 		if (c != d)
  432: 		  parse_err("Invalid or misplaced option -%c", *c);
  433: 		return i-1;
  434: 	      }
  435: 	  }
  436:     }
  437: 
  438:   return i;
  439: }
  440: 
  441: static int parse_filter(int argc, char **argv, int i, struct pci_filter *filter)
  442: {
  443:   char *c = argv[i++];
  444:   char *d;
  445: 
  446:   if (!c[1] || !strchr("sd", c[1]))
  447:     parse_err("Invalid option -%c", c[1]);
  448:   if (c[2])
  449:     d = (c[2] == '=') ? c+3 : c+2;
  450:   else if (i < argc)
  451:     d = argv[i++];
  452:   else
  453:     parse_err("Option -%c requires an argument", c[1]);
  454:   switch (c[1])
  455:     {
  456:     case 's':
  457:       if (d = pci_filter_parse_slot(filter, d))
  458: 	parse_err("Unable to parse filter -s %s", d);
  459:       break;
  460:     case 'd':
  461:       if (d = pci_filter_parse_id(filter, d))
  462: 	parse_err("Unable to parse filter -d %s", d);
  463:       break;
  464:     default:
  465:       parse_err("Unknown filter option -%c", c[1]);
  466:     }
  467: 
  468:   return i;
  469: }
  470: 
  471: static const struct reg_name *parse_reg_name(char *name)
  472: {
  473:   const struct reg_name *r;
  474: 
  475:   for (r = pci_reg_names; r->name; r++)
  476:     if (!strcasecmp(r->name, name))
  477:       return r;
  478:   return NULL;
  479: }
  480: 
  481: static int parse_x32(char *c, char **stopp, unsigned int *resp)
  482: {
  483:   char *stop;
  484:   unsigned long int l;
  485: 
  486:   if (!*c)
  487:     return -1;
  488:   errno = 0;
  489:   l = strtoul(c, &stop, 16);
  490:   if (errno)
  491:     return -1;
  492:   if ((l & ~0U) != l)
  493:     return -1;
  494:   *resp = l;
  495:   if (*stop)
  496:     {
  497:       if (stopp)
  498: 	*stopp = stop;
  499:       return 0;
  500:     }
  501:   else
  502:     {
  503:       if (stopp)
  504: 	*stopp = NULL;
  505:       return 1;
  506:     }
  507: }
  508: 
  509: static void parse_register(struct op *op, char *base)
  510: {
  511:   const struct reg_name *r;
  512:   unsigned int cap;
  513: 
  514:   op->cap_type = op->cap_id = 0;
  515:   if (parse_x32(base, NULL, &op->addr) > 0)
  516:     return;
  517:   else if (r = parse_reg_name(base))
  518:     {
  519:       switch (r->cap & 0xff0000)
  520: 	{
  521: 	case 0x10000:
  522: 	  op->cap_type = PCI_CAP_NORMAL;
  523: 	  break;
  524: 	case 0x20000:
  525: 	  op->cap_type = PCI_CAP_EXTENDED;
  526: 	  break;
  527: 	}
  528:       op->cap_id = r->cap & 0xffff;
  529:       op->addr = r->offset;
  530:       if (r->width && !op->width)
  531: 	op->width = r->width;
  532:       return;
  533:     }
  534:   else if (!strncasecmp(base, "CAP", 3))
  535:     {
  536:       if (parse_x32(base+3, NULL, &cap) > 0 && cap < 0x100)
  537: 	{
  538: 	  op->cap_type = PCI_CAP_NORMAL;
  539: 	  op->cap_id = cap;
  540: 	  op->addr = 0;
  541: 	  return;
  542: 	}
  543:     }
  544:   else if (!strncasecmp(base, "ECAP", 4))
  545:     {
  546:       if (parse_x32(base+4, NULL, &cap) > 0 && cap < 0x1000)
  547: 	{
  548: 	  op->cap_type = PCI_CAP_EXTENDED;
  549: 	  op->cap_id = cap;
  550: 	  op->addr = 0;
  551: 	  return;
  552: 	}
  553:     }
  554:   parse_err("Unknown register \"%s\"", base);
  555: }
  556: 
  557: static void parse_op(char *c, struct pci_dev **selected_devices)
  558: {
  559:   char *base, *offset, *width, *value;
  560:   char *e, *f;
  561:   int n, j;
  562:   struct op *op;
  563: 
  564:   /* Split the argument */
  565:   base = xstrdup(c);
  566:   if (value = strchr(base, '='))
  567:     *value++ = 0;
  568:   if (width = strchr(base, '.'))
  569:     *width++ = 0;
  570:   if (offset = strchr(base, '+'))
  571:     *offset++ = 0;
  572: 
  573:   /* Look for setting of values and count how many */
  574:   n = 0;
  575:   if (value)
  576:     {
  577:       if (!*value)
  578: 	parse_err("Missing value");
  579:       n++;
  580:       for (e=value; *e; e++)
  581: 	if (*e == ',')
  582: 	  n++;
  583:     }
  584: 
  585:   /* Allocate the operation */
  586:   op = xmalloc(sizeof(struct op) + n*sizeof(struct value));
  587:   op->dev_vector = selected_devices;
  588:   op->num_values = n;
  589: 
  590:   /* What is the width suffix? */
  591:   if (width)
  592:     {
  593:       if (width[1])
  594: 	parse_err("Invalid width \"%s\"", width);
  595:       switch (*width & 0xdf)
  596: 	{
  597: 	case 'B':
  598: 	  op->width = 1; break;
  599: 	case 'W':
  600: 	  op->width = 2; break;
  601: 	case 'L':
  602: 	  op->width = 4; break;
  603: 	default:
  604: 	  parse_err("Invalid width \"%c\"", *width);
  605: 	}
  606:     }
  607:   else
  608:     op->width = 0;
  609: 
  610:   /* Find the register */
  611:   parse_register(op, base);
  612:   if (!op->width)
  613:     parse_err("Missing width");
  614: 
  615:   /* Add offset */
  616:   if (offset)
  617:     {
  618:       unsigned int off;
  619:       if (parse_x32(offset, NULL, &off) <= 0 || off >= 0x1000)
  620: 	parse_err("Invalid offset \"%s\"", offset);
  621:       op->addr += off;
  622:     }
  623: 
  624:   /* Check range */
  625:   if (op->addr >= 0x1000 || op->addr + op->width*(n ? n : 1) > 0x1000)
  626:     parse_err("Register number %02x out of range", op->addr);
  627:   if (op->addr & (op->width - 1))
  628:     parse_err("Unaligned register address %02x", op->addr);
  629: 
  630:   /* Parse the values */
  631:   for (j=0; j<n; j++)
  632:     {
  633:       unsigned int ll, lim;
  634:       e = strchr(value, ',');
  635:       if (e)
  636: 	*e++ = 0;
  637:       if (parse_x32(value, &f, &ll) < 0 || f && *f != ':')
  638: 	parse_err("Invalid value \"%s\"", value);
  639:       lim = max_values[op->width];
  640:       if (ll > lim && ll < ~0UL - lim)
  641: 	parse_err("Value \"%s\" is out of range", value);
  642:       op->values[j].value = ll;
  643:       if (f && *f == ':')
  644: 	{
  645: 	  if (parse_x32(f+1, NULL, &ll) <= 0)
  646: 	    parse_err("Invalid mask \"%s\"", f+1);
  647: 	  if (ll > lim && ll < ~0UL - lim)
  648: 	    parse_err("Mask \"%s\" is out of range", f+1);
  649: 	  op->values[j].mask = ll;
  650: 	  op->values[j].value &= ll;
  651: 	}
  652:       else
  653: 	op->values[j].mask = ~0U;
  654:       value = e;
  655:     }
  656: 
  657:   *last_op = op;
  658:   last_op = &op->next;
  659:   op->next = NULL;
  660: }
  661: 
  662: static void parse_ops(int argc, char **argv, int i)
  663: {
  664:   enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT;
  665:   struct pci_filter filter;
  666:   struct pci_dev **selected_devices = NULL;
  667: 
  668:   while (i < argc)
  669:     {
  670:       char *c = argv[i++];
  671: 
  672:       if (*c == '-')
  673: 	{
  674: 	  if (state != STATE_GOT_FILTER)
  675: 	    pci_filter_init(pacc, &filter);
  676: 	  i = parse_filter(argc, argv, i-1, &filter);
  677: 	  state = STATE_GOT_FILTER;
  678: 	}
  679:       else
  680: 	{
  681: 	  if (state == STATE_INIT)
  682: 	    parse_err("Filter specification expected");
  683: 	  if (state == STATE_GOT_FILTER)
  684: 	    selected_devices = select_devices(&filter);
  685: 	  if (!selected_devices[0] && !force)
  686: 	    fprintf(stderr, "setpci: Warning: No devices selected for \"%s\".\n", c);
  687: 	  parse_op(c, selected_devices);
  688: 	  state = STATE_GOT_OP;
  689: 	}
  690:     }
  691:   if (state == STATE_INIT)
  692:     parse_err("No operation specified");
  693: }
  694: 
  695: int
  696: main(int argc, char **argv)
  697: {
  698:   int i;
  699: 
  700:   pacc = pci_alloc();
  701:   pacc->error = die;
  702:   i = parse_options(argc, argv);
  703: 
  704:   pci_init(pacc);
  705:   pci_scan_bus(pacc);
  706: 
  707:   parse_ops(argc, argv, i);
  708:   scan_ops(first_op);
  709:   execute(first_op);
  710: 
  711:   return 0;
  712: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>