]>
Commit | Line | Data |
---|---|---|
4dd39346 MM |
1 | /* |
2 | * The PCI Library -- Initialization and related things | |
3 | * | |
4 | * Copyright (c) 1997--2008 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 <stdlib.h> | |
11 | #include <stdarg.h> | |
12 | #include <string.h> | |
13 | ||
14 | #include "internal.h" | |
15 | ||
16 | static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = { | |
17 | NULL, | |
18 | #ifdef PCI_HAVE_PM_LINUX_SYSFS | |
19 | &pm_linux_sysfs, | |
20 | #else | |
21 | NULL, | |
22 | #endif | |
23 | #ifdef PCI_HAVE_PM_LINUX_PROC | |
24 | &pm_linux_proc, | |
25 | #else | |
26 | NULL, | |
27 | #endif | |
28 | #ifdef PCI_HAVE_PM_INTEL_CONF | |
29 | &pm_intel_conf1, | |
30 | &pm_intel_conf2, | |
31 | #else | |
32 | NULL, | |
33 | NULL, | |
34 | #endif | |
35 | #ifdef PCI_HAVE_PM_FBSD_DEVICE | |
36 | &pm_fbsd_device, | |
37 | #else | |
38 | NULL, | |
39 | #endif | |
40 | #ifdef PCI_HAVE_PM_AIX_DEVICE | |
41 | &pm_aix_device, | |
42 | #else | |
43 | NULL, | |
44 | #endif | |
45 | #ifdef PCI_HAVE_PM_NBSD_LIBPCI | |
46 | &pm_nbsd_libpci, | |
47 | #else | |
48 | NULL, | |
49 | #endif | |
50 | #ifdef PCI_HAVE_PM_OBSD_DEVICE | |
51 | &pm_obsd_device, | |
52 | #else | |
53 | NULL, | |
54 | #endif | |
55 | #ifdef PCI_HAVE_PM_DUMP | |
56 | &pm_dump, | |
57 | #else | |
58 | NULL, | |
59 | #endif | |
60 | }; | |
61 | ||
62 | struct pci_access * | |
63 | pci_alloc(void) | |
64 | { | |
65 | struct pci_access *a = malloc(sizeof(struct pci_access)); | |
66 | int i; | |
67 | ||
68 | memset(a, 0, sizeof(*a)); | |
69 | pci_set_name_list_path(a, PCI_PATH_IDS_DIR "/" PCI_IDS, 0); | |
98ccf6d6 MM |
70 | #ifdef PCI_USE_DNS |
71 | pci_define_param(a, "net.domain", PCI_ID_DOMAIN); | |
72 | pci_define_param(a, "net.cache_path", "~/.pciids-cache"); | |
4dd39346 | 73 | a->id_lookup_mode = PCI_LOOKUP_CACHE; |
98ccf6d6 | 74 | #endif |
4dd39346 MM |
75 | for(i=0; i<PCI_ACCESS_MAX; i++) |
76 | if (pci_methods[i] && pci_methods[i]->config) | |
77 | pci_methods[i]->config(a); | |
78 | return a; | |
79 | } | |
80 | ||
81 | void * | |
82 | pci_malloc(struct pci_access *a, int size) | |
83 | { | |
84 | void *x = malloc(size); | |
85 | ||
86 | if (!x) | |
87 | a->error("Out of memory (allocation of %d bytes failed)", size); | |
88 | return x; | |
89 | } | |
90 | ||
91 | void | |
92 | pci_mfree(void *x) | |
93 | { | |
94 | if (x) | |
95 | free(x); | |
96 | } | |
97 | ||
fa182368 MM |
98 | char * |
99 | pci_strdup(struct pci_access *a, char *s) | |
100 | { | |
101 | int len = strlen(s) + 1; | |
102 | char *t = pci_malloc(a, len); | |
103 | memcpy(t, s, len); | |
104 | return t; | |
105 | } | |
106 | ||
4dd39346 MM |
107 | static void |
108 | pci_generic_error(char *msg, ...) | |
109 | { | |
110 | va_list args; | |
111 | ||
112 | va_start(args, msg); | |
113 | fputs("pcilib: ", stderr); | |
114 | vfprintf(stderr, msg, args); | |
115 | fputc('\n', stderr); | |
116 | exit(1); | |
117 | } | |
118 | ||
119 | static void | |
120 | pci_generic_warn(char *msg, ...) | |
121 | { | |
122 | va_list args; | |
123 | ||
124 | va_start(args, msg); | |
125 | fputs("pcilib: ", stderr); | |
126 | vfprintf(stderr, msg, args); | |
127 | fputc('\n', stderr); | |
128 | } | |
129 | ||
130 | static void | |
131 | pci_generic_debug(char *msg, ...) | |
132 | { | |
133 | va_list args; | |
134 | ||
135 | va_start(args, msg); | |
136 | vfprintf(stdout, msg, args); | |
137 | va_end(args); | |
138 | } | |
139 | ||
140 | static void | |
141 | pci_null_debug(char *msg UNUSED, ...) | |
142 | { | |
143 | } | |
144 | ||
fa182368 MM |
145 | char * |
146 | pci_get_param(struct pci_access *acc, char *param) | |
147 | { | |
148 | struct pci_param *p; | |
149 | ||
150 | for (p=acc->params; p; p=p->next) | |
151 | if (!strcmp(p->param, param)) | |
152 | return p->value; | |
153 | return NULL; | |
154 | } | |
155 | ||
156 | void | |
157 | pci_define_param(struct pci_access *acc, char *param, char *value) | |
158 | { | |
159 | struct pci_param *p = pci_malloc(acc, sizeof(*p)); | |
160 | ||
161 | p->next = acc->params; | |
162 | acc->params = p; | |
163 | p->param = param; | |
164 | p->value = value; | |
165 | p->value_malloced = 0; | |
166 | } | |
167 | ||
168 | int | |
98ccf6d6 | 169 | pci_set_param_internal(struct pci_access *acc, char *param, char *value, int copy) |
fa182368 MM |
170 | { |
171 | struct pci_param *p; | |
172 | ||
173 | for (p=acc->params; p; p=p->next) | |
174 | if (!strcmp(p->param, param)) | |
175 | { | |
176 | if (p->value_malloced) | |
177 | pci_mfree(p->value); | |
98ccf6d6 MM |
178 | p->value_malloced = copy; |
179 | if (copy) | |
180 | p->value = pci_strdup(acc, value); | |
181 | else | |
182 | p->value = value; | |
fa182368 MM |
183 | return 0; |
184 | } | |
185 | return -1; | |
186 | } | |
187 | ||
98ccf6d6 MM |
188 | int |
189 | pci_set_param(struct pci_access *acc, char *param, char *value) | |
190 | { | |
191 | return pci_set_param_internal(acc, param, value, 1); | |
192 | } | |
193 | ||
fa182368 MM |
194 | static void |
195 | pci_free_params(struct pci_access *acc) | |
196 | { | |
197 | struct pci_param *p; | |
198 | ||
199 | while (p = acc->params) | |
200 | { | |
201 | acc->params = p->next; | |
202 | if (p->value_malloced) | |
203 | pci_mfree(p->value); | |
204 | pci_mfree(p); | |
205 | } | |
206 | } | |
207 | ||
208 | struct pci_param * | |
209 | pci_walk_params(struct pci_access *acc, struct pci_param *prev) | |
210 | { | |
211 | /* So far, the params form a simple linked list, but this can change in the future */ | |
212 | if (!prev) | |
213 | return acc->params; | |
214 | else | |
215 | return prev->next; | |
216 | } | |
217 | ||
4dd39346 MM |
218 | void |
219 | pci_init(struct pci_access *a) | |
220 | { | |
221 | if (!a->error) | |
222 | a->error = pci_generic_error; | |
223 | if (!a->warning) | |
224 | a->warning = pci_generic_warn; | |
225 | if (!a->debug) | |
226 | a->debug = pci_generic_debug; | |
227 | if (!a->debugging) | |
228 | a->debug = pci_null_debug; | |
229 | ||
230 | if (a->method) | |
231 | { | |
232 | if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method]) | |
233 | a->error("This access method is not supported."); | |
234 | a->methods = pci_methods[a->method]; | |
235 | } | |
236 | else | |
237 | { | |
238 | unsigned int i; | |
239 | for(i=0; i<PCI_ACCESS_MAX; i++) | |
240 | if (pci_methods[i]) | |
241 | { | |
242 | a->debug("Trying method %d...", i); | |
243 | if (pci_methods[i]->detect(a)) | |
244 | { | |
245 | a->debug("...OK\n"); | |
246 | a->methods = pci_methods[i]; | |
247 | a->method = i; | |
248 | break; | |
249 | } | |
250 | a->debug("...No.\n"); | |
251 | } | |
252 | if (!a->methods) | |
253 | a->error("Cannot find any working access method."); | |
254 | } | |
255 | a->debug("Decided to use %s\n", a->methods->name); | |
256 | a->methods->init(a); | |
257 | } | |
258 | ||
259 | void | |
260 | pci_cleanup(struct pci_access *a) | |
261 | { | |
262 | struct pci_dev *d, *e; | |
263 | ||
264 | for(d=a->devices; d; d=e) | |
265 | { | |
266 | e = d->next; | |
267 | pci_free_dev(d); | |
268 | } | |
269 | if (a->methods) | |
270 | a->methods->cleanup(a); | |
271 | pci_free_name_list(a); | |
fa182368 | 272 | pci_free_params(a); |
4dd39346 | 273 | pci_set_name_list_path(a, NULL, 0); |
4dd39346 MM |
274 | pci_mfree(a); |
275 | } |