X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=setpci.c;h=8f2841c6529a046a59875d1a4fc2fcd9cee40b98;hb=dc01dd60affb4688453f8b7204af66246f0850db;hp=3efd1965292c33449613f743b88341c529853de3;hpb=33bc28a56667f0857e1225a0c4e71aac92c060eb;p=pciutils.git diff --git a/setpci.c b/setpci.c index 3efd196..8f2841c 100644 --- a/setpci.c +++ b/setpci.c @@ -1,9 +1,7 @@ /* - * $Id: setpci.c,v 1.10 1999/12/04 12:32:57 mj Exp $ + * The PCI Utilities -- Manipulate PCI Configuration Registers * - * Linux PCI Utilities -- Manipulate PCI Configuration Registers - * - * Copyright (c) 1998 Martin Mares + * Copyright (c) 1998--2006 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -20,18 +18,26 @@ static int force; /* Don't complain if no devices match */ static int verbose; /* Verbosity level */ static int demo_mode; /* Only show */ +const char program_name[] = "setpci"; + static struct pci_access *pacc; +struct value { + unsigned int value; + unsigned int mask; +}; + struct op { struct op *next; struct pci_dev **dev_vector; unsigned int addr; unsigned int width; /* Byte width of the access */ int num_values; /* Number of values to write; <0=read */ - unsigned int values[0]; + struct value values[0]; }; static struct op *first_op, **last_op = &first_op; +static unsigned int max_values[] = { 0, 0xff, 0xffff, 0, 0xffffffff }; static struct pci_dev ** select_devices(struct pci_filter *filt) @@ -53,62 +59,88 @@ select_devices(struct pci_filter *filt) static void exec_op(struct op *op, struct pci_dev *dev) { - char *mm[] = { NULL, "%02x", "%04x", NULL, "%08x" }; - char *m = mm[op->width]; - unsigned int x; + char *formats[] = { NULL, "%02x", "%04x", NULL, "%08x" }; + char *mask_formats[] = { NULL, "%02x->(%02x:%02x)->%02x", "%04x->(%04x:%04x)->%04x", NULL, "%08x->(%08x:%08x)->%08x" }; + unsigned int x, y; int i, addr; + int width = op->width; if (verbose) printf("%02x:%02x.%x:%02x", dev->bus, dev->dev, dev->func, op->addr); addr = op->addr; if (op->num_values >= 0) - for(i=0; inum_values; i++) - { - if (verbose) - { - putchar(' '); - printf(m, op->values[i]); - } - if (demo_mode) - continue; - switch (op->width) - { - case 1: - pci_write_byte(dev, addr, op->values[i]); - break; - case 2: - pci_write_word(dev, addr, op->values[i]); - break; - default: - pci_write_long(dev, addr, op->values[i]); - break; - } - addr += op->width; - } + { + for(i=0; inum_values; i++) + { + 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); + } + } + else + { + switch (width) + { + case 1: + y = pci_read_byte(dev, addr); + break; + case 2: + y = pci_read_word(dev, addr); + break; + default: + y = pci_read_long(dev, addr); + 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); + } + } + if (!demo_mode) + { + switch (width) + { + case 1: + pci_write_byte(dev, addr, x); + break; + case 2: + pci_write_word(dev, addr, x); + break; + default: + pci_write_long(dev, addr, x); + break; + } + } + addr += width; + } + if (verbose) + putchar('\n'); + } else { if (verbose) printf(" = "); - if (!demo_mode) + switch (width) { - switch (op->width) - { - case 1: - x = pci_read_byte(dev, addr); - break; - case 2: - x = pci_read_word(dev, addr); - break; - default: - x = pci_read_long(dev, addr); - break; - } - printf(m, x); + case 1: + x = pci_read_byte(dev, addr); + break; + case 2: + x = pci_read_word(dev, addr); + break; + default: + x = pci_read_long(dev, addr); + break; } - else - putchar('?'); + printf(formats[width], x); + putchar('\n'); } - putchar('\n'); } static void @@ -141,12 +173,12 @@ scan_ops(struct op *op) } struct reg_name { - int offset; - int width; - char *name; + unsigned int offset; + unsigned int width; + const char *name; }; -static struct reg_name pci_reg_names[] = { +static const struct reg_name pci_reg_names[] = { { 0x00, 2, "VENDOR_ID", }, { 0x02, 2, "DEVICE_ID", }, { 0x04, 2, "COMMAND", }, @@ -214,23 +246,30 @@ static struct reg_name pci_reg_names[] = { { 0x00, 0, NULL } }; -static void usage(void) __attribute__((noreturn)); - -static void -usage(void) +static void NONRET +usage(char *msg, ...) { + 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\ -f\t\tDon't complain if there's nothing to do\n\ -v\t\tBe verbose\n\ -D\t\tList changes, don't commit them\n" GENERIC_HELP -":\t-s [[]:][][.[]]\n\ -\t|\t-d []:[]\n\ -:\t\t[.(B|W|L)]\n\ - |\t\t\n\ -:\t[,...]\n\ -"); +":\t-s [[[]:][]:][][.[]]\n" +"\t|\t-d []:[]\n" +":\t\t[.(B|W|L)]\n" +" |\t\t\n" +":\t[,...]\n" +":\t\n" +" |\t:\n"); exit(1); } @@ -290,18 +329,18 @@ main(int argc, char **argv) argc--; argv++; } else - usage(); + usage(NULL); c = ""; } else arg = NULL; if (!parse_generic_option(*e, pacc, arg)) - usage(); + usage(NULL); } else { if (c != d) - usage(); + usage(NULL); goto next; } } @@ -319,22 +358,23 @@ next: char *d, *e, *f; int n, i; struct op *op; - unsigned long ll, lim; + unsigned long ll; + unsigned int lim; if (*c == '-') { if (!c[1] || !strchr("sd", c[1])) - usage(); + usage(NULL); if (c[2]) d = (c[2] == '=') ? c+3 : c+2; - else if (argc) + else if (argc > 1) { argc--; argv++; d = argv[0]; } else - usage(); + usage(NULL); if (state != STATE_GOT_FILTER) { pci_filter_init(pacc, &filter); @@ -351,11 +391,11 @@ next: die("-d: %s", d); break; default: - usage(); + usage(NULL); } } else if (state == STATE_INIT) - usage(); + usage(NULL); else { if (state == STATE_GOT_FILTER) @@ -363,16 +403,17 @@ next: if (!selected_devices[0] && !force) fprintf(stderr, "setpci: Warning: No devices selected for `%s'.\n", c); state = STATE_GOT_OP; + /* look for setting of values and count how many */ d = strchr(c, '='); if (d) { *d++ = 0; if (!*d) - usage(); + usage("Missing value"); for(e=d, n=1; *e; e++) if (*e == ',') n++; - op = xmalloc(sizeof(struct op) + n*sizeof(unsigned int)); + op = xmalloc(sizeof(struct op) + n*sizeof(struct value)); } else { @@ -386,7 +427,7 @@ next: { *e++ = 0; if (e[1]) - usage(); + usage("Missing width"); switch (*e & 0xdf) { case 'B': @@ -396,7 +437,7 @@ next: case 'L': op->width = 4; break; default: - usage(); + usage("Invalid width \"%c\"", *e); } } else @@ -404,31 +445,48 @@ next: ll = strtol(c, &f, 16); if (f && *f) { - struct reg_name *r; + const struct reg_name *r; for(r = pci_reg_names; r->name; r++) if (!strcasecmp(r->name, c)) break; - if (!r->name || e) - usage(); + if (!r->name) + usage("Unknown register \"%s\"", c); + if (e && op->width != r->width) + usage("Explicit width doesn't correspond with the named register \"%s\"", c); ll = r->offset; op->width = r->width; } - if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100) + if (ll > 0x1000 || ll + op->width*((n < 0) ? 1 : n) > 0x1000) die("Register number out of range!"); if (ll & (op->width - 1)) die("Unaligned register address!"); op->addr = ll; + /* read in all the values to be set */ for(i=0; iwidth << 3) - 1)) - 1; - if (f && *f || - (ll > lim && ll < ~0UL - lim)) - usage(); - op->values[i] = ll; + lim = max_values[op->width]; + if (f && *f && *f != ':') + usage("Invalid value \"%s\"", d); + if (ll > lim && ll < ~0UL - lim) + usage("Value \"%s\" is out of range", d); + op->values[i].value = ll; + if (f && *f == ':') + { + d = ++f; + ll = strtoul(d, &f, 16); + if (f && *f) + usage("Invalid mask \"%s\"", d); + if (ll > lim && ll < ~0UL - lim) + usage("Mask \"%s\" is out of range", d); + op->values[i].mask = ll; + op->values[i].value &= ll; + } + else + op->values[i].mask = ~0U; d = e; } *last_op = op; @@ -439,7 +497,7 @@ next: argv++; } if (state == STATE_INIT) - usage(); + usage("No operation specified"); scan_ops(first_op); execute(first_op);