Annotation of embedaddon/pciutils/setpci.c, revision 1.1
1.1 ! misho 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>