Переглянути джерело

Suppport DMA modes in console application (not functional yet)

Suren A. Chilingaryan 13 роки тому
батько
коміт
de984f8b97
12 змінених файлів з 233 додано та 33 видалено
  1. 6 0
      ToDo
  2. 151 9
      cli.c
  3. 16 3
      dma.c
  4. 8 2
      dma.h
  5. 2 2
      dma/nwl.c
  6. 6 5
      dma/nwl.h
  7. 3 3
      dma/nwl_buffers.h
  8. 6 2
      dma/nwl_dma.h
  9. 1 1
      irq.c
  10. 14 6
      pcilib.h
  11. 18 0
      tools.c
  12. 2 0
      tools.h

+ 6 - 0
ToDo

@@ -1,3 +1,9 @@
+1. Read registers from XML description. It also makes sense to provide
+   formal XML-based language for DMA implementation. 
+   a) Writting/Reading register values
+   b) Wait until <register1>=<value> on <register2>=<value> report error
+   c) ... ?
 2. Hint for register value representation in the bank (hex, decimal)
 3. Implement software registers
 4. Support FIFO reads/writes from/to registers
+5. Provide OR and AND operations on registers in cli

+ 151 - 9
cli.c

@@ -20,6 +20,7 @@
 //#include "pci.h"
 #include "tools.h"
 #include "kernel.h"
+#include "error.h"
 
 /* defines */
 #define MAX_KBUF 14
@@ -37,7 +38,8 @@
 
 #define isnumber pcilib_isnumber
 #define isxnumber pcilib_isxnumber
-
+#define isnumber_n pcilib_isnumber_n
+#define isxnumber_n pcilib_isxnumber_n
 
 typedef uint8_t access_t;
 
