Subversion Repositories HelenOS

Rev

Rev 4221 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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