/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: 2015-04-27 00:28:57 UTC
  • Revision ID: csa@suren.me-20150427002857-82fk6r3e8rfgy4wr
First stand-alone ipecamera implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define _PCILIB_PCI_C
2
 
//#define PCILIB_FILE_IO
3
 
#define _POSIX_C_SOURCE 199309L
4
 
 
5
 
#include <stdio.h>
6
 
#include <string.h>
7
 
#include <strings.h>
8
 
#include <stdlib.h>
9
 
#include <stdint.h>
10
 
#include <fcntl.h>
11
 
#include <unistd.h>
12
 
#include <sys/ioctl.h>
13
 
#include <sys/mman.h>
14
 
#include <arpa/inet.h>
15
 
#include <errno.h>
16
 
#include <assert.h>
17
 
 
18
 
#include "pcilib.h"
19
 
#include "pci.h"
20
 
#include "kernel.h"
21
 
#include "tools.h"
22
 
#include "error.h"
23
 
 
24
 
#include "ipecamera/model.h"
25
 
#include "kapture/model.h"
26
 
 
27
 
 
28
 
pcilib_t *pcilib_open(const char *device, pcilib_model_t model) {
29
 
    pcilib_t *ctx = malloc(sizeof(pcilib_t));
30
 
 
31
 
    if (ctx) {
32
 
        memset(ctx, 0, sizeof(pcilib_t));       
33
 
    
34
 
        ctx->handle = open(device, O_RDWR);
35
 
        if (ctx->handle < 0) {
36
 
            pcilib_error("Error opening device (%s)", device);
37
 
            free(ctx);
38
 
            return NULL;
39
 
        }
40
 
        
41
 
        ctx->page_mask = (uintptr_t)-1;
42
 
        ctx->model = model;
43
 
 
44
 
        if (!model) model = pcilib_get_model(ctx);
45
 
        
46
 
        memcpy(&ctx->model_info, pcilib_model + model, sizeof(pcilib_model_description_t));
47
 
 
48
 
        pcilib_init_event_engine(ctx);
49
 
    }
50
 
 
51
 
    return ctx;
52
 
}
53
 
 
54
 
pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx) {
55
 
    return &ctx->model_info;
56
 
}
57
 
 
58
 
const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) {
59
 
    int ret;
60
 
    
61
 
    if (ctx->page_mask ==  (uintptr_t)-1) {
62
 
        ret = ioctl( ctx->handle, PCIDRIVER_IOC_PCI_INFO, &ctx->board_info );
63
 
        if (ret) {
64
 
            pcilib_error("PCIDRIVER_IOC_PCI_INFO ioctl have failed");
65
 
            return NULL;
66
 
        }
67
 
        
68
 
        ctx->page_mask = pcilib_get_page_mask();
69
 
    }
70
 
    
71
 
    return &ctx->board_info;
72
 
}
73
 
 
74
 
 
75
 
 
76
 
pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) {
77
 
    return ctx->event_ctx;
78
 
}
79
 
 
80
 
pcilib_model_t pcilib_get_model(pcilib_t *ctx) {
81
 
    if (ctx->model == PCILIB_MODEL_DETECT) {
82
 
//      unsigned short vendor_id;
83
 
//      unsigned short device_id;
84
 
 
85
 
        //return PCILIB_MODEL_PCI;
86
 
        
87
 
        const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
88
 
        if (!board_info) return PCILIB_MODEL_PCI;
89
 
 
90
 
        if ((board_info->vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info->device_id == PCIE_IPECAMERA_DEVICE_ID))
91
 
            ctx->model = PCILIB_MODEL_IPECAMERA;
92
 
        else if ((board_info->vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info->device_id == PCIE_KAPTURE_DEVICE_ID))
93
 
            ctx->model = PCILIB_MODEL_IPECAMERA;
94
 
        else
95
 
            ctx->model = PCILIB_MODEL_PCI;
96
 
    }
97
 
    
98
 
    return ctx->model;
99
 
}
100
 
 
101
 
static pcilib_bar_t pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size) {
102
 
    int n = 0;
103
 
    pcilib_bar_t i;
104
 
        
105
 
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
106
 
    if (!board_info) return PCILIB_BAR_INVALID;
107
 
                
108
 
    for (i = 0; i < PCILIB_MAX_BANKS; i++) {
109
 
        if (board_info->bar_length[i] > 0) {
110
 
            if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i;
111
 
 
112
 
            if (n) n = -1;
113
 
            else n = i + 1;
114
 
        }
115
 
    }
116
 
 
117
 
    if (n > 0) return n - 1;
118
 
 
119
 
    return PCILIB_BAR_INVALID;
120
 
}
121
 
 
122
 
