From 6639fd175ae561240639c2c54da409bbc0f94835 Mon Sep 17 00:00:00 2001 From: Daniel Schaefer Date: Sun, 14 Oct 2018 22:48:57 +0200 Subject: [PATCH] Enable setpci to target n-th capability of id Because a capability can exist multiple times with the same id, there needs to be a way to target a specific one. Instead of the current behaviour which always targets the first one. Now you can optionally add `@number` (e.g `@1`) after the width to choose which one to target. --- setpci.c | 33 ++++++++++++++++++++++++++++----- setpci.man | 7 +++++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/setpci.c b/setpci.c index 82e02a5..13b6a6b 100644 --- a/setpci.c +++ b/setpci.c @@ -36,6 +36,7 @@ struct op { unsigned int addr; unsigned int width; /* Byte width of the access */ unsigned int num_values; /* Number of values to write; 0=read */ + unsigned int number; /* The n-th capability of that id */ struct value values[0]; }; @@ -84,11 +85,19 @@ exec_op(struct op *op, struct pci_dev *dev) if (op->cap_type) { struct pci_cap *cap; - cap = pci_find_cap(dev, op->cap_id, op->cap_type); + unsigned int cap_nr = op->number; + cap = pci_find_cap_nr(dev, op->cap_id, op->cap_type, &cap_nr); if (cap) - addr = cap->addr; + addr = cap->addr; + else if (cap_nr == 0) + die("%s: Instance #%d of %s %04x not found - there are no capabilities with that id.", slot, + op->number, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), + op->cap_id); else - die("%s: %s %04x not found", slot, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), op->cap_id); + die("%s: Instance #%d of %s %04x not found - there %s only %d capability with that id.", slot, + op->number, ((op->cap_type == PCI_CAP_NORMAL) ? "Capability" : "Extended capability"), + op->cap_id, ((cap_nr == 1) ? "is" : "are"), cap_nr); + trace(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x @%02x) " : "(ecap %04x @%03x) "), op->cap_id, addr); } addr += op->addr; @@ -341,7 +350,7 @@ GENERIC_HELP "Setting commands:\n" ":\t-s [[[]:][]:][][.[]]\n" "\t\t-d []:[]\n" -":\t\t[+][.(B|W|L)]\n" +":\t\t[+][.(B|W|L)][@]\n" ":\t\t
\n" "\t\t\n" "\t\t[E]CAP_\n" @@ -557,7 +566,7 @@ static void parse_register(struct op *op, char *base) static void parse_op(char *c, struct pci_dev **selected_devices) { - char *base, *offset, *width, *value; + char *base, *offset, *width, *value, *number; char *e, *f; int n, j; struct op *op; @@ -566,6 +575,8 @@ static void parse_op(char *c, struct pci_dev **selected_devices) base = xstrdup(c); if (value = strchr(base, '=')) *value++ = 0; + if (number = strchr(base, '@')) + *number++ = 0; if (width = strchr(base, '.')) *width++ = 0; if (offset = strchr(base, '+')) @@ -608,6 +619,18 @@ static void parse_op(char *c, struct pci_dev **selected_devices) else op->width = 0; + /* Check which n-th capability of the same id we want */ + if (number) + { + unsigned int num; + if (parse_x32(number, NULL, &num) <= 0 || (int) num < 0) + parse_err("Invalid number \"%s\"", number); + op->number = num; + + } + else + op->number = 0; + /* Find the register */ parse_register(op, base); if (!op->width) diff --git a/setpci.man b/setpci.man index d71628a..27dc958 100644 --- a/setpci.man +++ b/setpci.man @@ -148,9 +148,12 @@ Each of the previous formats can be followed by \fB+offset\fP to add an offset (a hex number) to the address. This feature can be useful for addressing of registers living within a capability, or to modify parts of standard registers. .IP \(bu -Finally, you should append a width specifier \fB.B\fP, \fB.W\fP, or \fB.L\fP to choose -how many bytes (1, 2, or 4) should be transferred. The width can be omitted if you are +To choose how many bytes (1, 2, or 4) should be transferred, you should append a width +specifier \fB.B\fP, \fB.W\fP, or \fB.L\fP. The width can be omitted if you are referring to a register by its name and the width of the register is well known. +.IP \(bu +Finally, if a capability exists multiple times you can choose which one to target using +\fB@number\fP. Indexing starts at 0. .PP All names of registers and width specifiers are case-insensitive. -- 2.39.2