summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--cli.c233
-rw-r--r--default.c2
-rw-r--r--event.c230
-rw-r--r--event.h22
-rw-r--r--pci.c540
-rw-r--r--pci.h3
-rw-r--r--pcilib.h31
-rw-r--r--register.c280
-rw-r--r--register.h11
-rw-r--r--tools.h2
11 files changed, 785 insertions, 571 deletions
diff --git a/Makefile b/Makefile
index f39abf5..6779487 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ include common.mk
###############################################################
# Target definitions
-OBJECTS = pci.o kmem.o dma.o default.o tools.o dma/nwl.o ipecamera/model.o ipecamera/image.o
+OBJECTS = pci.o register.o kmem.o dma.o event.o default.o tools.o dma/nwl.o ipecamera/model.o ipecamera/image.o
libpcilib.so: $(OBJECTS)
echo -e "LD \t$@"
diff --git a/cli.c b/cli.c
index 123c54e..c55d051 100644
--- a/cli.c
+++ b/cli.c
@@ -17,7 +17,7 @@
#include <getopt.h>
-#include "pci.h"
+//#include "pci.h"
#include "tools.h"
#include "kernel.h"
@@ -63,6 +63,7 @@ typedef enum {
typedef enum {
OPT_DEVICE = 'd',
OPT_MODEL = 'm',
+ OPT_TYPE = 't',
OPT_BAR = 'b',
OPT_ACCESS = 'a',
OPT_ENDIANESS = 'e',
@@ -82,6 +83,7 @@ typedef enum {
static struct option long_options[] = {
{"device", required_argument, 0, OPT_DEVICE },
{"model", required_argument, 0, OPT_MODEL },
+ {"type", required_argument, 0, OPT_TYPE },
{"bar", required_argument, 0, OPT_BAR },
{"access", required_argument, 0, OPT_ACCESS },
{"endianess", required_argument, 0, OPT_ENDIANESS },
@@ -132,7 +134,8 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" -m <model> - Memory model (autodetected)\n"
" pci - Plain\n"
" ipecamera - IPE Camera\n"
-" -b <bank> - Data/Register bank (autodetected)\n"
+" -t <plain|fifo|dma> - Access type (default: plain)\n"
+" -b <bank> - PCI bar, Register bank, or DMA channel\n"
"\n"
" Options:\n"
" -s <size> - Number of words (default: 1)\n"
@@ -302,22 +305,34 @@ void Info(pcilib_t *handle, pcilib_model_t model) {
}
-int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar) {
+#define BENCH_MAX_DMA_SIZE 16 * 1024 * 1024
+#define BENCH_MAX_FIFO_SIZE 1024 * 1024
+
+int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access) {
int err;
- int i, errors;
+ int i, j, errors;
void *data, *buf, *check;
+ void *fifo;
struct timeval start, end;
unsigned long time;
- unsigned int size, max_size;
+ size_t size, min_size, max_size;
double mbs_in, mbs_out, mbs;
const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);
if (mode == ACCESS_DMA) {
- for (size = 1024 ; size < 16 * 1024 * 1024; size *= 4) {
- mbs_in = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_FROM_DEVICE);
- mbs_out = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_TO_DEVICE);
- mbs = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_BIDIRECTIONAL);
+ if (n) {
+ min_size = n * access;
+ max_size = n * access;
+ } else {
+ min_size = 1024;
+ max_size = BENCH_MAX_DMA_SIZE;
+ }
+
+ for (size = min_size; size < max_size; size *= 4) {
+ mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_FROM_DEVICE);
+ mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_TO_DEVICE);
+ mbs = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_BIDIRECTIONAL);
printf("%8i KB - ", size / 1024);
printf("RW: ");
@@ -337,10 +352,17 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
return 0;
}
-
- if (bar < 0) {
+
+ if (bar == PCILIB_BAR_INVALID) {
unsigned long maxlength = 0;
+
+
for (i = 0; i < PCILIB_MAX_BANKS; i++) {
+ if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + access))) {
+ bar = i;
+ break;
+ }
+
if (board_info->bar_length[i] > maxlength) {
maxlength = board_info->bar_length[i];
bar = i;
@@ -350,36 +372,71 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
if (bar < 0) Error("Data banks are not available");
}
+ if (n) {
+ if ((mode == ACCESS_BAR)&&(n * access > board_info->bar_length[bar])) Error("The specified size (%i) exceeds the size of bar (%i)", n * access, board_info->bar_length[bar]);
- max_size = board_info->bar_length[bar];
+ min_size = n * access;
+ max_size = n * access;
+ } else {
+ min_size = access;
+ if (mode == ACCESS_BAR) max_size = board_info->bar_length[bar];
+ else max_size = BENCH_MAX_FIFO_SIZE;
+ }
err = posix_memalign( (void**)&buf, 256, max_size );
if (!err) err = posix_memalign( (void**)&check, 256, max_size );
if ((err)||(!buf)||(!check)) Error("Allocation of %i bytes of memory have failed", max_size);
- printf("Transfer time (Bank: %i):\n", bar);
data = pcilib_map_bar(handle, bar);
-
- for (size = 4 ; size < max_size; size *= 8) {
+ if (!data) Error("Can't map bar %i", bar);
+
+ if (mode == ACCESS_FIFO) {
+ fifo = data + (addr - board_info->bar_start[bar]) + (board_info->bar_start[bar] & pcilib_get_page_mask());
+// pcilib_resolve_register_address(handle, bar, addr);
+ if (!fifo) Error("Can't resolve address (%lx) in bar (%u)", addr, bar);
+ }
+
+ if (mode == ACCESS_FIFO)
+ printf("Transfer time (Bank: %i, Fifo: %lx):\n", bar, addr);
+ else
+ printf("Transfer time (Bank: %i):\n", bar);
+
+ for (size = min_size ; size < max_size; size *= 8) {
gettimeofday(&start,NULL);
- for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
- pcilib_memcpy(buf, data, size);
+ if (mode == ACCESS_BAR) {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_memcpy(buf, data, size);
+ }
+ } else {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ for (j = 0; j < (size/access); j++) {
+ pcilib_memcpy(buf + j * access, fifo, access);
+ }
+ }
}
gettimeofday(&end,NULL);
time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
- printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+ printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
fflush(0);
gettimeofday(&start,NULL);
- for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
- pcilib_memcpy(data, buf, size);
+ if (mode == ACCESS_BAR) {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_memcpy(data, buf, size);
+ }
+ } else {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ for (j = 0; j < (size/access); j++) {
+ pcilib_memcpy(fifo, buf + j * access, access);
+ }
+ }
}
gettimeofday(&end,NULL);
time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
- printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+ printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
}
pcilib_unmap_bar(handle, bar, data);
@@ -388,36 +445,51 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
for (size = 4 ; size < max_size; size *= 8) {
gettimeofday(&start,NULL);
- for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
- pcilib_read(handle, bar, 0, size, buf);
+ if (mode == ACCESS_BAR) {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_read(handle, bar, 0, size, buf);
+ }
+ } else {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_read_fifo(handle, bar, addr, access, size / access, buf);
+ }
}
gettimeofday(&end,NULL);
time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
- printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+ printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
fflush(0);
gettimeofday(&start,NULL);
- for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
- pcilib_write(handle, bar, 0, size, buf);
+ if (mode == ACCESS_BAR) {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_write(handle, bar, 0, size, buf);
+ }
+ } else {
+ for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_write_fifo(handle, bar, addr, access, size / access, buf);
+ }
}
+
gettimeofday(&end,NULL);
time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
- printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+ printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
+
+ if (mode == ACCESS_BAR) {
+ gettimeofday(&start,NULL);
+ for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) {
+ pcilib_write(handle, bar, 0, size, buf);
+ pcilib_read(handle, bar, 0, size, check);
+ if (memcmp(buf, check, size)) ++errors;
+ }
+ gettimeofday(&end,NULL);
- gettimeofday(&start,NULL);
- for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) {
- pcilib_write(handle, bar, 0, size, buf);
- pcilib_read(handle, bar, 0, size, check);
- if (memcmp(buf, check, size)) ++errors;
+ time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
+ printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
+ if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS);
}
- gettimeofday(&end,NULL);
-
- time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
- printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
- if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS);
printf("\n");
}
@@ -433,9 +505,11 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) {
void *buf;
int i, err;
+ size_t ret;
int size = n * abs(access);
int block_width, blocks_per_line;
int numbers_per_block, numbers_per_line;
+ pcilib_dma_t dmaid;
numbers_per_block = BLOCK_SIZE / access;
@@ -448,13 +522,20 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_b
err = posix_memalign( (void**)&buf, 256, size );
if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size);
- if (mode == ACCESS_DMA) {
- pcilib_dma_t dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
+ switch (mode) {
+ case ACCESS_DMA:
+ dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
- pcilib_read_dma(handle, dmaid, addr, size, buf);
-
+ ret = pcilib_read_dma(handle, dmaid, addr, size, buf);
+ if (ret <= 0) Error("No data is returned by DMA engine");
+ size = ret;
addr = 0;
- } else {
+ break;
+ case ACCESS_FIFO:
+ pcilib_read_fifo(handle, bar, addr, access, n, buf);
+ addr = 0;
+ break;
+ default:
pcilib_read(handle, bar, addr, size, buf);
}
if (endianess) pcilib_swap(buf, buf, abs(access), n);
@@ -592,9 +673,12 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_t model, const char *bank,
}
int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) {
+ int read_back = 0;
void *buf, *check;
int res, i, err;
int size = n * abs(access);
+ size_t ret;
+ pcilib_dma_t dmaid;
err = posix_memalign( (void**)&buf, 256, size );
if (!err) err = posix_memalign( (void**)&check, 256, size );
@@ -611,10 +695,27 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
}
if (endianess) pcilib_swap(buf, buf, abs(access), n);
- pcilib_write(handle, bar, addr, size, buf);
- pcilib_read(handle, bar, addr, size, check);
-
- if (memcmp(buf, check, size)) {
+
+ switch (mode) {
+ case ACCESS_DMA:
+ dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma);
+ if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
+ ret = pcilib_write_dma(handle, dmaid, addr, size, buf);
+ if (ret != size) {
+ if (!ret) Error("No data is written by DMA engine");
+ else Error("Only %lu bytes of %lu is written by DMA engine", ret, size);
+ }
+ break;
+ case ACCESS_FIFO:
+ pcilib_write_fifo(handle, bar, addr, access, n, buf);
+ break;
+ default:
+ pcilib_write(handle, bar, addr, size, buf);
+ pcilib_read(handle, bar, addr, size, check);
+ read_back = 1;
+ }
+
+ if ((read_back)&&(memcmp(buf, check, size))) {
printf("Write failed: the data written and read differ, the foolowing is read back:\n");
if (endianess) pcilib_swap(check, check, abs(access), n);
ReadData(handle, mode, dma, bar, addr, n, access, endianess);
@@ -730,6 +831,7 @@ int main(int argc, char **argv) {
pcilib_model_t model = PCILIB_MODEL_DETECT;
MODE mode = MODE_INVALID;
+ const char *type = NULL;
ACCESS_MODE amode = ACCESS_BAR;
const char *fpga_device = DEFAULT_FPGA_DEVICE;
pcilib_bar_t bar = PCILIB_BAR_DETECT;
@@ -749,7 +851,9 @@ int main(int argc, char **argv) {
pcilib_t *handle;
- while ((c = getopt_long(argc, argv, "hqilpr::w::g::d:m:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) {
+ int size_set = 0;
+
+ while ((c = getopt_long(argc, argv, "hqilpr::w::g::d:m:t:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) {
extern int optind;
switch (c) {
case OPT_HELP:
@@ -805,7 +909,10 @@ int main(int argc, char **argv) {
case OPT_MODEL:
if (!strcasecmp(optarg, "pci")) model = PCILIB_MODEL_PCI;
else if (!strcasecmp(optarg, "ipecamera")) model = PCILIB_MODEL_IPECAMERA;
- else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);\
+ else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);
+ break;
+ case OPT_TYPE:
+ type = optarg;
break;
case OPT_BAR:
bank = optarg;
@@ -825,6 +932,7 @@ int main(int argc, char **argv) {
case OPT_SIZE:
if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1))
Usage(argc, argv, "Invalid size is specified (%s)", optarg);
+ size_set = 1;
break;
case OPT_ENDIANESS:
if ((*optarg == 'b')||(*optarg == 'B')) {
@@ -895,13 +1003,24 @@ int main(int argc, char **argv) {
if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied");
}
+ if (type) {
+ if (!strcasecmp(type, "fifo")) amode = ACCESS_FIFO;
+ else if (!strcasecmp(type, "dma")) amode = ACCESS_DMA;
+ else if ((!strcasecmp(type, "bar"))||(!strcasecmp(optarg, "bar"))) amode = ACCESS_BAR;
+ else Usage(argc, argv, "Invalid access type (%s) is specified", type);
+ }
+
if (addr) {
- if (!strncmp(addr, "dma", 3)) {
+ if ((!strncmp(addr, "dma", 3))&&((addr[3]==0)||isnumber(addr+3))) {
+ if ((type)&&(amode != ACCESS_DMA)) Usage(argc, argv, "Conflicting access modes, the DMA read is requested, but access type is (%s)", type);
+ if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting DMA channels are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank);
dma = atoi(addr + 3);
amode = ACCESS_DMA;
- } else if (!strncmp(addr, "bar", 3)) {
+ } else if ((!strncmp(addr, "bar", 3))&&((addr[3]==0)||isnumber(addr+3))) {
+ if ((type)&&(amode != ACCESS_BAR)) Usage(argc, argv, "Conflicting access modes, the plain PCI read is requested, but access type is (%s)", type);
+ if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting PCI bars are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank);
bar = atoi(addr + 3);
- amode = ACCESS_DMA;
+ amode = ACCESS_BAR;
} else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) {
// check if the address in the register range
pcilib_register_range_t *ranges = pcilib_model[model].ranges;
@@ -911,7 +1030,7 @@ int main(int argc, char **argv) {
if ((start >= ranges[i].start)&&(start <= ranges[i].end)) break;
// register access in plain mode
- if (ranges[i].start != ranges[i].end) ++mode;
+ if (ranges[i].start != ranges[i].end) ++mode;
}
} else {
if (pcilib_find_register(handle, bank, addr) == PCILIB_REGISTER_INVALID) {
@@ -923,7 +1042,12 @@ int main(int argc, char **argv) {
}
}
- if (bank) {
+
+ if ((bank)&&(amode == ACCESS_DMA)) {
+ if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0))
+ Usage(argc, argv, "Invalid DMA channel (%s) is specified", bank);
+ else dma = itmp;
+ } else if (bank) {
switch (mode) {
case MODE_BENCHMARK:
case MODE_READ:
@@ -937,6 +1061,7 @@ int main(int argc, char **argv) {
Usage(argc, argv, "Invalid data bank (%s) is specified", bank);
}
}
+
switch (mode) {
case MODE_INFO:
@@ -946,7 +1071,7 @@ int main(int argc, char **argv) {
List(handle, model, bank);
break;
case MODE_BENCHMARK:
- Benchmark(handle, amode, dma, bar);
+ Benchmark(handle, amode, dma, bar, start, size_set?size:0, access);
break;
case MODE_READ:
if (addr) {
diff --git a/default.c b/default.c
index f771599..f104879 100644
--- a/default.c
+++ b/default.c
@@ -6,8 +6,6 @@
#include "default.h"
#include "error.h"
-#define BIT_MASK(bits) ((1ll << (bits)) - 1)
-
#define default_datacpy(dst, src, access, bank) pcilib_datacpy(dst, src, access, 1, bank->raw_endianess)
int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value) {
diff --git a/event.c b/event.c
new file mode 100644
index 0000000..2eb7fc4
--- /dev/null
+++ b/event.c
@@ -0,0 +1,230 @@
+#define _POSIX_C_SOURCE 199309L
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "pci.h"
+
+#include "tools.h"
+#include "error.h"
+
+pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
+ int i;
+ pcilib_register_bank_t res;
+ unsigned long addr;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+ pcilib_event_description_t *events = pcilib_model[model].events;
+
+ for (i = 0; events[i].name; i++) {
+ if (!strcasecmp(events[i].name, event)) return (1<<i);
+ }
+
+ return (pcilib_event_t)-1;
+}
+
+
+int pcilib_reset(pcilib_t *ctx) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ api = pcilib_model[model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->reset)
+ return api->reset(ctx->event_ctx);
+
+ return 0;
+}
+
+int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ api = pcilib_model[model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->start)
+ return api->start(ctx->event_ctx, event_mask, callback, user);
+
+ return 0;
+}
+
+int pcilib_stop(pcilib_t *ctx) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ api = pcilib_model[model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->stop)
+ return api->stop(ctx->event_ctx);
+
+ return 0;
+}
+
+pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ api = pcilib_model[model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->next_event)
+ return api->next_event(ctx->event_ctx, event_mask, timeout);
+
+ pcilib_error("Event enumeration is not suppored by API");
+ return PCILIB_EVENT_ID_INVALID;
+}
+
+int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
+ pcilib_event_api_description_t *api;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ api = pcilib_model[model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->trigger)
+ return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
+
+ pcilib_error("Self triggering is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+}
+
+
+void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) {
+ pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return NULL;
+ }
+
+ if (api->get_data)
+ return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size);
+
+ return NULL;
+}
+
+void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
+ pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return NULL;
+ }
+
+ if (api->get_data)
+ return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size);
+
+ return NULL;
+}
+
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
+ pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+ if (!api) {
+ pcilib_error("Event API is not supported by the selected model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (api->return_data)
+ return api->return_data(ctx->event_ctx, event_id);
+
+ return 0;
+}
+
+
+typedef struct {
+ pcilib_t *ctx;
+
+ size_t *size;
+ void **data;
+} pcilib_grab_callback_user_data_t;
+
+static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
+ int err;
+ void *data;
+ size_t size;
+ int allocated = 0;
+
+ pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
+
+ data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
+ if (!data) {
+ pcilib_error("Error getting event data");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ if (*(user->data)) {
+ if ((user->size)&&(*(user->size) < size)) {
+ pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ *(user->size) = size;
+ } else {
+ *(user->data) = malloc(size);
+ if (!*(user->data)) {
+ pcilib_error("Memory allocation (%i bytes) for event data is failed");
+ return PCILIB_ERROR_MEMORY;
+ }
+ if (*(user->size)) *(user->size) = size;
+ allocated = 1;
+ }
+
+ memcpy(*(user->data), data, size);
+
+ err = pcilib_return_data(user->ctx, event_id);
+ if (err) {
+ if (allocated) {
+ free(*(user->data));
+ *(user->data) = NULL;
+ }
+ pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
+ return err;
+ }
+
+ return 0;
+}
+
+int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
+ int err;
+
+ pcilib_grab_callback_user_data_t user = {ctx, size, data};
+
+ err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
+ if (!err) {
+ if (timeout) nanosleep(timeout, NULL);
+ else err = pcilib_trigger(ctx, event_mask, 0, NULL);
+ }
+ pcilib_stop(ctx);
+ return 0;
+}
diff --git a/event.h b/event.h
new file mode 100644
index 0000000..b60fc29
--- /dev/null
+++ b/event.h
@@ -0,0 +1,22 @@
+#ifndef _PCILIB_EVENT_H
+#define _PCILIB_EVENT_H
+
+#include "pcilib.h"
+
+struct pcilib_event_api_description_s {
+ pcilib_context_t *(*init)(pcilib_t *ctx);
+ void (*free)(pcilib_context_t *ctx);
+
+ int (*reset)(pcilib_context_t *ctx);
+
+ int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user);
+ int (*stop)(pcilib_context_t *ctx);
+ int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
+
+ pcilib_event_id_t (*next_event)(pcilib_context_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout);
+ void* (*get_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size);
+ int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id);
+};
+
+
+#endif /* _PCILIB_EVENT_H */
diff --git a/pci.c b/pci.c
index 4347ab7..9426658 100644
--- a/pci.c
+++ b/pci.c
@@ -16,17 +16,13 @@
#include <errno.h>
#include <assert.h>
+#include "pci.h"
+
#include "kernel.h"
#include "tools.h"
-
-#include "dma.h"
-#include "pci.h"
-#include "ipecamera/model.h"
#include "error.h"
-#define BIT_MASK(bits) ((1l << (bits)) - 1)
-
-
+#include "ipecamera/model.h"
static void pcilib_print_error(const char *msg, ...) {
@@ -220,126 +216,6 @@ void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
#endif
}
-int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
- int i;
- void *data;
- unsigned int offset;
- char local_buf[size];
-
-
- pcilib_detect_address(ctx, &bar, &addr, size);
- data = pcilib_map_bar(ctx, bar);
-
-/*
- for (i = 0; i < size/4; i++) {
- ((uint32_t*)((char*)data+addr))[i] = 0x100 * i + 1;
- }
-*/
- pcilib_memcpy(buf, data + addr, size);
-
- pcilib_unmap_bar(ctx, bar, data);
-}
-
-int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
- int i;
- void *data;
- unsigned int offset;
- char local_buf[size];
-
-
- pcilib_detect_address(ctx, &bar, &addr, size);
- data = pcilib_map_bar(ctx, bar);
-
- pcilib_memcpy(data + addr, buf, size);
-
- pcilib_unmap_bar(ctx, bar, data);
-}
-
-
-pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
- pcilib_register_bank_t i;
- pcilib_model_t model = pcilib_get_model(ctx);
- pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
-
- for (i = 0; banks[i].access; i++)
- if (banks[i].addr == bank) return i;
-
- return -1;
-}
-
-pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankname) {
- pcilib_register_bank_t i;
- pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
-
- for (i = 0; banks[i].access; i++)
- if (!strcasecmp(banks[i].name, bankname)) return i;
-
- return -1;
-}
-
-pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank) {
- pcilib_register_bank_t res;
- unsigned long addr;
-
- if (!bank) {
- pcilib_model_t model = pcilib_get_model(ctx);
- pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
- if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0;
- return -1;
- }
-
- if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) {
- res = pcilib_find_bank_by_addr(ctx, addr);
- if (res != PCILIB_REGISTER_BANK_INVALID) return res;
- }
-
- return pcilib_find_bank_by_name(ctx, bank);
-}
-
- // FIXME create hash during map_register space
-pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) {
- pcilib_register_t i;
- pcilib_register_bank_t bank_id;
- pcilib_register_bank_addr_t bank_addr;
-
- pcilib_model_t model = pcilib_get_model(ctx);
-
- pcilib_register_description_t *registers = pcilib_model[model].registers;
-
- if (bank) {
- bank_id = pcilib_find_bank(ctx, bank);
- if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
- pcilib_error("Invalid bank (%s) is specified", bank);
- return -1;
- }
-
- bank_addr = pcilib_model[model].banks[bank_id].addr;
- }
-
- for (i = 0; registers[i].bits; i++) {
- if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i;
- }
-
- return (pcilib_register_t)-1;
-};
-
-
-pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
- int i;
- pcilib_register_bank_t res;
- unsigned long addr;
-
- pcilib_model_t model = pcilib_get_model(ctx);
- pcilib_event_description_t *events = pcilib_model[model].events;
-
- for (i = 0; events[i].name; i++) {
- if (!strcasecmp(events[i].name, event)) return (1<<i);
- }
-
- return (pcilib_event_t)-1;
-}
-
-
int pcilib_map_register_space(pcilib_t *ctx) {
int err;
pcilib_register_bank_t i;
@@ -467,6 +343,11 @@ char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_
// First checking the default register bar
size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) {
+ if (!ctx->bar_space[ctx->reg_bar]) {
+ pcilib_error("The register bar is not mapped");
+ return NULL;
+ }
+
return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask);
}
@@ -475,14 +356,26 @@ char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_
if (bar != PCILIB_BAR_INVALID) {
size_t offset = addr - ctx->board_info.bar_start[bar];
if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) {
+ if (!ctx->bar_space[bar]) {
+ pcilib_error("The requested bar (%i) is not mapped", bar);
+ return NULL;
+ }
return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask);
}
}
} else {
+ if (!ctx->bar_space[bar]) {
+ pcilib_error("The requested bar (%i) is not mapped", bar);
+ return NULL;
+ }
+
if (addr < ctx->board_info.bar_length[bar]) {
return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask);
}
+ if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) {
+ return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
+ }
}
return NULL;
@@ -531,393 +424,56 @@ void pcilib_close(pcilib_t *ctx) {
}
}
-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) {
- int err;
- int rest;
- size_t i;
-
- pcilib_model_t model = pcilib_get_model(ctx);
- pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
-
- assert(bits < 8 * sizeof(pcilib_register_value_t));
-
- if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
- pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
- return PCILIB_ERROR_OUTOFRANGE;
- }
+int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
+ int i;
+ void *data;
- err = pcilib_map_register_space(ctx);
- if (err) {
- pcilib_error("Failed to map the register space");
- return err;
- }
-
- //n += bits / b->access;
- //bits %= b->access;
-
- for (i = 0; i < n; i++) {
- err = pcilib_protocol[b->protocol].read(ctx, b, addr + i, b->access, buf + i);
- if (err) break;
- }
-
- if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].read(ctx, b, addr + n, bits, buf + n);
-
- return err;
-}
+ pcilib_detect_address(ctx, &bar, &addr, size);
+ data = pcilib_map_bar(ctx, bar);
-int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
- pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
- if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
- if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
- else pcilib_error("Register bank should be specified");
- return PCILIB_ERROR_INVALID_BANK;
- }
+ pcilib_memcpy(buf, data + addr, size);
- return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+ pcilib_unmap_bar(ctx, bar, data);
}
-int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) {
- int err;
- size_t i, n, bits;
- pcilib_register_value_t res;
- pcilib_register_description_t *r;
- pcilib_register_bank_description_t *b;
- pcilib_model_t model = pcilib_get_model(ctx);
-
- r = pcilib_model[model].registers + reg;
- b = pcilib_model[model].banks + r->bank;
-
- n = r->bits / b->access;
- bits = r->bits % b->access;
-
- pcilib_register_value_t buf[n + 1];
- err = pcilib_read_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
-
- if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
- pcilib_error("Big-endian byte order support is not implemented");
- return PCILIB_ERROR_NOTSUPPORTED;
- } else {
- res = 0;
- if (bits) ++n;
- for (i = 0; i < n; i++) {
- res |= buf[i] << (i * b->access);
- }
- }
-
- *value = res;
-
- return err;
-}
+int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
+ int i;
+ void *data;
+ pcilib_detect_address(ctx, &bar, &addr, size);
+ data = pcilib_map_bar(ctx, bar);
-int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) {
- int err;
- int reg;
-
- reg = pcilib_find_register(ctx, bank, regname);
- if (reg < 0) {
- pcilib_error("Register (%s) is not found", regname);
- return PCILIB_ERROR_NOTFOUND;
- }
+ pcilib_memcpy(data + addr, buf, size);
- return pcilib_read_register_by_id(ctx, reg, value);
-
-// registers[reg].bank
-// printf("%li %li", sizeof(pcilib_model[model].banks), sizeof(pcilib_register_bank_description_t));
+ pcilib_unmap_bar(ctx, bar, data);
}
-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) {
- int err;
- int rest;
- size_t i;
+int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
+ int i;
+ void *data;
- pcilib_model_t model = pcilib_get_model(ctx);
- pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
-
- assert(bits < 8 * sizeof(pcilib_register_value_t));
-
- if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
- pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
- return PCILIB_ERROR_OUTOFRANGE;
- }
+ pcilib_detect_address(ctx, &bar, &addr, fifo_size);
+ data = pcilib_map_bar(ctx, bar);
- err = pcilib_map_register_space(ctx);
- if (err) {
- pcilib_error("Failed to map the register space");
- return err;
- }
-
- //n += bits / b->access;
- //bits %= b->access;
-
for (i = 0; i < n; i++) {
- err = pcilib_protocol[b->protocol].write(ctx, b, addr + i, b->access, buf[i]);
- if (err) break;
- }
-
- if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].write(ctx, b, addr + n, bits, buf[n]);
-
- return err;
-}
-
-int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
- pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
- if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
- if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
- else pcilib_error("Register bank should be specified");
- return PCILIB_ERROR_INVALID_BANK;
- }
-
- return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, buf);
-}
-
-
-int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) {
- int err;
- size_t i, n, bits;
- pcilib_register_value_t res;
- pcilib_register_description_t *r;
- pcilib_register_bank_description_t *b;
- pcilib_model_t model = pcilib_get_model(ctx);
-
- r = pcilib_model[model].registers + reg;
- b = pcilib_model[model].banks + r->bank;
-
- n = r->bits / b->access;
- bits = r->bits % b->access;
-
- pcilib_register_value_t buf[n + 1];
- memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t));
-
- if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
- pcilib_error("Big-endian byte order support is not implemented");
- return PCILIB_ERROR_NOTSUPPORTED;
- } else {
- if (b->access == sizeof(pcilib_register_value_t) * 8) {
- buf[0] = value;
- } else {
- for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
- buf[i] = res & BIT_MASK(b->access);
- res >>= b->access;
- }
-
- if (res) {
- pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
- return PCILIB_ERROR_OUTOFRANGE;
- }
- }
- }
-
- err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
- return err;
-}
-
-int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) {
- int err;
- int reg;
-
- reg = pcilib_find_register(ctx, bank, regname);
- if (reg < 0) {
- pcilib_error("Register (%s) is not found", regname);
- return PCILIB_ERROR_NOTFOUND;
- }
-
- return pcilib_write_register_by_id(ctx, reg, value);
-}
-
-
-int pcilib_reset(pcilib_t *ctx) {
- pcilib_event_api_description_t *api;
-
- pcilib_model_t model = pcilib_get_model(ctx);
-
- api = pcilib_model[model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
-
- if (api->reset)
- return api->reset(ctx->event_ctx);
-
- return 0;
-}
-
-int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
- pcilib_event_api_description_t *api;
-
- pcilib_model_t model = pcilib_get_model(ctx);
-
- api = pcilib_model[model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
-
- if (api->start)
- return api->start(ctx->event_ctx, event_mask, callback, user);
-
- return 0;
-}
-
-int pcilib_stop(pcilib_t *ctx) {
- pcilib_event_api_description_t *api;
-
- pcilib_model_t model = pcilib_get_model(ctx);
-
- api = pcilib_model[model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
-
- if (api->stop)
- return api->stop(ctx->event_ctx);
-
- return 0;
-}
-
-pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout) {
- pcilib_event_api_description_t *api;
-
- pcilib_model_t model = pcilib_get_model(ctx);
-
- api = pcilib_model[model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
+ pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size);
}
-
- if (api->next_event)
- return api->next_event(ctx->event_ctx, event_mask, timeout);
-
- pcilib_error("Event enumeration is not suppored by API");
- return PCILIB_EVENT_ID_INVALID;
-}
-
-int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
- pcilib_event_api_description_t *api;
- pcilib_model_t model = pcilib_get_model(ctx);
-
- api = pcilib_model[model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
-
- if (api->trigger)
- return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
-
- pcilib_error("Self triggering is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
-}
-
-
-void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) {
- pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return NULL;
- }
-
- if (api->get_data)
- return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size);
-
- return NULL;
-}
-
-void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
- pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return NULL;
- }
-
- if (api->get_data)
- return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size);
-
- return NULL;
-}
-
-int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
- pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
- if (!api) {
- pcilib_error("Event API is not supported by the selected model");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
-
- if (api->return_data)
- return api->return_data(ctx->event_ctx, event_id);
-
- return 0;
+ pcilib_unmap_bar(ctx, bar, data);
}
-
-typedef struct {
- pcilib_t *ctx;
-
- size_t *size;
- void **data;
-} pcilib_grab_callback_user_data_t;
-
-static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
- int err;
+int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
+ int i;
void *data;
- size_t size;
- int allocated = 0;
- pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
+ pcilib_detect_address(ctx, &bar, &addr, fifo_size);
+ data = pcilib_map_bar(ctx, bar);
- data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
- if (!data) {
- pcilib_error("Error getting event data");
- return PCILIB_ERROR_FAILED;
+ for (i = 0; i < n; i++) {
+ pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size);
}
-
- if (*(user->data)) {
- if ((user->size)&&(*(user->size) < size)) {
- pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
- return PCILIB_ERROR_MEMORY;
- }
- *(user->size) = size;
- } else {
- *(user->data) = malloc(size);
- if (!*(user->data)) {
- pcilib_error("Memory allocation (%i bytes) for event data is failed");
- return PCILIB_ERROR_MEMORY;
- }
- if (*(user->size)) *(user->size) = size;
- allocated = 1;
- }
-
- memcpy(*(user->data), data, size);
-
- err = pcilib_return_data(user->ctx, event_id);
- if (err) {
- if (allocated) {
- free(*(user->data));
- *(user->data) = NULL;
- }
- pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
- return err;
- }
-
- return 0;
+ pcilib_unmap_bar(ctx, bar, data);
}
-int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
- int err;
-
- pcilib_grab_callback_user_data_t user = {ctx, size, data};
-
- err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
- if (!err) {
- if (timeout) nanosleep(timeout, NULL);
- else err = pcilib_trigger(ctx, event_mask, 0, NULL);
- }
- pcilib_stop(ctx);
- return 0;
-}
diff --git a/pci.h b/pci.h
index d01ce86..0427c8a 100644
--- a/pci.h
+++ b/pci.h
@@ -8,7 +8,10 @@
#include "pcilib_types.h"
#include "pcilib.h"
+#include "register.h"
#include "kmem.h"
+#include "dma.h"
+#include "event.h"
struct pcilib_s {
int handle;
diff --git a/pcilib.h b/pcilib.h
index 1e1ff36..8386f9b 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -22,8 +22,8 @@ typedef void pcilib_context_t;
typedef void pcilib_dma_context_t;
typedef struct pcilib_dma_api_description_s pcilib_dma_api_description_t;
-
-
+typedef struct pcilib_event_api_description_s pcilib_event_api_description_t;
+typedef struct pcilib_protocol_description_s pcilib_protocol_description_t;
typedef unsigned long pcilib_irq_source_t;
typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */
@@ -71,6 +71,10 @@ typedef enum {
PCILIB_DMA_FLAG_EOP = 1
} pcilib_dma_flags_t;
+typedef enum {
+ PCILIB_REGISTER_STANDARD = 0,
+ PCILIB_REGISTER_FIFO
+} pcilib_register_type_t;
#define PCILIB_BAR_DETECT ((pcilib_bar_t)-1)
#define PCILIB_BAR_INVALID ((pcilib_bar_t)-1)
@@ -142,11 +146,6 @@ typedef struct {
const char *description;
} pcilib_event_description_t;
-typedef struct {
- int (*read)(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value);
- int (*write)(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value);
-} pcilib_protocol_description_t;
-
typedef enum {
PCILIB_DMA_FROM_DEVICE = 1,
PCILIB_DMA_TO_DEVICE = 2,
@@ -173,21 +172,6 @@ typedef struct {
typedef int (*pcilib_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user);
typedef struct {
- pcilib_context_t *(*init)(pcilib_t *ctx);
- void (*free)(pcilib_context_t *ctx);
-
- int (*reset)(pcilib_context_t *ctx);
-
- int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user);
- int (*stop)(pcilib_context_t *ctx);
- int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
-
- pcilib_event_id_t (*next_event)(pcilib_context_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout);
- void* (*get_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size);
- int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id);
-} pcilib_event_api_description_t;
-
-typedef struct {
uint8_t access;
uint8_t endianess;
@@ -228,6 +212,9 @@ pcilib_dma_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direc
int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf);
int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf);
+int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf);
+int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf);
+
typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf);
diff --git a/register.c b/register.c
new file mode 100644
index 0000000..cb6bd88
--- /dev/null
+++ b/register.c
@@ -0,0 +1,280 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "pci.h"
+
+#include "tools.h"
+#include "error.h"
+
+pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
+ pcilib_register_bank_t i;
+ pcilib_model_t model = pcilib_get_model(ctx);
+ pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
+
+ for (i = 0; banks[i].access; i++)
+ if (banks[i].addr == bank) return i;
+
+ return -1;
+}
+
+pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankname) {
+ pcilib_register_bank_t i;
+ pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
+
+ for (i = 0; banks[i].access; i++)
+ if (!strcasecmp(banks[i].name, bankname)) return i;
+
+ return -1;
+}
+
+pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank) {
+ pcilib_register_bank_t res;
+ unsigned long addr;
+
+ if (!bank) {
+ pcilib_model_t model = pcilib_get_model(ctx);
+ pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
+ if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0;
+ return -1;
+ }
+
+ if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) {
+ res = pcilib_find_bank_by_addr(ctx, addr);
+ if (res != PCILIB_REGISTER_BANK_INVALID) return res;
+ }
+
+ return pcilib_find_bank_by_name(ctx, bank);
+}
+
+ // FIXME create hash during map_register space
+pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) {
+ pcilib_register_t i;
+ pcilib_register_bank_t bank_id;
+ pcilib_register_bank_addr_t bank_addr;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ pcilib_register_description_t *registers = pcilib_model[model].registers;
+
+ if (bank) {
+ bank_id = pcilib_find_bank(ctx, bank);
+ if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+ pcilib_error("Invalid bank (%s) is specified", bank);
+ return -1;
+ }
+
+ bank_addr = pcilib_model[model].banks[bank_id].addr;
+ }
+
+ for (i = 0; registers[i].bits; i++) {
+ if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i;
+ }
+
+ return (pcilib_register_t)-1;
+};
+
+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) {
+ int err;
+ int rest;
+ size_t i;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+ pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
+
+ assert(bits < 8 * sizeof(pcilib_register_value_t));
+
+ if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+ pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+ return PCILIB_ERROR_OUTOFRANGE;
+ }
+
+ err = pcilib_map_register_space(ctx);
+ if (err) {
+ pcilib_error("Failed to map the register space");
+ return err;
+ }
+
+ //n += bits / b->access;
+ //bits %= b->access;
+
+ for (i = 0; i < n; i++) {
+ err = pcilib_protocol[b->protocol].read(ctx, b, addr + i, b->access, buf + i);
+ if (err) break;
+ }
+
+ if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].read(ctx, b, addr + n, bits, buf + n);
+
+ return err;
+}
+
+int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
+ pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
+ if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+ if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
+ else pcilib_error("Register bank should be specified");
+ return PCILIB_ERROR_INVALID_BANK;
+ }
+
+ return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+}
+
+int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) {
+ int err;
+ size_t i, n, bits;
+ pcilib_register_value_t res;
+ pcilib_register_description_t *r;
+ pcilib_register_bank_description_t *b;
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ r = pcilib_model[model].registers + reg;
+ b = pcilib_model[model].banks + r->bank;
+
+ n = r->bits / b->access;
+ bits = r->bits % b->access;
+
+ pcilib_register_value_t buf[n + 1];
+ err = pcilib_read_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
+
+ if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
+ pcilib_error("Big-endian byte order support is not implemented");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ } else {
+ res = 0;
+ if (bits) ++n;
+ for (i = 0; i < n; i++) {
+ res |= buf[i] << (i * b->access);
+ }
+ }
+
+ *value = res;
+
+ return err;
+}
+
+
+int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) {
+ int err;
+ int reg;
+
+ reg = pcilib_find_register(ctx, bank, regname);
+ if (reg < 0) {
+ pcilib_error("Register (%s) is not found", regname);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ return pcilib_read_register_by_id(ctx, reg, value);
+
+// registers[reg].bank
+// printf("%li %li", sizeof(pcilib_model[model].banks), sizeof(pcilib_register_bank_description_t));
+}
+
+
+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) {
+ int err;
+ int rest;
+ size_t i;
+
+ pcilib_model_t model = pcilib_get_model(ctx);
+ pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
+
+ assert(bits < 8 * sizeof(pcilib_register_value_t));
+
+ if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+ pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+ return PCILIB_ERROR_OUTOFRANGE;
+ }
+
+ err = pcilib_map_register_space(ctx);
+ if (err) {
+ pcilib_error("Failed to map the register space");
+ return err;
+ }
+
+ //n += bits / b->access;
+ //bits %= b->access;
+
+ for (i = 0; i < n; i++) {
+ err = pcilib_protocol[b->protocol].write(ctx, b, addr + i, b->access, buf[i]);
+ if (err) break;
+ }
+
+ if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].write(ctx, b, addr + n, bits, buf[n]);
+
+ return err;
+}
+
+int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
+ pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
+ if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+ if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
+ else pcilib_error("Register bank should be specified");
+ return PCILIB_ERROR_INVALID_BANK;
+ }
+
+ return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+}
+
+
+int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) {
+ int err;
+ size_t i, n, bits;
+ pcilib_register_value_t res;
+ pcilib_register_description_t *r;
+ pcilib_register_bank_description_t *b;
+ pcilib_model_t model = pcilib_get_model(ctx);
+
+ r = pcilib_model[model].registers + reg;
+ b = pcilib_model[model].banks + r->bank;
+
+ n = r->bits / b->access;
+ bits = r->bits % b->access;
+
+ pcilib_register_value_t buf[n + 1];
+ memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t));
+
+ if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
+ pcilib_error("Big-endian byte order support is not implemented");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ } else {
+ if (b->access == sizeof(pcilib_register_value_t) * 8) {
+ buf[0] = value;
+ } else {
+ for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
+ buf[i] = res & BIT_MASK(b->access);
+ res >>= b->access;
+ }
+
+ if (res) {
+ pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
+ return PCILIB_ERROR_OUTOFRANGE;
+ }
+ }
+ }
+
+ err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
+ return err;
+}
+
+int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) {
+ int err;
+ int reg;
+
+ reg = pcilib_find_register(ctx, bank, regname);
+ if (reg < 0) {
+ pcilib_error("Register (%s) is not found", regname);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ return pcilib_write_register_by_id(ctx, reg, value);
+}
diff --git a/register.h b/register.h
new file mode 100644
index 0000000..1a8daef
--- /dev/null
+++ b/register.h
@@ -0,0 +1,11 @@
+#ifndef _PCILIB_REGISTER_H
+#define _PCILIB_REGISTER_H
+
+#include "pcilib.h"
+
+struct pcilib_protocol_description_s {
+ int (*read)(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value);
+ int (*write)(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value);
+};
+
+#endif /* _PCILIB_REGISTER_H */
diff --git a/tools.h b/tools.h
index 3454fc4..3bd1b20 100644
--- a/tools.h
+++ b/tools.h
@@ -6,6 +6,8 @@
#include "pci.h"
+#define BIT_MASK(bits) ((1ll << (bits)) - 1)
+
#define min2(a, b) (((a)<(b))?(a):(b))
int pcilib_isnumber(const char *str);