Sfoglia il codice sorgente

Support FIFO reading/writting, code restructurization, few fixes

Suren A. Chilingaryan 13 anni fa
parent
commit
d98d86bd6b
11 ha cambiato i file con 785 aggiunte e 571 eliminazioni
  1. 1 1
      Makefile
  2. 179 54
      cli.c
  3. 0 2
      default.c
  4. 230 0
      event.c
  5. 22 0
      event.h
  6. 48 492
      pci.c
  7. 3 0
      pci.h
  8. 9 22
      pcilib.h
  9. 280 0
      register.c
  10. 11 0
      register.h
  11. 2 0
      tools.h

+ 1 - 1
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$@"

+ 179 - 54
cli.c

@@ -17,7 +17,7 @@
 
 #include <getopt.h>
 
-#include "pci.h"
+//#include "pci.h"
 #include "tools.h"
 #include "kernel.h"
 
@@ -63,6 +63,7 @@ typedef enum {
 typedef enum {
     OPT_DEVICE = 'd',
     OPT_MODEL = 'm',
+    OPT_TYPE = 't',
     OPT_BAR = 'b',
     OPT_ACCESS = 'a',
     OPT_ENDIANESS = 'e',
@@ -82,6 +83,7 @@ typedef enum {
 static struct option long_options[] = {
     {"device",			required_argument, 0, OPT_DEVICE },
     {"model",			required_argument, 0, OPT_MODEL },
+    {"type",			required_argument, 0, OPT_TYPE },
     {"bar",			required_argument, 0, OPT_BAR },
     {"access",			required_argument, 0, OPT_ACCESS },
     {"endianess",		required_argument, 0, OPT_ENDIANESS },
@@ -132,7 +134,8 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	-m <model>		- Memory model (autodetected)\n"
 "	   pci			- Plain\n"
 "	   ipecamera		- IPE Camera\n"
-"	-b <bank>		- Data/Register bank (autodetected)\n"
+"	-t <plain|fifo|dma>	- Access type (default: plain)\n"
+"	-b <bank>		- PCI bar, Register bank, or DMA channel\n"
 "\n"
 "  Options:\n"
 "	-s <size>		- Number of words (default: 1)\n"
@@ -302,22 +305,34 @@ void Info(pcilib_t *handle, pcilib_model_t model) {
 }
 
 
-int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar) {
+#define BENCH_MAX_DMA_SIZE 16 * 1024 * 1024
+#define BENCH_MAX_FIFO_SIZE 1024 * 1024
+
+int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access) {
     int err;
-    int i, errors;
+    int i, j, errors;
     void *data, *buf, *check;
+    void *fifo;
     struct timeval start, end;
     unsigned long time;
-    unsigned int size, max_size;
+    size_t size, min_size, max_size;
     double mbs_in, mbs_out, mbs;
     
     const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);
 
     if (mode == ACCESS_DMA) {
-        for (size = 1024 ; size < 16 * 1024 * 1024; size *= 4) {
-	    mbs_in = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_FROM_DEVICE);
-	    mbs_out = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_TO_DEVICE);
-	    mbs = pcilib_benchmark_dma(handle, dma, 0, size, BENCHMARK_ITERATIONS, PCILIB_DMA_BIDIRECTIONAL);
+	if (n) {
+	    min_size = n * access;
+	    max_size = n * access;
+	} else {
+	    min_size = 1024;
+	    max_size = BENCH_MAX_DMA_SIZE;
+	}
+	
+        for (size = min_size; size < max_size; size *= 4) {
+	    mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_FROM_DEVICE);
+	    mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_TO_DEVICE);
+	    mbs = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_BIDIRECTIONAL);
 	    printf("%8i KB - ", size / 1024);
 	    
 	    printf("RW: ");
@@ -337,10 +352,17 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
 	
 	return 0;
     }
-		
-    if (bar < 0) {
+
+    if (bar == PCILIB_BAR_INVALID) {
 	unsigned long maxlength = 0;
+	
+
 	for (i = 0; i < PCILIB_MAX_BANKS; i++) {
+	    if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + access))) {
+		bar = i;
+		break;
+	    }
+
 	    if (board_info->bar_length[i] > maxlength) {
 		maxlength = board_info->bar_length[i];
 		bar = i;
@@ -350,36 +372,71 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
 	if (bar < 0) Error("Data banks are not available");
     }
     
+    if (n) {
+	if ((mode == ACCESS_BAR)&&(n * access > board_info->bar_length[bar])) Error("The specified size (%i) exceeds the size of bar (%i)", n * access, board_info->bar_length[bar]);
 
-    max_size = board_info->bar_length[bar];
+	min_size = n * access;
+	max_size = n * access;
+    } else {
+	min_size = access;
+	if (mode == ACCESS_BAR) max_size = board_info->bar_length[bar];
+	else max_size = BENCH_MAX_FIFO_SIZE;
+    }
     
     err = posix_memalign( (void**)&buf, 256, max_size );
     if (!err) err = posix_memalign( (void**)&check, 256, max_size );
     if ((err)||(!buf)||(!check)) Error("Allocation of %i bytes of memory have failed", max_size);
 
-    printf("Transfer time (Bank: %i):\n", bar);    
     data = pcilib_map_bar(handle, bar);
