summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--driver/ioctl.c58
-rw-r--r--driver/pciDriver.h50
-rw-r--r--pcilib/pci.c49
-rw-r--r--pcilib/pci.h5
-rw-r--r--pcitool/cli.c93
5 files changed, 234 insertions, 21 deletions
diff --git a/driver/ioctl.c b/driver/ioctl.c
index a78d366..e003476 100644
--- a/driver/ioctl.c
+++ b/driver/ioctl.c
@@ -28,6 +28,9 @@
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/sched.h>
+#include <linux/iommu.h>
+
+#include "../pcilib/version.h"
#include "config.h" /* Configuration for the driver */
#include "compat.h" /* Compatibility functions/definitions */
@@ -409,6 +412,53 @@ static int ioctl_clear_ioq(pcidriver_privdata_t *privdata, unsigned long arg)
/**
*
+ * Gets the device and API versions.
+ *
+ * @see pcilib_driver_version_t
+ *
+ */
+static int ioctl_version(pcidriver_privdata_t *privdata, unsigned long arg)
+{
+ int ret;
+ pcilib_driver_version_t info;
+
+ info = (pcilib_driver_version_t) {
+ .version = PCILIB_VERSION,
+ .interface = PCIDRIVER_INTERFACE_VERSION,
+ .ioctls = PCIDRIVER_IOC_MAX + 1
+ };
+
+ WRITE_TO_USER(pcilib_driver_version_t, info);
+
+ return 0;
+}
+
+
+/**
+ *
+ * Gets current device and driver configuration
+ *
+ * @see pcilib_device_state_t
+ *
+ */
+static int ioctl_device_state(pcidriver_privdata_t *privdata, unsigned long arg)
+{
+ int ret;
+ pcilib_device_state_t info;
+
+ info = (pcilib_device_state_t) {
+ .iommu = iommu_present(privdata->pdev->dev.bus),
+ .dma_mask = privdata->pdev->dma_mask
+ };
+
+ WRITE_TO_USER(pcilib_device_state_t, info);
+
+ return 0;
+}
+
+
+/**
+ *
* Sets DMA mask for the following DMA mappings.
*
* @param arg Not a pointer, but a number of bits
@@ -491,8 +541,14 @@ long pcidriver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
case PCIDRIVER_IOC_CLEAR_IOQ:
return ioctl_clear_ioq(privdata, arg);
+
+ case PCIDRIVER_IOC_VERSION:
+ return ioctl_version(privdata, arg);
+
+ case PCIDRIVER_IOC_DEVICE_STATE:
+ return ioctl_device_state(privdata, arg);
- case PCIDRIVER_IOC_SET_DMA_MASK:
+ case PCIDRIVER_IOC_DMA_MASK:
return ioctl_set_dma_mask(privdata, arg);
default:
diff --git a/driver/pciDriver.h b/driver/pciDriver.h
index 845fc15..d314952 100644
--- a/driver/pciDriver.h
+++ b/driver/pciDriver.h
@@ -58,6 +58,8 @@
#include <linux/ioctl.h>
+#define PCIDRIVER_INTERFACE_VERSION 1 /**< Driver API version, only the pcilib with the same driver interface version is allowed */
+
/* Identifies the PCI-E Xilinx ML605 */
#define PCIE_XILINX_VENDOR_ID 0x10ee
#define PCIE_ML605_DEVICE_ID 0x6024
@@ -119,6 +121,19 @@
#define KMEM_FLAG_REUSED_HW PCILIB_KMEM_FLAG_HARDWARE /**< Indicates that reused buffer had a HW reference before the call */
/* Types */
+
+typedef struct {
+ unsigned long version; /**< pcilib version */
+ unsigned long interface; /**< driver interface version */
+ unsigned long ioctls; /**< number of supporterd ioctls */
+ unsigned long reserved[5]; /**< reserved for the future use */
+} pcilib_driver_version_t;
+
+typedef struct {
+ unsigned long iommu;
+ unsigned long dma_mask;
+} pcilib_device_state_t;
+
typedef struct {
unsigned short vendor_id;
unsigned short device_id;
@@ -193,31 +208,34 @@ typedef struct {
* This type is only 8-bits wide, and half-documented in
* <linux-src>/Documentation/ioctl-number.txt.
* previous SHL -> 'S' definition, conflicts with several devices,
- * so I changed it to be pci -> 'p', in the range 0xA0-AF
+ * so I changed it to be pci -> 'p', in the range 0xA0-BF
*/
#define PCIDRIVER_IOC_MAGIC 'p'
#define PCIDRIVER_IOC_BASE 0xA0
-#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 )
-#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 )
-#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * )
-#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * )
-#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * )
-#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * )
-#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * )
-#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * )
-#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * )
-#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 )
+#define PCIDRIVER_IOC_MMAP_MODE _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 0 )
+#define PCIDRIVER_IOC_MMAP_AREA _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 1 )
+#define PCIDRIVER_IOC_KMEM_ALLOC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 2, kmem_handle_t * )
+#define PCIDRIVER_IOC_KMEM_FREE _IOW ( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 3, kmem_handle_t * )
+#define PCIDRIVER_IOC_KMEM_SYNC _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 4, kmem_sync_t * )
+#define PCIDRIVER_IOC_UMEM_SGMAP _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 5, umem_handle_t * )
+#define PCIDRIVER_IOC_UMEM_SGUNMAP _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 6, umem_handle_t * )
+#define PCIDRIVER_IOC_UMEM_SGGET _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 7, umem_sglist_t * )
+#define PCIDRIVER_IOC_UMEM_SYNC _IOW( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 8, umem_handle_t * )
+#define PCIDRIVER_IOC_WAITI _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 9 )
/* And now, the methods to access the PCI configuration area */
-#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * )
-#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * )
-#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * )
+#define PCIDRIVER_IOC_PCI_CFG_RD _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 10, pci_cfg_cmd * )
+#define PCIDRIVER_IOC_PCI_CFG_WR _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 11, pci_cfg_cmd * )
+#define PCIDRIVER_IOC_PCI_INFO _IOWR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 12, pcilib_board_info_t * )
/* Clear interrupt queues */
-#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 )
+#define PCIDRIVER_IOC_CLEAR_IOQ _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 13 )
-#define PCIDRIVER_IOC_SET_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14 )
+#define PCIDRIVER_IOC_VERSION _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 14, pcilib_driver_version_t * )
+#define PCIDRIVER_IOC_DEVICE_STATE _IOR( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 15, pcilib_device_state_t * )
+#define PCIDRIVER_IOC_DMA_MASK _IO( PCIDRIVER_IOC_MAGIC, PCIDRIVER_IOC_BASE + 16)
+#define PCIDRIVER_IOC_MAX 16
#endif
diff --git a/pcilib/pci.c b/pcilib/pci.c
index e45aaba..26dfdbf 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -108,6 +108,7 @@ static int pcilib_detect_model(pcilib_t *ctx, const char *model) {
pcilib_t *pcilib_open(const char *device, const char *model) {
int err, xmlerr;
pcilib_t *ctx = malloc(sizeof(pcilib_t));
+ const pcilib_driver_version_t *drv_version;
if (!model)
model = getenv("PCILIB_MODEL");
@@ -123,6 +124,13 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
return NULL;
}
+ drv_version = pcilib_get_driver_version(ctx);
+ if (!drv_version) {
+ pcilib_error("Driver verification has failed (%s)", device);
+ free(ctx);
+ return NULL;
+ }
+
ctx->page_mask = (uintptr_t)-1;
if ((model)&&(!strcasecmp(model, "maintenance"))) {
@@ -224,6 +232,34 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
}
+const pcilib_driver_version_t *pcilib_get_driver_version(pcilib_t *ctx) {
+ int ret;
+
+ if (!ctx->driver_version.version) {
+ ret = ioctl( ctx->handle, PCIDRIVER_IOC_VERSION, &ctx->driver_version );
+ if (ret) {
+ pcilib_error("PCIDRIVER_IOC_DRIVER_VERSION ioctl have failed");
+ return NULL;
+ }
+
+ if (ctx->driver_version.interface != PCIDRIVER_INTERFACE_VERSION) {
+ pcilib_error("Using pcilib (version: %u.%u.%u, driver interface: 0x%lx) with incompatible driver (version: %u.%u.%u, interface: 0x%lx)",
+ PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION),
+ PCILIB_VERSION_GET_MINOR(PCILIB_VERSION),
+ PCILIB_VERSION_GET_MICRO(PCILIB_VERSION),
+ PCIDRIVER_INTERFACE_VERSION,
+ PCILIB_VERSION_GET_MAJOR(ctx->driver_version.version),
+ PCILIB_VERSION_GET_MINOR(ctx->driver_version.version),
+ PCILIB_VERSION_GET_MICRO(ctx->driver_version.version),
+ ctx->driver_version.interface
+ );
+ return NULL;
+ }
+ }
+
+ return &ctx->driver_version;
+}
+
const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) {
int ret;
@@ -236,7 +272,7 @@ const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) {
ctx->page_mask = pcilib_get_page_mask();
}
-
+
return &ctx->board_info;
}
@@ -432,8 +468,17 @@ const pcilib_pcie_link_info_t *pcilib_get_pcie_link_info(pcilib_t *ctx) {
return &ctx->link_info;
}
+int pcilib_get_device_state(pcilib_t *ctx, pcilib_device_state_t *state) {
+ int ret = ioctl( ctx->handle, PCIDRIVER_IOC_DEVICE_STATE, state);
+ if (ret < 0) {
+ pcilib_error("PCIDRIVER_IOC_DEVICE_STATE ioctl have failed");
+ return PCILIB_ERROR_FAILED;
+ }
+ return 0;
+}
+
int pcilib_set_dma_mask(pcilib_t *ctx, int mask) {
- if (ioctl( ctx->handle, PCIDRIVER_IOC_SET_DMA_MASK, mask ) < 0)
+ if (ioctl(ctx->handle, PCIDRIVER_IOC_DMA_MASK, mask) < 0)
return PCILIB_ERROR_FAILED;
return 0;
diff --git a/pcilib/pci.h b/pcilib/pci.h
index bf977fc..b81d295 100644
--- a/pcilib/pci.h
+++ b/pcilib/pci.h
@@ -48,6 +48,7 @@ struct pcilib_s {
int handle; /**< file handle of device */
uintptr_t page_mask; /**< Selects bits which define offset within the page */
+ pcilib_driver_version_t driver_version; /**< Version reported by the driver */
pcilib_board_info_t board_info; /**< The mandatory information about board as defined by PCI specification */
pcilib_pcie_link_info_t link_info; /**< Infomation about PCIe connection */
char *bar_space[PCILIB_MAX_BARS]; /**< Pointers to the mapped BARs in virtual address space */
@@ -112,8 +113,12 @@ extern "C" {
#endif
pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx);
+
+const pcilib_driver_version_t *pcilib_get_driver_version(pcilib_t *ctx);
const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx);
const pcilib_pcie_link_info_t *pcilib_get_pcie_link_info(pcilib_t *ctx);
+int pcilib_get_device_state(pcilib_t *ctx, pcilib_device_state_t *state);
+
int pcilib_map_register_space(pcilib_t *ctx);
int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr);
diff --git a/pcitool/cli.c b/pcitool/cli.c
index 8943347..65e24dc 100644
--- a/pcitool/cli.c
+++ b/pcitool/cli.c
@@ -74,6 +74,7 @@ typedef enum {
typedef enum {
MODE_INVALID,
+ MODE_VERSION,
MODE_INFO,
MODE_LIST,
MODE_BENCHMARK,
@@ -95,6 +96,7 @@ typedef enum {
MODE_DISABLE_IRQ,
MODE_ACK_IRQ,
MODE_WAIT_IRQ,
+ MODE_SET_DMASK,
MODE_ALLOC_KMEM,
MODE_LIST_KMEM,
MODE_READ_KMEM,
@@ -148,7 +150,8 @@ typedef enum {
OPT_GRAB = 'g',
OPT_QUIETE = 'q',
OPT_HELP = 'h',
- OPT_RESET = 128,
+ OPT_VERSION = 128,
+ OPT_RESET,
OPT_BENCHMARK,
OPT_TRIGGER,
OPT_DATA_TYPE,
@@ -169,6 +172,7 @@ typedef enum {
OPT_ACK_IRQ,
OPT_WAIT_IRQ,
OPT_ITERATIONS,
+ OPT_SET_DMASK,
OPT_ALLOC_KMEM,
OPT_LIST_KMEM,
OPT_FREE_KMEM,
@@ -222,6 +226,7 @@ static struct option long_options[] = {
{"disable-irq", optional_argument, 0, OPT_DISABLE_IRQ },
{"acknowledge-irq", optional_argument, 0, OPT_ACK_IRQ },
{"wait-irq", optional_argument, 0, OPT_WAIT_IRQ },
+ {"set-dma-mask", required_argument, 0, OPT_SET_DMASK },
{"list-kernel-memory", optional_argument, 0, OPT_LIST_KMEM },
{"read-kernel-memory", required_argument, 0, OPT_READ_KMEM },
{"alloc-kernel-memory", required_argument, 0, OPT_ALLOC_KMEM },
@@ -239,6 +244,7 @@ static struct option long_options[] = {
{"verify", no_argument, 0, OPT_VERIFY },
{"multipacket", no_argument, 0, OPT_MULTIPACKET },
{"wait", no_argument, 0, OPT_WAIT },
+ {"version", no_argument, 0, OPT_VERSION },
{"help", no_argument, 0, OPT_HELP },
{ 0, 0, 0, 0 }
};
@@ -268,6 +274,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" -w <addr|dmaX|reg|prop> - Write Data/Register/Property\n"
" --benchmark <barX|dmaX> - Performance Evaluation\n"
" --reset - Reset board\n"
+" --version - Version information\n"
" --help - Help message\n"
"\n"
" Property/Register Modes:\n"
@@ -297,6 +304,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {
" --read-dma-buffer <dma:buf> - Read the specified buffer\n"
"\n"
" Kernel Modes:\n"
+" --set-dma-mask [bits] - Set DMA address width (DANGEROUS)\n"
" --list-kernel-memory [use] - List kernel buffers\n"
" --read-kernel-memory <blk> - Read the specified block of the kernel memory\n"
" block is specified as: use:block_number\n"
@@ -840,6 +848,49 @@ void RegisterInfo(pcilib_t *handle, pcilib_register_t reg) {
pcilib_free_register_info(handle, info);
}
+void Version(pcilib_t *handle, const pcilib_model_description_t *model_info) {
+ const pcilib_driver_version_t *driver_version;
+
+ driver_version = pcilib_get_driver_version(handle);
+
+ printf("pcilib version: %u.%u.%u\n",
+ PCILIB_VERSION_GET_MAJOR(PCILIB_VERSION),
+ PCILIB_VERSION_GET_MINOR(PCILIB_VERSION),
+ PCILIB_VERSION_GET_MICRO(PCILIB_VERSION)
+ );
+
+ printf("driver version: %lu.%lu.%lu, interface: 0x%lx, registered ioctls: %lu\n",
+ PCILIB_VERSION_GET_MAJOR(driver_version->version),
+ PCILIB_VERSION_GET_MINOR(driver_version->version),
+ PCILIB_VERSION_GET_MICRO(driver_version->version),
+ driver_version->interface,
+ driver_version->ioctls
+ );
+
+ if (model_info) {
+ pcilib_version_t version = model_info->interface_version;
+ printf("Model: %s", handle->model);
+ if (version) {
+ printf(", version: %u.%u.%u\n",
+ PCILIB_VERSION_GET_MAJOR(version),
+ PCILIB_VERSION_GET_MINOR(version),
+ PCILIB_VERSION_GET_MICRO(version)
+ );
+ } else {
+ printf(" (embedded)\n");
+ }
+ }
+
+ if (model_info->dma) {
+ pcilib_version_t version = model_info->dma->api->version;
+ printf("DMA Engine: %s, version: %u.%u.%u\n", model_info->dma->name,
+ PCILIB_VERSION_GET_MAJOR(version),
+ PCILIB_VERSION_GET_MINOR(version),
+ PCILIB_VERSION_GET_MICRO(version)
+ );
+ }
+}
+
void Info(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *target) {
int i, j;
DIR *dir;
@@ -850,14 +901,33 @@ void Info(pcilib_t *handle, const pcilib_model_description_t *model_info, const
const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);
const pcilib_pcie_link_info_t *link_info = pcilib_get_pcie_link_info(handle);
+ int have_state;
+ pcilib_device_state_t state;
+
path = getenv("PCILIB_PLUGIN_DIR");
if (!path) path = PCILIB_PLUGIN_DIR;
+ have_state = !pcilib_get_device_state(handle, &state);
+
if (board_info)
printf("Vendor: %x, Device: %x, Bus: %x, Slot: %x, Function: %x, Model: %s\n", board_info->vendor_id, board_info->device_id, board_info->bus, board_info->slot, board_info->func, handle->model);
if (link_info) {
- printf(" PCIe x%u (gen%u), DMA Payload: %u (of %u)\n", link_info->link_width, link_info->link_speed, 1<<link_info->payload, 1<<link_info->max_payload);
+ printf(" PCIe x%u (gen%u), DMA Payload: %u (of %u)", link_info->link_width, link_info->link_speed, 1<<link_info->payload, 1<<link_info->max_payload);
+ if (have_state) {
+ int bits = 0;
+ unsigned long mask;
+
+ for (mask = state.dma_mask; mask&1; mask>>=1) bits++;
+
+ printf(", DMA Mask: ");
+
+ if (mask) printf("0x%lx", state.dma_mask);
+ else printf("%u bits", bits);
+
+ printf(", IOMMU: %s", state.iommu?"on":"off");
+ }
+ printf("\n");
}
if (board_info)
@@ -3018,6 +3088,8 @@ int main(int argc, char **argv) {
FILE *ofile = NULL;
size_t iterations = BENCHMARK_ITERATIONS;
+ unsigned long dma_mask = 0;
+
pcilib_t *handle;
int size_set = 0;
@@ -3032,6 +3104,10 @@ int main(int argc, char **argv) {
case OPT_HELP:
Usage(argc, argv, NULL);
break;
+ case OPT_VERSION:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+ mode = MODE_VERSION;
+ break;
case OPT_INFO:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
@@ -3207,6 +3283,13 @@ int main(int argc, char **argv) {
irq_source = itmp;
}
break;
+ case OPT_SET_DMASK:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+ mode = MODE_SET_DMASK;
+
+ if ((!isnumber(optarg))||(sscanf(optarg, "%lu", &dma_mask) != 1)||(dma_mask<24)||(dma_mask>64))
+ Usage(argc, argv, "Invalid DMA mask is specified (%s)", optarg);
+ break;
case OPT_LIST_KMEM:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
mode = MODE_LIST_KMEM;
@@ -3729,6 +3812,9 @@ int main(int argc, char **argv) {
}
switch (mode) {
+ case MODE_VERSION:
+ Version(handle, model_info);
+ break;
case MODE_INFO:
Info(handle, model_info, info_target);
break;
@@ -3799,6 +3885,9 @@ int main(int argc, char **argv) {
case MODE_WAIT_IRQ:
WaitIRQ(handle, model_info, irq_source, timeout);
break;
+ case MODE_SET_DMASK:
+ pcilib_set_dma_mask(handle, dma_mask);
+ break;
case MODE_LIST_KMEM:
if (use) DetailKMEM(handle, fpga_device, use, block);
else ListKMEM(handle, fpga_device);