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 */
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; i<op->num_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
{
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)
{
}
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:
x = pci_read_long(dev, addr);
break;
}
- printf(formats[width], x);
+ printf(formats[width]+1, x);
putchar('\n');
}
}
static void
scan_ops(struct op *op)
{
+ if (demo_mode)
+ return;
while (op)
{
if (op->num_values)
}
}
-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 [<options>] (<device>+ <reg>[=<values>]*)*\n"
"\n"
"<values>:\t<value>[,<value>...]\n"
"<value>:\t<hex>\n"
"\t\t<hex>:<mask>\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] == '-')
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;
}
}
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;
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)
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;
}
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)
if (value)
{
if (!*value)
- usage("Missing value");
+ parse_err("Missing value");
n++;
for (e=value; *e; e++)
if (*e == ',')
if (width)
{
if (width[1])
- usage("Invalid width \"%s\"", width);
+ parse_err("Invalid width \"%s\"", width);
switch (*width & 0xdf)
{
case 'B':
case 'L':
op->width = 4; break;
default:
- usage("Invalid width \"%c\"", *width);
+ parse_err("Invalid width \"%c\"", *width);
}
}
else
/* 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; j<n; j++)
e = strchr(value, ',');
if (e)
*e++ = 0;
- if (parse_x32(value, &f, &ll) < 0 || *f && *f != ':')
- usage("Invalid value \"%s\"", value);
+ if (parse_x32(value, &f, &ll) < 0 || f && *f != ':')
+ parse_err("Invalid value \"%s\"", value);
lim = max_values[op->width];
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;
}
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