-    
-    for (size = 4 ; size < max_size; size *= 8) {
+    if (!data) Error("Can't map bar %i", bar);
+
+    if (mode == ACCESS_FIFO) {
+        fifo = data + (addr - board_info->bar_start[bar]) + (board_info->bar_start[bar] & pcilib_get_page_mask());
+//	pcilib_resolve_register_address(handle, bar, addr);
+	if (!fifo) Error("Can't resolve address (%lx) in bar (%u)", addr, bar);
+    }
+
+    if (mode == ACCESS_FIFO)
+	printf("Transfer time (Bank: %i, Fifo: %lx):\n", bar, addr);
+    else
+	printf("Transfer time (Bank: %i):\n", bar);
+	
+    for (size = min_size ; size < max_size; size *= 8) {
 	gettimeofday(&start,NULL);
-	for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
-	    pcilib_memcpy(buf, data, size);
+	if (mode == ACCESS_BAR) {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_memcpy(buf, data, size);
+	    }
+	} else {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		for (j = 0; j < (size/access); j++) {
+		    pcilib_memcpy(buf + j * access, fifo, access);
+		}
+	    }
 	}
 	gettimeofday(&end,NULL);
 
 	time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
-	printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+	printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
 	
 	fflush(0);
 
 	gettimeofday(&start,NULL);
-	for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
-	    pcilib_memcpy(data, buf, size);
+	if (mode == ACCESS_BAR) {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_memcpy(data, buf, size);
+	    }
+	} else {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		for (j = 0; j < (size/access); j++) {
+		    pcilib_memcpy(fifo, buf + j * access, access);
+		}
+	    }
 	}
 	gettimeofday(&end,NULL);
 
 	time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
-	printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+	printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
     }
     
     pcilib_unmap_bar(handle, bar, data);
@@ -388,36 +445,51 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
     
     for (size = 4 ; size < max_size; size *= 8) {
 	gettimeofday(&start,NULL);
-	for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
-	    pcilib_read(handle, bar, 0, size, buf);
+	if (mode == ACCESS_BAR) {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_read(handle, bar, 0, size, buf);
+	    }
+	} else {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_read_fifo(handle, bar, addr, access, size / access, buf);
+	    }
 	}
 	gettimeofday(&end,NULL);
 
 	time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
-	printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+	printf("%8i bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
 	
 	fflush(0);
 
 	gettimeofday(&start,NULL);
-	for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
-	    pcilib_write(handle, bar, 0, size, buf);
+	if (mode == ACCESS_BAR) {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_write(handle, bar, 0, size, buf);
+	    }
+	} else {
+	    for (i = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_write_fifo(handle, bar, addr, access, size / access, buf);
+	    }
 	}
+	
 	gettimeofday(&end,NULL);
 
 	time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
-	printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
+	printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
+
+	if (mode == ACCESS_BAR) {
+	    gettimeofday(&start,NULL);
+	    for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) {
+		pcilib_write(handle, bar, 0, size, buf);
+		pcilib_read(handle, bar, 0, size, check);
+		if (memcmp(buf, check, size)) ++errors;
+	    }
+	    gettimeofday(&end,NULL);
 
-	gettimeofday(&start,NULL);
-	for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) {
-	    pcilib_write(handle, bar, 0, size, buf);
-	    pcilib_read(handle, bar, 0, size, check);
-	    if (memcmp(buf, check, size)) ++errors;
+	    time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
+	    printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.));
+	    if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS);
 	}
-	gettimeofday(&end,NULL);
-
-	time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec);
-	printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024 * 1024));
-	if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS);
 	printf("\n");
     }
     
@@ -433,9 +505,11 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
 int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) {
     void *buf;
     int i, err;
+    size_t ret;
     int size = n * abs(access);
     int block_width, blocks_per_line;
     int numbers_per_block, numbers_per_line; 
+    pcilib_dma_t dmaid;
     
     numbers_per_block = BLOCK_SIZE / access;
 
@@ -448,13 +522,20 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_b
     err = posix_memalign( (void**)&buf, 256, size );
     if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size);
     
-    if (mode == ACCESS_DMA) {
-	pcilib_dma_t dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
+    switch (mode) {
+      case ACCESS_DMA:
+	dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
 	if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
-	pcilib_read_dma(handle, dmaid, addr, size, buf);
-
+	ret = pcilib_read_dma(handle, dmaid, addr, size, buf);
+	if (ret <= 0) Error("No data is returned by DMA engine");
+	size = ret;
 	addr = 0;
-    } else {
+      break;
+      case ACCESS_FIFO:
+	pcilib_read_fifo(handle, bar, addr, access, n, buf);
+	addr = 0;
+      break;
+      default:
 	pcilib_read(handle, bar, addr, size, buf);
     }
     if (endianess) pcilib_swap(buf, buf, abs(access), n);
@@ -592,9 +673,12 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_t model, const char *bank,
 }
 
 int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) {
+    int read_back = 0;
     void *buf, *check;
     int res, i, err;
     int size = n * abs(access);
+    size_t ret;
+    pcilib_dma_t dmaid;
 
     err = posix_memalign( (void**)&buf, 256, size );
     if (!err) err = posix_memalign( (void**)&check, 256, size );
@@ -611,10 +695,27 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_
     }
 
     if (endianess) pcilib_swap(buf, buf, abs(access), n);
