~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/srv/pci/libpci/access.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      The PCI Library -- User Access
 
3
 *
 
4
 *      Copyright (c) 1997--2003 Martin Mares <mj@ucw.cz>
 
5
 *
 
6
 *      May 8, 2006 - Modified and ported to HelenOS by Jakub Jermar.
 
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
        &pm_intel_conf1,
 
20
        &pm_intel_conf2,
 
21
};
 
22
 
 
23
struct pci_access *pci_alloc(void)
 
24
{
 
25
        struct pci_access *a = malloc(sizeof(struct pci_access));
 
26
        int i;
 
27
 
 
28
        if (!a)
 
29
                return NULL;
 
30
                
 
31
        bzero(a, sizeof(*a));
 
32
        for (i = 0; i < PCI_ACCESS_MAX; i++)
 
33
                if (pci_methods[i] && pci_methods[i]->config)
 
34
                        pci_methods[i]->config(a);
 
35
        return a;
 
36
}
 
37
 
 
38
void *pci_malloc(struct pci_access *a, int size)
 
39
{
 
40
        void *x = malloc(size);
 
41
 
 
42
        if (!x)
 
43
                a->error("Out of memory (allocation of %d bytes failed)", size);
 
44
        return x;
 
45
}
 
46
 
 
47
void pci_mfree(void *x)
 
48
{
 
49
        if (x)
 
50
                free(x);
 
51
}
 
52
 
 
53
static void pci_generic_error(char *msg, ...)
 
54
{
 
55
        va_list args;
 
56
 
 
57
        va_start(args, msg);
 
58
        puts("pcilib: ");
 
59
        vprintf(msg, args);
 
60
        putchar('\n');
 
61
        exit(1);
 
62
}
 
63
 
 
64
static void pci_generic_warn(char *msg, ...)
 
65
{
 
66
        va_list args;
 
67
 
 
68
        va_start(args, msg);
 
69
        puts("pcilib: ");
 
70
        vprintf(msg, args);
 
71
        putchar('\n');
 
72
}
 
73
 
 
74
static void pci_generic_debug(char *msg, ...)
 
75
{
 
76
        va_list args;
 
77
 
 
78
        va_start(args, msg);
 
79
        vprintf(msg, args);
 
80
        va_end(args);
 
81
}
 
82
 
 
83
static void pci_null_debug(char *msg UNUSED, ...)
 
84
{
 
85
}
 
86
 
 
87
void pci_init(struct pci_access *a)
 
88
{
 
89
        if (!a->error)
 
90
                a->error = pci_generic_error;
 
91
        if (!a->warning)
 
92
                a->warning = pci_generic_warn;
 
93
        if (!a->debug)
 
94
                a->debug = pci_generic_debug;
 
95
        if (!a->debugging)
 
96
                a->debug = pci_null_debug;
 
97
 
 
98
        if (a->method) {
 
99
                if (a->method >= PCI_ACCESS_MAX || !pci_methods[a->method])
 
100
                        a->error("This access method is not supported.");
 
101
                a->methods = pci_methods[a->method];
 
102
        } else {
 
103
                unsigned int i;
 
104
                for (i = 0; i < PCI_ACCESS_MAX; i++)
 
105
                        if (pci_methods[i]) {
 
106
                                a->debug("Trying method %d...", i);
 
107
                                if (pci_methods[i]->detect(a)) {
 
108
                                        a->debug("...OK\n");
 
109
                                        a->methods = pci_methods[i];
 
110
                                        a->method = i;
 
111
                                        break;
 
112
                                }
 
113
                                a->debug("...No.\n");
 
114
                        }
 
115
                if (!a->methods)
 
116
                        a->error("Cannot find any working access method.");
 
117
        }
 
118
        a->debug("Decided to use %s\n", a->methods->name);
 
119
        a->methods->init(a);
 
120
}
 
121
 
 
122
void pci_cleanup(struct pci_access *a)
 
123
{
 
124
        struct pci_dev *d, *e;
 
125
 
 
126
        for (d = a->devices; d; d = e) {
 
127
                e = d->next;
 
128
                pci_free_dev(d);
 
129
        }
 
130
        if (a->methods)
 
131
                a->methods->cleanup(a);
 
132
        pci_free_name_list(a);
 
133
        pci_mfree(a);
 
134
}
 
135
 
 
136
void pci_scan_bus(struct pci_access *a)
 
137
{
 
138
        a->methods->scan(a);
 
139
}
 
140
 
 
141
struct pci_dev *pci_alloc_dev(struct pci_access *a)
 
