From: Martin Mares Date: Fri, 26 Dec 2003 21:24:27 +0000 (+0000) Subject: Support masking in setpci X-Git-Tag: v3.0.0~156 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=b7351143a18cdcc60f1a1b3efef94864b0f61e9c;p=pciutils.git Support masking in setpci setpci.c: Individual bits to be set can be specified as :. Contributed by Thayne Harbaugh and cleaned up by me. git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-9 --- diff --git a/ChangeLog b/ChangeLog index 0fff412..17ab108 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,12 @@ * Makefile: Added some more warnings. + * setpci.c: Cleaned up mask/value code. + +2003-12-08 Thayne Harbaugh + + * setpci.c: Individual bits to be set can be specified as :. + 2003-11-29 Martin Mares * Imported the pciutils sources to my Arch repository. Good-bye, CVS. diff --git a/setpci.c b/setpci.c index cf91c89..a341507 100644 --- a/setpci.c +++ b/setpci.c @@ -1,7 +1,7 @@ /* * Linux PCI Utilities -- Manipulate PCI Configuration Registers * - * Copyright (c) 1998 Martin Mares + * Copyright (c) 1998--2003 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -20,16 +20,22 @@ static int demo_mode; /* Only show */ 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) @@ -51,45 +57,76 @@ 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 (op->width) + switch (width) { case 1: x = pci_read_byte(dev, addr); @@ -101,12 +138,12 @@ exec_op(struct op *op, struct pci_dev *dev) x = pci_read_long(dev, addr); break; } - printf(m, x); + printf(formats[width], x); } else putchar('?'); + putchar('\n'); } - putchar('\n'); } static void @@ -141,10 +178,10 @@ scan_ops(struct op *op) struct reg_name { int offset; int width; - char *name; + 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", }, @@ -223,12 +260,13 @@ usage(void) -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); } @@ -317,7 +355,8 @@ next: char *d, *e, *f; int n, i; struct op *op; - unsigned long ll, lim; + unsigned long ll; + unsigned int lim; if (*c == '-') { @@ -361,6 +400,7 @@ 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) { @@ -370,7 +410,7 @@ next: 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 { @@ -402,7 +442,7 @@ 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; @@ -416,17 +456,39 @@ next: 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 || + lim = max_values[op->width]; + if (f && *f && (*f != ':') || (ll > lim && ll < ~0UL - lim)) - usage(); - op->values[i] = ll; + { + fprintf(stderr, "bad value \"%s\"\n\n", d); + usage(); + } + if (f && *f == ':') + { + op->values[i].value = ll; + d = ++f; + ll = strtoul(d, &f, 16); + if (f && *f || + (ll > lim && ll < ~0UL - lim)) + { + fprintf(stderr, "bad value:mask pair \"%s\"\n\n", d); + usage(); + } + op->values[i].mask = ll; + op->values[i].value &= op->values[i].mask; + } + else + { + op->values[i].value = ll; + op->values[i].mask = ~0U; + } d = e; } *last_op = op; diff --git a/setpci.man b/setpci.man index f12f028..2825532 100644 --- a/setpci.man +++ b/setpci.man @@ -74,10 +74,17 @@ To set a register, write .BR reg = values where .B reg -is the same you would use to query the register and +is the same as you would use to query the register and .B values is a comma-separated list of values you want to write starting with the given -address. +address. Each value to be written can be specified either as a hexadecimal number +or as a +.BR bits : mask +pair which causes the bits corresponding to binary ones in the +.B mask +to be changed to values of the corresponding bits in the +.B bits +. .SH REGISTER NAMES .PP @@ -195,6 +202,11 @@ Increase debug level of the library. (All systems) .PP `setpci -s 12:3.4 3c.l=1,2,3' writes longword 1 to register 3c, 2 to register 3d and 3 to register 3e of device at bus 12, slot 3, function 4. +.PP +`setpci -s 13:8.4 40.b=50:d0,04:0c,ff' works on bus 13, device 8, function +4: turns bit 7 off and bits 6 and 4 on in the byte register 40; turns +bit 3 off and bit 2 on in the byte register 41; sets byte register +42 to ff. .SH SEE ALSO .BR lspci (8)