-    pcilib_write(handle, bar, addr, size, buf);
-    pcilib_read(handle, bar, addr, size, check);
-    
-    if (memcmp(buf, check, size)) {
+
+    switch (mode) {
+      case ACCESS_DMA:
+	dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma);
+	if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
+	ret = pcilib_write_dma(handle, dmaid, addr, size, buf);
+	if (ret != size) {
+	    if (!ret) Error("No data is written by DMA engine");
+	    else Error("Only %lu bytes of %lu is written by DMA engine", ret, size);
+	}
+      break;
+      case ACCESS_FIFO:
+	pcilib_write_fifo(handle, bar, addr, access, n, buf);
+      break;
+      default:
+	pcilib_write(handle, bar, addr, size, buf);
+	pcilib_read(handle, bar, addr, size, check);
+	read_back = 1;
+    }
+
+    if ((read_back)&&(memcmp(buf, check, size))) {
 	printf("Write failed: the data written and read differ, the foolowing is read back:\n");
         if (endianess) pcilib_swap(check, check, abs(access), n);
 	ReadData(handle, mode, dma, bar, addr, n, access, endianess);
@@ -730,6 +831,7 @@ int main(int argc, char **argv) {
     
     pcilib_model_t model = PCILIB_MODEL_DETECT;
     MODE mode = MODE_INVALID;
+    const char *type = NULL;
     ACCESS_MODE amode = ACCESS_BAR;
     const char *fpga_device = DEFAULT_FPGA_DEVICE;
     pcilib_bar_t bar = PCILIB_BAR_DETECT;
@@ -749,7 +851,9 @@ int main(int argc, char **argv) {
 
     pcilib_t *handle;
     
-    while ((c = getopt_long(argc, argv, "hqilpr::w::g::d:m:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) {
+    int size_set = 0;
+    
+    while ((c = getopt_long(argc, argv, "hqilpr::w::g::d:m:t:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) {
 	extern int optind;
 	switch (c) {
 	    case OPT_HELP:
@@ -805,7 +909,10 @@ int main(int argc, char **argv) {
 	    case OPT_MODEL:
 		if (!strcasecmp(optarg, "pci")) model = PCILIB_MODEL_PCI;
 		else if (!strcasecmp(optarg, "ipecamera")) model = PCILIB_MODEL_IPECAMERA;
-		else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);\
+		else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);
+	    break;
+	    case OPT_TYPE:
+		type = optarg;
 	    break;
 	    case OPT_BAR:
 		bank = optarg;
@@ -825,6 +932,7 @@ int main(int argc, char **argv) {
 	    case OPT_SIZE:
 		if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1))
 		    Usage(argc, argv, "Invalid size is specified (%s)", optarg);
+		size_set = 1;
 	    break;
 	    case OPT_ENDIANESS:
 		if ((*optarg == 'b')||(*optarg == 'B')) {
@@ -895,13 +1003,24 @@ int main(int argc, char **argv) {
         if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied");
     }
 
+    if (type) {
+	if (!strcasecmp(type, "fifo")) amode = ACCESS_FIFO;
+	else if (!strcasecmp(type, "dma")) amode = ACCESS_DMA;
+	else if ((!strcasecmp(type, "bar"))||(!strcasecmp(optarg, "bar"))) amode = ACCESS_BAR;
+	else Usage(argc, argv, "Invalid access type (%s) is specified", type);
+    }
+
     if (addr) {
-	if (!strncmp(addr, "dma", 3)) {
+	if ((!strncmp(addr, "dma", 3))&&((addr[3]==0)||isnumber(addr+3))) {
+	    if ((type)&&(amode != ACCESS_DMA)) Usage(argc, argv, "Conflicting access modes, the DMA read is requested, but access type is (%s)", type);
+	    if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting DMA channels are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank);
 	    dma = atoi(addr + 3);
 	    amode = ACCESS_DMA;
-	} else if (!strncmp(addr, "bar", 3)) {
+	} else if ((!strncmp(addr, "bar", 3))&&((addr[3]==0)||isnumber(addr+3))) {
+	    if ((type)&&(amode != ACCESS_BAR)) Usage(argc, argv, "Conflicting access modes, the plain PCI read is requested, but access type is (%s)", type);
+	    if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting PCI bars are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank);
 	    bar = atoi(addr + 3);
-	    amode = ACCESS_DMA;
+	    amode = ACCESS_BAR;
 	} else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) {
 		// check if the address in the register range
 	    pcilib_register_range_t *ranges =  pcilib_model[model].ranges;
@@ -911,7 +1030,7 @@ int main(int argc, char **argv) {
 		    if ((start >= ranges[i].start)&&(start <= ranges[i].end)) break;
 	    		
 		    // register access in plain mode
-		if (ranges[i].start != ranges[i].end) ++mode;
+		if (ranges[i].start != ranges[i].end) ++mode;	
 	    }
 	} else {
 	    if (pcilib_find_register(handle, bank, addr) == PCILIB_REGISTER_INVALID) {
@@ -923,7 +1042,12 @@ int main(int argc, char **argv) {
 	} 
     }
     
-    if (bank) {
+
+    if ((bank)&&(amode == ACCESS_DMA)) {
+	if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0)) 
+	    Usage(argc, argv, "Invalid DMA channel (%s) is specified", bank);
+	else dma = itmp;
+    } else if (bank) {
 	switch (mode) {
 	    case MODE_BENCHMARK:
 	    case MODE_READ:
@@ -937,6 +1061,7 @@ int main(int argc, char **argv) {
 		    Usage(argc, argv, "Invalid data bank (%s) is specified", bank);
 	}
     }
+    
 
     switch (mode) {
      case MODE_INFO:
@@ -946,7 +1071,7 @@ int main(int argc, char **argv) {
         List(handle, model, bank);
      break;
      case MODE_BENCHMARK:
-        Benchmark(handle, amode, dma, bar);
+        Benchmark(handle, amode, dma, bar, start, size_set?size:0, access);
      break;
      case MODE_READ:
         if (addr) {

+ 0 - 2
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) {

+ 230 - 0
event.c

@@ -0,0 +1,230 @@
+#define _POSIX_C_SOURCE 199309L
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "pci.h"
+
+#include "tools.h"
+#include "error.h"
+
+pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
+    int i;
+    pcilib_register_bank_t res;
+    unsigned long addr;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+    pcilib_event_description_t *events = pcilib_model[model].events;
+    
+    for (i = 0; events[i].name; i++) {
+	if (!strcasecmp(events[i].name, event)) return (1<<i);
+    }
+
+    return (pcilib_event_t)-1;
+}
+
+
+int pcilib_reset(pcilib_t *ctx) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+    
+    if (api->reset) 
+	return api->reset(ctx->event_ctx);
+	
+    return 0;
+}
+
+int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->start) 
+	return api->start(ctx->event_ctx, event_mask, callback, user);
+
+    return 0;
+}
+
+int pcilib_stop(pcilib_t *ctx) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->stop) 
+	return api->stop(ctx->event_ctx);
+
+    return 0;
+}
+
+pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->next_event) 
+	return api->next_event(ctx->event_ctx, event_mask, timeout);
+
+    pcilib_error("Event enumeration is not suppored by API");
+    return PCILIB_EVENT_ID_INVALID;
+}
+
+int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
+    pcilib_event_api_description_t *api;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    api = pcilib_model[model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->trigger) 
+	return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
+
+    pcilib_error("Self triggering is not supported by the selected model");
+    return PCILIB_ERROR_NOTSUPPORTED;
+}
+
+
+void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) {
+    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return NULL;
+    }
+
+    if (api->get_data) 
+	return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size);
+
+    return NULL;
+}
+
+void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
+    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return NULL;
+    }
+
+    if (api->get_data) 
+	return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size);
+
+    return NULL;
+}
+
+int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
+    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
+    if (!api) {
+	pcilib_error("Event API is not supported by the selected model");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    }
+
+    if (api->return_data) 
+	return api->return_data(ctx->event_ctx, event_id);
+
+    return 0;
+}
+
+
+typedef struct {
+    pcilib_t *ctx;
+    
+    size_t *size;
+    void **data;
+} pcilib_grab_callback_user_data_t;
+
+static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
+    int err;
+    void *data;
+    size_t size;
+    int allocated = 0;
+
+    pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
+
+    data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
+    if (!data) {
+	pcilib_error("Error getting event data");
+	return PCILIB_ERROR_FAILED;
+    }
+    
+    if (*(user->data)) {
+	if ((user->size)&&(*(user->size) < size)) {
+	    pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
+	    return PCILIB_ERROR_MEMORY;
+	}
+
+	*(user->size) = size;
+    } else {
+	*(user->data) = malloc(size);
+	if (!*(user->data)) {
+	    pcilib_error("Memory allocation (%i bytes) for event data is failed");
+	    return PCILIB_ERROR_MEMORY;
+	}
+	if (*(user->size)) *(user->size) = size;
+	allocated = 1;
+    }
+    
+    memcpy(*(user->data), data, size);
+    
+    err = pcilib_return_data(user->ctx, event_id);
+    if (err) {
+	if (allocated) {
+	    free(*(user->data));
+	    *(user->data) = NULL;
+	}
+	pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
+	return err;
+    }
+    
+    return 0;
+}
+
+int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
+    int err;
+    
+    pcilib_grab_callback_user_data_t user = {ctx, size, data};
+    
+    err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
+    if (!err) {
+	if (timeout) nanosleep(timeout, NULL);
+        else err = pcilib_trigger(ctx, event_mask, 0, NULL);
+    }
+    pcilib_stop(ctx);
+    return 0;
+}

