]> mj.ucw.cz Git - pciutils.git/blob - lib/dump.c
5a5b50eb9f1cce751bff4b02b89c06331945fdb8
[pciutils.git] / lib / dump.c
1 /*
2  *      The PCI Library -- Reading of Bus Dumps
3  *
4  *      Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL.
7  */
8
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <errno.h>
13
14 #include "internal.h"
15
16 struct dump_data {
17   int len;
18   byte data[1];
19 };
20
21 static int
22 dump_detect(struct pci_access *a)
23 {
24   return !!a->method_params[PCI_ACCESS_DUMP];
25 }
26
27 static void
28 dump_alloc_data(struct pci_dev *dev, int len)
29 {
30   struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1);
31   dd->len = len;
32   memset(dd->data, 0xff, len);
33   dev->aux = dd;
34 }
35
36 static void
37 dump_init(struct pci_access *a)
38 {
39   char *name = a->method_params[PCI_ACCESS_DUMP];
40   FILE *f;
41   char buf[256];
42   struct pci_dev *dev = NULL;
43   int len, mn, bn, dn, fn, i, j;
44
45   if (!a)
46     a->error("dump: File name not given.");
47   if (!(f = fopen(name, "r")))
48     a->error("dump: Cannot open %s: %s", name, strerror(errno));
49   while (fgets(buf, sizeof(buf)-1, f))
50     {
51       char *z = strchr(buf, '\n');
52       if (!z)
53         a->error("dump: line too long or unterminated");
54       *z-- = 0;
55       if (z >= buf && *z == '\r')
56         *z-- = 0;
57       len = z - buf + 1;
58       mn = 0;
59       if ((len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' &&
60            sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) ||
61           (len >= 13 && buf[4] == ':' && buf[7] == ':' && buf[10] == '.' && buf[12] == ' ' &&
62            sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4))
63         {
64           dev = pci_get_dev(a, mn, bn, dn, fn);
65           dump_alloc_data(dev, 256);
66           pci_link_dev(a, dev);
67         }
68       else if (!len)
69         dev = NULL;
70       else if (dev &&
71                (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') &&
72                sscanf(buf, "%x: ", &i) == 1)
73         {
74           struct dump_data *dd = dev->aux;
75           z = strchr(buf, ' ');
76           while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2]))
77             {
78               z++;
79               if (sscanf(z, "%x", &j) != 1 || i >= 256)
80                 a->error("dump: Malformed line");
81               if (i >= 4096)
82                 break;
83               if (i > dd->len)          /* Need to re-allocate the buffer */
84                 {
85                   dump_alloc_data(dev, 4096);
86                   memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256);
87                   pci_mfree(dd);
88                   dd = dev->aux;
89                 }
90               dd->data[i++] = j;
91               z += 2;
92             }
93         }
94     }
95 }
96
97 static void
98 dump_cleanup(struct pci_access *a UNUSED)
99 {
100 }
101
102 static void
103 dump_scan(struct pci_access *a UNUSED)
104 {
105 }
106
107 static int
108 dump_read(struct pci_dev *d, int pos, byte *buf, int len)
109 {
110   struct dump_data *dd;
111   if (!(dd = d->aux))
112     {
113       struct pci_dev *e = d->access->devices;
114       while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func))
115         e = e->next;
116       if (!e)
117         return 0;
118       dd = e->aux;
119     }
120   if (pos + len > dd->len)
121     return 0;
122   memcpy(buf, dd->data + pos, len);
123   return 1;
124 }
125
126 static int
127 dump_write(struct pci_dev *d UNUSED, int pos UNUSED, byte *buf UNUSED, int len UNUSED)
128 {
129   d->access->error("Writing to dump files is not supported.");
130   return 0;
131 }
132
133 static void
134 dump_cleanup_dev(struct pci_dev *d)
135 {
136   if (d->aux)
137     {
138       pci_mfree(d->aux);
139       d->aux = NULL;
140     }
141 }
142
143 struct pci_methods pm_dump = {
144   "dump",
145   NULL,                                 /* config */
146   dump_detect,
147   dump_init,
148   dump_cleanup,
149   dump_scan,
150   pci_generic_fill_info,
151   dump_read,
152   dump_write,
153   NULL,                                 /* init_dev */
154   dump_cleanup_dev
155 };