diff options
-rw-r--r-- | dma/ipe.c | 118 | ||||
-rw-r--r-- | dma/ipe.h | 11 | ||||
-rw-r--r-- | dma/ipe_private.h | 20 | ||||
-rw-r--r-- | misc/ipedevices.xml | 7 | ||||
-rwxr-xr-x | pci | 2 | ||||
-rw-r--r-- | pcilib/pci.c | 26 | ||||
-rw-r--r-- | pcilib/xml.c | 196 | ||||
-rw-r--r-- | pcilib/xml.h | 10 | ||||
-rw-r--r-- | pcitool.spec.in | 8 | ||||
-rwxr-xr-x | run | 2 | ||||
-rw-r--r-- | xml/CMakeLists.txt | 5 | ||||
-rw-r--r-- | xml/devices.xsd | 24 | ||||
-rw-r--r-- | xml/devices/testdevice.xml | 4 | ||||
-rw-r--r-- | xml/test/camera.xml | 2 | ||||
-rw-r--r-- | xml/test/dma.xml | 2 |
15 files changed, 336 insertions, 101 deletions
@@ -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; @@ -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> @@ -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) @@ -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> |