summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dma/ipe.c118
-rw-r--r--dma/ipe.h11
-rw-r--r--dma/ipe_private.h20
-rw-r--r--misc/ipedevices.xml7
-rwxr-xr-xpci2
-rw-r--r--pcilib/pci.c26
-rw-r--r--pcilib/xml.c196
-rw-r--r--pcilib/xml.h10
-rw-r--r--pcitool.spec.in8
-rwxr-xr-xrun2
-rw-r--r--xml/CMakeLists.txt5
-rw-r--r--xml/devices.xsd24
-rw-r--r--xml/devices/testdevice.xml4
-rw-r--r--xml/test/camera.xml2
-rw-r--r--xml/test/dma.xml2
15 files changed, 336 insertions, 101 deletions
diff --git a/dma/ipe.c b/dma/ipe.c
index fb35dbc..614d260 100644
--- a/dma/ipe.c
+++ b/dma/ipe.c
@@ -27,7 +27,7 @@
pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, const char *model, const void *arg) {
int err = 0;
- pcilib_register_value_t value;
+ pcilib_register_value_t version_value;
// const pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib);
@@ -51,50 +51,51 @@ pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, const char *model, const vo
ctx->base_addr[2] = (void*)pcilib_resolve_bank_address_by_id(pcilib, 0, dma_bankc);
+ RD(IPEDMA_REG_VERSION, version_value);
+ ctx->version = IPEDMA_VERSION(version_value);
+
if ((model)&&(!strcasecmp(model, "ipecamera"))) {
- ctx->version = 2;
+ ctx->gen = 2;
} else {
- RD(IPEDMA_REG_VERSION, value);
-
- if (value >= 0xa7) {
- ctx->version = 3;
+ if (IPEDMA_GENERATION(version_value) > 2) {
+ ctx->gen = 3;
} else {
- ctx->version = 2;
+ ctx->gen = 2;
}
err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_app_registers, NULL);
}
-
- if (ctx->version >= 3) {
- ctx->reg_last_read = IPEDMA_REG3_LAST_READ;
+ if (ctx->gen > 2) {
+ ctx->mode64 = 1;
+ ctx->addr64 = 1;
+#ifdef IPEDMA_STREAMING_MODE
+ if (IPEDMA_STREAMING(version_value)) ctx->streaming = 1;
+#endif /* IPEDMA_STREAMING_MODE */
+
+ ctx->reg_last_read = IPEDMA_REG3_LAST_READ;
if (!err)
err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_v3_registers, NULL);
- } else {
+ } else {
+#ifdef IPEDMA_ENFORCE_64BIT_MODE
+ // According to Lorenzo, some gen2 boards have problems with 64-bit addressing. Therefore, we only enable it for gen3 boards unless enforced
+ ctx->mode64 = 1;
+#endif /* IPEDMA_ENFORCE_64BIT_MODE */
+ ctx->addr64 = 0;
+ ctx->streaming = 0;
+
ctx->reg_last_read = IPEDMA_REG2_LAST_READ;
-
if (!err)
err = pcilib_add_registers(pcilib, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, ipe_dma_v2_registers, NULL);
- }
-
+ }
+
+ pcilib_info("IPEDMA gen%lu version %lu (64-bit mode: %u, 64-bit addressing: %u, streaming: %u)", ctx->gen, ctx->version, ctx->mode64, ctx->addr64, ctx->streaming);
+
if (err) {
free(ctx);
pcilib_error("Error (%i) registering firmware-dependent IPEDMA registers", err);
return NULL;
}
-
- RD(IPEDMA_REG_PCIE_GEN, value);
-
-#ifdef IPEDMA_ENFORCE_64BIT_MODE
- ctx->mode64 = 1;
-#else /* IPEDMA_ENFORCE_64BIT_MODE */
- // According to Lorenzo, some gen2 boards have problems with 64-bit addressing. Therefore, we only enable it for gen3 boards unless enforced
- if ((value&IPEDMA_MASK_PCIE_GEN) > 2) ctx->mode64 = 1;
-#endif /* IPEDMA_ENFORCE_64BIT_MODE */
-
-#ifdef IPEDMA_STREAMING_MODE
- if (value&IPEDMA_MASK_STREAMING_MODE) ctx->streaming = 1;
-#endif /* IPEDMA_STREAMING_MODE */
}
return (pcilib_dma_context_t*)ctx;
@@ -122,7 +123,7 @@ static void dma_ipe_disable(ipe_dma_t *ctx) {
usleep(IPEDMA_RESET_DELAY);
// Reseting configured DMA pages
- if (ctx->version < 3) {
+ if (ctx->gen < 3) {
WR(IPEDMA_REG2_PAGE_COUNT, 0);
}
usleep(IPEDMA_RESET_DELAY);
@@ -210,7 +211,7 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm
ctx->dma_flags = 0;
#ifdef IPEDMA_CONFIGURE_DMA_MASK
- if (ctx->version >= 3) mask = 64;
+ if (ctx->addr64) mask = 64;
err = pcilib_set_dma_mask(ctx->dmactx.pcilib, mask);
if (err) {
@@ -276,12 +277,9 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm
}
desc_va = pcilib_kmem_get_ua(ctx->dmactx.pcilib, desc);
- if (ctx->version < 3) {
- if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
- else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
- } else {
- last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
- }
+ if (ctx->addr64) last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
+ else if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
+ else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
// get page size if default size was used
if (!ctx->page_size) {
@@ -324,7 +322,7 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm
WR(IPEDMA_REG_UPDATE_THRESHOLD, IPEDMA_DMA_PROGRESS_THRESHOLD);
// Reseting configured DMA pages
- if (ctx->version < 3) {
+ if (ctx->gen < 3) {
WR(IPEDMA_REG2_PAGE_COUNT, 0);
}
@@ -335,17 +333,14 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm
WR(ctx->reg_last_read, ctx->ring_size);
#endif /* IPEDMA_BUG_LAST_READ */
- if (ctx->version < 3) {
- WR(IPEDMA_REG2_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
- } else {
- WR64(IPEDMA_REG3_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
- }
-
// Instructing DMA engine that writting should start from the first DMA page
- if (ctx->version < 3)
- *(uint32_t*)last_written_addr_ptr = 0;
- else
+ if (ctx->addr64) {
+ WR64(IPEDMA_REG3_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
*(uint64_t*)last_written_addr_ptr = 0;
+ } else {
+ WR(IPEDMA_REG2_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, desc, 0));
+ *(uint32_t*)last_written_addr_ptr = 0;
+ }
// In ring buffer mode, the hardware taking care to preserve an empty buffer to help distinguish between
// completely empty and completely full cases. In streaming mode, it is our responsibility to track this
@@ -355,15 +350,15 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm
for (i = 0; i < num_pages; i++) {
uintptr_t bus_addr_check, bus_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, pages, i);
- if (ctx->version < 3) {
- WR(IPEDMA_REG2_PAGE_ADDR, bus_addr);
- } else {
+ if (ctx->addr64) {
WR64(IPEDMA_REG3_PAGE_ADDR, bus_addr);
+ } else {
+ WR(IPEDMA_REG2_PAGE_ADDR, bus_addr);
}
if (bus_addr%4096) printf("Bad address %lu: %lx\n", i, bus_addr);
- if (ctx->version < 3) {
+ if ((!ctx->addr64)&&(!ctx->streaming)) {
RD(IPEDMA_REG2_PAGE_ADDR, bus_addr_check);
if (bus_addr_check != bus_addr) {
pcilib_error("Written (%x) and read (%x) bus addresses does not match\n", bus_addr, bus_addr_check);
@@ -449,13 +444,13 @@ int dma_ipe_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcil
if (!status) return -1;
- if (ctx->version < 3) {
+ if (ctx->addr64) {
+ last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
+ last_written_addr = *(uint64_t*)last_written_addr_ptr;
+ } else {
if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
last_written_addr = *(uint32_t*)last_written_addr_ptr;
- } else {
- last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
- last_written_addr = *(uint64_t*)last_written_addr_ptr;
}
pcilib_debug(DMA, "Current DMA status - last read: %4u, last_read_addr: %4u (0x%x), last_written: %4lu (0x%lx)", ctx->last_read,
@@ -563,18 +558,17 @@ int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin
desc_va = (void*)pcilib_kmem_get_ua(ctx->dmactx.pcilib, ctx->desc);
- if (ctx->version < 3) {
+ if (ctx->addr64) {
+ last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
+ empty_detected_ptr = desc_va + sizeof(uint32_t);
+// empty_detected_ptr = &empty_detected_dummy;
+ } else {
if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
empty_detected_ptr = NULL; // Not properly supported
// empty_detected_ptr = last_written_addr_ptr - 2;
- } else {
- last_written_addr_ptr = desc_va + 2 * sizeof(uint32_t);
- empty_detected_ptr = desc_va + sizeof(uint32_t);
-// empty_detected_ptr = &empty_detected_dummy;
}
-
switch (sched_getscheduler(0)) {
case SCHED_FIFO:
case SCHED_RR:
@@ -666,10 +660,10 @@ int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin
else last_free = ctx->ring_size - 1;
uintptr_t buf_ba = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, last_free);
- if (ctx->version < 3) {
- WR(IPEDMA_REG2_PAGE_ADDR, buf_ba);
- } else {
+ if (ctx->addr64) {
WR64(IPEDMA_REG3_PAGE_ADDR, buf_ba);
+ } else {
+ WR(IPEDMA_REG2_PAGE_ADDR, buf_ba);
}
# ifdef IPEDMA_STREAMING_CHECKS
pcilib_register_value_t streaming_status;
diff --git a/dma/ipe.h b/dma/ipe.h
index 18452bd..2cd045d 100644
--- a/dma/ipe.h
+++ b/dma/ipe.h
@@ -44,7 +44,7 @@ static const pcilib_dma_engine_description_t ipe_dma_engines[] = {
static const pcilib_register_bank_description_t ipe_dma_banks[] = {
{ PCILIB_REGISTER_BANK_DMA, PCILIB_REGISTER_PROTOCOL_DEFAULT, PCILIB_BAR0, 0, 0, 32, 0x0200, PCILIB_LITTLE_ENDIAN, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"},
- { PCILIB_REGISTER_BANK_DMA1, PCILIB_REGISTER_PROTOCOL_DEFAULT, PCILIB_BAR0, 0x9000, 0x9000, 32, 0x0100, PCILIB_LITTLE_ENDIAN, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma9000", "Additional DMA Registers"},
+ { PCILIB_REGISTER_BANK_DMA1, PCILIB_REGISTER_PROTOCOL_DEFAULT, PCILIB_BAR0, 0x9000, 0x9000, 32, 0x0100, PCILIB_LITTLE_ENDIAN, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma9000", "DMA Application Registers"},
{ PCILIB_REGISTER_BANK_DMACONF, PCILIB_REGISTER_PROTOCOL_SOFTWARE, PCILIB_BAR_NOBAR, 0, 0, 32, 0x1000, PCILIB_HOST_ENDIAN, PCILIB_HOST_ENDIAN, "0x%lx", "dmaconf", "DMA Configuration"},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
};
@@ -71,9 +71,10 @@ static const pcilib_register_description_t ipe_dma_registers[] = {
{0x000C, 24, 8, 0, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_up_addr", "Upper address for 64 bit memory addressing"},
{0x0010, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_count", "Write DMA TLP Count"},
{0x0014, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_pattern", "DMA generator data pattern"},
- {0x0018, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dma_mode_flags", "DMA operation mode"},
- {0x0018, 0, 4, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "pcie_gen", "PCIe version 2/3 depending on the used XILINX core"},
- {0x0018, 4, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "streaming_dma", "Streaming mode (enabled/disabled)"},
+ {0x0018, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dma_firmware_mode", "DMA operation mode"},
+ {0x0018, 0, 4, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma_firmware_gen", "Generation of DMA engine (2/3 depending on the used XILINX core and PCIe generation)"},
+ {0x0018, 4, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma_firmware_streaming", "Streaming mode (enabled/disabled)"},
+ {0x0018, 16, 16, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma_firmware_version", "Version of DMA firmware"},
{0x0028, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_perf", "MWR Performance"},
{0x003C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "cfg_lnk_width", "Negotiated and max width of PCIe Link"},
{0x003C, 0, 6, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_cap_max_lnk_width", "Max link width"},
@@ -101,7 +102,7 @@ static const pcilib_register_description_t ipe_dma_app_registers[] = {
{0x0000, 8, 1, 0, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA1, "fix_cntgen", "Enable fixed pattern mode of dummy generator"},
{0x0004, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA1, "cntgen_pattern", "Pattern for fixed pattern dummy generator"},
{0x0008, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA1, "update_word0", "Content of first 32-bit word in the progress register"},
- {0x0020, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA1, "dma_firmware", "Version of DMA firmware"},
+ {0x0030, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA1, "dma_app_version", "Version of DMA application"},
{0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL}
};
diff --git a/dma/ipe_private.h b/dma/ipe_private.h
index e3cb217..98d71c1 100644
--- a/dma/ipe_private.h
+++ b/dma/ipe_private.h
@@ -28,13 +28,16 @@
#define REG(bank, addr) ((bank<<IPEDMA_REG_BANK_SHIFT)|addr)
#define CONFREG(addr) REG(2, addr)
-#define IPEDMA_REG_VERSION REG(1, 0x20)
+#define IPEDMA_REG_VERSION 0x18
+#define IPEDMA_REG_APPVERSION REG(1, 0x20)
+#define IPEDMA_GENERATION(ver) (ver&0xF)
+#define IPEDMA_STREAMING(ver) ((ver>>4)&0x1)
+#define IPEDMA_VERSION(ver) ((ver>>16)&0xFFFF)
#define IPEDMA_REG_RESET 0x00
#define IPEDMA_REG_CONTROL 0x04
#define IPEDMA_REG_TLP_SIZE 0x0C
#define IPEDMA_REG_TLP_COUNT 0x10
-#define IPEDMA_REG_PCIE_GEN 0x18
#define IPEDMA_REG_UPDATE_THRESHOLD 0x60
#define IPEDMA_REG_STREAMING_STATUS 0x68
@@ -54,8 +57,8 @@
#define IPEDMA_FLAG_NOSYNC 0x01 /**< Do not call kernel space for page synchronization */
#define IPEDMA_FLAG_NOSLEEP 0x02 /**< Do not sleep in the loop while waiting for the data */
-#define IPEDMA_MASK_PCIE_GEN 0xF
-#define IPEDMA_MASK_STREAMING_MODE 0x10
+//#define IPEDMA_MASK_PCIE_GEN 0xF
+//#define IPEDMA_MASK_STREAMING_MODE 0x10
#define IPEDMA_RESET_DELAY 10000 /**< Sleep between accessing DMA control and reset registers */
#define IPEDMA_ADD_PAGE_DELAY 1000 /**< Delay between submitting successive DMA pages into IPEDMA_REG_PAGE_ADDR register */
@@ -84,13 +87,16 @@ struct ipe_dma_s {
pcilib_irq_type_t irq_preserve; /**< indicates that IRQs should not be disabled during clean-up */
int irq_started; /**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */
- uint32_t version; /**< hardware version */
+ uint32_t gen; /**< hardware generation, currently corresponds to PCIe generation 2/3 */
+ uint32_t version; /**< hardware revision */
+ int mode64; /**< indicates 64-bit operation mode (for gen2, gen3 always operates in 64-bit mode) */
+ int addr64; /**< indicates that 64-bit addressing mode is used (gen3 only) */
+ int streaming; /**< indicates if DMA is operating in streaming or ring-buffer mode (gen3 only) */
+
int started; /**< indicates that DMA buffers are initialized and reading is allowed */
int writting; /**< indicates that we are in middle of writting packet */
int reused; /**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */
int preserve; /**< indicates that DMA should not be stopped during clean-up */
- int mode64; /**< indicates 64-bit operation mode */
- int streaming; /**< indicates if DMA is operating in streaming or ring-buffer mode */
uint32_t dma_flags; /**< Various operation flags, see IPEDMA_FLAG_* */
size_t dma_timeout; /**< DMA timeout,IPEDMA_DMA_TIMEOUT is used by default */
diff --git a/misc/ipedevices.xml b/misc/ipedevices.xml
new file mode 100644
index 0000000..889a917
--- /dev/null
+++ b/misc/ipedevices.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<devices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <device vendor="10ee" device="0" model="ipecamera"/>
+ <device vendor="10ee" device="1" model="ipecamera"/>
+ <device vendor="10ee" device="2" model="ipedma"/>
+ <device vendor="10ee" device="3" model="ipedma"/>
+</devices>
diff --git a/pci b/pci
index 5639dc0..bf9de61 100755
--- a/pci
+++ b/pci
@@ -2,4 +2,4 @@
APP_PATH=`dirname $0`
-PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_MODEL_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $APP_PATH/pcitool/pci $*
+PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_MODEL_DIR="$APP_PATH/xml" PCILIB_DATA_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $APP_PATH/pcitool/pci $*
diff --git a/pcilib/pci.c b/pcilib/pci.c
index c9cd1d2..6451559 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -86,13 +86,6 @@ static int pcilib_detect_model(pcilib_t *ctx, const char *model) {
pcilib_add_register_ranges(ctx, PCILIB_MODEL_MODIFICATON_FLAGS_DEFAULT, 0, model_info->ranges);
}
- // Load XML registers
-
- // Check for all installed models
- // memcpy(&ctx->model_info, model, sizeof(pcilib_model_description_t));
- // how we reconcile the banks from event model and dma description? The banks specified in the DMA description should override corresponding banks of events...
-
-
if (!model_info) {
if ((model)&&(strcasecmp(model, "pci"))/*&&(no xml)*/)
return PCILIB_ERROR_NOTFOUND;
@@ -108,6 +101,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_board_info_t *board_info;
const pcilib_driver_version_t *drv_version;
if (!model)
@@ -138,6 +132,17 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
return ctx;
}
+ board_info = pcilib_get_board_info(ctx);
+ if (!board_info) {
+ pcilib_error("Failed to enumerate PCI device");
+ pcilib_close(ctx);
+ return NULL;
+ }
+
+ // Check if model is specified in the XML configuration
+ if (!model)
+ model = pcilib_detect_xml_model(ctx, board_info->vendor_id, board_info->device_id);
+
err = pcilib_init_locking(ctx);
if (err) {
pcilib_error("Error (%i) initializing locking subsystem", err);
@@ -151,6 +156,7 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
pcilib_free_py(ctx);
}
+
ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE;
ctx->alloc_views = PCILIB_DEFAULT_VIEW_SPACE;
ctx->alloc_units = PCILIB_DEFAULT_UNIT_SPACE;
@@ -179,11 +185,7 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
err = pcilib_detect_model(ctx, model);
if ((err)&&(err != PCILIB_ERROR_NOTFOUND)) {
- const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);
- if (board_info)
- pcilib_error("Error (%i) configuring model %s (%x:%x)", err, (model?model:""), board_info->vendor_id, board_info->device_id);
- else
- pcilib_error("Error (%i) configuring model %s", err, (model?model:""));
+ pcilib_error("Error (%i) configuring model %s (%x:%x)", err, (model?model:""), board_info->vendor_id, board_info->device_id);
pcilib_close(ctx);
return NULL;
}
diff --git a/pcilib/xml.c b/pcilib/xml.c
index b980a83..467c9c7 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -49,12 +49,11 @@
#define REGISTERS_PATH ((xmlChar*)"./register") /**< all standard registers nodes */
#define BIT_REGISTERS_PATH ((xmlChar*)"./field") /**< all bits registers nodes */
#define REGISTER_VIEWS_PATH ((xmlChar*)"./view") /**< supported register & field views */
-#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
+#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
#define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum") /**< path to complete nodes of views */
#define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") /**< all elements in the enum */
#define UNITS_PATH ((xmlChar*)"/model/unit") /**< path to complete nodes of units */
-#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
-
+#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
static const char *pcilib_xml_bank_default_format = "0x%lx";
@@ -892,7 +891,7 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon
return 0;
}
-static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) {
+static int pcilib_xml_load_xsd_file(pcilib_t *ctx, const char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) {
int err;
xmlSchemaParserCtxtPtr ctxt;
@@ -923,6 +922,7 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema
*validator = xmlSchemaNewValidCtxt(*schema);
if (!*validator) {
xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlSchemaFree(*schema); *schema = NULL;
if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
else pcilib_error("Failed to create a validation context");
return PCILIB_ERROR_FAILED;
@@ -931,6 +931,8 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema
err = xmlSchemaSetValidOptions(*validator, XML_SCHEMA_VAL_VC_I_CREATE);
if (err) {
xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlSchemaFreeValidCtxt(*validator); *validator = NULL;
+ xmlSchemaFree(*schema); *schema = NULL;
if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);
else pcilib_error("Failed to configure the validation context to populate default attributes");
return PCILIB_ERROR_FAILED;
@@ -939,8 +941,87 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema
return 0;
}
+/*
+static xmlDocPtr pcilib_xml_load_xml_file(pcilib_t *ctx, const char *xsd_filename, const char *xml_filename) {
+ int err;
+ xmlDocPtr doc;
+ xmlSchemaPtr schema;
+ xmlSchemaValidCtxtPtr validator;
+ xmlParserCtxtPtr parser;
+
+ err = pcilib_xml_load_xsd_file(ctx, xsd_filename, &schema, &validator);
+ if (err) {
+ pcilib_error("Error (%i) parsing the devices schema (%s)", err, xsd_filename);
+ return NULL;
+ }
-static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) {
+ parser = xmlNewParserCtxt();
+ if (!parser) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlSchemaFree(schema);
+ xmlSchemaFreeValidCtxt(validator);
+ if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to create an XML parser context");
+ return NULL;
+ }
+
+ doc = xmlCtxtReadFile(parser, xml_filename, NULL, 0);
+ if (!doc) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlFreeParserCtxt(parser);
+ xmlSchemaFree(schema);
+ xmlSchemaFreeValidCtxt(validator);
+ if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", xml_filename, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error parsing %s", xml_filename);
+ return NULL;
+ }
+
+ err = xmlSchemaValidateDoc(validator, doc);
+ if (err) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser);
+ xmlFreeDoc(doc);
+ xmlFreeParserCtxt(parser);
+ xmlSchemaFree(schema);
+ xmlSchemaFreeValidCtxt(validator);
+ if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", xml_filename, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error validating %s", xml_filename);
+ return NULL;
+ }
+
+ xmlFreeParserCtxt(parser);
+ xmlSchemaFree(schema);
+ xmlSchemaFreeValidCtxt(validator);
+
+ return doc;
+}
+*/
+
+static xmlXPathObjectPtr pcilib_xml_eval_xpath_expression(pcilib_t *ctx, xmlDocPtr doc, const xmlChar *query) {
+ xmlXPathContextPtr xpath;
+ xmlXPathObjectPtr nodes;
+
+ xpath = xmlXPathNewContext(doc);
+ if (!xpath) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("xmlXpathNewContext reported error %d - %s", xmlerr->code, xmlerr->message);
+ else pcilib_error("Error creating XPath context");
+ return NULL;
+ }
+
+ nodes = xmlXPathEvalExpression(query, xpath);
+ if (!nodes) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlXPathFreeContext(xpath);
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", query, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", query);
+ return NULL;
+ }
+
+ xmlXPathFreeContext(xpath);
+ return nodes;
+}
+
+static int pcilib_xml_load_xsd(pcilib_t *ctx, const char *model_dir) {
int err;
struct stat st;
@@ -969,7 +1050,7 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) {
-static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
+static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, xmlParserCtxtPtr parser, xmlSchemaValidCtxtPtr validator, const char *path, const char *name) {
int err;
char *full_name;
xmlDocPtr doc;
@@ -982,17 +1063,17 @@ static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const cha
sprintf(full_name, "%s/%s", path, name);
- doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0);
+ doc = xmlCtxtReadFile(parser, full_name, NULL, 0);
if (!doc) {
- xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser);
if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error parsing %s", full_name);
return NULL;
}
- err = xmlSchemaValidateDoc(ctx->xml.parts_validator, doc);
+ err = xmlSchemaValidateDoc(validator, doc);
if (err) {
- xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser);
xmlFreeDoc(doc);
if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error validating %s", full_name);
@@ -1002,6 +1083,11 @@ static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const cha
return doc;
}
+static xmlDocPtr pcilib_xml_load_model_file(pcilib_t *ctx, const char *path, const char *name) {
+ return pcilib_xml_load_file(ctx, ctx->xml.parser, ctx->xml.parts_validator, path, name);
+}
+
+
static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const char *location) {
int err;
@@ -1039,7 +1125,7 @@ static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const c
if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
if (file->d_type != DT_REG) continue;
- newdoc = pcilib_xml_load_file(ctx, model_path, file->d_name);
+ newdoc = pcilib_xml_load_model_file(ctx, model_path, file->d_name);
if (!newdoc) {
pcilib_error("Error processing XML file %s", file->d_name);
continue;
@@ -1190,3 +1276,91 @@ void pcilib_free_xml(pcilib_t *ctx) {
xmlMemoryDump();
*/
}
+
+
+char *pcilib_detect_xml_model(pcilib_t *ctx, unsigned int vendor_id, unsigned int device_id) {
+ int err;
+ char *model = NULL;
+ xmlSchemaPtr schema; /**< Pointer to the parsed xsd schema */
+ xmlSchemaValidCtxtPtr validator; /**< Pointer to the XML validation context */
+ xmlParserCtxtPtr parser; /**< Pointer to the XML parser context */
+
+ DIR *rep;
+ struct dirent *file = NULL;
+ struct stat st;
+ const char *data_dir;
+ char *xsd_path, *xml_path;
+
+ xmlXPathObjectPtr nodes;
+ xmlChar xpath_query[64];
+
+ xmlStrPrintf(xpath_query, sizeof(xpath_query), (xmlChar*)"/devices/device[@vendor=%x and @device=%x]/@model", vendor_id, device_id);
+
+ data_dir = getenv("PCILIB_DATA_DIR");
+ if (!data_dir) data_dir = PCILIB_DATA_DIR;
+
+ xsd_path = (char*)alloca(strlen(data_dir) + 32);
+ xml_path = (char*)alloca(strlen(data_dir) + 32);
+ if ((!xsd_path)||(!xml_path)) {
+ pcilib_error("Error allocating stack memory");
+ return NULL;
+ }
+
+ sprintf(xsd_path, "%s/devices.xsd", data_dir);
+ sprintf(xml_path, "%s/devices", data_dir);
+ if (stat(xsd_path, &st)||stat(xml_path, &st)) {
+ pcilib_info("No XML devices are defined, missing devices schema or list");
+ return NULL;
+ }
+
+ parser = xmlNewParserCtxt();
+ if (!parser) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to create an XML parser context");
+ return NULL;
+ }
+
+ err = pcilib_xml_load_xsd_file(ctx, xsd_path, &schema, &validator);
+ if (err) {
+ xmlFreeParserCtxt(parser);
+ pcilib_error("Error (%i) parsing the device schema (%s)", err, xsd_path);
+ return NULL;
+ }
+
+ rep = opendir(xml_path);
+ if (!rep) goto cleanup;
+
+ while ((model == NULL)&&((file = readdir(rep)) != NULL)) {
+ xmlDocPtr doc;
+
+ size_t len = strlen(file->d_name);
+ if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
+ if (file->d_type != DT_REG) continue;
+
+ doc = pcilib_xml_load_file(ctx, parser, validator, xml_path, file->d_name);
+ if (!doc) continue;
+
+ nodes = pcilib_xml_eval_xpath_expression(ctx, doc, xpath_query);
+ if (!nodes) {
+ xmlFreeDoc(doc);
+ continue;
+ }
+
+ if (!xmlXPathNodeSetIsEmpty(nodes->nodesetval)) {
+ xmlNodePtr node = nodes->nodesetval->nodeTab[0];
+ model = strdup((char*)node->children->content);
+ }
+
+ xmlXPathFreeObject(nodes);
+ xmlFreeDoc(doc);
+ }
+ closedir(rep);
+
+cleanup:
+ xmlSchemaFree(schema);
+ xmlSchemaFreeValidCtxt(validator);
+ xmlFreeParserCtxt(parser);
+
+ return model;
+}
diff --git a/pcilib/xml.h b/pcilib/xml.h
index d8a9693..f6fc91b 100644
--- a/pcilib/xml.h
+++ b/pcilib/xml.h
@@ -40,6 +40,16 @@ struct pcilib_xml_s {
extern "C" {
#endif
+/**
+ * Resolves device model from vendor and device ids using XML configuration
+ * The association of vendor/device id pairs with model are provided devices.xml under PCILIB_MODEL_DIR
+ * @param[in,out] ctx - pcilib context
+ * @param[in] vendor_id - the vendor id
+ * @param[in] device_id - the device id
+ * @return - the name of model or NULL on an error and unknown device. It is caller responsibility to free returned string.
+ */
+char *pcilib_detect_xml_model(pcilib_t *ctx, unsigned int vendor_id, unsigned int device_id);
+
/** Initializes XML stack and loads a default set of XML files.
* The default location for XML files is /usr/local/share/pcilib/models/@b{model}.
* This can be altered using CMake PCILIB_MODEL_DIR variable while building or using
diff --git a/pcitool.spec.in b/pcitool.spec.in
index 136d47c..8de8002 100644
--- a/pcitool.spec.in
+++ b/pcitool.spec.in
@@ -146,6 +146,10 @@ cp -r driver $RPM_BUILD_ROOT/usr/src/%{modname}-%{version}/
# Sample model
cp -r xml/test $RPM_BUILD_ROOT/%{_datadir}/pcilib${PCILIB_ABI_VERSION}/models/
+cp -r xml/devices $RPM_BUILD_ROOT/%{_datadir}/pcilib${PCILIB_ABI_VERSION}/
+
+# Default configuration
+install -m 644 misc/ipedevices.xml $RPM_BUILD_ROOT/%{_datadir}/pcilib${PCILIB_ABI_VERSION}/devices/
# Servers
mkdir -p $RPM_BUILD_ROOT/%{_unitdir}
@@ -203,8 +207,11 @@ exit 0
%doc docs/HARDWARE
%dir %{_libdir}/pcilib${PCILIB_ABI_VERSION}/
%dir %{_datadir}/pcilib${PCILIB_ABI_VERSION}/
+%dir %{_datadir}/pcilib${PCILIB_ABI_VERSION}/devices/
%dir %{_datadir}/pcilib${PCILIB_ABI_VERSION}/models/
+%{_datadir}/pcilib${PCILIB_ABI_VERSION}/*.xsd
%{_datadir}/pcilib${PCILIB_ABI_VERSION}/models/*.xsd
+%{_datadir}/pcilib${PCILIB_ABI_VERSION}/devices/ipedevices.xml
%{_libdir}/libpcilib.so.*
%files -n libpcilib-devel
@@ -219,6 +226,7 @@ exit 0
%files -n pcilib-test
%defattr(-, root, root)
%{_datadir}/pcilib${PCILIB_ABI_VERSION}/models/test
+%{_datadir}/pcilib${PCILIB_ABI_VERSION}/devices/testdevice.xml
%files -n pcilib-dkms
%defattr(-, root, root)
diff --git a/run b/run
index ebc558b..e8637b4 100755
--- a/run
+++ b/run
@@ -2,4 +2,4 @@
APP_PATH=`dirname $0`
-PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_SCRIPTS_DIR="$APP_PATH/pyserver/scripts" PCILIB_MODEL_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $*
+PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_SCRIPTS_DIR="$APP_PATH/pyserver/scripts" PCILIB_MODEL_DIR="$APP_PATH/xml" PCILIB_DATA_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $*
diff --git a/xml/CMakeLists.txt b/xml/CMakeLists.txt
index a7ac800..8848c79 100644
--- a/xml/CMakeLists.txt
+++ b/xml/CMakeLists.txt
@@ -1,3 +1,8 @@
+
+install(FILES devices.xsd
+ DESTINATION ${PCILIB_DATA_DIR}
+)
+
install(FILES model.xsd references.xsd types.xsd
DESTINATION ${PCILIB_MODEL_DIR}
)
diff --git a/xml/devices.xsd b/xml/devices.xsd
new file mode 100644
index 0000000..27e9b39
--- /dev/null
+++ b/xml/devices.xsd
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:include schemaLocation="types.xsd"/>
+
+ <xsd:simpleType name="hex16_t">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="([a-fA-F0-9]){1,4}"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:complexType name="device_t">
+ <xsd:attribute name="vendor" type="hex16_t" />
+ <xsd:attribute name="device" type="hex16_t" />
+ <xsd:attribute name="model" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:element name="devices">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="device" type="device_t" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+ </xsd:element>
+</xsd:schema>
diff --git a/xml/devices/testdevice.xml b/xml/devices/testdevice.xml
new file mode 100644
index 0000000..d7f7d11
--- /dev/null
+++ b/xml/devices/testdevice.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<devices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <device vendor="0000" device="0" model="test"/>
+</devices>
diff --git a/xml/test/camera.xml b/xml/test/camera.xml
index 6568f17..882963c 100644
--- a/xml/test/camera.xml
+++ b/xml/test/camera.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x9000" write_address="0x9000" word_size="32" endianess="little" format="0x%lx" name="fpga" description="IPECamera Registers">
+ <bank size="0x0200" protocol="software_registers" read_address="0x9000" write_address="0x9000" word_size="32" endianess="little" format="0x%lx" name="fpga" description="IPECamera Registers">
<register address="0x00" offset="0" size="32" default="0" rwmask="0" mode="RW" name="spi_conf_input"/>
<register address="0x10" offset="0" size="32" default="0" rwmask="0" mode="R" name="spi_conf_output"/>
<register address="0x20" offset="0" size="32" default="0" rwmask="0" mode="RW" name="spi_clk_speed"/>
diff --git a/xml/test/dma.xml b/xml/test/dma.xml
index 1d20725..582a7a3 100644
--- a/xml/test/dma.xml
+++ b/xml/test/dma.xml
@@ -1,4 +1,4 @@
<?xml version="1.0"?>
<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x0" write_address="0x0" word_size="32" endianess="little" format="0x%lx" name="dma" description="DMA Registers"/>
+ <bank size="0x0200" protocol="software_registers" read_address="0x0" write_address="0x0" word_size="32" endianess="little" format="0x%lx" name="dma" description="DMA Registers"/>
</model>