]> mj.ucw.cz Git - pciutils.git/blobdiff - setpci.c
lspci: Clarify "PCIe-to-PCI/PCI-X" desc and Bridge Retry Config Enable
[pciutils.git] / setpci.c
index 1c78db051352f581c3be717cda01ac21a98406df..acf768971702edcaff5d9e14c28eb18268f6669d 100644 (file)
--- a/setpci.c
+++ b/setpci.c
@@ -10,7 +10,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
-#include <unistd.h>
 #include <errno.h>
 
 #define PCIUTILS_SETPCI
@@ -60,48 +59,55 @@ select_devices(struct pci_filter *filt)
   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);
+  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 (verbose)
-       printf(((op->cap_type == PCI_CAP_NORMAL) ? "(cap %02x)" : "(ecap %04x)"), op->cap_id);
       cap = pci_find_cap(dev, op->cap_id, op->cap_type);
       if (cap)
        addr = cap->addr;
       else
-       {
-         /* FIXME: Report the error properly */
-         die("Capability %04x not found", op->cap_id);
-       }
+       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
            {
@@ -118,11 +124,7 @@ exec_op(struct op *op, struct pci_dev *dev)
                  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)
            {
@@ -141,15 +143,11 @@ exec_op(struct op *op, struct pci_dev *dev)
            }
          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:
@@ -162,7 +160,7 @@ exec_op(struct op *op, struct pci_dev *dev)
          x = pci_read_long(dev, addr);
          break;
        }
-      printf(formats[width], x);
+      printf(formats[width]+1, x);
       putchar('\n');
     }
 }
@@ -188,6 +186,8 @@ execute(struct op *op)
 static void
 scan_ops(struct op *op)
 {
+  if (demo_mode)
+    return;
   while (op)
     {
       if (op->num_values)
@@ -322,17 +322,9 @@ dump_registers(void)
     }
 }
 
-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"
@@ -356,24 +348,40 @@ GENERIC_HELP
 "<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"))
+  if (argc == 2)
     {
-      puts("setpci version " PCIUTILS_VERSION);
-      exit(0);
-    }
-  if (argc == 2 && !strcmp(argv[1], "--dumpregs"))
-    {
-      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] == '-')
@@ -410,18 +418,18 @@ parse_options(int argc, char **argv)
                    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;
              }
          }
@@ -436,25 +444,25 @@ static int parse_filter(int argc, char **argv, int i, struct pci_filter *filter)
   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;
@@ -473,11 +481,12 @@ static const struct reg_name *parse_reg_name(char *name)
 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)
@@ -490,7 +499,11 @@ static int parse_x32(char *c, char **stopp, unsigned int *resp)
       return 0;
     }
   else
-    return 1;
+    {
+      if (stopp)
+       *stopp = NULL;
+      return 1;
+    }
 }
 
 static void parse_register(struct op *op, char *base)
@@ -538,7 +551,7 @@ static void parse_register(struct op *op, char *base)
          return;
        }
     }
-  usage("Unknown register \"%s\"", base);
+  parse_err("Unknown register \"%s\"", base);
 }
 
 static void parse_op(char *c, struct pci_dev **selected_devices)
@@ -562,7 +575,7 @@ 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 == ',')
@@ -578,7 +591,7 @@ static void parse_op(char *c, struct pci_dev **selected_devices)
   if (width)
     {
       if (width[1])
-       usage("Invalid width \"%s\"", width);
+       parse_err("Invalid width \"%s\"", width);
       switch (*width & 0xdf)
        {
        case 'B':
@@ -588,7 +601,7 @@ static void parse_op(char *c, struct pci_dev **selected_devices)
        case 'L':
          op->width = 4; break;
        default:
-         usage("Invalid width \"%c\"", *width);
+         parse_err("Invalid width \"%c\"", *width);
        }
     }
   else
@@ -597,22 +610,22 @@ static void parse_op(char *c, struct pci_dev **selected_devices)
   /* 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++)
@@ -621,18 +634,18 @@ static void parse_op(char *c, struct pci_dev **selected_devices)
       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);
+      if (ll > lim && ll < ~0U - lim)
+       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);
-         if (ll > lim && ll < ~0UL - lim)
-           usage("Mask \"%s\" is out of range", f+1);
+           parse_err("Invalid mask \"%s\"", f+1);
+         if (ll > lim && ll < ~0U - lim)
+           parse_err("Mask \"%s\" is out of range", f+1);
          op->values[j].mask = ll;
          op->values[j].value &= ll;
        }
@@ -666,17 +679,17 @@ static void parse_ops(int argc, char **argv, int i)
       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