@@ -51,7 +53,10 @@ typedef enum {
     MODE_WRITE,
     MODE_WRITE_REGISTER,
     MODE_RESET,
-    MODE_GRAB
+    MODE_GRAB,
+    MODE_START_DMA,
+    MODE_STOP_DMA,
+    MODE_WAIT_IRQ
 } MODE;
 
 typedef enum {
@@ -68,6 +73,7 @@ typedef enum {
     OPT_ENDIANESS = 'e',
     OPT_SIZE = 's',
     OPT_OUTPUT = 'o',
+    OPT_TIMEOUT = 't',
     OPT_INFO = 'i',
     OPT_BENCHMARK = 'p',
     OPT_LIST = 'l',
@@ -76,6 +82,9 @@ typedef enum {
     OPT_GRAB = 'g',
     OPT_QUIETE = 'q',
     OPT_RESET = 128,
+    OPT_START_DMA = 129,
+    OPT_STOP_DMA = 130,
+    OPT_WAIT_IRQ = 131,
     OPT_HELP = 'h',
 } OPTIONS;
 
@@ -87,6 +96,7 @@ static struct option long_options[] = {
     {"endianess",		required_argument, 0, OPT_ENDIANESS },
     {"size",			required_argument, 0, OPT_SIZE },
     {"output",			required_argument, 0, OPT_OUTPUT },
+    {"timeout",			required_argument, 0, OPT_TIMEOUT },
     {"info",			no_argument, 0, OPT_INFO },
     {"list",			no_argument, 0, OPT_LIST },
     {"reset",			no_argument, 0, OPT_RESET },
@@ -94,6 +104,9 @@ static struct option long_options[] = {
     {"read",			optional_argument, 0, OPT_READ },
     {"write",			optional_argument, 0, OPT_WRITE },
     {"grab",			optional_argument, 0, OPT_GRAB },
+    {"start-dma",		required_argument, 0, OPT_START_DMA },
+    {"stop-dma",		optional_argument, 0, OPT_STOP_DMA },
+    {"wait-irq",		optional_argument, 0, OPT_WAIT_IRQ },
     {"quiete",			no_argument, 0, OPT_QUIETE },
     {"help",			no_argument, 0, OPT_HELP },
     { 0, 0, 0, 0 }
@@ -128,8 +141,8 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	--help			- Help message\n"
 "\n"
 "  DMA Modes:\n"
-"	--start-dma <num>	- Start specified DMA engine\n"
-"	--stop-dma [num]	- Stop specified engine or DMA subsystem\n"
+"	--start-dma <num>[r|w]	- Start specified DMA engine\n"
+"	--stop-dma [num][r|w]	- Stop specified engine or DMA subsystem\n"
 "	--wait-irq <source>	- Wait for IRQ\n"
 "\n"
 "  Addressing:\n"
@@ -144,7 +157,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
 "	-a [fifo|dma]<bits>	- Access type and bits per word (default: 32)\n"
 "	-e <l|b>		- Endianess Little/Big (default: host)\n"
 "	-o <file>		- Output to file (default: stdout)\n"
-//"	-t <timeout>		- Timeout in microseconds\n"
+"	-t <timeout>		- Timeout in microseconds\n"
 "\n"
 "  Information:\n"
 "	-q 			- Quiete mode (suppress warnings)\n"
@@ -547,7 +560,7 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, p
     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);
+	if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
 	err = pcilib_read_dma(handle, dmaid, addr, size, buf, &ret);
 	if ((err)||(ret <= 0)) Error("No data is returned by DMA engine");
 	size = ret;
@@ -722,7 +735,7 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma,
     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);
+	if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
 	err = pcilib_write_dma(handle, dmaid, addr, size, buf, &ret);
 	if ((err)||(ret != size)) {
 	    if (!ret) Error("No data is written by DMA engine");
@@ -845,12 +858,73 @@ int Grab(pcilib_t *handle, const char *event, const char *output) {
     return 0;
 }
 
+
+int StartStopDMA(pcilib_t *handle,  pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, int start) {
+    int err;
+    pcilib_dma_engine_t dmaid;
+    
+    if (dma_direction&PCILIB_DMA_FROM_DEVICE) {
+        if (dma == PCILIB_DMA_ENGINE_ADDR_INVALID) {
+	    if (start) Error("DMA engine should be specified");
+	    dmaid = PCILIB_DMA_ENGINE_INVALID;
+	} else {
+	    dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
+	    if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (C2S %lu) is specified", dma);
+	}
+	
+	if (start) {
+	    err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERMANENT);
+    	    if (err) Error("Error starting DMA engine (C2S %lu)", dma);
+	} else {
+	    err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERMANENT);
+    	    if (err) Error("Error stopping DMA engine (C2S %lu)", dma);
+	}
+    }
+
+    if (dma_direction&PCILIB_DMA_TO_DEVICE) {
+        if (dma == PCILIB_DMA_ENGINE_ADDR_INVALID) {
+	    if (start) Error("DMA engine should be specified");
+	    dmaid = PCILIB_DMA_ENGINE_INVALID;
+	} else {
+	    dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma);
+	    if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (S2C %lu) is specified", dma);
+	}
+	
+	if (start) {
+	    err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERMANENT);
+    	    if (err) Error("Error starting DMA engine (S2C %lu)", dma);
+	} else {
+	    err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERMANENT);
+    	    if (err) Error("Error stopping DMA engine (S2C %lu)", dma);
+	}
+    }
+
+    return 0;
+}
+
+int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_source_t irq_source, pcilib_timeout_t timeout) {
+    int err;
+    size_t count;
+    
+    err = pcilib_enable_irq(handle, 0);
+    if (err) Error("Error enabling IRQs");
+
+    err = pcilib_wait_irq(handle, irq_source, timeout, &count);
+    if (err) {
+	if (err == PCILIB_ERROR_TIMEOUT) Error("Timeout waiting for IRQ");
+	else Error("Error waiting for IRQ");
+    }
+
+    return 0;
+}
+
+
 int main(int argc, char **argv) {
     int i;
     long itmp;
     unsigned char c;
 
-    char *num_offset;
+    const char *num_offset;
 
     int details = 0;
     int quiete = 0;
@@ -867,13 +941,17 @@ int main(int argc, char **argv) {
     const char *bank = NULL;
     char **data = NULL;
     const char *event = NULL;
+    const char *dma_channel = NULL;
+    pcilib_irq_source_t irq_source;
+    pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL;
     
-    pcilib_dma_engine_addr_t dma;
+    pcilib_dma_engine_addr_t dma = PCILIB_DMA_ENGINE_ADDR_INVALID;
     uintptr_t start = -1;
     size_t size = 1;
     access_t access = 4;
     int skip = 0;
     int endianess = 0;
+    size_t timeout = 0;
     const char *output = NULL;
 
     pcilib_t *handle;
@@ -932,6 +1010,32 @@ int main(int argc, char **argv) {
 		if (optarg) event = optarg;
 		else if ((optind < argc)&&(argv[optind][0] != '-')) event = argv[optind++];
 	    break;
+	    case OPT_START_DMA:
+		if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+		
+		mode = MODE_START_DMA;
+		if (optarg) dma_channel = optarg;
+		else if ((optind < argc)&&(argv[optind][0] != '-')) dma_channel = argv[optind++];
+	    break;
+	    case OPT_STOP_DMA:
+		if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+		
+		mode = MODE_STOP_DMA;
+		if (optarg) dma_channel = optarg;
+		else if ((optind < argc)&&(argv[optind][0] != '-')) dma_channel = argv[optind++];
+	    break;
+	    case OPT_WAIT_IRQ:
+		if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+		
+		mode = MODE_WAIT_IRQ;
+		if (optarg) num_offset = optarg;
+		else if ((optind < argc)&&(argv[optind][0] != '-'))  num_offset = argv[optind++];
+		
+		if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1))
+		    Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset);
+
+		irq_source = itmp;
+	    break;
 	    case OPT_DEVICE:
 		fpga_device = optarg;
 	    break;
