X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=setpci.c;h=5711e5105a9d49ab107c1cff3d82140d0da8f054;hb=e2864327195d067728dd904f8ff72959c8097508;hp=7e84acbf6ebb70698d3365ef6df5915407acadf6;hpb=a82ca6381c44611ebb27ffa86b7a55a670ad6bb5;p=pciutils.git diff --git a/setpci.c b/setpci.c index 7e84acb..5711e51 100644 --- a/setpci.c +++ b/setpci.c @@ -32,7 +32,8 @@ struct value { struct op { struct op *next; struct pci_dev **dev_vector; - unsigned int cap; /* Capability: 0=none, 10000-100ff=normal, 20000-2ffff=extended */ + u16 cap_type; /* PCI_CAP_xxx or 0 */ + u16 cap_id; unsigned int addr; unsigned int width; /* Byte width of the access */ unsigned int num_values; /* Number of values to write; 0=read */ @@ -59,57 +60,55 @@ select_devices(struct pci_filter *filt) return b; } +static void PCI_PRINTF(1,2) +trace(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (verbose) + vprintf(fmt, args); + va_end(args); +} + static void exec_op(struct op *op, struct pci_dev *dev) { - char *formats[] = { NULL, "%02x", "%04x", NULL, "%08x" }; - char *mask_formats[] = { NULL, "%02x->(%02x:%02x)->%02x", "%04x->(%04x:%04x)->%04x", NULL, "%08x->(%08x:%08x)->%08x" }; + const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x" }; + const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x" }; unsigned int i, x, y; int addr = 0; int width = op->width; + char slot[16]; - if (verbose) - printf("%02x:%02x.%x", dev->bus, dev->dev, dev->func); - if (op->cap) + sprintf(slot, "%04x:%02x:%02x.%x", dev->domain, dev->bus, dev->dev, dev->func); + trace("%s ", slot); + if (op->cap_type) { struct pci_cap *cap; - if (op->cap < 0x20000) - { - if (verbose) - printf("(cap %02x)", op->cap - 0x10000); - cap = pci_find_cap(dev, op->cap - 0x10000, PCI_CAP_NORMAL); - } - else - { - if (verbose) - printf("(ecap %04x)", op->cap - 0x20000); - cap = pci_find_cap(dev, op->cap - 0x20000, PCI_CAP_EXTENDED); - } + cap = pci_find_cap(dev, op->cap_id, op->cap_type); if (cap) addr = cap->addr; else - { - /* FIXME: Report the error properly */ - die("Capability %08x not found", op->cap); - } + die("%s: %s %04x not found", slot, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), op->cap_id); + trace(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x @%02x) " : "(ecap %04x @%03x) "), op->cap_id, addr); } addr += op->addr; - if (verbose) - printf(":%02x", addr); + trace("@%02x", addr); + + /* We have already checked it when parsing, but addressing relative to capabilities can change the address. */ + if (addr & (width-1)) + die("%s: Unaligned access of width %d to register %04x", slot, width, addr); + if (addr + width > 0x1000) + die("%s: Access of width %d to register %04x out of range", slot, width, addr); + if (op->num_values) { for (i=0; inum_values; i++) { - if (addr + width > 0x1000) - die("Out of range"); /* FIXME */ if ((op->values[i].mask & max_values[width]) == max_values[width]) { x = op->values[i].value; - if (verbose) - { - putchar(' '); - printf(formats[width], op->values[i].value); - } + trace(formats[width], op->values[i].value); } else { @@ -126,11 +125,7 @@ exec_op(struct op *op, struct pci_dev *dev) break; } x = (y & ~op->values[i].mask) | op->values[i].value; - if (verbose) - { - putchar(' '); - printf(mask_formats[width], y, op->values[i].value, op->values[i].mask, x); - } + trace(mask_formats[width], y, op->values[i].value, op->values[i].mask, x); } if (!demo_mode) { @@ -149,15 +144,11 @@ exec_op(struct op *op, struct pci_dev *dev) } addr += width; } - if (verbose) - putchar('\n'); + trace("\n"); } else { - if (verbose) - printf(" = "); - if (addr + width > 0x1000) - die("Out of range"); /* FIXME */ + trace(" = "); switch (width) { case 1: @@ -170,7 +161,7 @@ exec_op(struct op *op, struct pci_dev *dev) x = pci_read_long(dev, addr); break; } - printf(formats[width], x); + printf(formats[width]+1, x); putchar('\n'); } } @@ -196,6 +187,8 @@ execute(struct op *op) static void scan_ops(struct op *op) { + if (demo_mode) + return; while (op) { if (op->num_values) @@ -330,17 +323,9 @@ dump_registers(void) } } -static void NONRET PCI_PRINTF(1,2) -usage(char *msg, ...) +static void NONRET +usage(void) { - va_list args; - va_start(args, msg); - if (msg) - { - fprintf(stderr, "setpci: "); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n\n"); - } fprintf(stderr, "Usage: setpci [] (+ [=]*)*\n" "\n" @@ -364,24 +349,40 @@ GENERIC_HELP ":\t[,...]\n" ":\t\n" "\t\t:\n"); + exit(0); +} + +static void NONRET PCI_PRINTF(1,2) +parse_err(const char *msg, ...) +{ + va_list args; + va_start(args, msg); + fprintf(stderr, "setpci: "); + vfprintf(stderr, msg, args); + fprintf(stderr, ".\nTry `setpci --help' for more information.\n"); exit(1); } static int parse_options(int argc, char **argv) { - char *opts = GENERIC_OPTIONS; + const char opts[] = GENERIC_OPTIONS; int i=1; - if (argc == 2 && !strcmp(argv[1], "--version")) - { - puts("setpci version " PCIUTILS_VERSION); - exit(0); - } - if (argc == 2 && !strcmp(argv[1], "--dumpregs")) + if (argc == 2) { - dump_registers(); - exit(0); + if (!strcmp(argv[1], "--help")) + usage(); + if (!strcmp(argv[1], "--version")) + { + puts("setpci version " PCIUTILS_VERSION); + exit(0); + } + if (!strcmp(argv[1], "--dumpregs")) + { + dump_registers(); + exit(0); + } } while (i < argc && argv[i][0] == '-') @@ -418,18 +419,18 @@ parse_options(int argc, char **argv) else if (i < argc) arg = argv[i++]; else - usage(NULL); + parse_err("Option -%c requires an argument", *e); c = ""; } else arg = NULL; if (!parse_generic_option(*e, pacc, arg)) - usage(NULL); + parse_err("Unable to parse option -%c", *e); } else { if (c != d) - usage(NULL); + parse_err("Invalid or misplaced option -%c", *c); return i-1; } } @@ -444,25 +445,25 @@ static int parse_filter(int argc, char **argv, int i, struct pci_filter *filter) char *d; if (!c[1] || !strchr("sd", c[1])) - usage(NULL); + parse_err("Invalid option -%c", c[1]); if (c[2]) d = (c[2] == '=') ? c+3 : c+2; else if (i < argc) d = argv[i++]; else - usage(NULL); + parse_err("Option -%c requires an argument", c[1]); switch (c[1]) { case 's': if (d = pci_filter_parse_slot(filter, d)) - die("-s: %s", d); + parse_err("Unable to parse filter -s %s", d); break; case 'd': if (d = pci_filter_parse_id(filter, d)) - die("-d: %s", d); + parse_err("Unable to parse filter -d %s", d); break; default: - usage(NULL); + parse_err("Unknown filter option -%c", c[1]); } return i; @@ -481,11 +482,12 @@ static const struct reg_name *parse_reg_name(char *name) static int parse_x32(char *c, char **stopp, unsigned int *resp) { char *stop; + unsigned long int l; if (!*c) return -1; errno = 0; - unsigned long int l = strtoul(c, &stop, 16); + l = strtoul(c, &stop, 16); if (errno) return -1; if ((l & ~0U) != l) @@ -498,21 +500,33 @@ static int parse_x32(char *c, char **stopp, unsigned int *resp) return 0; } else - return 1; + { + if (stopp) + *stopp = NULL; + return 1; + } } static void parse_register(struct op *op, char *base) { const struct reg_name *r; + unsigned int cap; + op->cap_type = op->cap_id = 0; if (parse_x32(base, NULL, &op->addr) > 0) - { - op->cap = 0; - return; - } + return; else if (r = parse_reg_name(base)) { - op->cap = r->cap; + switch (r->cap & 0xff0000) + { + case 0x10000: + op->cap_type = PCI_CAP_NORMAL; + break; + case 0x20000: + op->cap_type = PCI_CAP_EXTENDED; + break; + } + op->cap_id = r->cap & 0xffff; op->addr = r->offset; if (r->width && !op->width) op->width = r->width; @@ -520,23 +534,25 @@ static void parse_register(struct op *op, char *base) } else if (!strncasecmp(base, "CAP", 3)) { - if (parse_x32(base+3, NULL, &op->cap) > 0 && op->cap < 0x100) + if (parse_x32(base+3, NULL, &cap) > 0 && cap < 0x100) { - op->cap += 0x10000; + op->cap_type = PCI_CAP_NORMAL; + op->cap_id = cap; op->addr = 0; return; } } else if (!strncasecmp(base, "ECAP", 4)) { - if (parse_x32(base+4, NULL, &op->cap) > 0 && op->cap < 0x1000) + if (parse_x32(base+4, NULL, &cap) > 0 && cap < 0x1000) { - op->cap += 0x20000; + op->cap_type = PCI_CAP_EXTENDED; + op->cap_id = cap; op->addr = 0; return; } } - usage("Unknown register \"%s\"", base); + parse_err("Unknown register \"%s\"", base); } static void parse_op(char *c, struct pci_dev **selected_devices) @@ -560,7 +576,7 @@ static void parse_op(char *c, struct pci_dev **selected_devices) if (value) { if (!*value) - usage("Missing value"); + parse_err("Missing value"); n++; for (e=value; *e; e++) if (*e == ',') @@ -576,7 +592,7 @@ static void parse_op(char *c, struct pci_dev **selected_devices) if (width) { if (width[1]) - usage("Invalid width \"%s\"", width); + parse_err("Invalid width \"%s\"", width); switch (*width & 0xdf) { case 'B': @@ -586,7 +602,7 @@ static void parse_op(char *c, struct pci_dev **selected_devices) case 'L': op->width = 4; break; default: - usage("Invalid width \"%c\"", *width); + parse_err("Invalid width \"%c\"", *width); } } else @@ -595,22 +611,22 @@ static void parse_op(char *c, struct pci_dev **selected_devices) /* Find the register */ parse_register(op, base); if (!op->width) - usage("Missing width"); + parse_err("Missing width"); /* Add offset */ if (offset) { unsigned int off; if (parse_x32(offset, NULL, &off) <= 0 || off >= 0x1000) - die("Invalid offset \"%s\"", offset); + parse_err("Invalid offset \"%s\"", offset); op->addr += off; } /* Check range */ if (op->addr >= 0x1000 || op->addr + op->width*(n ? n : 1) > 0x1000) - die("Register number out of range!"); + parse_err("Register number %02x out of range", op->addr); if (op->addr & (op->width - 1)) - die("Unaligned register address!"); + parse_err("Unaligned register address %02x", op->addr); /* Parse the values */ for (j=0; jwidth]; if (ll > lim && ll < ~0UL - lim) - usage("Value \"%s\" is out of range", value); + parse_err("Value \"%s\" is out of range", value); op->values[j].value = ll; - if (*f == ':') + if (f && *f == ':') { if (parse_x32(f+1, NULL, &ll) <= 0) - usage("Invalid mask \"%s\"", f+1); + parse_err("Invalid mask \"%s\"", f+1); if (ll > lim && ll < ~0UL - lim) - usage("Mask \"%s\" is out of range", f+1); + parse_err("Mask \"%s\" is out of range", f+1); op->values[j].mask = ll; op->values[j].value &= ll; } @@ -664,17 +680,17 @@ static void parse_ops(int argc, char **argv, int i) else { if (state == STATE_INIT) - usage(NULL); + parse_err("Filter specification expected"); if (state == STATE_GOT_FILTER) selected_devices = select_devices(&filter); if (!selected_devices[0] && !force) - fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c); + fprintf(stderr, "setpci: Warning: No devices selected for \"%s\".\n", c); parse_op(c, selected_devices); state = STATE_GOT_OP; } } if (state == STATE_INIT) - usage("No operation specified"); + parse_err("No operation specified"); } int