+ 22 - 0
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 */

+ 48 - 492
pci.c

@@ -16,17 +16,13 @@
 #include <errno.h>
 #include <assert.h>
 
+#include "pci.h"
+
 #include "kernel.h"
 #include "tools.h"
-
-#include "dma.h"
-#include "pci.h"
-#include "ipecamera/model.h"
 #include "error.h"
 
-#define BIT_MASK(bits) ((1l << (bits)) - 1)
-
-
+#include "ipecamera/model.h"
 
 
 static void pcilib_print_error(const char *msg, ...) {
@@ -220,126 +216,6 @@ void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) {
 #endif
 }
 
-int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
-    int i;
-    void *data;
-    unsigned int offset;
-    char local_buf[size];
-    
-
-    pcilib_detect_address(ctx, &bar, &addr, size);
-    data = pcilib_map_bar(ctx, bar);
-
-/*
-    for (i = 0; i < size/4; i++)  {
-	((uint32_t*)((char*)data+addr))[i] = 0x100 * i + 1;
-    }
-*/
-    pcilib_memcpy(buf, data + addr, size);
-    
-    pcilib_unmap_bar(ctx, bar, data);    
-}
-
-int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
-    int i;
-    void *data;
-    unsigned int offset;
-    char local_buf[size];
-    
-
-    pcilib_detect_address(ctx, &bar, &addr, size);
-    data = pcilib_map_bar(ctx, bar);
-
-    pcilib_memcpy(data + addr, buf, size);
-    
-    pcilib_unmap_bar(ctx, bar, data);    
-}
-
-
-pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
-    pcilib_register_bank_t i;
-    pcilib_model_t model = pcilib_get_model(ctx);
-    pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
-
-    for (i = 0; banks[i].access; i++)
-	if (banks[i].addr == bank) return i;
-	
-    return -1;
-}
-
-pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankname) {
-    pcilib_register_bank_t i;
-    pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
-
-    for (i = 0; banks[i].access; i++)
-	if (!strcasecmp(banks[i].name, bankname)) return i;
-	
-    return -1;
-}
-
-pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank) {
-    pcilib_register_bank_t res;
-    unsigned long addr;
-    
-    if (!bank) {
-	pcilib_model_t model = pcilib_get_model(ctx);
-	pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
-	if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0;
-	return -1;
-    }
-    
-    if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) {
-	res = pcilib_find_bank_by_addr(ctx, addr);
-	if (res != PCILIB_REGISTER_BANK_INVALID) return res;
-    }
-    
-    return pcilib_find_bank_by_name(ctx, bank);
-}
-
-    // FIXME create hash during map_register space
-pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) {
-    pcilib_register_t i;
-    pcilib_register_bank_t bank_id;
-    pcilib_register_bank_addr_t bank_addr;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-    
-    pcilib_register_description_t *registers =  pcilib_model[model].registers;
-    
-    if (bank) {
-	bank_id = pcilib_find_bank(ctx, bank);
-	if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
-	    pcilib_error("Invalid bank (%s) is specified", bank);
-	    return -1;
-	}
-	
-	bank_addr = pcilib_model[model].banks[bank_id].addr;
-    }
-    
-    for (i = 0; registers[i].bits; i++) {
-	if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i;
-    }
-    
-    return (pcilib_register_t)-1;
-};
-
-
-pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) {
-    int i;
-    pcilib_register_bank_t res;
-    unsigned long addr;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-    pcilib_event_description_t *events = pcilib_model[model].events;
-    
-    for (i = 0; events[i].name; i++) {
-	if (!strcasecmp(events[i].name, event)) return (1<<i);
-    }
-
-    return (pcilib_event_t)-1;
-}
-
-
 int pcilib_map_register_space(pcilib_t *ctx) {
     int err;
     pcilib_register_bank_t i;
@@ -467,6 +343,11 @@ char  *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_
 	    // First checking the default register bar
 	size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar];
 	if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) {
+	    if (!ctx->bar_space[ctx->reg_bar]) {
+		pcilib_error("The register bar is not mapped");
+		return NULL;
+	    }
+
 	    return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask);
 	}
 	    