@@ -994,6 +1098,10 @@ int main(int argc, char **argv) {
 		} else Usage(argc, argv, "Invalid endianess is specified (%s)", optarg);
 		
 	    break;
+	    case OPT_TIMEOUT:
+		if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1))
+		    Usage(argc, argv, "Invalid timeout is specified (%s)", optarg);
+	    break;
 	    case OPT_OUTPUT:
 		output = optarg;
 	    break;
@@ -1050,6 +1158,31 @@ int main(int argc, char **argv) {
 	    } else ++mode;
 	}
      break;
+     case MODE_START_DMA:
+     case MODE_STOP_DMA:
+        if ((dma_channel)&&(*dma_channel)) {
+	    itmp = strlen(dma_channel) - 1;
+	    if (dma_channel[itmp] == 'r') dma_direction = PCILIB_DMA_FROM_DEVICE;
+	    else if (dma_channel[itmp] == 'w') dma_direction = PCILIB_DMA_TO_DEVICE;
+
+	    if (dma_direction != PCILIB_DMA_BIDIRECTIONAL) itmp--;
+	    
+	    if (strncmp(dma_channel, "dma", 3)) num_offset = dma_channel;
+	    else {
+		num_offset = dma_channel + 3;
+		itmp -= 3;
+	    }
+	    
+	    if (bank) {
+		if (strncmp(num_offset, bank, itmp)) Usage(argc, argv, "Conflicting DMA channels are specified in mode parameter (%s) and bank parameter (%s)", dma_channel, bank);
+	    }
+		 
+	    if (!isnumber_n(num_offset, itmp))
+		 Usage(argc, argv, "Invalid DMA channel (%s) is specified", dma_channel);
+
+	    dma = atoi(num_offset);
+	}
+     break;
      default:
         if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied");
     }
@@ -1146,6 +1279,15 @@ int main(int argc, char **argv) {
      case MODE_GRAB:
         Grab(handle, event, output);
      break;
+     case MODE_START_DMA:
+        StartStopDMA(handle, model_info, dma, dma_direction, 1);
+     break;
+     case MODE_STOP_DMA:
+        StartStopDMA(handle, model_info, dma, dma_direction, 0);
+     break;
+     case MODE_WAIT_IRQ:
+        WaitIRQ(handle, model_info, irq_source, timeout);
+     break;
     }
 
     pcilib_close(handle);

+ 16 - 3
dma.c

@@ -47,13 +47,26 @@ pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_
     }
     
     if (info->engines[i]) return i;
-    return PCILIB_DMA_INVALID;
+    return PCILIB_DMA_ENGINE_INVALID;
 }
 
 int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) {
     ctx->dma_info.engines[engine] = desc;
 }
 
+int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+}
+
+int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+}
+
+int pcilib_enable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
+}
+
+int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) {
+}
+
+
 typedef struct {
     size_t size;
     void *data;
@@ -79,7 +92,7 @@ static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t
     return 1;
 }
 
-int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
+int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
     int err; 
 
     const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);
@@ -135,7 +148,7 @@ int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) {
 }
 
 
