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