@@ -475,14 +356,26 @@ char  *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_
 	if (bar != PCILIB_BAR_INVALID) {
 	    size_t offset = addr - ctx->board_info.bar_start[bar];
 	    if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) {
+		if (!ctx->bar_space[bar]) {
+		    pcilib_error("The requested bar (%i) is not mapped", bar);
+		    return NULL;
+		}
 		return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask);
 	    }
 	}
     } else {
+	if (!ctx->bar_space[bar]) {
+	    pcilib_error("The requested bar (%i) is not mapped", bar);
+	    return NULL;
+	}
+	
 	if (addr < ctx->board_info.bar_length[bar]) {
 	    return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask);
 	}
 	
+	if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) {
+	    return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask);
+	}
     }
 
     return NULL;
@@ -531,393 +424,56 @@ void pcilib_close(pcilib_t *ctx) {
     }
 }
 
-static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
-    int err;
-    int rest;
-    size_t i;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-    pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
-
-    assert(bits < 8 * sizeof(pcilib_register_value_t));
-    
-    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
-	pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
-	return PCILIB_ERROR_OUTOFRANGE;
-    }
+int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
+    int i;
+    void *data;
 
-    err = pcilib_map_register_space(ctx);
-    if (err) {
-	pcilib_error("Failed to map the register space");
-	return err;
-    }
-    
-    //n += bits / b->access;
-    //bits %= b->access; 
-    
-    for (i = 0; i < n; i++) {
-	err = pcilib_protocol[b->protocol].read(ctx, b, addr + i, b->access, buf + i);
-	if (err) break;
-    }
-    
-    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].read(ctx, b, addr + n, bits, buf + n);
-    
-    return err;
-}
+    pcilib_detect_address(ctx, &bar, &addr, size);
+    data = pcilib_map_bar(ctx, bar);
 
-int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
-    pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
-    if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
-	if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
-	else pcilib_error("Register bank should be specified");
-	return PCILIB_ERROR_INVALID_BANK;
-    }
+    pcilib_memcpy(buf, data + addr, size);
     
-    return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+    pcilib_unmap_bar(ctx, bar, data);    
 }
 