-int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *buf, size_t *written) {
+int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) {
     int err; 
 
     const pcilib_dma_info_t *info =  pcilib_get_dma_info(ctx);

+ 8 - 2
dma.h

@@ -7,8 +7,14 @@ struct pcilib_dma_api_description_s {
     pcilib_dma_context_t *(*init)(pcilib_t *ctx);
     void (*free)(pcilib_dma_context_t *ctx);
 
-    int (*push)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *buf, size_t *written);
-    int (*stream)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr);
+    int (*pcilib_start_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+    int (*pcilib_stop_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+
+    int (*pcilib_enable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags);
+    int (*pcilib_disable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags);
+
+    int (*push)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written);
+    int (*stream)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr);
 
     double (*benchmark)(pcilib_dma_context_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
 };

+ 2 - 2
dma/nwl.c

@@ -341,7 +341,7 @@ int dma_nwl_sync_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info,
 
 #include "nwl_buffers.h"    
 
-int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *data, size_t *written) {
+int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written) {
     int err;
     size_t pos;
     size_t bufnum;
@@ -383,7 +383,7 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma,
     return 0;
 }
 
-int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
+int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) {
     int err, ret;
     size_t res = 0;
     size_t bufnum;

+ 6 - 5
dma/nwl.h

@@ -17,8 +17,9 @@ typedef struct {
     pcilib_kmem_handle_t *ring;
     pcilib_kmem_handle_t *pages;
     
-    int started;			// indicates if DMA buffers are initialized and reading is allowed
-    int writting;			// indicates if we are in middle of writting packet
+    int started;			/**< indicates that DMA buffers are initialized and reading is allowed */
+    int writting;			/**< indicates that we are in middle of writting packet */
+    int preserve;			/**< indicates that DMA should not be stopped during clean-up */
 } pcilib_nwl_engine_description_t;
 
 
@@ -28,9 +29,9 @@ struct nwl_dma_s {
     pcilib_register_bank_description_t *dma_bank;
     char *base_addr;
     
-    pcilib_irq_type_t irq_enabled;
-
-    int started;
+    pcilib_irq_type_t irq_enabled;	/**< indicates that IRQs are enabled */
+    int irq_preserve;			/**< indicates that IRQs should not be disabled during clean-up */
+    int started;			/**< indicates that DMA subsystem is initialized and DMA engine can start */
     
     pcilib_dma_engine_t n_engines;
     pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];

+ 3 - 3
dma/nwl_buffers.h

@@ -102,7 +102,7 @@ next_buffer:
 }
 
 
-static size_t dma_nwl_get_next_buffer(nwl_dma_t * ctx, pcilib_nwl_engine_description_t *info, size_t n_buffers, size_t timeout) {
+static size_t dma_nwl_get_next_buffer(nwl_dma_t * ctx, pcilib_nwl_engine_description_t *info, size_t n_buffers, pcilib_timeout_t timeout) {
     struct timeval start, cur;
 
     size_t res, n = 0;
@@ -139,7 +139,7 @@ static size_t dma_nwl_get_next_buffer(nwl_dma_t * ctx, pcilib_nwl_engine_descrip
     return info->head;
 }
 
-static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t size, int eop, size_t timeout) {
+static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t size, int eop, pcilib_timeout_t timeout) {
     int flags;
     
     uint32_t val;
@@ -178,7 +178,7 @@ static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *
 }
 
 
-static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t *size, int *eop, size_t timeout) {
+static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, size_t *size, int *eop, pcilib_timeout_t timeout) {
     uint32_t val;
     struct timeval start, cur;
     uint32_t status_size, status, control;

+ 6 - 2
dma/nwl_dma.h

@@ -11,8 +11,8 @@ typedef struct nwl_dma_s nwl_dma_t;
 pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx);
 void  dma_nwl_free(pcilib_dma_context_t *vctx);
 
-int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *data, size_t *written);
-int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr);
+int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written);
+int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr);
 double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
 
 