int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) {
123
 
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
124
 
    if (!board_info) return PCILIB_ERROR_NOTFOUND;
125
 
    
126
 
    if (*bar == PCILIB_BAR_DETECT) {
127
 
        *bar = pcilib_detect_bar(ctx, *addr, size);
128
 
        if (*bar == PCILIB_BAR_INVALID) {
129
 
            pcilib_error("The requested data block at address 0x%x with size %zu does not belongs to any available memory bank", *addr, size);
130
 
            return PCILIB_ERROR_NOTFOUND;
131
 
        }
132
 
        if (*addr < board_info->bar_start[*bar]) 
133
 
            *addr += board_info->bar_start[*bar];
134
 
    } else {
135
 
        if ((*addr < board_info->bar_start[*bar])||((board_info->bar_start[*bar] + board_info->bar_length[*bar]) < (((uintptr_t)*addr) + size))) {
136
 
            if ((board_info->bar_length[*bar]) >= (((uintptr_t)*addr) + size)) {
137
 
                *addr += board_info->bar_start[*bar];
138
 
            } else {
139
 
                pcilib_error("The requested data block at address 0x%x with size %zu 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]);
140
 
                return PCILIB_ERROR_NOTFOUND;
141
 
            }
142
 
        }
143
 
    }
144
 
 
145
 
    *addr -= board_info->bar_start[*bar];
146
 
    *addr += board_info->bar_start[*bar] & ctx->page_mask;
147
 
 
148
 
    return 0;
149
 
}
150
 
 
151
 
void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) {
152
 
    void *res;
153
 
    int ret; 
154
 
 
155
 
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
156
 
    if (!board_info) return NULL;
157
 
    
158
 
    if (ctx->bar_space[bar]) return ctx->bar_space[bar];
159
 
    
160
 
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI );
161
 
    if (ret) {
162
 
        pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar);
163
 
        return NULL;
164
 
    }
165
 
 
166
 
    ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar );
167
 
    if (ret) {
168
 
        pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar);
169
 
        return NULL;
170
 
    }
171
 
 
172
 
#ifdef PCILIB_FILE_IO
173
 
    file_io_handle = open("/root/data", O_RDWR);
174
 
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 );
175
 
#else
176
 
    res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
177
 
#endif
178
 
    if ((!res)||(res == MAP_FAILED)) {
179
 
        pcilib_error("Failed to mmap data bank %i", bar);
180
 
        return NULL;
181
 
    }
182
 
 
183
 
    
184
 
    return res;
185
 
}
186
 
 
187
 
void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
188
 
    const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
189
 
    if (!board_info) return;
190
 
 
191
 
    if (ctx->bar_space[bar]) return;
192
 
    
193
 
    munmap(data, board_info->bar_length[bar]);
194
 
#ifdef PCILIB_FILE_IO
195
 
    close(ctx->file_io_handle);
196
 
#endif
197
 
}
198
 
 
199
 
int pcilib_map_register_space(pcilib_t *ctx) {
200
 
    int err;
201
 
    pcilib_register_bank_t i;
202
 
    
203
 
    if (!ctx->reg_bar_mapped)  {
204
 
        pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
205
 
        pcilib_register_bank_description_t *banks = model_info->banks;
206
 
    
207
 
        for (i = 0; ((banks)&&(banks[i].access)); i++) {
208
 
//          uint32_t buf[2];
209
 
            void *reg_space;
210
 
            pcilib_bar_t bar = banks[i].bar;
211
 
 
212
 
            if (bar == PCILIB_BAR_DETECT) {
213
 
                uintptr_t addr = banks[0].read_addr;
214
 
            
215
 
                err = pcilib_detect_address(ctx, &bar, &addr, 1);
216
 
                if (err) return err;
217
 
                
218
 
                if (!ctx->bar_space[bar]) {
219
 
                    reg_space = pcilib_map_bar(ctx, bar);
220
 
//                  pcilib_memcpy(&buf, reg_space, 8);
221
 
            
222
 
                    if (reg_space) {
223
 
                        ctx->bar_space[bar] = reg_space;
224
 
                    } else {
225
 
                        return PCILIB_ERROR_FAILED;
226
 
                    }
227
 
                }
228
 
            } else if (!ctx->bar_space[bar]) {
229
 
                reg_space = pcilib_map_bar(ctx, bar);
230
 
                if (reg_space) {
231
 
                    ctx->bar_space[bar] = reg_space;
232
 
                } else {
233
 
                    return PCILIB_ERROR_FAILED;
234
 
                }
235
 
//              pcilib_memcpy(&buf, reg_space, 8);
236
 
                
237
 
            }
238
 
            if (!i) ctx->reg_bar = bar;
239
 
        }
240
 
        
241
 
        ctx->reg_bar_mapped = 1;
242
 
    }
243
 
    
244
 
    return 0;
245
 
}
246
 
 
247
 
