]> mj.ucw.cz Git - pciutils.git/blob - lib/access.c
Changed all my email addresses to mj@ucw.cz.
[pciutils.git] / lib / access.c
1 /*
2  *      $Id: access.c,v 1.8 2002/03/30 15:39:25 mj Exp $
3  *
4  *      The PCI Library -- User Access
5  *
6  *      Copyright (c) 1997--1999 Martin Mares <mj@ucw.cz>
7  *
8  *      Can be freely distributed and used under the terms of the GNU GPL.
9  */
10
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <string.h>
15
16 #include "internal.h"
17
18 static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
19   NULL,
20 #ifdef HAVE_PM_LINUX_PROC
21   &pm_linux_proc,
22 #else
23   NULL,
24 #endif
25 #ifdef HAVE_PM_SYSCALLS
26   &pm_syscalls,
27 #else
28   NULL,
29 #endif
30 #ifdef HAVE_PM_INTEL_CONF
31   &pm_intel_conf1,
32   &pm_intel_conf2,
33 #else
34   NULL,
35   NULL,
36 #endif
37 #ifdef HAVE_PM_FBSD_DEVICE
38   &pm_fbsd_device,
39 #else
40   NULL,
41 #endif
42 #ifdef HAVE_PM_AIX_DEVICE
43   &pm_aix_device,
44 #else
45   NULL,
46 #endif
47 #ifdef HAVE_PM_DUMP
48   &pm_dump,
49 #else
50   NULL,
51 #endif
52 };
53
54 struct pci_access *
55 pci_alloc(void)
56 {
57   struct pci_access *a = malloc(sizeof(struct pci_access));
58   int i;
59
60   bzero(a, sizeof(*a));
61   a->id_file_name = PATH_PCI_IDS;
62   for(i=0; i<PCI_ACCESS_MAX; i++)
63     if (pci_methods[i] && pci_methods[i]->config)
64       pci_methods[i]->config(a);
65   return a;
66 }
67
68 void *
69 pci_malloc(struct pci_access *a, int size)
70 {
71   void *x = malloc(size);
72
73   if (!x)
74     a->error("Out of memory (allocation of %d bytes failed)", size);
75   return x;
76 }
77
78 void
79 pci_mfree(void *x)
80 {
81   if (x)
82     free(x);
83 }
84
85 static void
86 pci_generic_error(char *msg, ...)
87 {
88   va_list args;
89
90   va_start(args, msg);
91   fputs("pcilib: ", stderr);
92   vfprintf(stderr, msg, args);
93   fputc('\n', stderr);
94   exit(1);
95 }
96
97 static void
98 pci_generic_warn(char *msg, ...)
99 {
100   va_list args;
101
102   va_start(args, msg);
103   fputs("pcilib: ", stderr);
104   vfprintf(stderr, msg, args);
105   fputc('\n', stderr);
106 }
107
108 static void
109 pci_generic_debug(char *msg, ...)
110 {
111   va_list args;
112
113   va_start(args, msg);
114   vfprintf(stdout, msg, args);
115   va_end(args);
116 }
117
118 static void
119 pci_null_debug(char * UNUSED msg, ...)
120 {
121 }
122
123 void
124 pci_init(struct pci_access *a)
125 {
126   if (!a->error)
127     a->error = pci_generic_error;
128   if (!a->warning)
129     a->warning = pci_generic_warn;
130   if (!a->debug)
131     a->debug = pci_generic_debug;
132   if (!a->debugging)
133     a->debug = pci_null_debug;
134
135   if (a->method)
136     {
137       if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
138         a->error("This access method is not supported.");
139       a->methods = pci_methods[a->method];
140     }
141   else
142     {
143       unsigned int i;
144       for(i=0; i<PCI_ACCESS_MAX; i++)
145         if (pci_methods[i])
146           {
147             a->debug("Trying method %d...", i);
148             if (pci_methods[i]->detect(a))
149               {
150                 a->debug("...OK\n");
151                 a->methods = pci_methods[i];
152                 a->method = i;
153                 break;
154               }
155             a->debug("...No.\n");
156           }
157       if (!a->methods)
158         a->error("Cannot find any working access method.");
159     }
160   a->debug("Decided to use %s\n", a->methods->name);
161   a->methods->init(a);
162 }
163
164 void
165 pci_cleanup(struct pci_access *a)
166 {
167   struct pci_dev *d, *e;
168
169   for(d=a->devices; d; d=e)
170     {
171       e = d->next;
172       pci_free_dev(d);
173     }
174   if (a->methods)
175     a->methods->cleanup(a);
176   pci_free_name_list(a);
177   pci_mfree(a);
178 }
179
180 void
181 pci_scan_bus(struct pci_access *a)
182 {
183   a->methods->scan(a);
184 }
185
186 struct pci_dev *
187 pci_alloc_dev(struct pci_access *a)
188 {
189   struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
190
191   bzero(d, sizeof(*d));
192   d->access = a;
193   d->methods = a->methods;
194   if (d->methods->init_dev)
195     d->methods->init_dev(d);
196   return d;
197 }
198
199 int
200 pci_link_dev(struct pci_access *a, struct pci_dev *d)
201 {
202   d->next = a->devices;
203   a->devices = d;
204
205   return 1;
206 }
207
208 struct pci_dev *
209 pci_get_dev(struct pci_access *a, int bus, int dev, int func)
210 {
211   struct pci_dev *d = pci_alloc_dev(a);
212
213   d->bus = bus;
214   d->dev = dev;
215   d->func = func;
216   return d;
217 }
218
219 void pci_free_dev(struct pci_dev *d)
220 {
221   if (d->methods->cleanup_dev)
222     d->methods->cleanup_dev(d);
223   pci_mfree(d);
224 }
225
226 static inline void
227 pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
228 {
229   if (pos & (len-1))
230     d->access->error("Unaligned read: pos=%02x, len=%d", pos, len);
231   if (pos + len <= d->cache_len)
232     memcpy(buf, d->cache + pos, len);
233   else if (!d->methods->read(d, pos, buf, len))
234     memset(buf, 0xff, len);
235 }
236
237 byte
238 pci_read_byte(struct pci_dev *d, int pos)
239 {
240   byte buf;
241   pci_read_data(d, &buf, pos, 1);
242   return buf;
243 }
244
245 word
246 pci_read_word(struct pci_dev *d, int pos)
247 {
248   word buf;
249   pci_read_data(d, &buf, pos, 2);
250   return le16_to_cpu(buf);
251 }
252
253 u32
254 pci_read_long(struct pci_dev *d, int pos)
255 {
256   u32 buf;
257   pci_read_data(d, &buf, pos, 4);
258   return le32_to_cpu(buf);
259 }
260
261 int
262 pci_read_block(struct pci_dev *d, int pos, byte *buf, int len)
263 {
264   return d->methods->read(d, pos, buf, len);
265 }
266
267 static inline int
268 pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
269 {
270   if (pos & (len-1))
271     d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
272   if (pos + len <= d->cache_len)
273     memcpy(d->cache + pos, buf, len);
274   return d->methods->write(d, pos, buf, len);
275 }
276
277 int
278 pci_write_byte(struct pci_dev *d, int pos, byte data)
279 {
280   return pci_write_data(d, &data, pos, 1);
281 }
282
283 int
284 pci_write_word(struct pci_dev *d, int pos, word data)
285 {
286   word buf = cpu_to_le16(data);
287   return pci_write_data(d, &buf, pos, 2);
288 }
289
290 int
291 pci_write_long(struct pci_dev *d, int pos, u32 data)
292 {
293   u32 buf = cpu_to_le32(data);
294   return pci_write_data(d, &buf, pos, 4);
295 }
296
297 int
298 pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
299 {
300   if (pos < d->cache_len)
301     {
302       int l = (pos + len >= d->cache_len) ? (d->cache_len - pos) : len;
303       memcpy(d->cache + pos, buf, l);
304     }
305   return d->methods->write(d, pos, buf, len);
306 }
307
308 int
309 pci_fill_info(struct pci_dev *d, int flags)
310 {
311   if (flags & PCI_FILL_RESCAN)
312     {
313       flags &= ~PCI_FILL_RESCAN;
314       d->known_fields = 0;
315     }
316   if (flags & ~d->known_fields)
317     d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
318   return d->known_fields;
319 }
320
321 void
322 pci_setup_cache(struct pci_dev *d, byte *cache, int len)
323 {
324   d->cache = cache;
325   d->cache_len = len;
326 }