/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to pci.c

  • Committer: Suren A. Chilingaryan
  • Date: 2011-03-08 21:46:14 UTC
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: csa@dside.dyndns.org-20110308214614-g5v841m61jilcrm2
Initial support of IPECamera protocol

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
#include <stdio.h>
4
4
#include <string.h>
 
5
#include <strings.h>
5
6
#include <stdlib.h>
6
7
#include <stdint.h>
7
8
#include <stdarg.h>
10
11
#include <sys/ioctl.h>
11
12
#include <sys/mman.h>
12
13
#include <errno.h>
 
14
#include <assert.h>
13
15
 
14
16
#include "driver/pciDriver.h"
15
17
 
18
20
 
19
21
#include "pci.h"
20
22
#include "ipecamera.h"
21
 
 
22
 
static pci_board_info board_info;
23
 
static page_mask = -1;
24
 
 
 
23
#include "error.h"
 
24
 
 
25
#define BIT_MASK(bits) ((1 << (bits)) - 1)
 
26
 
 
27
 
 
28
//#define PCILIB_FILE_IO
 
29
 
 
30
struct pcilib_s {
 
31
    int handle;
 
32
    
 
33
    uintptr_t page_mask;
 
34
    pci_board_info board_info;
 
35
    pcilib_model_t model;
 
36
 
 
37
    pcilib_bar_t reg_bar;
 
38
    char *reg_space;
 
39
    
 
40
#ifdef PCILIB_FILE_IO
 
41
    int file_io_handle;
 
42
#endif /* PCILIB_FILE_IO */
 
43
};
25
44
 
26
45
static void pcilib_print_error(const char *msg, ...) {
27
46
    va_list va;
29
48
    va_start(va, msg);
30
49
    vprintf(msg, va);
31
50
    va_end(va);
32
 
}
33
 
 
34
 
static void (*Error)(const char *msg, ...) = pcilib_print_error;
35
 
 
36
 
int pcilib_open(const char *device) {
37
 
    int handle = open(device, O_RDWR);
38
 
    return handle;
39
 
}
40
 
 
41
 
void pcilib_close(int handle) {
42
 
    close(handle);
43
 
}
 
51
    printf("\n");
 
52
}
 
53
 
 
54
void (*pcilib_error)(const char *msg, ...) = pcilib_print_error;
 
55
void (*pcilib_warning)(const char *msg, ...) = pcilib_print_error;
44
56
 
45
57
int pcilib_set_error_handler(void (*err)(const char *msg, ...)) {
46
 
    Error = err;
47
 
}
48
 
 
49
 
const pci_board_info *pcilib_get_board_info(int handle) {
 
58
    pcilib_error = err;
 
59
}
 
60
 
 
61
pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
 
62
    pcilib_t *ctx = malloc(sizeof(pcilib_t));
 
63
 
 
64
    if (ctx) {
 
65
        ctx->handle = open(device, O_RDWR);
 
66
        ctx->page_mask = (uintptr_t)-1;
 
67
        ctx->model = model;
 
68
        ctx->reg_space = NULL;
 
69
    }
 
70
 
 
71
    return ctx;
 
72
}
 
