From 39b33ce4be920b19a6b0f694febf8609ae64512b Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Tue, 12 Apr 2011 02:57:02 +0200 Subject: Infrastructure for event API --- Makefile | 3 +- cli.c | 92 ++++++++++++++-- common.mk | 3 + driver/base.c | 1 + error.h | 1 + ipecamera.c | 139 ------------------------ ipecamera.h | 86 --------------- ipecamera/image.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++ ipecamera/image.h | 22 ++++ ipecamera/ipecamera.h | 6 ++ ipecamera/model.c | 147 ++++++++++++++++++++++++++ ipecamera/model.h | 110 +++++++++++++++++++ pci.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++-- pci.h | 8 +- pcilib.h | 59 ++++++++++- 15 files changed, 1000 insertions(+), 251 deletions(-) delete mode 100644 ipecamera.c delete mode 100644 ipecamera.h create mode 100644 ipecamera/image.c create mode 100644 ipecamera/image.h create mode 100644 ipecamera/ipecamera.h create mode 100644 ipecamera/model.c create mode 100644 ipecamera/model.h diff --git a/Makefile b/Makefile index a1e3968..5183431 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ include common.mk ############################################################### # Target definitions -OBJECTS = pci.o ipecamera.o default.o tools.o +OBJECTS = pci.o default.o tools.o ipecamera/model.o ipecamera/image.o libpcilib.so: $(OBJECTS) echo -e "LD \t$@" @@ -26,6 +26,7 @@ pci: cli.o libpcilib.so install: pci install -m 644 pcilib.h $(DESTDIR)/include + install -m 644 ipecamera/ipecamera.h $(DESTDIR)/include if [ -d $(DESTDIR)/lib64 ]; then install -m 755 libpcilib.so $(DESTDIR)/lib64; else install -m 755 libpcilib.so $(DESTDIR)/lib; fi install -m 755 pci $(DESTDIR)/bin ldconfig diff --git a/cli.c b/cli.c index 4fe56c9..9a54618 100644 --- a/cli.c +++ b/cli.c @@ -18,7 +18,6 @@ #include #include "pci.h" -#include "ipecamera.h" #include "tools.h" #include "kernel.h" @@ -50,7 +49,9 @@ typedef enum { MODE_READ, MODE_READ_REGISTER, MODE_WRITE, - MODE_WRITE_REGISTER + MODE_WRITE_REGISTER, + MODE_RESET, + MODE_GRAB } MODE; typedef enum { @@ -60,11 +61,14 @@ typedef enum { OPT_ACCESS = 'a', OPT_ENDIANESS = 'e', OPT_SIZE = 's', + OPT_OUTPUT = 'o', OPT_INFO = 'i', OPT_BENCHMARK = 'p', OPT_LIST = 'l', OPT_READ = 'r', OPT_WRITE = 'w', + OPT_GRAB = 'g', + OPT_RESET = 128, OPT_HELP = 'h', } OPTIONS; @@ -75,11 +79,14 @@ static struct option long_options[] = { {"access", required_argument, 0, OPT_ACCESS }, {"endianess", required_argument, 0, OPT_ENDIANESS }, {"size", required_argument, 0, OPT_SIZE }, + {"size", required_argument, 0, OPT_OUTPUT }, {"info", no_argument, 0, OPT_INFO }, {"list", no_argument, 0, OPT_LIST }, + {"reset", no_argument, 0, OPT_RESET }, {"benchmark", no_argument, 0, OPT_BENCHMARK }, {"read", optional_argument, 0, OPT_READ }, {"write", optional_argument, 0, OPT_WRITE }, + {"grab", optional_argument, 0, OPT_GRAB }, {"help", no_argument, 0, OPT_HELP }, { 0, 0, 0, 0 } }; @@ -108,6 +115,8 @@ void Usage(int argc, char *argv[], const char *format, ...) { " -p - Performance Evaluation\n" " -r - Read Data/Register\n" " -w - Write Data/Register\n" +" -g - Grab Event\n" +" --reset - Reset board\n" " --help - Help message\n" "\n" " Addressing:\n" @@ -121,6 +130,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " -s - Number of words (default: 1)\n" " -a - Bits per word (default: 32)\n" " -e - Endianess Little/Big (default: host)\n" +" -o - Output to file (default: stdout)\n" "\n" " Data:\n" " Data can be specified as sequence of hexdecimal number or\n" @@ -557,6 +567,38 @@ int WriteRegister(pcilib_t *handle, pcilib_model_t model, const char *bank, cons return 0; } +int Grab(pcilib_t *handle, const char *output) { + int err; + + void *data = NULL; + size_t size, written; + + FILE *o; + + err = pcilib_grab(handle, PCILIB_ALL_EVENTS, &size, &data, NULL); + if (err) { + Error("Grabbing event is failed"); + } + + if (output) { + o = fopen(output, "w"); + if (!o) { + Error("Failed to open file \"%s\"", output); + } + + printf("Writting %i bytes into %s...\n", size, output); + } else o = stdout; + + written = fwrite(data, 1, size, o); + if (written != size) { + if (written > 0) Error("Write failed, only %z bytes out of %z are stored", written, size); + else Error("Write failed"); + } + + if (o != stdout) fclose(o); + + return 0; +} int main(int argc, char **argv) { int i; @@ -571,16 +613,18 @@ int main(int argc, char **argv) { const char *reg = NULL; const char *bank = NULL; char **data = NULL; + const char *event = NULL; uintptr_t start = -1; size_t size = 1; access_t access = 4; int skip = 0; int endianess = 0; + const char *output = NULL; pcilib_t *handle; - while ((c = getopt_long(argc, argv, "hilpr::w::d:m:b:a:s:e:", long_options, NULL)) != (unsigned char)-1) { + while ((c = getopt_long(argc, argv, "hilpr::w::d:m:b:a:s:e:g:", long_options, NULL)) != (unsigned char)-1) { extern int optind; switch (c) { case OPT_HELP: @@ -596,6 +640,11 @@ int main(int argc, char **argv) { mode = MODE_LIST; break; + case OPT_RESET: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_RESET; + break; case OPT_BENCHMARK: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -615,6 +664,13 @@ int main(int argc, char **argv) { if (optarg) addr = optarg; else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; break; + case OPT_GRAB: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_GRAB; + if (optarg) event = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) event = argv[optind++]; + break; case OPT_DEVICE: fpga_device = optarg; break; @@ -652,6 +708,9 @@ int main(int argc, char **argv) { } else Usage(argc, argv, "Invalid endianess is specified (%s)", optarg); break; + case OPT_OUTPUT: + output = optarg; + break; default: Usage(argc, argv, "Unknown option (%s)", argv[optind]); } @@ -674,11 +733,22 @@ int main(int argc, char **argv) { if (!addr) Usage(argc, argv, "The address is not specified"); if (((argc - optind) == 1)&&(*argv[optind] == '*')) { int vallen = strlen(argv[optind]); - data = (char**)malloc(size * (vallen + sizeof(char*))); - if (!data) Error("Error allocating memory for data array"); - for (i = 0; i < size; i++) { - data[i] = ((char*)data) + size * sizeof(char*) + i * vallen; - strcpy(data[i], argv[optind] + 1); + if (vallen > 1) { + data = (char**)malloc(size * (vallen + sizeof(char*))); + if (!data) Error("Error allocating memory for data array"); + + for (i = 0; i < size; i++) { + data[i] = ((char*)data) + size * sizeof(char*) + i * vallen; + strcpy(data[i], argv[optind] + 1); + } + } else { + data = (char**)malloc(size * (9 + sizeof(char*))); + if (!data) Error("Error allocating memory for data array"); + + for (i = 0; i < size; i++) { + data[i] = ((char*)data) + size * sizeof(char*) + i * 9; + sprintf(data[i], "%x", i); + } } } else if ((argc - optind) == size) data = argv + optind; else Usage(argc, argv, "The %i data values is specified, but %i required", argc - optind, size); @@ -757,6 +827,12 @@ int main(int argc, char **argv) { if (reg) WriteRegister(handle, model, bank, reg, data); else WriteRegisterRange(handle, model, bank, start, size, data); break; + case MODE_RESET: + pcilib_reset(handle); + break; + case MODE_GRAB: + Grab(handle, output); + break; } pcilib_close(handle); diff --git a/common.mk b/common.mk index f8dae8b..e203330 100644 --- a/common.mk +++ b/common.mk @@ -19,6 +19,9 @@ CFLAGS += $(addprefix -I ,$(INCDIR)) -fPIC -std=c99 SRC = $(wildcard *.cpp) SRCC = $(wildcard *.c) +SRC += $(wildcard ipecamera/*.cpp) +SRCC += $(wildcard ipecamera/*.c) + # Corresponding object files OBJ = $(addprefix $(OBJDIR)/,$(SRC:.cpp=.o)) OBJ += $(addprefix $(OBJDIR)/,$(SRCC:.c=.o)) diff --git a/driver/base.c b/driver/base.c index c740856..b999cac 100644 --- a/driver/base.c +++ b/driver/base.c @@ -626,6 +626,7 @@ int pcidriver_mmap_pci(pcidriver_privdata_t *privdata, struct vm_area_struct *vm /* Check sizes */ vma_size = (vmap->vm_end - vmap->vm_start); + if ((vma_size != bar_length) && ((bar_length < PAGE_SIZE) && (vma_size != PAGE_SIZE))) { mod_info( "mmap size is not correct! bar: %lu - vma: %lu\n", bar_length, vma_size ); diff --git a/error.h b/error.h index d64c518..198df3e 100644 --- a/error.h +++ b/error.h @@ -12,6 +12,7 @@ enum { PCILIB_ERROR_NOTSUPPORTED, PCILIB_ERROR_NOTFOUND, PCILIB_ERROR_OUTOFRANGE, + PCILIB_ERROR_NOTINITIALIZED } pcilib_errot_t; diff --git a/ipecamera.c b/ipecamera.c deleted file mode 100644 index 9c238f5..0000000 --- a/ipecamera.c +++ /dev/null @@ -1,139 +0,0 @@ -#define _IPECAMERA_C -#include -#include - -#include "tools.h" -#include "ipecamera.h" -#include "error.h" - -#define ADDR_MASK 0x7F00 -#define WRITE_BIT 0x8000 -#define RETRIES 10 - -#define READ_READY_BIT 0x20000 -#define READ_ERROR_BIT 0x40000 - -#define ipecamera_datacpy(dst, src, bank) pcilib_datacpy(dst, src, 4, 1, bank->raw_endianess) - -static pcilib_register_value_t ipecamera_bit_mask[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; - -int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value) { - uint32_t val; - char *wr, *rd; - struct timeval start, cur; - int retries = RETRIES; - - assert(addr < 128); - - wr = pcilib_resolve_register_address(ctx, bank->write_addr); - rd = pcilib_resolve_register_address(ctx, bank->read_addr); - if ((!rd)||(!wr)) { - pcilib_error("Error resolving addresses of read & write registers"); - return PCILIB_ERROR_INVALID_ADDRESS; - } - -retry: - val = (addr << 8); - - //printf("%i %x %p %p\n", addr, val, wr, rd); - - ipecamera_datacpy(wr, &val, bank); - - gettimeofday(&start, NULL); - - ipecamera_datacpy(&val, rd, bank); - while ((val & READ_READY_BIT) == 0) { - gettimeofday(&cur, NULL); - if (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > PCILIB_REGISTER_TIMEOUT) break; - - ipecamera_datacpy(&val, rd, bank); - } - - if ((val & READ_READY_BIT) == 0) { - pcilib_error("Timeout reading register value"); - return PCILIB_ERROR_TIMEOUT; - } - - if (val & READ_ERROR_BIT) { - pcilib_error("Error reading register value"); - return PCILIB_ERROR_FAILED; - } - - if (((val&ADDR_MASK) >> 8) != addr) { - if (--retries > 0) { - pcilib_warning("Address verification failed during register read, retrying (try %i of %i)...", RETRIES - retries, RETRIES); - goto retry; - } - pcilib_error("Address verification failed during register read"); - return PCILIB_ERROR_VERIFY; - } - - -// printf("%i\n", val&ipecamera_bit_mask[bits]); - - *value = val&ipecamera_bit_mask[bits]; - - return 0; -} - -int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value) { - uint32_t val; - char *wr, *rd; - struct timeval start, cur; - int retries = RETRIES; - - assert(addr < 128); - assert(value < 256); - - wr = pcilib_resolve_register_address(ctx, bank->write_addr); - rd = pcilib_resolve_register_address(ctx, bank->read_addr); - if ((!rd)||(!wr)) { - pcilib_error("Error resolving addresses of read & write registers"); - return PCILIB_ERROR_INVALID_ADDRESS; - } - -retry: - val = WRITE_BIT|(addr << 8)|(value&0xFF); - - //printf("%i %x %p %p\n", addr, val, wr, rd); - - ipecamera_datacpy(wr, &val, bank); - - gettimeofday(&start, NULL); - - ipecamera_datacpy(&val, rd, bank); - while ((val & READ_READY_BIT) == 0) { - gettimeofday(&cur, NULL); - if (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > PCILIB_REGISTER_TIMEOUT) break; - - ipecamera_datacpy(&val, rd, bank); - } - - if ((val & READ_READY_BIT) == 0) { - pcilib_error("Timeout writting register value"); - return PCILIB_ERROR_TIMEOUT; - } - - if (val & READ_ERROR_BIT) { - pcilib_error("Error writting register value"); - return PCILIB_ERROR_FAILED; - } - - if (((val&ADDR_MASK) >> 8) != addr) { - if (--retries > 0) { - pcilib_warning("Address verification failed during register read, retrying (try %i of %i)...", RETRIES - retries, RETRIES); - goto retry; - } - pcilib_error("Address verification failed during register write"); - return PCILIB_ERROR_VERIFY; - } - - if ((val&ipecamera_bit_mask[bits]) != value) { - pcilib_error("Value verification failed during register read (%lu != %lu)", val&ipecamera_bit_mask[bits], value); - return PCILIB_ERROR_VERIFY; - } - - //printf("%i\n", val&ipecamera_bit_mask[bits]); - - return 0; -} diff --git a/ipecamera.h b/ipecamera.h deleted file mode 100644 index 9061dea..0000000 --- a/ipecamera.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef _IPECAMERA_H -#define _IPECAMERA_H - -#include - -#include "pcilib.h" - -#define IPECAMERA_REGISTER_SPACE 0xfeaffc00 -#define IPECAMERA_REGISTER_WRITE (IPECAMERA_REGISTER_SPACE + 0) -#define IPECAMERA_REGISTER_READ (IPECAMERA_REGISTER_WRITE + 4) - -#ifdef _IPECAMERA_C -pcilib_register_bank_description_t ipecamera_register_banks[] = { - { PCILIB_REGISTER_BANK0, 128, IPECAMERA_REGISTER_PROTOCOL, IPECAMERA_REGISTER_READ, IPECAMERA_REGISTER_WRITE, PCILIB_BIG_ENDIAN, 8, PCILIB_LITTLE_ENDIAN, "cmosis", "CMOSIS CMV2000 Registers" }, - { PCILIB_REGISTER_BANK1, 64, PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_SPACE, IPECAMERA_REGISTER_SPACE, PCILIB_BIG_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "fpga", "IPECamera Registers" }, - { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } -}; - -pcilib_register_description_t ipecamera_registers[] = { -{1, 16, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines", ""}, -{3, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start1", ""}, -{5, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start2", ""}, -{7, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start3", ""}, -{9, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start4", ""}, -{11, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start5", ""}, -{13, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start6", ""}, -{15, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start7", ""}, -{17, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start8", ""}, -{19, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines1", ""}, -{21, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines2", ""}, -{23, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines3", ""}, -{25, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines4", ""}, -{27, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines5", ""}, -{29, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines6", ""}, -{31, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines7", ""}, -{33, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines8", ""}, -{35, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_s", ""}, -{37, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_a", ""}, -{39, 1, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "color", ""}, -{40, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "image_flipping", ""}, -{41, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_flags", ""}, -{42, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time", ""}, -{45, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step", ""}, -{48, 24, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp1", ""}, -{51, 24, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp2", ""}, -{54, 2, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes", ""}, -{55, 8, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq", ""}, -{56, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time2", ""}, -{59, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step2", ""}, -{68, 2, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes2", ""}, -{69, 8, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq2", ""}, -{70, 16, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_frames", ""}, -{72, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "output_mode", ""}, -{78, 12, 85, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "training_pattern", ""}, -{80, 18, 0x3FFFF,PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "channel_en", ""}, -{89, 8, 96, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow2", ""}, -{90, 8, 96, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow3", ""}, -{100, 14, 16260, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "offset", ""}, -{102, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "pga", ""}, -{103, 8, 32, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_gain", ""}, -{111, 1, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "bit_mode", ""}, -{112, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_resolution", ""}, -{126, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "temp", ""}, -{0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_conf_input", ""}, -{1, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "spi_conf_output", ""}, -{2, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_clk_speed", ""}, -{3, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "firmware_version", ""}, -{6, 16, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "cmosis_temperature", ""}, -{7, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "temperature_sample_timing", ""}, -{0, 0, 0, 0, 0, NULL, NULL} -}; - -pcilib_register_range_t ipecamera_register_ranges[] = { - {0, 128, PCILIB_REGISTER_BANK0}, {0, 0, 0} -}; - -#else -extern pcilib_register_description_t ipecamera_registers[]; -extern pcilib_register_bank_description_t ipecamera_register_banks[]; -extern pcilib_register_range_t ipecamera_register_ranges[]; -#endif - -int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value); -int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value); - -#endif /* _IPECAMERA_H */ diff --git a/ipecamera/image.c b/ipecamera/image.c new file mode 100644 index 0000000..e7661b2 --- /dev/null +++ b/ipecamera/image.c @@ -0,0 +1,287 @@ +#define _IPECAMERA_IMAGE_C +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "../tools.h" +#include "../error.h" + +#include "pcilib.h" + +#include "model.h" +#include "image.h" + +#define IPECAMERA_SLEEP_TIME 250000 + +struct ipecamera_s { + pcilib_t *pcilib; + + char *data; + size_t size; + + pcilib_callback_t cb; + void *cb_user; + + int width; + int height; + + pcilib_event_id_t event_id; + + pcilib_register_t control_reg, status_reg; + pcilib_register_t start_reg, end_reg; + pcilib_register_t lines_reg; + pcilib_register_t exposure_reg; + + void *buffer; +}; + + +#define FIND_REG(var, bank, name) \ + ctx->var = pcilib_find_register(pcilib, bank, name); \ + if (ctx->var == PCILIB_REGISTER_INVALID) { \ + err = -1; \ + pcilib_error("Unable to find a %s register", name); \ + } + + +#define GET_REG(reg, var) \ + err = pcilib_read_register_by_id(pcilib, ctx->reg, &var); \ + if (err) { \ + pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ + return err; \ + } + +#define SET_REG(reg, val) \ + err = pcilib_write_register_by_id(pcilib, ctx->reg, val); \ + if (err) { \ + pcilib_error("Error writting %s register", ipecamera_registers[ctx->reg].name); \ + return err; \ + } + +#define CHECK_REG(reg, check) \ + err = pcilib_read_register_by_id(pcilib, ctx->reg, &value); \ + if (err) { \ + pcilib_error("Error reading %s register", ipecamera_registers[ctx->reg].name); \ + return err; \ + } \ + if (!(check)) { \ + pcilib_error("Unexpected value (%li) of register %s", value, ipecamera_registers[ctx->reg].name); \ + return err; \ + } + + +void *ipecamera_init(pcilib_t *pcilib) { + int err = 0; + + ipecamera_t *ctx = malloc(sizeof(ipecamera_t)); + + if (ctx) { + ctx->pcilib = pcilib; + + ctx->data = pcilib_resolve_data_space(pcilib, 0, &ctx->size); + if (!ctx->data) { + err = -1; + pcilib_error("Unable to resolve the data space"); + } + + ctx->buffer = malloc(1088 * 2048 * 2); + if (!ctx->buffer) { + err = -1; + pcilib_error("Unable to allocate ring buffer"); + } + + FIND_REG(status_reg, "fpga", "status"); + FIND_REG(control_reg, "fpga", "control"); + FIND_REG(start_reg, "fpga", "start_address"); + FIND_REG(end_reg, "fpga", "end_address"); + + FIND_REG(lines_reg, "cmosis", "number_lines"); + FIND_REG(exposure_reg, "cmosis", "exp_time"); + + if (err) { + free(ctx); + return NULL; + } + } + + return (void*)ctx; +} + +void ipecamera_free(void *vctx) { + if (vctx) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (ctx->buffer) free(ctx->buffer); + free(ctx); + } +} + +int ipecamera_reset(void *vctx) { + int err; + pcilib_t *pcilib; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + pcilib_register_t control, status; + pcilib_register_value_t value; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + pcilib = ctx->pcilib; + control = ctx->control_reg; + status = ctx->status_reg; + + // Set Reset bit to CMOSIS + err = pcilib_write_register_by_id(pcilib, control, 5); + if (err) { + pcilib_error("Error setting CMOSIS reset bit"); + return err; + } + usleep(IPECAMERA_SLEEP_TIME); + + // Remove Reset bit to CMOSIS + err = pcilib_write_register_by_id(pcilib, control, 1); + if (err) { + pcilib_error("Error reseting CMOSIS reset bit"); + return err; + } + usleep(IPECAMERA_SLEEP_TIME); + + // Special settings for CMOSIS v.2 + value = 01; err = pcilib_write_register_space(pcilib, "cmosis", 115, 1, &value); + if (err) { + pcilib_error("Error setting CMOSIS configuration"); + return err; + } + usleep(IPECAMERA_SLEEP_TIME); + + value = 07; err = pcilib_write_register_space(pcilib, "cmosis", 82, 1, &value); + if (err) { + pcilib_error("Error setting CMOSIS configuration"); + return err; + } + usleep(IPECAMERA_SLEEP_TIME); + + // This is temporary for verification purposes + memset(ctx->data, 0, ctx->size); + + err = pcilib_read_register_by_id(pcilib, status, &value); + if (err) { + pcilib_error("Error reading status register"); + return err; + } + + if (value != 0x0849FFFF) { + pcilib_error("Unexpected value (%lx) of status register", value); + return PCILIB_ERROR_VERIFY; + } + + return 0; +} + +int ipecamera_start(void *vctx, pcilib_event_t event_mask, pcilib_callback_t cb, void *user) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + ctx->cb = cb; + ctx->cb_user = user; + + + ctx->event_id = 0; + + ctx->width = 1270; + ctx->height = 1088; //GET_REG(lines_reg, lines); + + // allocate memory + + return 0; +} + + +int ipecamera_stop(void *vctx) { + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + return 0; +} + + +static int ipecamera_get_line(ipecamera_t *ctx, int line) { + int err; + pcilib_t *pcilib = ctx->pcilib; + pcilib_register_value_t ptr, size, value; + + ipecamera_reset((void*)ctx); + + SET_REG(lines_reg, 1); + + SET_REG(control_reg, 149); + usleep(IPECAMERA_SLEEP_TIME); + CHECK_REG(status_reg, 0x0849FFFF); + + GET_REG(start_reg, ptr); + GET_REG(end_reg, size); + size -= ptr; + + printf("%i: %i %i\n", line, ptr, size); + + SET_REG(control_reg, 141); + usleep(IPECAMERA_SLEEP_TIME); + CHECK_REG(status_reg, 0x0849FFFF); +} + + +static int ipecamera_get_image(ipecamera_t *ctx) { + int err; + int i; + pcilib_t *pcilib = ctx->pcilib; + + for (i = 0; i < 1088; i++) { + ipecamera_get_line(ctx, i); + } + + ctx->event_id++; +} + + +int ipecamera_trigger(void *vctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { + int err; + pcilib_t *pcilib; + ipecamera_t *ctx = (ipecamera_t*)vctx; + + if (!ctx) { + pcilib_error("IPECamera imaging is not initialized"); + return PCILIB_ERROR_NOTINITIALIZED; + + } + + err = ipecamera_get_image(ctx); + if (!err) err = ctx->cb(event, ctx->event_id, ctx->cb_user); + + return err; +} + + +void* ipecamera_get(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) { + if (size) *size = ctx->width * ctx->height * 2; + return ctx->buffer; +} + +int ipecamera_return(void *ctx, pcilib_event_id_t event_id) { + return 0; +} diff --git a/ipecamera/image.h b/ipecamera/image.h new file mode 100644 index 0000000..d174b95 --- /dev/null +++ b/ipecamera/image.h @@ -0,0 +1,22 @@ +#ifndef _IPECAMERA_IMAGE_H +#define _IPECAMERA_IMAGE_H + +#include + +#include "pcilib.h" + +typedef struct ipecamera_s ipecamera_t; + +void *ipecamera_init(pcilib_t *pcilib); +void ipecamera_free(void *ctx); + +int ipecamera_reset(void *ctx); +int ipecamera_start(void *ctx, pcilib_event_t event_mask, pcilib_callback_t cb, void *user); +int ipecamera_stop(void *ctx); +int ipecamera_trigger(void *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); + +void* ipecamera_get(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size); +int ipecamera_return(void *ctx, pcilib_event_id_t event_id); + + +#endif /* _IPECAMERA_IMAGE_H */ diff --git a/ipecamera/ipecamera.h b/ipecamera/ipecamera.h new file mode 100644 index 0000000..8b27516 --- /dev/null +++ b/ipecamera/ipecamera.h @@ -0,0 +1,6 @@ +#ifndef _IPECAMERA_H +#define _IPECAMERA_H + + + +#endif /* _IPECAMERA_H */ diff --git a/ipecamera/model.c b/ipecamera/model.c new file mode 100644 index 0000000..4e475b1 --- /dev/null +++ b/ipecamera/model.c @@ -0,0 +1,147 @@ +#define _IPECAMERA_MODEL_C +#include +#include + +#include "../tools.h" +#include "../error.h" +#include "model.h" + +#define ADDR_MASK 0x7F00 +#define WRITE_BIT 0x8000 +#define RETRIES 10 + +#define READ_READY_BIT 0x20000 +#define READ_ERROR_BIT 0x40000 + +#define ipecamera_datacpy(dst, src, bank) pcilib_datacpy(dst, src, 4, 1, bank->raw_endianess) + +static pcilib_register_value_t ipecamera_bit_mask[9] = { 0, 1, 3, 7, 15, 31, 63, 127, 255 }; + +int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value) { + uint32_t val; + char *wr, *rd; + struct timeval start, cur; + int retries = RETRIES; + + assert(addr < 128); + + wr = pcilib_resolve_register_address(ctx, bank->write_addr); + rd = pcilib_resolve_register_address(ctx, bank->read_addr); + if ((!rd)||(!wr)) { + pcilib_error("Error resolving addresses of read & write registers"); + return PCILIB_ERROR_INVALID_ADDRESS; + } + +retry: + val = (addr << 8); + + //printf("%i %x %p %p\n", addr, val, wr, rd); + + ipecamera_datacpy(wr, &val, bank); + + gettimeofday(&start, NULL); + + ipecamera_datacpy(&val, rd, bank); + while ((val & READ_READY_BIT) == 0) { + gettimeofday(&cur, NULL); + if (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > PCILIB_REGISTER_TIMEOUT) break; + + ipecamera_datacpy(&val, rd, bank); + } + + if ((val & READ_READY_BIT) == 0) { + pcilib_error("Timeout reading register value"); + return PCILIB_ERROR_TIMEOUT; + } + + if (val & READ_ERROR_BIT) { + pcilib_error("Error reading register value"); + return PCILIB_ERROR_FAILED; + } + + if (((val&ADDR_MASK) >> 8) != addr) { + if (--retries > 0) { + pcilib_warning("Address verification failed during register read, retrying (try %i of %i)...", RETRIES - retries, RETRIES); + goto retry; + } + pcilib_error("Address verification failed during register read"); + return PCILIB_ERROR_VERIFY; + } + + +// printf("%i\n", val&ipecamera_bit_mask[bits]); + + *value = val&ipecamera_bit_mask[bits]; + + return 0; +} + +int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value) { + uint32_t val; + char *wr, *rd; + struct timeval start, cur; + int retries = RETRIES; + + assert(addr < 128); + assert(value < 256); + + wr = pcilib_resolve_register_address(ctx, bank->write_addr); + rd = pcilib_resolve_register_address(ctx, bank->read_addr); + if ((!rd)||(!wr)) { + pcilib_error("Error resolving addresses of read & write registers"); + return PCILIB_ERROR_INVALID_ADDRESS; + } + +retry: + val = WRITE_BIT|(addr << 8)|(value&0xFF); + + //printf("%i %x %p %p\n", addr, val, wr, rd); + + ipecamera_datacpy(wr, &val, bank); + + gettimeofday(&start, NULL); + + ipecamera_datacpy(&val, rd, bank); + while ((val & READ_READY_BIT) == 0) { + gettimeofday(&cur, NULL); + if (((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) > PCILIB_REGISTER_TIMEOUT) break; + + ipecamera_datacpy(&val, rd, bank); + } + + if ((val & READ_READY_BIT) == 0) { + if (--retries > 0) { + pcilib_warning("Timeout occured during register write, retrying (try %i of %i)...", RETRIES - retries, RETRIES); + goto retry; + } + + pcilib_error("Timeout writting register value"); + return PCILIB_ERROR_TIMEOUT; + } + + if (val & READ_ERROR_BIT) { + pcilib_error("Error writting register value"); + return PCILIB_ERROR_FAILED; + } + + if (((val&ADDR_MASK) >> 8) != addr) { + if (--retries > 0) { + pcilib_warning("Address verification failed during register write, retrying (try %i of %i)...", RETRIES - retries, RETRIES); + goto retry; + } + pcilib_error("Address verification failed during register write"); + return PCILIB_ERROR_VERIFY; + } + + if ((val&ipecamera_bit_mask[bits]) != value) { + pcilib_error("Value verification failed during register read (%lu != %lu)", val&ipecamera_bit_mask[bits], value); + return PCILIB_ERROR_VERIFY; + } + + //printf("%i\n", val&ipecamera_bit_mask[bits]); + + return 0; +} + + + diff --git a/ipecamera/model.h b/ipecamera/model.h new file mode 100644 index 0000000..f3f46dd --- /dev/null +++ b/ipecamera/model.h @@ -0,0 +1,110 @@ +#ifndef _IPECAMERA_MODEL_H +#define _IPECAMERA_MODEL_H + +#include + +#include "pcilib.h" +#include "image.h" + +#define IPECAMERA_REGISTER_SPACE 0xfeaffc00 +#define IPECAMERA_REGISTER_WRITE (IPECAMERA_REGISTER_SPACE + 0) +#define IPECAMERA_REGISTER_READ (IPECAMERA_REGISTER_WRITE + 4) + +#ifdef _IPECAMERA_MODEL_C +pcilib_register_bank_description_t ipecamera_register_banks[] = { + { PCILIB_REGISTER_BANK0, 128, IPECAMERA_REGISTER_PROTOCOL, IPECAMERA_REGISTER_READ, IPECAMERA_REGISTER_WRITE, PCILIB_BIG_ENDIAN, 8, PCILIB_LITTLE_ENDIAN, "cmosis", "CMOSIS CMV2000 Registers" }, + { PCILIB_REGISTER_BANK1, 64, PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_SPACE, IPECAMERA_REGISTER_SPACE, PCILIB_BIG_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "fpga", "IPECamera Registers" }, + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL } +}; + +pcilib_register_description_t ipecamera_registers[] = { +{1, 0, 16, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines", ""}, +{3, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start1", ""}, +{5, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start2", ""}, +{7, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start3", ""}, +{9, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start4", ""}, +{11, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start5", ""}, +{13, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start6", ""}, +{15, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start7", ""}, +{17, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "start8", ""}, +{19, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines1", ""}, +{21, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines2", ""}, +{23, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines3", ""}, +{25, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines4", ""}, +{27, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines5", ""}, +{29, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines6", ""}, +{31, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines7", ""}, +{33, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_lines8", ""}, +{35, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_s", ""}, +{37, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "sub_a", ""}, +{39, 0, 1, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "color", ""}, +{40, 0, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "image_flipping", ""}, +{41, 0, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_flags", ""}, +{42, 0, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time", ""}, +{45, 0, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step", ""}, +{48, 0, 24, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp1", ""}, +{51, 0, 24, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_kp2", ""}, +{54, 0, 2, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes", ""}, +{55, 0, 8, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq", ""}, +{56, 0, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_time2", ""}, +{59, 0, 24, 1088, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_step2", ""}, +{68, 0, 2, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "nr_slopes2", ""}, +{69, 0, 8, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "exp_seq2", ""}, +{70, 0, 16, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "number_frames", ""}, +{72, 0, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "output_mode", ""}, +{78, 0, 12, 85, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "training_pattern", ""}, +{80, 0, 18, 0x3FFFF,PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "channel_en", ""}, +{89, 0, 8, 96, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow2", ""}, +{90, 0, 8, 96, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "vlow3", ""}, +{100, 0, 14, 16260, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "offset", ""}, +{102, 0, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "pga", ""}, +{103, 0, 8, 32, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_gain", ""}, +{111, 0, 1, 1, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "bit_mode", ""}, +{112, 0, 2, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "adc_resolution", ""}, +{126, 0, 16, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK0, "temp", ""}, +{0, 0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_conf_input", ""}, +{1, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "spi_conf_output", ""}, +{2, 0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "spi_clk_speed", ""}, +{3, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "firmware_version", ""}, +{4, 0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "control", ""}, +{5, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "status", ""}, +{6, 0, 16, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "cmosis_temperature", ""}, +{7, 0, 32, 0, PCILIB_REGISTER_RW, PCILIB_REGISTER_BANK1, "temperature_sample_timing", ""}, +{8, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "start_address", ""}, +{9, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "end_address", ""}, +{10, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "last_write_address", ""}, +{11, 0, 32, 0, PCILIB_REGISTER_R, PCILIB_REGISTER_BANK1, "last_write_value", ""}, +{0, 0, 0, 0, 0, 0, NULL, NULL} +}; + +pcilib_register_range_t ipecamera_register_ranges[] = { + {0, 128, PCILIB_REGISTER_BANK0}, {0, 0, 0} +}; + +#else +extern pcilib_register_description_t ipecamera_registers[]; +extern pcilib_register_bank_description_t ipecamera_register_banks[]; +extern pcilib_register_range_t ipecamera_register_ranges[]; +#endif + +#ifdef _IPECAMERA_IMAGE_C +pcilib_event_api_description_t ipecamera_image_api = { + ipecamera_init, + ipecamera_free, + + ipecamera_reset, + ipecamera_start, + ipecamera_stop, + ipecamera_trigger, + + ipecamera_get, + ipecamera_return +}; +#else +extern pcilib_event_api_description_t ipecamera_image_api; +#endif + +int ipecamera_read(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t *value); +int ipecamera_write(pcilib_t *ctx, pcilib_register_bank_description_t *bank, pcilib_register_addr_t addr, uint8_t bits, pcilib_register_value_t value); + +#endif /* _IPECAMERA_MODEL_H */ diff --git a/pci.c b/pci.c index 461d2f3..2a25e0d 100644 --- a/pci.c +++ b/pci.c @@ -1,4 +1,5 @@ #define _PCILIB_PCI_C +#define _POSIX_C_SOURCE 199309L #include #include @@ -17,7 +18,7 @@ #include "tools.h" #include "pci.h" -#include "ipecamera.h" +#include "ipecamera/model.h" #include "error.h" #define BIT_MASK(bits) ((1l << (bits)) - 1) @@ -34,6 +35,12 @@ struct pcilib_s { pcilib_bar_t reg_bar; char *reg_space; + + pcilib_bar_t data_bar; + char *data_space; + size_t data_size; + + void *event_ctx; #ifdef PCILIB_FILE_IO int file_io_handle; @@ -60,6 +67,7 @@ int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(con } pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { + pcilib_event_api_description_t *api; pcilib_t *ctx = malloc(sizeof(pcilib_t)); if (ctx) { @@ -67,6 +75,10 @@ pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { ctx->page_mask = (uintptr_t)-1; ctx->model = model; ctx->reg_space = NULL; + + if (!model) model = pcilib_get_model(ctx); + api = pcilib_model[model].event_api; + if ((api)&&(api->init)) ctx->event_ctx = api->init(ctx); } return ctx; @@ -297,12 +309,67 @@ static int pcilib_map_register_space(pcilib_t *ctx) { } } - return -1; + return PCILIB_ERROR_NOTFOUND; } return 0; } + +static int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) { + int err; + int i; + + if (!ctx->data_space) { + const pci_board_info *board_info = pcilib_get_board_info(ctx); + + err = pcilib_map_register_space(ctx); + if (err) { + pcilib_error("Error mapping register space"); + return err; + } + + if (addr) { + } + + int data_bar = -1; + + for (i = 0; i < PCILIB_MAX_BANKS; i++) { + if ((i == ctx->reg_bar)||(!board_info->bar_length[i])) continue; + + if (addr) { + if (board_info->bar_start[i] == addr) { + data_bar = i; + break; + } + } else { + if (data_bar >= 0) { + data_bar = -1; + break; + } + + data_bar = i; + } + } + + if (data_bar < 0) { + if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr); + else pcilib_error("Unable to find the data space"); + return PCILIB_ERROR_NOTFOUND; + } + + ctx->data_bar = data_bar; + ctx->data_space = pcilib_map_bar(ctx, data_bar); + ctx->data_size = board_info->bar_length[data_bar]; + + if (!ctx->data_space) { + pcilib_error("Unable to map the data space"); + return PCILIB_ERROR_FAILED; + } + } + + return 0; +} static void pcilib_unmap_register_space(pcilib_t *ctx) { if (ctx->reg_space) { @@ -311,6 +378,13 @@ static void pcilib_unmap_register_space(pcilib_t *ctx) { } } +static void pcilib_unmap_data_space(pcilib_t *ctx) { + if (ctx->data_space) { + pcilib_unmap_bar(ctx, ctx->data_bar, ctx->data_space); + ctx->data_space = NULL; + } +} + char *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) { size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar]; if (offset < ctx->board_info.bar_length[ctx->reg_bar]) { @@ -319,11 +393,31 @@ char *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr) { return NULL; } +char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) { + int err; + + err = pcilib_map_data_space(ctx, addr); + if (err) { + pcilib_error("Failed to map the specified address space (%lx)", addr); + return NULL; + } + + if (size) *size = ctx->data_size; + + return ctx->data_space + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask); +} + void pcilib_close(pcilib_t *ctx) { if (ctx) { + pcilib_model_t model = pcilib_get_model(ctx); + pcilib_event_api_description_t *api = pcilib_model[model].event_api; + + if ((api)&&(api->free)) api->free(ctx->event_ctx); + if (ctx->data_space) pcilib_unmap_data_space(ctx); if (ctx->reg_space) pcilib_unmap_register_space(ctx); close(ctx->handle); + free(ctx); } } @@ -491,17 +585,21 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg pcilib_error("Big-endian byte order support is not implemented"); return PCILIB_ERROR_NOTSUPPORTED; } else { - for (i = 0, res = value; (res > 0)&&(i <= n); ++i) { - buf[i] = res & BIT_MASK(b->access); - res >>= b->access; - } + if (b->access == sizeof(res) * 8) { + buf[i] = res; + } 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 to big to fit in the register %s", value, r->name); - return PCILIB_ERROR_OUTOFRANGE; + 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; } @@ -511,8 +609,175 @@ int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, int reg; reg = pcilib_find_register(ctx, bank, regname); - if (reg < 0) pcilib_error("Register (%s) is not found", 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; +} + +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(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, 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/pci.h b/pci.h index 7da0a11..9426c33 100644 --- a/pci.h +++ b/pci.h @@ -11,13 +11,13 @@ const pci_board_info *pcilib_get_board_info(pcilib_t *ctx); #ifdef _PCILIB_PCI_C -# include "ipecamera.h" +# include "ipecamera/model.h" # include "default.h" pcilib_model_description_t pcilib_model[3] = { - { NULL, NULL, NULL }, - { NULL, NULL, NULL }, - { ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges } + { NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL }, + { ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, &ipecamera_image_api } }; pcilib_protocol_description_t pcilib_protocol[3] = { diff --git a/pcilib.h b/pcilib.h index 7924128..57c68c9 100644 --- a/pcilib.h +++ b/pcilib.h @@ -3,8 +3,16 @@ #define PCILIB_MAX_BANKS 6 +#include #include +#ifndef __timespec_defined +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif /* __timespec_defined */ + #define pcilib_memcpy pcilib_memcpy32 #define pcilib_datacpy pcilib_datacpy32 @@ -17,6 +25,9 @@ typedef uint8_t pcilib_register_bank_t; /**< Type holding the register bank num typedef uint8_t pcilib_register_bank_addr_t; /**< Type holding the register bank number */ typedef uint8_t pcilib_register_size_t; /**< Type holding the size in bits of the register */ typedef uint32_t pcilib_register_value_t; /**< Type holding the register value */ +typedef uint64_t pcilib_event_id_t; + +typedef uint32_t pcilib_event_t; typedef enum { PCILIB_LITTLE_ENDIAN = 0, @@ -35,12 +46,15 @@ typedef enum { PCILIB_REGISTER_RW = 3 } pcilib_register_mode_t; - typedef enum { PCILIB_DEFAULT_PROTOCOL, IPECAMERA_REGISTER_PROTOCOL } pcilib_register_protocol_t; +typedef enum { + PCILIB_EVENT_DATA +} pcilib_event_data_type_t; + #define PCILIB_BAR_DETECT ((pcilib_bar_t)-1) #define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1) #define PCILIB_ADDRESS_INVALID ((uintptr_t)-1) @@ -49,6 +63,7 @@ typedef enum { #define PCILIB_REGISTER_BANK1 1 #define PCILIB_REGISTER_BANK2 2 #define PCILIB_REGISTER_BANK3 3 +#define PCILIB_ALL_EVENTS ((pcilib_event_t)-1) typedef struct { pcilib_register_bank_addr_t addr; @@ -69,6 +84,7 @@ typedef struct { typedef struct { pcilib_register_addr_t addr; + pcilib_register_size_t offset; pcilib_register_size_t bits; pcilib_register_value_t defvalue; pcilib_register_mode_t mode; @@ -93,10 +109,28 @@ typedef struct { 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 int (*pcilib_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user); + +typedef struct { + void *(*init)(pcilib_t *ctx); + void (*free)(void *ctx); + + int (*reset)(void *ctx); + + int (*start)(void *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user); + int (*stop)(void *ctx); + int (*trigger)(void *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); + void* (*get_data)(void *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size); + int (*return_data)(void *ctx, pcilib_event_id_t event_id); +} pcilib_event_api_description_t; + typedef struct { pcilib_register_description_t *registers; pcilib_register_bank_description_t *banks; pcilib_register_range_t *ranges; + + pcilib_event_api_description_t *event_api; } pcilib_model_description_t; #ifndef _PCILIB_PCI_C @@ -112,7 +146,8 @@ void pcilib_close(pcilib_t *ctx); void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar); void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data); -char *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr); +char *pcilib_resolve_register_address(pcilib_t *ctx, uintptr_t addr); +char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size); pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank); pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg); @@ -127,4 +162,24 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value); int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value); +int pcilib_reset(pcilib_t *ctx); +int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user); +int pcilib_stop(pcilib_t *ctx); + +int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); + +void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size); +/* + * This function is provided to find potentially corrupted data. If the data is overwritten by + * the time return_data is called it will return error. + */ +int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id); + +/* + * @param data - will be allocated and shuld be freed if NULL, otherwise used and size should contain correct size. + * In case of failure the content of data is undefined. + * @param timeout - will be autotriggered if NULL + */ +int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout); + #endif /* _PCITOOL_PCILIB_H */ -- cgit v1.2.3