-int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) {
-    int err;
-    size_t i, n, bits;
-    pcilib_register_value_t res;
-    pcilib_register_description_t *r;
-    pcilib_register_bank_description_t *b;
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    r = pcilib_model[model].registers + reg;
-    b = pcilib_model[model].banks + r->bank;
-    
-    n = r->bits / b->access;
-    bits = r->bits % b->access; 
-
-    pcilib_register_value_t buf[n + 1];
-    err = pcilib_read_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
-
-    if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
-	pcilib_error("Big-endian byte order support is not implemented");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    } else {
-	res = 0;
-	if (bits) ++n;
-	for (i = 0; i < n; i++) {
-	    res |= buf[i] << (i * b->access);
-	}
-    }
-    
-    *value = res;
-    
-    return err;
-}
+int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) {
+    int i;
+    void *data;
 
+    pcilib_detect_address(ctx, &bar, &addr, size);
+    data = pcilib_map_bar(ctx, bar);
 
-int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) {
-    int err;
-    int reg;
-    
-    reg = pcilib_find_register(ctx, bank, regname);
-    if (reg < 0) {
-	pcilib_error("Register (%s) is not found", regname);
-	return PCILIB_ERROR_NOTFOUND;
-    }
+    pcilib_memcpy(data + addr, buf, size);
     
-    return pcilib_read_register_by_id(ctx, reg, value);
-
-//    registers[reg].bank
-//    printf("%li %li", sizeof(pcilib_model[model].banks), sizeof(pcilib_register_bank_description_t));
+    pcilib_unmap_bar(ctx, bar, data);    
 }
 
 
-static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
-    int err;
-    int rest;
-    size_t i;
+int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
+    int i;
+    void *data;
     
-    pcilib_model_t model = pcilib_get_model(ctx);
-    pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
-
-    assert(bits < 8 * sizeof(pcilib_register_value_t));
-
-    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
-	pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
-	return PCILIB_ERROR_OUTOFRANGE;
-    }
+    pcilib_detect_address(ctx, &bar, &addr, fifo_size);
+    data = pcilib_map_bar(ctx, bar);
 
-    err = pcilib_map_register_space(ctx);
-    if (err) {
-	pcilib_error("Failed to map the register space");
-	return err;
-    }
-    
-    //n += bits / b->access;
-    //bits %= b->access; 
-    
     for (i = 0; i < n; i++) {
-	err = pcilib_protocol[b->protocol].write(ctx, b, addr + i, b->access, buf[i]);
-	if (err) break;
-    }
-    
-    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].write(ctx, b, addr + n, bits, buf[n]);
-    
-    return err;
-}
-
-int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
-    pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
-    if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
-	if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
-	else pcilib_error("Register bank should be specified");
-	return PCILIB_ERROR_INVALID_BANK;
-    }
-    
-    return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, buf);
-}
-
-
-int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) {
-    int err;
-    size_t i, n, bits;
-    pcilib_register_value_t res;
-    pcilib_register_description_t *r;
-    pcilib_register_bank_description_t *b;
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    r = pcilib_model[model].registers + reg;
-    b = pcilib_model[model].banks + r->bank;
-    
-    n = r->bits / b->access;
-    bits = r->bits % b->access; 
-
-    pcilib_register_value_t buf[n + 1];
-    memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t));
-    
-    if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
-	pcilib_error("Big-endian byte order support is not implemented");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    } else {
-	if (b->access == sizeof(pcilib_register_value_t) * 8) {
-	    buf[0] = value;
-	} else {
-	    for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
-		buf[i] = res & BIT_MASK(b->access);
-	        res >>= b->access;
-	    }
-	
-	    if (res) {
-		pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
-		return PCILIB_ERROR_OUTOFRANGE;
-	    }
-	}
-    }
-
-    err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
-    return err;
-}
-
-int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) {
-    int err;
-    int reg;
-    
-    reg = pcilib_find_register(ctx, bank, regname);
-    if (reg < 0) {
-	pcilib_error("Register (%s) is not found", regname);
-	return PCILIB_ERROR_NOTFOUND;
-    }
-
-    return pcilib_write_register_by_id(ctx, reg, value);
-}
-
-
-int pcilib_reset(pcilib_t *ctx) {
-    pcilib_event_api_description_t *api;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    api = pcilib_model[model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    }
-    
-    if (api->reset) 
-	return api->reset(ctx->event_ctx);
-	
-    return 0;
-}
-
-int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, void *callback, void *user) {
-    pcilib_event_api_description_t *api;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    api = pcilib_model[model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    }
-
-    if (api->start) 
-	return api->start(ctx->event_ctx, event_mask, callback, user);
-
-    return 0;
-}
-
-int pcilib_stop(pcilib_t *ctx) {
-    pcilib_event_api_description_t *api;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    api = pcilib_model[model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    }
-
-    if (api->stop) 
-	return api->stop(ctx->event_ctx);
-
-    return 0;
-}
-
-pcilib_event_id_t pcilib_get_next_event(pcilib_t *ctx, pcilib_event_t event_mask, const struct timespec *timeout) {
-    pcilib_event_api_description_t *api;
-    
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    api = pcilib_model[model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
+	pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size);
     }