73
 
 
74
const pci_board_info *pcilib_get_board_info(pcilib_t *ctx) {
50
75
    int ret;
51
76
    
52
 
    if (page_mask < 0) {
53
 
        ret = ioctl( handle, PCIDRIVER_IOC_PCI_INFO, &board_info );
54
 
        if (ret) Error("PCIDRIVER_IOC_PCI_INFO ioctl have failed");
 
77
    if (ctx->page_mask ==  (uintptr_t)-1) {
 
78
        ret = ioctl( ctx->handle, PCIDRIVER_IOC_PCI_INFO, &ctx->board_info );
 
79
        if (ret) pcilib_error("PCIDRIVER_IOC_PCI_INFO ioctl have failed");
55
80
        
56
 
        page_mask = get_page_mask();
 
81
        ctx->page_mask = pcilib_get_page_mask();
57
82
    }
58
83
    
59
 
    return &board_info;
 
84
    return &ctx->board_info;
60
85
}
61
86
 
62
87
 
63
 
pcilib_model_t pcilib_detect_model(int handle) {
 
88
pcilib_model_t pcilib_get_model(pcilib_t *ctx) {
 
89
    if (ctx->model == PCILIB_MODEL_DETECT) {
64
90
        unsigned short vendor_id;
65
91
        unsigned short device_id;
66
92
 
67
 
    pcilib_get_board_info(handle);
 
93
        const pci_board_info *board_info = pcilib_get_board_info(ctx);
68
94
 
69
 
    if ((board_info.vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info.device_id ==  PCIE_IPECAMERA_DEVICE_ID)) return PCILIB_MODEL_IPECAMERA;
70
 
    return PCILIB_MODEL_PCI;
 
95
        if ((board_info->vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info->device_id == PCIE_IPECAMERA_DEVICE_ID))
 
96
            ctx->model = PCILIB_MODEL_IPECAMERA;
 
97
        else
 
98
            ctx->model = PCILIB_MODEL_PCI;
 
99
    }
 
100
    
 
101
    return ctx->model;
71
102
}
72
103
 
73
 
static int pcilib_detect_bar(int handle, unsigned long addr, int size) {
 
104
static int pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size) {
74
105
    int ret,i;
75
106
        
76
 
    pcilib_get_board_info(handle);
 
107
    const pci_board_info *board_info = pcilib_get_board_info(ctx);
77
108
                
78
109
    for (i = 0; i < PCILIB_MAX_BANKS; i++) {
79
 
        if ((addr >= board_info.bar_start[i])&&((board_info.bar_start[i] + board_info.bar_length[i]) >= (addr + size))) return i;
 
110
        if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i;
80
111
    }
81
112
        
82
113
    return -1;
83
114
}
84
115
 
85
 
static void *pcilib_detect_address(int handle, int *bar, unsigned long *addr, int size) {
86
 
    if (*bar < 0) {
87
 
        *bar = pcilib_detect_bar(handle, *addr, size);
88
 
        if (*bar < 0) Error("The requested data block at address 0x%x with size 0x%x does not belongs to any available memory bank", *addr, size);
 
116
static void pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) {
 
117
    const pci_board_info *board_info = pcilib_get_board_info(ctx);
 
118
    
 
119
    if (*bar == PCILIB_BAR_DETECT) {
 
120
        *bar = pcilib_detect_bar(ctx, *addr, size);
 
121
        if (*bar < 0) pcilib_error("The requested data block at address 0x%x with size 0x%x does not belongs to any available memory bank", *addr, size);
89
122
    } else {
90
 
        pcilib_get_board_info(handle);
91
 
        
92
 
        if ((*addr < board_info.bar_start[*bar])||((board_info.bar_start[*bar] + board_info.bar_length[*bar]) < (((uintptr_t)*addr) + size))) {
93
 
            if ((board_info.bar_length[*bar]) >= (((uintptr_t)*addr) + size)) 
94
 
                *addr += board_info.bar_start[*bar];
 
123
        if ((*addr < board_info->bar_start[*bar])||((board_info->bar_start[*bar] + board_info->bar_length[*bar]) < (((uintptr_t)*addr) + size))) {
 
124
            if ((board_info->bar_length[*bar]) >= (((uintptr_t)*addr) + size)) 
 
125
                *addr += board_info->bar_start[*bar];
95
126
            else
96
 
                Error("The requested data block at address 0x%x with size 0x%x does not belong the specified memory bank (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info.bar_start[*bar], board_info.bar_length[*bar]);
 
127
                pcilib_error("The requested data block at address 0x%x with size 0x%x does not belong the specified memory bank (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info->bar_start[*bar], board_info->bar_length[*bar]);
97
128
        }
98
129
    }
99
130
    
100
 
    *addr -= board_info.bar_start[*bar];
101
 
    *addr += board_info.bar_start[*bar] & page_mask;
 
131
    *addr -= board_info->bar_start[*bar];
 
132
    *addr += board_info->bar_start[*bar] & ctx->page_mask;
102
133
}
103
134
 
104
 
 
105
 
#ifdef FILE_IO
106
 
int file_io_handle;
107
 
#endif /* FILE_IO */
108
 
 
109
 
void *pcilib_map_bar(int handle, int bar) {
 
135
void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) {
110
136
    void *res;
111
137
    int ret; 
112
138
 
113
 
    pcilib_get_board_info(handle);
 
139
    const pci_board_info *board_info = pcilib_get_board_info(ctx);
114
140
    
115
 
    ret = ioctl( handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI );
116
 
    if (ret) Error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar);
117
 
 
118
 
    ret = ioctl( handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar );
119
 
    if (ret) Error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar);
120
 
 
121
 
#ifdef FILE_IO
122
 
    file_io_handle = open("/root/drivers/pciDriver/data", O_RDWR);
123
 
    res = mmap( 0, board_info.bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, file_io_handle, 0 );
 
141
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI );
 
142
    if (ret) pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar);
 
143
 
 
144
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar );
 
145
    if (ret) pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar);
 
146
 
 
147
#ifdef PCILIB_FILE_IO
 
148
    file_io_handle = open("/root/data", O_RDWR);
 
149
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 );
124
150
#else
125
 
    res = mmap( 0, board_info.bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, handle, 0 );
 