int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) {
248
 
    int err;
249
 
    pcilib_bar_t i;
250
 
    
251
 
    if (!ctx->data_bar_mapped) {
252
 
        const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
253
 
        if (!board_info) return PCILIB_ERROR_FAILED;
254
 
 
255
 
        err = pcilib_map_register_space(ctx);
256
 
        if (err) {
257
 
            pcilib_error("Error mapping register space");
258
 
            return err;
259
 
        }
260
 
        
261
 
        int data_bar = -1;      
262
 
        
263
 
        for (i = 0; i < PCILIB_MAX_BANKS; i++) {
264
 
            if ((ctx->bar_space[i])||(!board_info->bar_length[i])) continue;
265
 
            
266
 
            if (addr) {
267
 
                if (board_info->bar_start[i] == addr) {
268
 
                    data_bar = i;
269
 
                    break;
270
 
                }
271
 
            } else {
272
 
                if (data_bar >= 0) {
273
 
                    data_bar = -1;
274
 
                    break;
275
 
                }
276
 
                
277
 
                data_bar = i;
278
 
            }
279
 
        }
280
 
            
281
 
 
282
 
        if (data_bar < 0) {
283
 
            if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr);
284
 
            else pcilib_error("Unable to find the data space");
285
 
            return PCILIB_ERROR_NOTFOUND;
286
 
        }
287
 
        
288
 
        ctx->data_bar = data_bar;
289
 
        
290
 
        if (!ctx->bar_space[data_bar]) {
291
 
            char *data_space = pcilib_map_bar(ctx, data_bar);
292
 
            if (data_space) ctx->bar_space[data_bar] = data_space;
293
 
            else {
294
 
                pcilib_error("Unable to map the data space");
295
 
                return PCILIB_ERROR_FAILED;
296
 
            }
297
 
        }
298
 
        
299
 
        ctx->data_bar_mapped = 0;
300
 
    }
301
 
    
302
 
    return 0;
303
 
}
304
 
        
305
 
/*
306
 
static void pcilib_unmap_register_space(pcilib_t *ctx) {
307
 
    if (ctx->reg_space) {
308
 
        pcilib_unmap_bar(ctx, ctx->reg_bar, ctx->reg_space);
309
 
        ctx->reg_space = NULL;
310
 
    }
311
 
}
312
 
 
313
 
static void pcilib_unmap_data_space(pcilib_t *ctx) {
314
 
    if (ctx->data_space) {
315
 
        pcilib_unmap_bar(ctx, ctx->data_bar, ctx->data_space);
316
 
        ctx->data_space = NULL;
317
 
    }
318
 
}
319
 
*/
320
 
 
321
 
char  *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr) {
322
 
    if (bar == PCILIB_BAR_DETECT) {
323
 
            // First checking the default register bar
324
 
        size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
325
 
        if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) {
326
 
            if (!ctx->bar_space[ctx->reg_bar]) {
327
 
                pcilib_error("The register bar is not mapped");
328
 
                return NULL;
329
 
            }
330
 
 
331
 
            return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask);
332
 
        }
333
 
            
334
 
            // Otherwise trying to detect
335
 
        bar = pcilib_detect_bar(ctx, addr, 1);
336
 
        if (bar != PCILIB_BAR_INVALID) {
337
 
            size_t offset = addr - ctx->board_info.bar_start[bar];
338
 
            if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) {
339
 
                if (!ctx->bar_space[bar]) {
340
 
                    pcilib_error("The requested bar (%i) is not mapped", bar);
341
 
                    return NULL;
342
 
                }
343
 
                return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask);
344
 
            }
345
 
        }
