From d98d86bd6b0d861462698e5bcfc8f712f8e350c7 Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Wed, 6 Jul 2011 02:10:24 +0200 Subject: Support FIFO reading/writting, code restructurization, few fixes --- Makefile | 2 +- cli.c | 233 +++++++++++++++++++------- default.c | 2 - event.c | 230 ++++++++++++++++++++++++++ event.h | 22 +++ pci.c | 540 ++++++------------------------------------------------------- pci.h | 3 + pcilib.h | 31 ++-- register.c | 280 ++++++++++++++++++++++++++++++++ register.h | 11 ++ tools.h | 2 + 11 files changed, 785 insertions(+), 571 deletions(-) create mode 100644 event.c create mode 100644 event.h create mode 100644 register.c create mode 100644 register.h 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 -#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 - Memory model (autodetected)\n" " pci - Plain\n" " ipecamera - IPE Camera\n" -" -b - Data/Register bank (autodetected)\n" +" -t - Access type (default: plain)\n" +" -b - PCI bar, Register bank, or DMA channel\n" "\n" " Options:\n" " -s - 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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<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 #include +#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<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, @@ -172,21 +171,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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); -- cgit v1.2.3