-
-    if (api->next_event) 
-	return api->next_event(ctx->event_ctx, event_mask, timeout);
-
-    pcilib_error("Event enumeration is not suppored by API");
-    return PCILIB_EVENT_ID_INVALID;
-}
-
-int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) {
-    pcilib_event_api_description_t *api;
     
-    pcilib_model_t model = pcilib_get_model(ctx);
-
-    api = pcilib_model[model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    }
-
-    if (api->trigger) 
-	return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data);
-
-    pcilib_error("Self triggering is not supported by the selected model");
-    return PCILIB_ERROR_NOTSUPPORTED;
-}
-
-
-void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) {
-    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return NULL;
-    }
-
-    if (api->get_data) 
-	return api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size);
-
-    return NULL;
-}
-
-void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) {
-    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return NULL;
-    }
-
-    if (api->get_data) 
-	return api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size);
-
-    return NULL;
-}
-
-int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id) {
-    pcilib_event_api_description_t *api = pcilib_model[ctx->model].event_api;
-    if (!api) {
-	pcilib_error("Event API is not supported by the selected model");
-	return PCILIB_ERROR_NOTSUPPORTED;
-    }
-
-    if (api->return_data) 
-	return api->return_data(ctx->event_ctx, event_id);
-
-    return 0;
+    pcilib_unmap_bar(ctx, bar, data);    
 }
 
-
-typedef struct {
-    pcilib_t *ctx;
-    
-    size_t *size;
-    void **data;
-} pcilib_grab_callback_user_data_t;
-
-static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) {
-    int err;
+int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) {
+    int i;
     void *data;
-    size_t size;
-    int allocated = 0;
 
-    pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser;
+    pcilib_detect_address(ctx, &bar, &addr, fifo_size);
+    data = pcilib_map_bar(ctx, bar);
 
-    data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size);
-    if (!data) {
-	pcilib_error("Error getting event data");
-	return PCILIB_ERROR_FAILED;
+    for (i = 0; i < n; i++) {
+	pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size);
     }
-    
-    if (*(user->data)) {
-	if ((user->size)&&(*(user->size) < size)) {
-	    pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size);
-	    return PCILIB_ERROR_MEMORY;
-	}
 
-	*(user->size) = size;
-    } else {
-	*(user->data) = malloc(size);
-	if (!*(user->data)) {
-	    pcilib_error("Memory allocation (%i bytes) for event data is failed");
-	    return PCILIB_ERROR_MEMORY;
-	}
-	if (*(user->size)) *(user->size) = size;
-	allocated = 1;
-    }
-    
-    memcpy(*(user->data), data, size);
-    
-    err = pcilib_return_data(user->ctx, event_id);
-    if (err) {
-	if (allocated) {
-	    free(*(user->data));
-	    *(user->data) = NULL;
-	}
-	pcilib_error("The event data had been overwritten before it was returned, data corruption may occur");
-	return err;
-    }
-    
-    return 0;
+    pcilib_unmap_bar(ctx, bar, data);    
 }
 
-int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, const struct timespec *timeout) {
-    int err;
-    
-    pcilib_grab_callback_user_data_t user = {ctx, size, data};
-    
-    err = pcilib_start(ctx, event_mask, pcilib_grab_callback, &user);
-    if (!err) {
-	if (timeout) nanosleep(timeout, NULL);
-        else err = pcilib_trigger(ctx, event_mask, 0, NULL);
-    }
-    pcilib_stop(ctx);
-    return 0;
-}

+ 3 - 0
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;

+ 9 - 22
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);
 

+ 280 - 0
register.c