346
 
    } else {
347
 
        if (!ctx->bar_space[bar]) {
348
 
            pcilib_error("The requested bar (%i) is not mapped", bar);
349
 
            return NULL;
350
 
        }
351
 
        
352
 
        if (addr < ctx->board_info.bar_length[bar]) {
353
 
            return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask);
354
 
        }
355
 
        
356
 
        if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) {
357
 
            return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
358
 
        }
359
 
    }
360
 
 
361
 
    return NULL;
362
 
}
363
 
 
364
 
char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
365
 
    int err;
366
 
    
367
 
    err = pcilib_map_data_space(ctx, addr);
368
 
    if (err) {
369
 
        pcilib_error("Failed to map the specified address space (%lx)", addr);
370
 
        return NULL;
371
 
    }
372
 
    
373
 
    if (size) *size = ctx->board_info.bar_length[ctx->data_bar];
374
 
    
375
 
    return ctx->bar_space[ctx->data_bar] + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask);
376
 
}
377
 
 
378
 
 
379
 
void pcilib_close(pcilib_t *ctx) {
380
 
    pcilib_bar_t i;
381
 
    
382
 
    if (ctx) {
383
 
        pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
384
 
        pcilib_event_api_description_t *eapi = model_info->event_api;
385
 
        pcilib_dma_api_description_t *dapi = model_info->dma_api;
386
 
    
387
 
        if ((eapi)&&(eapi->free)) eapi->free(ctx->event_ctx);
388
 
        if ((dapi)&&(dapi->free)) dapi->free(ctx->dma_ctx);
389
 
        
390
 
        if (ctx->model_info.registers != model_info->registers) {
391
 
            free(ctx->model_info.registers);
392
 
            ctx->model_info.registers = pcilib_model[ctx->model].registers;
393
 
        }
394
 
        
395
 
        if (ctx->kmem_list) {
396
 
            pcilib_warning("Not all kernel buffers are properly cleaned");
397
 
        
398
 
            while (ctx->kmem_list) {
399
 
                pcilib_free_kernel_memory(ctx, ctx->kmem_list, 0);
400
 
            }
401
 
        }
402
 
 
403
 
        for (i = 0; i < PCILIB_MAX_BANKS; i++) {
404
 
            if (ctx->bar_space[i]) {
405
 
                char *ptr = ctx->bar_space[i];
406
 
                ctx->bar_space[i] = NULL;
407
 
                pcilib_unmap_bar(ctx, i, ptr);
408
 
            }
409
 
        }
410
 
        close(ctx->handle);
411
 
        
412
 
        free(ctx);
413
 
    }
414
 
}
415
 
 
416
 
int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
417
 
    void *data;
418
 
 
419
 
    pcilib_detect_address(ctx, &bar, &addr, size);
420
 
    data = pcilib_map_bar(ctx, bar);
421
 
 
422
 
    pcilib_memcpy(buf, data + addr, size);
423
 
 
424
 
    pcilib_unmap_bar(ctx, bar, data);
425
 
 
426
 
    return 0;
427
 
}
428
 
 
429
 
int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
430
 
    void *data;
431
 
 
432
 
    pcilib_detect_address(ctx, &bar, &addr, size);
433
 
    data = pcilib_map_bar(ctx, bar);
434
 
 
435
 
    pcilib_memcpy(data + addr, buf, size);
436
 
 
437
 
    pcilib_unmap_bar(ctx, bar, data);
438
 
 
439
 
    return 0;
440
 
}
441
 
 
442
 
 
443
 
int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
444
 
    int i;
445
 
    void *data;
446
 
 
447
 
    pcilib_detect_address(ctx, &bar, &addr, fifo_size);
448
 
    data = pcilib_map_bar(ctx, bar);
449
 
 
450
 
    for (i = 0; i < n; i++) {
451
 
        pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size);
452
 
    }
453
 
 
454
 
    pcilib_unmap_bar(ctx, bar, data);
455
 
 
456
 
    return 0;
457
 
}
458
 
 
459
 
int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
460
 
    int i;
461
 
    void *data;
462
 
 
463
 
    pcilib_detect_address(ctx, &bar, &addr, fifo_size);
464
 
    data = pcilib_map_bar(ctx, bar);
465
 
 
466
 
    for (i = 0; i < n; i++) {
467
 
        pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size);
468
 
    }
469
 
 
470
 
    pcilib_unmap_bar(ctx, bar, data);
471
 
 
472
 
    return 0;
473
 
}