142
{
 
143
        struct pci_dev *d = pci_malloc(a, sizeof(struct pci_dev));
 
144
 
 
145
        bzero(d, sizeof(*d));
 
146
        d->access = a;
 
147
        d->methods = a->methods;
 
148
        d->hdrtype = -1;
 
149
        if (d->methods->init_dev)
 
150
                d->methods->init_dev(d);
 
151
        return d;
 
152
}
 
153
 
 
154
int pci_link_dev(struct pci_access *a, struct pci_dev *d)
 
155
{
 
156
        d->next = a->devices;
 
157
        a->devices = d;
 
158
 
 
159
        return 1;
 
160
}
 
161
 
 
162
struct pci_dev *pci_get_dev(struct pci_access *a, int domain, int bus,
 
163
                            int dev, int func)
 
164
{
 
165
        struct pci_dev *d = pci_alloc_dev(a);
 
166
 
 
167
        d->domain = domain;
 
168
        d->bus = bus;
 
169
        d->dev = dev;
 
170
        d->func = func;
 
171
        return d;
 
172
}
 
173
 
 
174
void pci_free_dev(struct pci_dev *d)
 
175
{
 
176
        if (d->methods->cleanup_dev)
 
177
                d->methods->cleanup_dev(d);
 
178
        pci_mfree(d);
 
179
}
 
180
 
 
181
static inline void
 
182
pci_read_data(struct pci_dev *d, void *buf, int pos, int len)
 
183
{
 
184
        if (pos & (len - 1))
 
185
                d->access->error("Unaligned read: pos=%02x, len=%d", pos,
 
186
                                 len);
 
187
        if (pos + len <= d->cache_len)
 
188
                memcpy(buf, d->cache + pos, len);
 
189
        else if (!d->methods->read(d, pos, buf, len))
 
190
                memset(buf, 0xff, len);
 
191
}
 
192
 
 
193
byte pci_read_byte(struct pci_dev *d, int pos)
 
194
{
 
195
        byte buf;
 
196
        pci_read_data(d, &buf, pos, 1);
 
197
        return buf;
 
198
}
 
199
 
 
200
word pci_read_word(struct pci_dev * d, int pos)
 
201
{
 
202
        word buf;
 
203
        pci_read_data(d, &buf, pos, 2);
 
204
        return le16_to_cpu(buf);
 
205
}
 
206
 
 
207
u32 pci_read_long(struct pci_dev * d, int pos)
 
208
{
 
209
        u32 buf;
 
210
        pci_read_data(d, &buf, pos, 4);
 
211
        return le32_to_cpu(buf);
 
212
}
 
213
 
 
214
int pci_read_block(struct pci_dev *d, int pos, byte * buf, int len)
 
215
{
 
216
        return d->methods->read(d, pos, buf, len);
 
217
}
 
218
 
 
219
static inline int
 
220
pci_write_data(struct pci_dev *d, void *buf, int pos, int len)
 
221
{
 
222
        if (pos & (len - 1))
 
223
                d->access->error("Unaligned write: pos=%02x,len=%d", pos, len);
 
224
        if (pos + len <= d->cache_len)
 
225
                memcpy(d->cache + pos, buf, len);
 
226
        return d->methods->write(d, pos, buf, len);
 
227
}
 
228
 
 
229
int pci_write_byte(struct pci_dev *d, int pos, byte data)
 
230
{
 
231
        return pci_write_data(d, &data, pos, 1);
 
232
}
 
233
 
 
234
int pci_write_word(struct pci_dev *d, int pos, word data)
 
235
{
 
236
        word buf = cpu_to_le16(data);
 
237
        return pci_write_data(d, &buf, pos, 2);
 
238
}
 
239
 
 
240
int pci_write_long(struct pci_dev *d, int pos, u32 data)
 
241
{
 
242
        u32 buf = cpu_to_le32(data);
 
243
        return pci_write_data(d, &buf, pos, 4);
 
244
}
 
245
 
 
246
int pci_write_block(struct pci_dev *d, int pos, byte * buf, int len)
 
247
{
 
248
        if (pos < d->cache_len) {
 
249
                int l = (pos + len >= d->cache_len) ? (d->cache_len - pos) : len;
 
250
                memcpy(d->cache + pos, buf, l);
 
251
        }
 
252
        return d->methods->write(d, pos, buf, len);
 
253
}
 
254
 
 
255
int pci_fill_info(struct pci_dev *d, int flags)
 
256
{
 
257
        if (flags & PCI_FILL_RESCAN) {
 
258
                flags &= ~PCI_FILL_RESCAN;
 
259
                d->known_fields = 0;
 
260
        }
 
261
        if (flags & ~d->known_fields)
 
262
                d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
 
263
        return d->known_fields;
 
264
}
 
265
 
 
266
void pci_setup_cache(struct pci_dev *d, byte * cache, int len)
 
267
{
 
268
        d->cache = cache;
 
269
        d->cache_len = len;
 
270
}