/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 dma.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
 
#include <stdio.h>
2
 
#include <string.h>
3
 
#include <strings.h>
4
 
#include <stdlib.h>
5
 
#include <stdint.h>
6
 
#include <stdarg.h>
7
 
#include <fcntl.h>
8
 
#include <unistd.h>
9
 
#include <sys/ioctl.h>
10
 
#include <sys/mman.h>
11
 
#include <arpa/inet.h>
12
 
#include <sys/time.h>
13
 
#include <errno.h>
14
 
#include <assert.h>
15
 
 
16
 
#include "error.h"
17
 
#include "pcilib.h"
18
 
#include "pci.h"
19
 
#include "dma.h"
20
 
 
21
 
const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) {
22
 
    if (!ctx->dma_ctx) {
23
 
        pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
24
 
 
25
 
        if ((ctx->event_ctx)&&(model_info->event_api->init_dma)) {
26
 
            pcilib_map_register_space(ctx);
27
 
            ctx->dma_ctx = model_info->event_api->init_dma(ctx->event_ctx);
28
 
        } else if ((model_info->dma_api)&&(model_info->dma_api->init)) {
29
 
            pcilib_map_register_space(ctx);
30
 
            ctx->dma_ctx = model_info->dma_api->init(ctx, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);
31
 
        }
32
 
        
33
 
        if (!ctx->dma_ctx) return NULL;
34
 
    }
35
 
    
36
 
    return &ctx->dma_info;
37
 
}
38
 
 
39
 
pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) {
40
 
    pcilib_dma_engine_t i;
41
 
 
42
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
43
 
    if (!info) {
44
 
        pcilib_error("DMA Engine is not configured in the current model");
45
 
        return PCILIB_ERROR_NOTSUPPORTED;
46
 
    }
47
 
    
48
 
    for (i = 0; info->engines[i]; i++) {
49
 
        if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break;
50
 
    }
51
 
    
52
 
    if (info->engines[i]) return i;
53
 
    return PCILIB_DMA_ENGINE_INVALID;
54
 
}
55
 
 
56
 
int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) {
57
 
    ctx->dma_info.engines[engine] = desc;
58
 
 
59
 
    return 0;
60
 
}
61
 
 
62
 
int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
63
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
64
 
    if (!info) {
65
 
        pcilib_error("DMA is not supported by the device");
66
 
        return PCILIB_ERROR_NOTSUPPORTED;
67
 
    }
68
 
 
69
 
    if (!ctx->model_info.dma_api) {
70
 
        pcilib_error("DMA Engine is not configured in the current model");
71
 
        return PCILIB_ERROR_NOTAVAILABLE;
72
 
    }
73
 
    
74
 
    if (!ctx->model_info.dma_api->start_dma) {
75
 
        return 0;
76
 
    }
77
 
    
78
 
    return ctx->model_info.dma_api->start_dma(ctx->dma_ctx, dma, flags);
79
 
}
80
 
 
81
 
int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
82
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
83
 
 
84
 
    if (!info) {
85
 
        pcilib_error("DMA is not supported by the device");
86
 
        return PCILIB_ERROR_NOTSUPPORTED;
87
 
    }
88
 
 
89
 
    if (!ctx->model_info.dma_api) {
90
 
        pcilib_error("DMA Engine is not configured in the current model");
91
 
        return PCILIB_ERROR_NOTAVAILABLE;
92
 
    }
93
 
    
94
 
    if (!ctx->model_info.dma_api->stop_dma) {
95
 
        return 0;
96
 
    }
97
 
 
98
 
    return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags);
99
 
}
100
 
 
101
 
int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) {
102
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
103
 
 
104
 
    if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->enable_irq)) return 0;
105
 
 
106
 
    return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags);
107
 
}
108
 
 
109
 
int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
110
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
111
 
 
112
 
    if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->disable_irq)) return 0;
113
 
 
114
 
    return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags);
115
 
}
116
 
 
117
 
int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) {
118
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
119
 
 
120
 
    if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->acknowledge_irq)) return 0;
121
 
 
122
 
    return ctx->model_info.dma_api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source);
123
 
}
124
 
 
125
 
typedef struct {
126
 
    size_t size;
127
 
    void *data;
128
 
    size_t pos;
129
 
    
130
 
    pcilib_dma_flags_t flags;
131
 
} pcilib_dma_read_callback_context_t;
132
 
 
133
 
static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
134
 
    pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg;
135
 
    
136
 
    if (ctx->pos + bufsize > ctx->size) {
137
 
        if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0)
138
 
            pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); 
139
 
        return -PCILIB_ERROR_TOOBIG;
140
 
    }
141
 
    
142
 
    memcpy(ctx->data + ctx->pos, buf, bufsize);
143
 
    ctx->pos += bufsize;
144
 
 
145
 
    if (flags & PCILIB_DMA_FLAG_EOP) {
146
 
        if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
147
 
            if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
148
 
            else return PCILIB_STREAMING_CONTINUE;
149
 
        }
150
 
        return PCILIB_STREAMING_STOP;
151
 
    }
152
 
    
153
 
    return PCILIB_STREAMING_REQ_FRAGMENT;
154
 
}
155
 
 
156
 
static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
157
 
    struct timeval *tv = (struct timeval*)arg;
158
 
    struct timeval cur;
159
 
    
160
 
    if (tv) {
161
 
        gettimeofday(&cur, NULL);
162
 
        if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP;
163
 
    }
164
 
    
165
 
    return PCILIB_STREAMING_REQ_PACKET;
166
 
}
167
 
 
168
 