@@ -0,0 +1,280 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "pci.h"
+
+#include "tools.h"
+#include "error.h"
+
+pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
+    pcilib_register_bank_t i;
+    pcilib_model_t model = pcilib_get_model(ctx);
+    pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
+
+    for (i = 0; banks[i].access; i++)
+	if (banks[i].addr == bank) return i;
+	
+    return -1;
+}
+
+pcilib_register_bank_t pcilib_find_bank_by_name(pcilib_t *ctx, const char *bankname) {
+    pcilib_register_bank_t i;
+    pcilib_register_bank_description_t *banks = pcilib_model[ctx->model].banks;
+
+    for (i = 0; banks[i].access; i++)
+	if (!strcasecmp(banks[i].name, bankname)) return i;
+	
+    return -1;
+}
+
+pcilib_register_bank_t pcilib_find_bank(pcilib_t *ctx, const char *bank) {
+    pcilib_register_bank_t res;
+    unsigned long addr;
+    
+    if (!bank) {
+	pcilib_model_t model = pcilib_get_model(ctx);
+	pcilib_register_bank_description_t *banks = pcilib_model[model].banks;
+	if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0;
+	return -1;
+    }
+    
+    if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) {
+	res = pcilib_find_bank_by_addr(ctx, addr);
+	if (res != PCILIB_REGISTER_BANK_INVALID) return res;
+    }
+    
+    return pcilib_find_bank_by_name(ctx, bank);
+}
+
+    // FIXME create hash during map_register space
+pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) {
+    pcilib_register_t i;
+    pcilib_register_bank_t bank_id;
+    pcilib_register_bank_addr_t bank_addr;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+    
+    pcilib_register_description_t *registers =  pcilib_model[model].registers;
+    
+    if (bank) {
+	bank_id = pcilib_find_bank(ctx, bank);
+	if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+	    pcilib_error("Invalid bank (%s) is specified", bank);
+	    return -1;
+	}
+	
+	bank_addr = pcilib_model[model].banks[bank_id].addr;
+    }
+    
+    for (i = 0; registers[i].bits; i++) {
+	if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i;
+    }
+    
+    return (pcilib_register_t)-1;
+};
+
+static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
+    int err;
+    int rest;
+    size_t i;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+    pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
+
+    assert(bits < 8 * sizeof(pcilib_register_value_t));
+    
+    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+	pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	return PCILIB_ERROR_OUTOFRANGE;
+    }
+
+    err = pcilib_map_register_space(ctx);
+    if (err) {
+	pcilib_error("Failed to map the register space");
+	return err;
+    }
+    
+    //n += bits / b->access;
+    //bits %= b->access; 
+    
+    for (i = 0; i < n; i++) {
+	err = pcilib_protocol[b->protocol].read(ctx, b, addr + i, b->access, buf + i);
+	if (err) break;
+    }
+    
+    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].read(ctx, b, addr + n, bits, buf + n);
+    
+    return err;
+}
+
+int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
+    pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
+    if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+	if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
+	else pcilib_error("Register bank should be specified");
+	return PCILIB_ERROR_INVALID_BANK;
+    }
+    
+    return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+}
+
+int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) {
+    int err;
+    size_t i, n, bits;
+    pcilib_register_value_t res;
+    pcilib_register_description_t *r;
+    pcilib_register_bank_description_t *b;
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    r = pcilib_model[model].registers + reg;
+    b = pcilib_model[model].banks + r->bank;
+    
+    n = r->bits / b->access;
+    bits = r->bits % b->access; 
+
+    pcilib_register_value_t buf[n + 1];
+    err = pcilib_read_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
+
+    if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
+	pcilib_error("Big-endian byte order support is not implemented");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    } else {
+	res = 0;
+	if (bits) ++n;
+	for (i = 0; i < n; i++) {
+	    res |= buf[i] << (i * b->access);
+	}
+    }
+    
+    *value = res;
+    
+    return err;
+}
+
+
+int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) {
+    int err;
+    int reg;
+    
+    reg = pcilib_find_register(ctx, bank, regname);
+    if (reg < 0) {
+	pcilib_error("Register (%s) is not found", regname);
+	return PCILIB_ERROR_NOTFOUND;
+    }
+    
+    return pcilib_read_register_by_id(ctx, reg, value);
+
+//    registers[reg].bank
+//    printf("%li %li", sizeof(pcilib_model[model].banks), sizeof(pcilib_register_bank_description_t));
+}
+
+
+static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, uint8_t bits, pcilib_register_value_t *buf) {
+    int err;
+    int rest;
+    size_t i;
+    
+    pcilib_model_t model = pcilib_get_model(ctx);
+    pcilib_register_bank_description_t *b = pcilib_model[model].banks + bank;
+
+    assert(bits < 8 * sizeof(pcilib_register_value_t));
+
+    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+	pcilib_error("Accessing sregister (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	return PCILIB_ERROR_OUTOFRANGE;
+    }
+
+    err = pcilib_map_register_space(ctx);
+    if (err) {
+	pcilib_error("Failed to map the register space");
+	return err;
+    }
+    
+    //n += bits / b->access;
+    //bits %= b->access; 
+    
+    for (i = 0; i < n; i++) {
+	err = pcilib_protocol[b->protocol].write(ctx, b, addr + i, b->access, buf[i]);
+	if (err) break;
+    }
+    
+    if ((bits > 0)&&(!err)) err = pcilib_protocol[b->protocol].write(ctx, b, addr + n, bits, buf[n]);
+    
+    return err;
+}
+
+int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) {
+    pcilib_register_bank_t bank_id = pcilib_find_bank(ctx, bank);
+    if (bank_id == PCILIB_REGISTER_BANK_INVALID) {
+	if (bank) pcilib_error("Invalid register bank is specified (%s)", bank);
+	else pcilib_error("Register bank should be specified");
+	return PCILIB_ERROR_INVALID_BANK;
+    }
+    
+    return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, buf);
+}
+
+
+int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) {
+    int err;
+    size_t i, n, bits;
+    pcilib_register_value_t res;
+    pcilib_register_description_t *r;
+    pcilib_register_bank_description_t *b;
+    pcilib_model_t model = pcilib_get_model(ctx);
+
+    r = pcilib_model[model].registers + reg;
+    b = pcilib_model[model].banks + r->bank;
+    
+    n = r->bits / b->access;
+    bits = r->bits % b->access; 
+
+    pcilib_register_value_t buf[n + 1];
+    memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t));
+    
+    if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) {
+	pcilib_error("Big-endian byte order support is not implemented");
+	return PCILIB_ERROR_NOTSUPPORTED;
+    } else {
+	if (b->access == sizeof(pcilib_register_value_t) * 8) {
+	    buf[0] = value;
+	} else {
+	    for (i = 0, res = value; (res > 0)&&(i <= n); ++i) {
+		buf[i] = res & BIT_MASK(b->access);
+	        res >>= b->access;
+	    }
+	
+	    if (res) {
+		pcilib_error("Value %i is too big to fit in the register %s", value, r->name);
+		return PCILIB_ERROR_OUTOFRANGE;
+	    }
+	}
+    }
+
+    err = pcilib_write_register_space_internal(ctx, r->bank, r->addr, n, bits, buf);
+    return err;
+}
+
+int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) {
+    int err;
+    int reg;
+    
+    reg = pcilib_find_register(ctx, bank, regname);
+    if (reg < 0) {
+	pcilib_error("Register (%s) is not found", regname);
+	return PCILIB_ERROR_NOTFOUND;
+    }
+
+    return pcilib_write_register_by_id(ctx, reg, value);
+}

+ 11 - 0
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 */

+ 2 - 0
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);