]> mj.ucw.cz Git - pciutils.git/blobdiff - lib/dump.c
lspci: Fix "Auxiliary" spelling error
[pciutils.git] / lib / dump.c
index 90293e44e98bd9f0dfdd63586910584485c930de..59cf7ed432d82db7d0ccb8ceded76538533f186c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The PCI Library -- Reading of Bus Dumps
  *
- *     Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
+ *     Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
 #include "internal.h"
 
+struct dump_data {
+  int len, allocated;
+  byte data[1];
+};
+
+static void
+dump_config(struct pci_access *a)
+{
+  pci_define_param(a, "dump.name", "", "Name of the bus dump file to read from");
+}
+
 static int
 dump_detect(struct pci_access *a)
 {
-  return !!a->method_params[PCI_ACCESS_DUMP];
+  char *name = pci_get_param(a, "dump.name");
+  return name && name[0];
+}
+
+static void
+dump_alloc_data(struct pci_dev *dev, int len)
+{
+  struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
+  dd->allocated = len;
+  dd->len = 0;
+  memset(dd->data, 0xff, len);
+  dev->aux = dd;
+}
+
+static int
+dump_validate(char *s, char *fmt)
+{
+  while (*fmt)
+    {
+      if (*fmt == '#' ? !isxdigit(*s) : *fmt != *s)
+       return 0;
+      fmt++, s++;
+    }
+  return 1;
 }
 
 static void
 dump_init(struct pci_access *a)
 {
-  char *name = a->method_params[PCI_ACCESS_DUMP];
+  char *name = pci_get_param(a, "dump.name");
   FILE *f;
   char buf[256];
   struct pci_dev *dev = NULL;
-  int len, bn, dn, fn, i, j;
+  int len, mn, bn, dn, fn, i, j;
 
-  if (!a)
+  if (!name)
     a->error("dump: File name not given.");
   if (!(f = fopen(name, "r")))
     a->error("dump: Cannot open %s: %s", name, strerror(errno));
@@ -36,35 +70,60 @@ dump_init(struct pci_access *a)
     {
       char *z = strchr(buf, '\n');
       if (!z)
-       a->error("dump: line too long or unterminated");
+       {
+         fclose(f);
+         a->error("dump: line too long or unterminated");
+       }
       *z-- = 0;
       if (z >= buf && *z == '\r')
        *z-- = 0;
       len = z - buf + 1;
-      if (len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' &&
-         sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3)
+      mn = 0;
+      if (dump_validate(buf, "##:##.# ") && sscanf(buf, "%x:%x.%d", &bn, &dn, &fn) == 3 ||
+         dump_validate(buf, "####:##:##.# ") && sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)
        {
-         dev = pci_get_dev(a, bn, dn, fn);
-         dev->aux = pci_malloc(a, 256);
-         memset(dev->aux, 0xff, 256);
+         dev = pci_get_dev(a, mn, bn, dn, fn);
+         dump_alloc_data(dev, 256);
          pci_link_dev(a, dev);
        }
       else if (!len)
        dev = NULL;
-      else if (dev && len >= 51 && buf[2] == ':' && buf[3] == ' ' &&
+      else if (dev &&
+              (dump_validate(buf, "##: ") || dump_validate(buf, "###: ")) &&
               sscanf(buf, "%x: ", &i) == 1)
        {
-         z = buf+3;
-         while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2]))
+         struct dump_data *dd = dev->aux;
+         z = strchr(buf, ' ') + 1;
+         while (isxdigit(z[0]) && isxdigit(z[1]) && (!z[2] || z[2] == ' ') &&
+                sscanf(z, "%x", &j) == 1 && j < 256)
            {
-             z++;
-             if (sscanf(z, "%x", &j) != 1 || i >= 256)
-               a->error("dump: Malformed line");
-             ((byte *) dev->aux)[i++] = j;
+             if (i >= 4096)
+               {
+                 fclose(f);
+                 a->error("dump: At most 4096 bytes of config space are supported");
+               }
+             if (i >= dd->allocated)   /* Need to re-allocate the buffer */
+               {
+                 dump_alloc_data(dev, 4096);
+                 memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256);
+                 pci_mfree(dd);
+                 dd = dev->aux;
+               }
+             dd->data[i++] = j;
+             if (i > dd->len)
+               dd->len = i;
              z += 2;
+             if (*z)
+               z++;
+           }
+         if (*z)
+           {
+             fclose(f);
+             a->error("dump: Malformed line");
            }
        }
     }
+  fclose(f);
 }
 
 static void
@@ -80,17 +139,19 @@ dump_scan(struct pci_access *a UNUSED)
 static int
 dump_read(struct pci_dev *d, int pos, byte *buf, int len)
 {
-  if (!d->aux)
+  struct dump_data *dd;
+  if (!(dd = d->aux))
     {
       struct pci_dev *e = d->access->devices;
-      while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func))
+      while (e && (e->domain != d->domain || e->bus != d->bus || e->dev != d->dev || e->func != d->func))
        e = e->next;
-      if (e)
-       d = e;
-      else
+      if (!e)
        return 0;
+      dd = e->aux;
     }
-  memcpy(buf, (byte *) d->aux + pos, len);
+  if (pos + len > dd->len)
+    return 0;
+  memcpy(buf, dd->data + pos, len);
   return 1;
 }
 
@@ -113,7 +174,8 @@ dump_cleanup_dev(struct pci_dev *d)
 
 struct pci_methods pm_dump = {
   "dump",
-  NULL,                                        /* config */
+  "Reading of register dumps (set the `dump.name' parameter)",
+  dump_config,
   dump_detect,
   dump_init,
   dump_cleanup,
@@ -121,6 +183,7 @@ struct pci_methods pm_dump = {
   pci_generic_fill_info,
   dump_read,
   dump_write,
+  NULL,                                        /* read_vpd */
   NULL,                                        /* init_dev */
   dump_cleanup_dev
 };