int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
169
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
170
 
    if (!info) {
171
 
        pcilib_error("DMA is not supported by the device");
172
 
        return PCILIB_ERROR_NOTSUPPORTED;
173
 
    }
174
 
 
175
 
    if (!ctx->model_info.dma_api) {
176
 
        pcilib_error("DMA Engine is not configured in the current model");
177
 
        return PCILIB_ERROR_NOTAVAILABLE;
178
 
    }
179
 
    
180
 
    if (!ctx->model_info.dma_api->stream) {
181
 
        pcilib_error("The DMA read is not supported by configured DMA engine");
182
 
        return PCILIB_ERROR_NOTSUPPORTED;
183
 
    }
184
 
    
185
 
    if (!info->engines[dma]) {
186
 
        pcilib_error("The DMA engine (%i) is not supported by device", dma);
187
 
        return PCILIB_ERROR_NOTAVAILABLE;
188
 
    }
189
 
 
190
 
    if ((info->engines[dma]->direction&PCILIB_DMA_FROM_DEVICE) == 0) {
191
 
        pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma);
192
 
        return PCILIB_ERROR_NOTSUPPORTED;
193
 
    }
194
 
 
195
 
    return ctx->model_info.dma_api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr);
196
 
}
197
 
 
198
 
int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) {
199
 
    int err; 
200
 
 
201
 
    pcilib_dma_read_callback_context_t opts = {
202
 
        size, buf, 0, flags
203
 
    };
204
 
    
205
 
    err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts);
206
 
    if (read_bytes) *read_bytes = opts.pos;
207
 
    return err;
208
 
}
209
 
 
210
 
int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) {
211
 
    int err; 
212
 
 
213
 
    pcilib_dma_read_callback_context_t opts = {
214
 
        size, buf, 0, 0
215
 
    };
216
 
    
217
 
    err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
218
 
    if (read_bytes) *read_bytes = opts.pos;
219
 
    return err;
220
 
}
221
 
 
222
 
 
223
 
int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
224
 
    int err;
225
 
    struct timeval tv, cur;
226
 
 
227
 
    gettimeofday(&tv, NULL);
228
 
    tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT;
229
 
    tv.tv_sec += tv.tv_usec / 1000000;
230
 
    tv.tv_usec += tv.tv_usec % 1000000;
231
 
    
232
 
    do {
233
 
            // IMMEDIATE timeout is not working properly, so default is set
234
 
        err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv);
235
 
        gettimeofday(&cur, NULL);
236
 
    } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec))));
237
 
 
238
 
    if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT;
239
 
    
240
 
    return 0;
241
 
}
242
 
 
243
 
 
244
 
int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) {
245
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
246
 
    if (!info) {
247
 
        pcilib_error("DMA is not supported by the device");
248
 
        return PCILIB_ERROR_NOTSUPPORTED;
249
 
    }
250
 
 
251
 
    if (!ctx->model_info.dma_api) {
252
 
        pcilib_error("DMA Engine is not configured in the current model");
253
 
        return PCILIB_ERROR_NOTAVAILABLE;
254
 
    }
255
 
    
256
 
    if (!ctx->model_info.dma_api->push) {
257
 
        pcilib_error("The DMA write is not supported by configured DMA engine");
258
 
        return PCILIB_ERROR_NOTSUPPORTED;
259
 
    }
260
 
    
261
 
    if (!info->engines[dma]) {
262
 
        pcilib_error("The DMA engine (%i) is not supported by device", dma);
263
 
        return PCILIB_ERROR_NOTAVAILABLE;
264
 
    }
265
 
 
266
 
    if ((info->engines[dma]->direction&PCILIB_DMA_TO_DEVICE) == 0) {
267
 
        pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma);
268
 
        return PCILIB_ERROR_NOTSUPPORTED;
269
 
    }
270
 
    
271
 
    return ctx->model_info.dma_api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written);
272
 
}
273
 
 
274
 
 
275
 
int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) {
276
 
    return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes);
277
 
}
278
 
 
279
 
double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
280
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
281
 
    if (!info) {
282
 
        pcilib_error("DMA is not supported by the device");
283
 
        return 0;
284
 
    }
285
 
 
286
 
    if (!ctx->model_info.dma_api) {
287
 
        pcilib_error("DMA Engine is not configured in the current model");
288
 
        return -1;
289
 
    }
290
 
    
291
 
    if (!ctx->model_info.dma_api->benchmark) {
292
 
        pcilib_error("The DMA benchmark is not supported by configured DMA engine");
293
 
        return -1;
294
 
   }
295
 
    
296
 
    if (!info->engines[dma]) {
297
 
        pcilib_error("The DMA engine (%i) is not supported by device", dma);
298
 
        return -1;
299
 
    }
300
 
 
301
 
    return ctx->model_info.dma_api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
302
 
}
303
 
 
304
 
int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
305
 
    const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
306
 
    if (!info) {
307
 
        pcilib_error("DMA is not supported by the device");
308
 
        return 0;
309
 
    }
310
 
 
311
 
    if (!ctx->model_info.dma_api) {
312
 
        pcilib_error("DMA Engine is not configured in the current model");
313
 
        return -1;
314
 
    }
315
 
    
316
 
    if (!ctx->model_info.dma_api->status) {
317
 
        memset(status, 0, sizeof(pcilib_dma_engine_status_t));
318
 
        return -1;
319
 
   }
320
 
    
321
 
    if (!info->engines[dma]) {
322
 
        pcilib_error("The DMA engine (%i) is not supported by device", dma);
323
 
        return -1;
324
 
    }
325
 
 
326
 
    return ctx->model_info.dma_api->status(ctx->dma_ctx, dma, status, n_buffers, buffers);
327
 
}