X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=setpci.c;h=497538a5b9d73658f23255001378e812137e613f;hb=239ff18adf556b63a16be968725ba9fd0e6d5227;hp=189b96a984f3ae8200e0547b73eb76f54bf1d2e1;hpb=e4842ff3b1ab7e061e0fb7f81fcb88d9995a63a2;p=pciutils.git diff --git a/setpci.c b/setpci.c index 189b96a..497538a 100644 --- a/setpci.c +++ b/setpci.c @@ -1,9 +1,9 @@ /* - * $Id: setpci.c,v 1.1 1998/03/31 21:02:20 mj Exp $ + * $Id: setpci.c,v 1.12 2002/03/30 15:39:24 mj Exp $ * * Linux PCI Utilities -- Manipulate PCI Configuration Registers * - * Copyright (c) 1998 Martin Mares + * Copyright (c) 1998 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -11,26 +11,20 @@ #include #include #include -#include +#include #include #include "pciutils.h" static int force; /* Don't complain if no devices match */ static int verbose; /* Verbosity level */ +static int demo_mode; /* Only show */ -struct device { - struct device *next; - byte bus, devfn, mark; - word vendid, devid; - int fd; -}; - -static struct device *first_dev; +static struct pci_access *pacc; struct op { struct op *next; - struct device **dev_vector; + 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 */ @@ -39,96 +33,89 @@ struct op { static struct op *first_op, **last_op = &first_op; -void * -xmalloc(unsigned int howmuch) -{ - void *p = malloc(howmuch); - if (!p) - { - fprintf(stderr, "setpci: Unable to allocate %d bytes of memory\n", howmuch); - exit(1); - } - return p; -} - -static void -scan_devices(void) -{ - struct device **last = &first_dev; - byte line[256]; - FILE *f; - - if (!(f = fopen(PROC_BUS_PCI "/devices", "r"))) - { - perror(PROC_BUS_PCI "/devices"); - exit(1); - } - while (fgets(line, sizeof(line), f)) - { - struct device *d = xmalloc(sizeof(struct device)); - unsigned int dfn, vend; - - sscanf(line, "%x %x", &dfn, &vend); - d->bus = dfn >> 8U; - d->devfn = dfn & 0xff; - d->vendid = vend >> 16U; - d->devid = vend & 0xffff; - d->fd = -1; - *last = d; - last = &d->next; - } - fclose(f); - *last = NULL; -} - -static struct device ** +static struct pci_dev ** select_devices(struct pci_filter *filt) { - struct device *z, **a, **b; + struct pci_dev *z, **a, **b; int cnt = 1; - for(z=first_dev; z; z=z->next) - if (z->mark = filter_match(filt, z->bus, z->devfn, z->vendid, z->devid)) + for(z=pacc->devices; z; z=z->next) + if (pci_filter_match(filt, z)) cnt++; a = b = xmalloc(sizeof(struct device *) * cnt); - for(z=first_dev; z; z=z->next) - if (z->mark) + for(z=pacc->devices; z; z=z->next) + if (pci_filter_match(filt, z)) *a++ = z; *a = NULL; return b; } static void -exec_op(struct op *op, struct device *dev) +exec_op(struct op *op, struct pci_dev *dev) { char *mm[] = { NULL, "%02x", "%04x", NULL, "%08x" }; char *m = mm[op->width]; - - if (dev->fd < 0) - { - char name[64]; - sprintf(name, PROC_BUS_PCI "/%02x/%02x.%x", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - dev->fd = open(name, O_RDWR ???? - } + unsigned int x; + int i, addr; if (verbose) - printf("%02x.%02x:%x.%c ", dev->bus, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), - "?BW?L"[op->width]); - if (op->num_values > 0) - { - } + 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; + } else { if (verbose) - printf("= "); + printf(" = "); + if (!demo_mode) + { + 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); + } + else + putchar('?'); } + putchar('\n'); } static void execute(struct op *op) { - struct device **vec = NULL; - struct device **pdev, *dev; + struct pci_dev **vec = NULL; + struct pci_dev **pdev, *dev; struct op *oops; while (op) @@ -142,17 +129,107 @@ execute(struct op *op) } } +static void +scan_ops(struct op *op) +{ + while (op) + { + if (op->num_values >= 0) + pacc->writeable = 1; + op = op->next; + } +} + +struct reg_name { + int offset; + int width; + char *name; +}; + +static struct reg_name pci_reg_names[] = { + { 0x00, 2, "VENDOR_ID", }, + { 0x02, 2, "DEVICE_ID", }, + { 0x04, 2, "COMMAND", }, + { 0x06, 2, "STATUS", }, + { 0x08, 1, "REVISION", }, + { 0x09, 1, "CLASS_PROG", }, + { 0x0a, 2, "CLASS_DEVICE", }, + { 0x0c, 1, "CACHE_LINE_SIZE", }, + { 0x0d, 1, "LATENCY_TIMER", }, + { 0x0e, 1, "HEADER_TYPE", }, + { 0x0f, 1, "BIST", }, + { 0x10, 4, "BASE_ADDRESS_0", }, + { 0x14, 4, "BASE_ADDRESS_1", }, + { 0x18, 4, "BASE_ADDRESS_2", }, + { 0x1c, 4, "BASE_ADDRESS_3", }, + { 0x20, 4, "BASE_ADDRESS_4", }, + { 0x24, 4, "BASE_ADDRESS_5", }, + { 0x28, 4, "CARDBUS_CIS", }, + { 0x2c, 4, "SUBSYSTEM_VENDOR_ID", }, + { 0x2e, 2, "SUBSYSTEM_ID", }, + { 0x30, 4, "ROM_ADDRESS", }, + { 0x3c, 1, "INTERRUPT_LINE", }, + { 0x3d, 1, "INTERRUPT_PIN", }, + { 0x3e, 1, "MIN_GNT", }, + { 0x3f, 1, "MAX_LAT", }, + { 0x18, 1, "PRIMARY_BUS", }, + { 0x19, 1, "SECONDARY_BUS", }, + { 0x1a, 1, "SUBORDINATE_BUS", }, + { 0x1b, 1, "SEC_LATENCY_TIMER", }, + { 0x1c, 1, "IO_BASE", }, + { 0x1d, 1, "IO_LIMIT", }, + { 0x1e, 2, "SEC_STATUS", }, + { 0x20, 2, "MEMORY_BASE", }, + { 0x22, 2, "MEMORY_LIMIT", }, + { 0x24, 2, "PREF_MEMORY_BASE", }, + { 0x26, 2, "PREF_MEMORY_LIMIT", }, + { 0x28, 4, "PREF_BASE_UPPER32", }, + { 0x2c, 4, "PREF_LIMIT_UPPER32", }, + { 0x30, 2, "IO_BASE_UPPER16", }, + { 0x32, 2, "IO_LIMIT_UPPER16", }, + { 0x38, 4, "BRIDGE_ROM_ADDRESS", }, + { 0x3e, 2, "BRIDGE_CONTROL", }, + { 0x10, 4, "CB_CARDBUS_BASE", }, + { 0x14, 2, "CB_CAPABILITIES", }, + { 0x16, 2, "CB_SEC_STATUS", }, + { 0x18, 1, "CB_BUS_NUMBER", }, + { 0x19, 1, "CB_CARDBUS_NUMBER", }, + { 0x1a, 1, "CB_SUBORDINATE_BUS", }, + { 0x1b, 1, "CB_CARDBUS_LATENCY", }, + { 0x1c, 4, "CB_MEMORY_BASE_0", }, + { 0x20, 4, "CB_MEMORY_LIMIT_0", }, + { 0x24, 4, "CB_MEMORY_BASE_1", }, + { 0x28, 4, "CB_MEMORY_LIMIT_1", }, + { 0x2c, 2, "CB_IO_BASE_0", }, + { 0x2e, 2, "CB_IO_BASE_0_HI", }, + { 0x30, 2, "CB_IO_LIMIT_0", }, + { 0x32, 2, "CB_IO_LIMIT_0_HI", }, + { 0x34, 2, "CB_IO_BASE_1", }, + { 0x36, 2, "CB_IO_BASE_1_HI", }, + { 0x38, 2, "CB_IO_LIMIT_1", }, + { 0x3a, 2, "CB_IO_LIMIT_1_HI", }, + { 0x40, 2, "CB_SUBSYSTEM_VENDOR_ID", }, + { 0x42, 2, "CB_SUBSYSTEM_ID", }, + { 0x44, 4, "CB_LEGACY_MODE_BASE", }, + { 0x00, 0, NULL } +}; + static void usage(void) __attribute__((noreturn)); static void usage(void) { fprintf(stderr, -"Usage: setpci [-f] [-v] (+ [=]*)*\n\ -: -s [[]:][][.[]]\n\ -\t| -d []:[]\n\ -: [.(B|W|L)]\n\ -: [,...]\n\ +"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\ "); exit(1); } @@ -162,14 +239,25 @@ main(int argc, char **argv) { enum { STATE_INIT, STATE_GOT_FILTER, STATE_GOT_OP } state = STATE_INIT; struct pci_filter filter; - struct device **selected_devices = NULL; + struct pci_dev **selected_devices = NULL; + char *opts = GENERIC_OPTIONS ; + if (argc == 2 && !strcmp(argv[1], "--version")) + { + puts("setpci version " PCIUTILS_VERSION); + return 0; + } argc--; argv++; + + pacc = pci_alloc(); + pacc->error = die; + while (argc && argv[0][0] == '-') { char *c = argv[0]+1; char *d = c; + char *e; while (*c) switch (*c) { @@ -181,19 +269,49 @@ main(int argc, char **argv) force++; c++; break; + case 'D': + demo_mode++; + c++; + break; case 0: break; default: - if (c != d) - usage(); - goto next; + if (e = strchr(opts, *c)) + { + char *arg; + c++; + if (e[1] == ':') + { + if (*c) + arg = c; + else if (argc > 1) + { + arg = argv[1]; + argc--; argv++; + } + else + usage(); + c = ""; + } + else + arg = NULL; + if (!parse_generic_option(*e, pacc, arg)) + usage(); + } + else + { + if (c != d) + usage(); + goto next; + } } argc--; argv++; } next: - scan_devices(); + pci_init(pacc); + pci_scan_bus(pacc); while (argc) { @@ -209,7 +327,7 @@ next: usage(); if (c[2]) d = (c[2] == '=') ? c+3 : c+2; - else if (argc) + else if (argc > 1) { argc--; argv++; @@ -219,24 +337,18 @@ next: usage(); if (state != STATE_GOT_FILTER) { - filter_init(&filter); + pci_filter_init(pacc, &filter); state = STATE_GOT_FILTER; } switch (c[1]) { case 's': - if (d = filter_parse_slot(&filter, d)) - { - fprintf(stderr, "setpci: -s: %s\n", d); - return 1; - } + if (d = pci_filter_parse_slot(&filter, d)) + die("-s: %s", d); break; case 'd': - if (d = filter_parse_id(&filter, d)) - { - fprintf(stderr, "setpci: -d: %s\n", d); - return 1; - } + if (d = pci_filter_parse_id(&filter, d)) + die("-d: %s", d); break; default: usage(); @@ -255,6 +367,8 @@ next: if (d) { *d++ = 0; + if (!*d) + usage(); for(e=d, n=1; *e; e++) if (*e == ',') n++; @@ -288,11 +402,22 @@ next: else op->width = 1; ll = strtol(c, &f, 16); - if (ll > 0x100 || ll + op->width*n > 0x100) + if (f && *f) { - fprintf(stderr, "setpci: Register number out of range!\n"); - return 1; + struct reg_name *r; + for(r = pci_reg_names; r->name; r++) + if (!strcasecmp(r->name, c)) + break; + if (!r->name || e) + usage(); + ll = r->offset; + op->width = r->width; } + if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100) + die("Register number out of range!"); + if (ll & (op->width - 1)) + die("Unaligned register address!"); + op->addr = ll; for(i=0; i