151
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
126
152
#endif
127
 
    if ((!res)||(res == MAP_FAILED)) Error("Failed to mmap data bank %i", bar);
 
153
    if ((!res)||(res == MAP_FAILED)) pcilib_error("Failed to mmap data bank %i", bar);
128
154
 
129
155
    
130
156
    return res;
131
157
}
132
158
 
133
 
void pcilib_unmap_bar(int handle, int bar, void *data) {
134
 
    munmap(data, board_info.bar_length[bar]);
135
 
#ifdef FILE_IO
136
 
    close(file_io_handle);
 
159
void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
 
160
    const pci_board_info *board_info = pcilib_get_board_info(ctx);
 
161
 
 
162
    munmap(data, board_info->bar_length[bar]);
 
163
#ifdef PCILIB_FILE_IO
 
164
    close(ctx->file_io_handle);
137
165
#endif
138
166
}
139
167
 
140
 
int pcilib_read(void *buf, int handle, int bar, unsigned long addr, int size) {
 
168
int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
141
169
    int i;
142
170
    void *data;
143
171
    unsigned int offset;
144
172
    char local_buf[size];
145
173
    
146
174
 
147
 
 
148
 
    pcilib_detect_address(handle, &bar, &addr, size);
149
 
    data = pcilib_map_bar(handle, bar);
 
175
    pcilib_detect_address(ctx, &bar, &addr, size);
 
176
    data = pcilib_map_bar(ctx, bar);
150
177
 
151
178
/*
152
179
    for (i = 0; i < size/4; i++)  {
156
183
 
157
184
    pcilib_memcpy(buf, data + addr, size);
158
185
    
159
 
    pcilib_unmap_bar(handle, bar, data);    
 
186
    pcilib_unmap_bar(ctx, bar, data);    
160
187
}
161
188
 
162
 
int pcilib_write(void *buf, int handle, int bar, unsigned long addr, int size) {
 
189
int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
163
190
    int i;
164
191
    void *data;
165
192
    unsigned int offset;
166
193
    char local_buf[size];
167
194
    
168
195
 
169
 
    pcilib_detect_address(handle, &bar, &addr, size);
170
 
    data = pcilib_map_bar(handle, bar);
 
196
    pcilib_detect_address(ctx, &bar, &addr, size);
 
197
    data = pcilib_map_bar(ctx, bar);
171
198
 
172
199
    pcilib_memcpy(data + addr, buf, size);
173
200
    
174
 
    pcilib_unmap_bar(handle, bar, data);    
 
201
    pcilib_unmap_bar(ctx, bar, data);    
175
202
}
176
203
 
177
204
 
178
 
int pcilib_find_register(pcilib_model_t model, const char *reg) {
179
 
    int i;
180
 
 
181
 
    pcilib_register_t *registers =  pcilib_model_description[model].registers;
182
 
    
183
 
    for (i = 0; registers[i].size; i++) {
 
205
    // FIXME create hash during map_register space
 
206
pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *reg) {
 
207
    pcilib_register_t i;
 
208
    
 
209
    pcilib_model_t model = pcilib_get_model(ctx);
 
210
    
 
211
    pcilib_register_description_t *registers =  pcilib_model[model].registers;
 
212
    
 
213
    for (i = 0; registers[i].bits; i++) {
184
214
        if (!strcasecmp(registers[i].name, reg)) return i;
185
215
    }
186
216
    
187
217
    return -1;
188
218
};
189
219
 
 
220
static pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
 
221
    pcilib_register_bank_t i;
 
222
    pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
 
223
 
 
224
    for (i = 0; banks[i].access; i++)
 
225
        if (banks[i].addr == bank) return i;
 
226
        
 
227
    return -1;
 
228
}
 
229
 
 
230
 
 
231
static int pcilib_map_register_space(pcilib_t *ctx) {
 
232
    if (!ctx->reg_space)  {
 
233
        pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
 
234
 
 
235
        if ((banks)&&(banks[0].access)) {
 
236
            void *reg_space;
 
237
            
 
238
            uintptr_t addr = banks[0].read_addr;
 
239
            pcilib_bar_t bar = PCILIB_BAR_DETECT;
 
240
            
 
241
            pcilib_detect_address(ctx, &bar, &addr, 1);
 
242
            reg_space = pcilib_map_bar(ctx, bar);
 
243
 
 
244
            uint32_t buf[2];
 
245
            pcilib_memcpy(&buf, reg_space, 8);
 
246
            
 
247
            if (reg_space) {
 
248
                ctx->reg_bar = bar;
 
249
                ctx->reg_space = reg_space;
 
250
 
 
251
                return 0;
 
252
            }
 
253
        }
 
254
        
 
255
        return -1;
 
256
    }
 
257
    
 
258
    return 0;
 
259
}
 
260
            
 
261
        
 
262
static void pcilib_unmap_register_space(pcilib_t *ctx) {
 
263
    if (ctx->reg_space) {
 
264
        pcilib_unmap_bar(ctx, ctx->reg_bar, ctx->reg_space);
 
265
        ctx->reg_space = NULL;
 
266
    }
 
267
}
 
268
 
 
269
char  *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) {
 
270
    size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
 
271
    if (offset < ctx->board_info.bar_length[ctx->reg_bar]) {
 
272
        return ctx->reg_space + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask);
 
273
    }
 
274
    return NULL;
 
275
}
 
276
 
 
277
 
 
278
void pcilib_close(pcilib_t *ctx) {
 
279
    if (ctx) {
 
280
        if (ctx->reg_space) pcilib_unmap_register_space(ctx);
 
281
        close(ctx->handle);
 
282
        free(ctx);
 
283
    }
 
284
}
 
285
 
 
286
 
 
287
 
 
288
 
 
289
static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
 
290
    int err;
 
291
    int rest;
 
292
    size_t i;
 
293
    
 
294
    pcilib_register_bank_description_t *b = pcilib_model[ctx->model].banks + bank;
 
295
 
 
296
    assert(bits < 8 * sizeof(pcilib_register_value_t));
 
297
 
 
298
    err = pcilib_map_register_space(ctx);
 
299
    if (err) {
 
300
        pcilib_error("Failed to map the register space");
 
301
        return err;
 
302
    }
 
303
    
 
304
    //n += bits / b->access;
 
305
    //bits %= b->access; 
 
306
    
 
307
    for (i = 0; i < n; i++) {
 
308
        err = pcilib_protocol[b->protocol].read(ctx, b, addr + i, b->access, buf + i);
 
309
        if (err) break;
 
310
    }
 
311
    
 
312
    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].read(ctx, b, addr + n, bits, buf + n);
 
313
    
 
314
    return err;
 
315
}
 
316
 
 
317
int pcilib_read_register_space(pcilib_t *ctx, pcilib_register_bank_addr_t bank_addr, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
 
318
    pcilib_register_bank_t bank = pcilib_find_bank(ctx, bank_addr);
 
319
    return pcilib_read_register_space_internal(ctx, bank, addr, n, 0, buf);
 
320
}
 
321
 
 
322
int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) {
 
323
    int err;
 
324
    size_t i, n, bits;
 
325
    pcilib_register_value_t res;
 
326
    pcilib_register_description_t *r;
 
327
    pcilib_register_bank_description_t *b;
 
328
 
 
329
    r = pcilib_model[ctx->model].registers + reg;
 
330
    b = pcilib_model[ctx->model].banks + r->bank;
 
331
    
 
332
    n = r->bits / b->access;
 
333
    bits = r->bits % b->access; 
 
334
 
 
335
    pcilib_register_value_t buf[n + 1];
 
336
    err = pcilib_read_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
 
337
 
 
338
    if (b->endianess) {
 
339
        pcilib_error("Big-endian byte order support is not implemented");
 
340
        return PCILIB_ERROR_NOTSUPPORTED;
 
341
    } else {
 
342
        res = 0;
 
343
        if (bits) ++n;
 
344
        for (i = 0; i < n; i++) {
 
345
            res |= buf[i] << (i * b->access);
 
346
        }
 
347
    }
 
348
    
 
349
    *value = res;
 
350
    
 
351
    return err;
 
352
}
 
353
 
 
354
 
 
355
int pcilib_read_register(pcilib_t *ctx, const char *regname, pcilib_register_value_t *value) {
 
356
    int err;
 
357
    int reg;
 
358
    
 
359
    reg = pcilib_find_register(ctx, regname);
 
360
    if (reg < 0) {
 
361
        pcilib_error("Register (%s) is not found", regname);
 
362
        return PCILIB_ERROR_NOTFOUND;
 
363
    }
 
364
    
 
365
    return pcilib_read_register_by_id(ctx, reg, value);
 
366
 
 
367
//    registers[reg].bank
 
368
//    printf("%li %li", sizeof(pcilib_model[ctx->model].banks), sizeof(pcilib_register_bank_description_t));
 
369
}
 
370
 
 
371
 
 
372
static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
 
373
    int err;
 
374
    int rest;
 
375
    size_t i;
 
376
    
 
377
    pcilib_register_bank_description_t *b = pcilib_model[ctx->model].banks + bank;
 
378
 
 
379
    assert(bits < 8 * sizeof(pcilib_register_value_t));
 
380
 
 
381
    err = pcilib_map_register_space(ctx);
 
382
    if (err) {
 
383
        pcilib_error("Failed to map the register space");
 
384
        return err;
 
385
    }
 
386
    
 
387
    //n += bits / b->access;
 
388
    //bits %= b->access; 
 
389
    
 
390
    for (i = 0; i < n; i++) {
 
391
        err = pcilib_protocol[b->protocol].write(ctx, b, addr + i, b->access, buf[i]);
 
392
        if (err) break;
 
393
    }
 
394
    
 
395
    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].write(ctx, b, addr + n, bits, buf[n]);
 
396
    
 
397
    return err;
 
398
}
 
399
 
 
400
int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) {
 
401
    int err;
 
402
    size_t i, n, bits;
 
403
    pcilib_register_value_t res;
 
404
    pcilib_register_description_t *r;
 
405
    pcilib_register_bank_description_t *b;
 
406
 
 
407
    r = pcilib_model[ctx->model].registers + reg;
 
408
    b = pcilib_model[ctx->model].banks + r->bank;
 
409
    
 
410
    n = r->bits / b->access;
 
411
    bits = r->bits % b->access; 
 
412
 
 
413
    pcilib_register_value_t buf[n + 1];
 
414
    memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t));
 
415
    
 
416
    if (b->endianess) {
 
417
        pcilib_error("Big-endian byte order support is not implemented");
 
418
        return PCILIB_ERROR_NOTSUPPORTED;
 
419
    } else {
 
420
        for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
 
421
            buf[i] = res & BIT_MASK(b->access);
 
422
            res >>= b->access;
 
423
        }
 
424
        
 
425
        if (res) {
 
426
            pcilib_error("Value %i is to big to fit in the register %s", value, r->name);
 
427
            return PCILIB_ERROR_OUTOFRANGE;
 
428
        }
 
429
    }
 
430
    
 
431
    err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
 
432
    return err;
 
433
}
 
434
 
 
435
int pcilib_write_register(pcilib_t *ctx, const char *regname, pcilib_register_value_t value) {
 
436
    int err;
 
437
    int reg;
 
438
    
 
439
    reg = pcilib_find_register(ctx, regname);
 
440
    if (reg < 0) pcilib_error("Register (%s) is not found", regname);
 
441
 
 
442
    return pcilib_write_register_by_id(ctx, reg, value);
 
443
}
190
444