@@ -20,6 +20,10 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
 pcilib_dma_api_description_t nwl_dma_api = {
     dma_nwl_init,
     dma_nwl_free,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
     dma_nwl_write_fragment,
     dma_nwl_stream_read,
     dma_nwl_benchmark

+ 1 - 1
irq.c

@@ -17,7 +17,7 @@
 #include "tools.h"
 #include "error.h"
 
-int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, size_t timeout, size_t *count) {
+int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, pcilib_timeout_t timeout, size_t *count) {
     int err;
     
     interrupt_wait_t arg = { 0 };

+ 14 - 6
pcilib.h

@@ -37,6 +37,7 @@ typedef uint8_t pcilib_dma_engine_addr_t;
 typedef uint8_t pcilib_dma_engine_t;
 typedef uint64_t pcilib_event_id_t;
 typedef uint32_t pcilib_event_t;
+typedef uint64_t pcilib_timeout_t;
 
 typedef enum {
     PCILIB_HOST_ENDIAN = 0,
@@ -70,7 +71,8 @@ typedef enum {
 typedef enum {
     PCILIB_DMA_FLAGS_DEFAULT = 0,
     PCILIB_DMA_FLAG_EOP = 1,
-    PCILIB_DMA_FLAG_WAIT = 2
+    PCILIB_DMA_FLAG_WAIT = 2,
+    PCILIB_DMA_FLAG_PERMANENT = 4
 } pcilib_dma_flags_t;
 
 typedef enum {
@@ -83,7 +85,8 @@ typedef enum {
 #define PCILIB_BAR_INVALID		((pcilib_bar_t)-1)
 #define PCILIB_BAR0			0
 #define PCILIB_BAR1			1
-#define PCILIB_DMA_INVALID		((pcilib_dma_engine_t)-1)
+#define PCILIB_DMA_ENGINE_INVALID	((pcilib_dma_engine_t)-1)
+#define PCILIB_DMA_ENGINE_ADDR_INVALID	((pcilib_dma_engine_addr_t)-1)
 #define PCILIB_REGISTER_INVALID		((pcilib_register_t)-1)
 #define PCILIB_ADDRESS_INVALID		((uintptr_t)-1)
 #define PCILIB_REGISTER_BANK_INVALID	((pcilib_register_bank_t)-1)
@@ -99,7 +102,7 @@ typedef enum {
 #define PCILIB_EVENTS_ALL		((pcilib_event_t)-1)
 #define PCILIB_EVENT_INVALID		((pcilib_event_t)-1)
 #define PCILIB_EVENT_ID_INVALID		0
-#define PCILIB_TIMEOUT_INFINITE		((size_t)-1)
+#define PCILIB_TIMEOUT_INFINITE		((pcilib_timeout_t)-1)
 #define PCILIB_TIMEOUT_IMMEDIATE	0
 
 typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf);
@@ -199,8 +202,13 @@ pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx);
 pcilib_t *pcilib_open(const char *device, pcilib_model_t model);
 void pcilib_close(pcilib_t *ctx);
 
+int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+int pcilib_enable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags);
+int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags);
+
 int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_source_t source);
-int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, size_t timeout, size_t *count);
+int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, pcilib_timeout_t timeout, size_t *count);
 
 void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar);
 void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data);
@@ -220,8 +228,8 @@ int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t f
 int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf);
 
 int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma);
-int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, pcilib_dma_callback_t cb, void *cbattr);
-int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, size_t timeout, void *buf, size_t *written_bytes);
+int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr);
+int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written_bytes);
 int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes);
 int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes);
 double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);

+ 18 - 0
tools.c

@@ -26,6 +26,24 @@ int pcilib_isxnumber(const char *str) {
     return 1;
 }
 
+int pcilib_isnumber_n(const char *str, size_t len) {
+    int i = 0;
+    for (i = 0; (str[i])&&(i < len); i++) 
+	if (!isdigit(str[i])) return 0;
+    return 1;
+}
+
+int pcilib_isxnumber_n(const char *str, size_t len) {
+    int i = 0;
+    
+    if ((len > 1)&&(str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) i += 2;
+    
+    for (; (str[i])&&(i < len); i++) 
+	if (!isxdigit(str[i])) return 0;
+
+    return 1;
+}
+
 
 uint16_t pcilib_swap16(uint16_t x) {
     return (((x<<8)&0xFFFF) | ((x>>8)&0xFFFF));

+ 2 - 0
tools.h

@@ -12,6 +12,8 @@
 
 int pcilib_isnumber(const char *str);
 int pcilib_isxnumber(const char *str);
+int pcilib_isnumber_n(const char *str, size_t len);
+int pcilib_isxnumber_n(const char *str, size_t len);
 
 uint16_t pcilib_swap16(uint16_t x);
 uint32_t pcilib_swap32(uint32_t x);