summaryrefslogtreecommitdiffstats
path: root/pcilib
diff options
context:
space:
mode:
Diffstat (limited to 'pcilib')
-rw-r--r--pcilib/CMakeLists.txt16
-rw-r--r--pcilib/lock.c10
-rw-r--r--pcilib/lock.h6
-rw-r--r--pcilib/locking.h8
-rw-r--r--pcilib/model.h3
-rw-r--r--pcilib/pci.c56
-rw-r--r--pcilib/pci.h36
-rw-r--r--pcilib/pcilib.h11
-rw-r--r--pcilib/register.h18
-rw-r--r--pcilib/unit.c49
-rw-r--r--pcilib/unit.h36
-rw-r--r--pcilib/view.c74
-rw-r--r--pcilib/view.h40
-rw-r--r--pcilib/views.c382
-rw-r--r--pcilib/views.h81
-rw-r--r--pcilib/xml.c1127
16 files changed, 905 insertions, 1048 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt
index 9688065..beaa253 100644
--- a/pcilib/CMakeLists.txt
+++ b/pcilib/CMakeLists.txt
@@ -5,17 +5,13 @@ include_directories(
${CMAKE_BINARY_DIR}/pcilib
${LIBXML2_INCLUDE_DIRS}
${PYTHON_INCLUDE_DIRS}
+ ${UTHASH_INCLUDE_DIRS}
)
-set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h
-views.h xml.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h
-debug.h env.h version.h config.h)
-add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c
-register.c views.c xml.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c)
-target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT}
-${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS} ${EXTRA_SYSTEM_LIBS}
-${LIBXML2_LIBRARIES} ${PYTHON_LIBRARIES})
-add_dependencies(pcilib dma protocols)
+set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h view.h unit.h xml.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h)
+add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c view.c unit.c xml.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c )
+target_link_libraries(pcilib dma protocols views ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS} ${EXTRA_SYSTEM_LIBS} ${LIBXML2_LIBRARIES} ${PYTHON_LIBRARIES})
+add_dependencies(pcilib dma protocols views)
install(TARGETS pcilib
LIBRARY DESTINATION lib${LIB_SUFFIX}
@@ -25,6 +21,6 @@ install(FILES pcilib.h
DESTINATION include
)
-install(FILES bar.h kmem.h locking.h lock.h bank.h register.h views.h xml.h dma.h event.h model.h error.h debug.h env.h tools.h export.h version.h
+install(FILES bar.h kmem.h locking.h lock.h bank.h register.h xml.h dma.h event.h model.h error.h debug.h env.h tools.h export.h version.h view.h unit.h
DESTINATION include/pcilib
)
diff --git a/pcilib/lock.c b/pcilib/lock.c
index 25e12a5..9e7cda2 100644
--- a/pcilib/lock.c
+++ b/pcilib/lock.c
@@ -22,14 +22,14 @@
* structure to define a lock
*/
struct pcilib_lock_s {
- pthread_mutex_t mutex; /**< the pthread robust mutex itself*/
- pcilib_lock_flags_t flags; /**<flag to define the property of the mutex*/
+ pthread_mutex_t mutex; /**< the pthread robust mutex */
+ pcilib_lock_flags_t flags; /**< flags to define the type of the mutex */
#ifdef HAVE_STDATOMIC_H
- volatile atomic_uint refs; /**< approximate number of processes that may require access to this lock*/
+ volatile atomic_uint refs; /**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */
#else /* HAVE_STDATOMIC_H */
- volatile uint32_t refs;/**< approximate number of processes that may require access to this lock*/
+ volatile uint32_t refs; /**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */
#endif /* HAVE_STDATOMIC_H */
- char name[]; /**< identifier name to search for a lock*/
+ char name[]; /**< lock identifier */
};
diff --git a/pcilib/lock.h b/pcilib/lock.h
index f1a5abf..e3a5b02 100644
--- a/pcilib/lock.h
+++ b/pcilib/lock.h
@@ -1,11 +1,11 @@
/**
* @file lock.h
* @brief this file is the header file for the functions that implement a semaphore API for the pcitool program, using pthread robust mutexes.
- * @details the use of pthread robust mutexes was chosen due to the fact we privilege security over fastness, and that pthread mutexes permits to recover semaphores even with crash ,and that it does not require access to resources that can be easily accessible from extern usage as flock file locking mechanism. A possible other locking mechanism could be the sysv semaphores, but we have a problem of how determine a perfect hash for the init function, and more, benchmarks proves that sysv semaphore aren't that stable. For pure locking/unlocking, pthread is better in performance than sysV, but it suffers from big initialization times. In this sense, a kernel memory space is used for saving the locks, and persistence permits to avoid initializations over uses.
+ * @details the use of pthread robust mutexes was chosen due to the fact we privilege security over fastness, and that pthread mutexes permits to recover semaphores even with crash ,and that it does not require access to resources that can be easily accessible from extern usage as flock file locking mechanism. A possible other locking mechanism could be the sysv semaphores, but we have a problem of how determine a perfect hash for the init function, and more, benchmarks proves that sysv semaphore aren't that stable. For pure locking/unlocking, pthread is better in performance than sysV, but it suffers from big initialization times. In this sense, a kernel memory space is used for saving the locks, and persistence permits to avoid initializations over uses.
*
- * We considered that mutex implmentation is enough compared to a reader/writer implementation. If it should change, please go to sysv semaphore.
+ * We considered that mutex implmentation is enough compared to a reader/writer implementation. If it should change, please go to sysv semaphore.
*
- * Basic explanation on how semaphores here work: a semaphore here is a positive integer, thus that can't go below zero, which is initiated with a value. when a process want access to the critical resource, it asks to decrement the value of the semaphore, and when it has finished, it reincrements it.basically, when the semaphore is equal to zero, any process must have to wait for it to be reincremented before decrementing it again. Here are defined two types of access to the semaphore corresponding to the reader/writer problem : an exclusive lock, which means that no other process than the one who have the resource can access it; a shared lock, which means that other processes who want to access to the resource with a shared lock can have the access, but a concurrent process who want to access the semaphore with an exclusive lock won't be able to.
+ * Basic explanation on how semaphores here work: a semaphore here is a positive integer, thus that can't go below zero, which is initiated with a value. when a process want access to the critical resource, it asks to decrement the value of the semaphore, and when it has finished, it reincrements it.basically, when the semaphore is equal to zero, any process must have to wait for it to be reincremented before decrementing it again. Here are defined two types of access to the semaphore corresponding to the reader/writer problem : an exclusive lock, which means that no other process than the one who have the resource can access it; a shared lock, which means that other processes who want to access to the resource with a shared lock can have the access, but a concurrent process who want to access the semaphore with an exclusive lock won't be able to.
* explanation on locks here : here locks are registered in kernel memory, where they are defined by a pthread_mutex_t and an identifier name, which corresponds most of the time to a mix of the register associated name and processus (but it's up to the user). The iterations like searching a lock are done on this id name.
*/
diff --git a/pcilib/locking.h b/pcilib/locking.h
index cc45576..5e4c6e9 100644
--- a/pcilib/locking.h
+++ b/pcilib/locking.h
@@ -14,7 +14,7 @@
#include <pcilib/kmem.h>
#include <pcilib/lock.h>
-typedef uint32_t pcilib_lock_id_t; /**< type to represent the index of a lock in the table of locks in the kernel space*/
+typedef uint32_t pcilib_lock_id_t; /**< type to represent the index of a lock in the table of locks in the kernel space*/
typedef struct pcilib_locking_s pcilib_locking_t;
@@ -22,9 +22,9 @@ typedef struct pcilib_locking_s pcilib_locking_t;
* structure defining the kernel space used for locks
*/
struct pcilib_locking_s {
- pcilib_kmem_handle_t *kmem; /**< kmem used to store mutexes */
- pcilib_lock_t *locking; /**< lock used while intializing kernel space */
-// pcilib_lock_t *mmap; /**< lock used to protect mmap operation */
+ pcilib_kmem_handle_t *kmem; /**< kmem used to store mutexes */
+ pcilib_lock_t *locking; /**< lock used while intializing kernel space */
+// pcilib_lock_t *mmap; /**< lock used to protect mmap operation */
};
#ifdef __cplusplus
diff --git a/pcilib/model.h b/pcilib/model.h
index 660c363..acb2217 100644
--- a/pcilib/model.h
+++ b/pcilib/model.h
@@ -6,6 +6,7 @@
#include <pcilib/dma.h>
#include <pcilib/event.h>
#include <pcilib/export.h>
+#include <pcilib/view.h>
typedef struct {
@@ -18,6 +19,8 @@ typedef struct {
const pcilib_register_bank_description_t *banks;
const pcilib_register_protocol_description_t *protocols;
const pcilib_register_range_t *ranges;
+ const pcilib_view_description_t **views;
+ const pcilib_unit_description_t *units;
const pcilib_event_description_t *events;
const pcilib_event_data_type_description_t *data_types;
diff --git a/pcilib/pci.c b/pcilib/pci.c
index b37e817..5c25473 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -139,34 +139,28 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
}
ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE;
- ctx->alloc_views=PCILIB_DEFAULT_VIEW_SPACE;
+ ctx->alloc_views = PCILIB_DEFAULT_VIEW_SPACE;
+ ctx->alloc_units = PCILIB_DEFAULT_UNIT_SPACE;
ctx->registers = (pcilib_register_description_t *)malloc(PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_description_t));
ctx->register_ctx = (pcilib_register_context_t *)malloc(PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_context_t));
- ctx->views = (pcilib_view_t*)malloc(PCILIB_DEFAULT_VIEW_SPACE * sizeof(pcilib_view_t));
- ctx->alloc_units=PCILIB_DEFAULT_UNIT_SPACE;
- ctx->units=(pcilib_unit_t*)malloc(PCILIB_DEFAULT_UNIT_SPACE * sizeof(pcilib_unit_t));
+ ctx->views = (pcilib_view_description_t**)malloc(PCILIB_DEFAULT_VIEW_SPACE * sizeof(pcilib_view_description_t*));
+ ctx->units = (pcilib_unit_description_t*)malloc(PCILIB_DEFAULT_UNIT_SPACE * sizeof(pcilib_unit_description_t));
- if ((!ctx->registers)||(!ctx->register_ctx)) {
+ if ((!ctx->registers)||(!ctx->register_ctx)||(!ctx->views)||(!ctx->units)) {
pcilib_error("Error allocating memory for register model");
pcilib_close(ctx);
return NULL;
}
- /* i think we need a better error handling here, because, it's not that a problem to not have views working, but how to block the use if the memory here was not good?, and we could have only one type of views that is working*/
- if((!ctx->units) || !(ctx->views)){
- pcilib_warning("Error allocating memory for views");
- }
-
-
memset(ctx->registers, 0, sizeof(pcilib_register_description_t));
+ memset(ctx->units, 0, sizeof(pcilib_unit_t));
+ memset(ctx->views, 0, sizeof(pcilib_view_t));
memset(ctx->banks, 0, sizeof(pcilib_register_bank_description_t));
memset(ctx->ranges, 0, sizeof(pcilib_register_range_t));
memset(ctx->register_ctx, 0, PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_context_t));
- memset(ctx->units,0,sizeof(pcilib_unit_t));
- memset(ctx->views,0,sizeof(pcilib_view_t));
for (i = 0; pcilib_protocols[i].api; i++);
memcpy(ctx->protocols, pcilib_protocols, i * sizeof(pcilib_register_protocol_description_t));
@@ -204,6 +198,8 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
ctx->model_info.banks = ctx->banks;
ctx->model_info.protocols = ctx->protocols;
ctx->model_info.ranges = ctx->ranges;
+ ctx->model_info.views = (const pcilib_view_description_t**)ctx->views;
+ ctx->model_info.units = ctx->units;
err = pcilib_init_register_banks(ctx);
if (err) {
@@ -363,7 +359,8 @@ char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) {
void pcilib_close(pcilib_t *ctx) {
- pcilib_bar_t i;
+ int i;
+ pcilib_bar_t bar;
if (ctx) {
pcilib_dma_engine_t dma;
@@ -383,10 +380,14 @@ void pcilib_close(pcilib_t *ctx) {
pcilib_free_register_banks(ctx);
- pcilib_free_xml(ctx);
-
- if (ctx->register_ctx)
+ if (ctx->register_ctx) {
+ pcilib_register_t reg;
+ for (reg = 0; reg < ctx->num_reg; reg++) {
+ if (ctx->register_ctx[reg].views)
+ free(ctx->register_ctx[reg].views);
+ }
free(ctx->register_ctx);
+ }
if (ctx->event_plugin)
pcilib_plugin_close(ctx->event_plugin);
@@ -402,23 +403,34 @@ void pcilib_close(pcilib_t *ctx) {
}
}
- for (i = 0; i < PCILIB_MAX_BARS; i++) {
- if (ctx->bar_space[i]) {
- char *ptr = ctx->bar_space[i];
- ctx->bar_space[i] = NULL;
- pcilib_unmap_bar(ctx, i, ptr);
+ for (bar = 0; bar < PCILIB_MAX_BARS; bar++) {
+ if (ctx->bar_space[bar]) {
+ char *ptr = ctx->bar_space[bar];
+ ctx->bar_space[bar] = NULL;
+ pcilib_unmap_bar(ctx, bar, ptr);
}
}
if (ctx->pci_cfg_space_fd >= 0)
close(ctx->pci_cfg_space_fd);
+ if (ctx->units);
+ free(ctx->units);
+
+ if (ctx->views) {
+ for (i = 0; ctx->views[i]; i++)
+ free(ctx->views[i]);
+ free(ctx->views);
+ }
+
if (ctx->registers)
free(ctx->registers);
if (ctx->model)
free(ctx->model);
+ pcilib_free_xml(ctx);
+
if (ctx->handle >= 0)
close(ctx->handle);
diff --git a/pcilib/pci.h b/pcilib/pci.h
index f364890..ab80101 100644
--- a/pcilib/pci.h
+++ b/pcilib/pci.h
@@ -9,12 +9,14 @@
#define PCILIB_MAX_BARS 6 /**< this is defined by PCI specification */
#define PCILIB_DEFAULT_REGISTER_SPACE 1024 /**< number of registers to allocate on init */
#define PCILIB_DEFAULT_VIEW_SPACE 128 /**< number of views to allocate on init */
-#define PCILIB_DEFAULT_UNIT_SPACE 128 /** number of units to allocate on init*/
+#define PCILIB_DEFAULT_UNIT_SPACE 128 /**< number of units to allocate on init */
#define PCILIB_MAX_REGISTER_BANKS 32 /**< maximum number of register banks to allocate space for */
#define PCILIB_MAX_REGISTER_RANGES 32 /**< maximum number of register ranges to allocate space for */
#define PCILIB_MAX_REGISTER_PROTOCOLS 32 /**< maximum number of register protocols to support */
#define PCILIB_MAX_DMA_ENGINES 32 /**< maximum number of supported DMA engines */
+#include <uthash.h>
+
#include "linux-3.10.h"
#include "driver/pciDriver.h"
@@ -28,7 +30,7 @@
#include "export.h"
#include "locking.h"
#include "xml.h"
-#include "views.h"
+#include "view.h"
typedef struct {
uint8_t max_link_speed, link_speed;
@@ -36,6 +38,26 @@ typedef struct {
uint8_t max_payload, payload;
} pcilib_pcie_link_info_t;
+struct pcilib_view_context_s {
+ UT_hash_handle hh;
+ pcilib_view_t view;
+ pcilib_view_api_description_t *api;
+ pcilib_view_description_t desc; /**< We will allocate more memory and store actual description instance here, so it should be the last member */
+};
+
+struct pcilib_unit_context_s {
+ UT_hash_handle hh;
+ pcilib_unit_t unit;
+ pcilib_unit_description_t desc;
+};
+
+typedef struct {
+ pcilib_register_bank_t bank; /**< Reference to bank containing the register */
+ pcilib_register_value_t min, max; /**< Minimum & maximum allowed values */
+ pcilib_xml_node_t *xml; /**< Additional XML properties */
+ pcilib_view_reference_t *views; /**< For non-static list of views, this vairables holds a copy of a NULL-terminated list from model (if present, memory should be de-allocated) */
+} pcilib_register_context_t;
+
struct pcilib_s {
int handle; /**< file handle of device */
@@ -65,8 +87,6 @@ struct pcilib_s {
size_t num_banks, num_protocols, num_ranges; /**< Number of registered banks, protocols, and register ranges */
size_t num_engines; /**< Number of configured DMA engines */
size_t dyn_banks; /**< Number of configured dynamic banks */
- size_t num_views,alloc_views; /**< Number of configured and allocated views*/
- size_t num_units,alloc_units; /**< Number of configured and allocated units*/
pcilib_register_description_t *registers; /**< List of currently defined registers (from all sources) */
pcilib_register_bank_description_t banks[PCILIB_MAX_REGISTER_BANKS + 1]; /**< List of currently defined register banks (from all sources) */
pcilib_register_range_t ranges[PCILIB_MAX_REGISTER_RANGES + 1]; /**< List of currently defined register ranges (from all sources) */
@@ -79,15 +99,17 @@ struct pcilib_s {
pcilib_dma_context_t *dma_ctx; /**< DMA context */
pcilib_context_t *event_ctx; /**< Implmentation context */
+ size_t num_views, alloc_views; /**< Number of configured and allocated views*/
+ size_t num_units, alloc_units; /**< Number of configured and allocated units*/
+ pcilib_view_description_t **views; /**< list of currently defined views */
+ pcilib_unit_description_t *units; /**< list of currently defined units */
+
pcilib_lock_t *dma_rlock[PCILIB_MAX_DMA_ENGINES]; /**< Per-engine locks to serialize streaming and read operations */
pcilib_lock_t *dma_wlock[PCILIB_MAX_DMA_ENGINES]; /**< Per-engine locks to serialize write operations */
struct pcilib_locking_s locks; /**< Context of locking subsystem */
struct pcilib_xml_s xml; /**< XML context */
- pcilib_view_t* views; /**< list of currently defined views*/
- pcilib_unit_t* units; /** list of currently defined units*/
-
#ifdef PCILIB_FILE_IO
int file_io_handle;
#endif /* PCILIB_FILE_IO */
diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h
index 6bb018d..8e55d00 100644
--- a/pcilib/pcilib.h
+++ b/pcilib/pcilib.h
@@ -13,6 +13,8 @@ typedef uint32_t pcilib_version_t;
typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */
typedef uint16_t pcilib_register_t; /**< Type holding the register position within the field listing registers in the model */
+typedef uint16_t pcilib_view_t; /**< Type holding the register view position within view listing in the model */
+typedef uint16_t pcilib_unit_t; /**< Type holding the value unit position within unit listing in the model */
typedef uint32_t pcilib_register_addr_t; /**< Type holding the register address within address-space of BARs */
typedef uint8_t pcilib_register_size_t; /**< Type holding the size in bits of the register */
typedef uint32_t pcilib_register_value_t; /**< Type holding the register value */
@@ -39,6 +41,12 @@ typedef enum {
} pcilib_endianess_t;
typedef enum {
+ PCILIB_TYPE_STRING = 0, /**< char* */
+ PCILIB_TYPE_DOUBLE = 1, /**< double */
+ PCILIB_TYPE_LONG = 2
+} pcilib_data_type_t;
+
+typedef enum {
PCILIB_DMA_IRQ = 1,
PCILIB_EVENT_IRQ = 2
} pcilib_irq_type_t;
@@ -192,6 +200,9 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg
int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value);
int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value);
+int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_data_type_t value_type, size_t value_size, void *value);
+int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_data_type_t value_type, size_t value_size, void *value);
+
int pcilib_reset(pcilib_t *ctx);
int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data);
diff --git a/pcilib/register.h b/pcilib/register.h
index 13d4c9b..74eeb12 100644
--- a/pcilib/register.h
+++ b/pcilib/register.h
@@ -3,7 +3,6 @@
#include <pcilib.h>
#include <pcilib/bank.h>
-#include <pcilib/views.h>
#define PCILIB_REGISTER_NO_BITS 0
#define PCILIB_REGISTER_ALL_BITS ((pcilib_register_value_t)-1)
@@ -25,6 +24,11 @@ typedef enum {
} pcilib_register_type_t;
typedef struct {
+ const char *name;
+ const char *view;
+} pcilib_view_reference_t;
+
+typedef struct {
pcilib_register_addr_t addr; /**< Register address in the bank */
pcilib_register_size_t offset; /**< Register offset in the byte (in bits) */
pcilib_register_size_t bits; /**< Register size in bits */
@@ -38,18 +42,12 @@ typedef struct {
are on in the value are cleared/inverted). For information only, no preprocessing on bits is performed. */
pcilib_register_type_t type; /**< Defines type of register is it standard register, subregister for bit fields or view, fifo */
pcilib_register_bank_addr_t bank; /**< Specified the address of the bank this register belongs to */
-
+
const char *name; /**< The access name of the register */
const char *description; /**< Brief description of the register */
-} pcilib_register_description_t;
-
-typedef struct {
- pcilib_register_bank_t bank; /**< Reference to bank containing the register */
- pcilib_register_value_t min, max; /**< Minimum & maximum allowed values */
- pcilib_xml_node_t *xml; /**< Additional XML properties */
- pcilib_view_t *views; /** list of views linked to this register*/
-} pcilib_register_context_t;
+ pcilib_view_reference_t *views; /**< List of supported views for this register */
+} pcilib_register_description_t;
#ifdef __cplusplus
diff --git a/pcilib/unit.c b/pcilib/unit.c
new file mode 100644
index 0000000..2dd7113
--- /dev/null
+++ b/pcilib/unit.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "pci.h"
+#include "pcilib.h"
+#include "unit.h"
+#include "error.h"
+
+
+pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *unit) {
+ pcilib_unit_t i;
+
+ for(i = 0; ctx->units[i].name; i++) {
+ if (!strcasecmp(ctx->units[i].name, unit))
+ return i;
+ }
+ return PCILIB_UNIT_INVALID;
+}
+
+
+int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *desc) {
+ if (!n) {
+ for (n = 0; desc[n].name; n++);
+ }
+
+ if ((ctx->num_units + n + 1) > ctx->alloc_units) {
+ size_t size;
+ pcilib_unit_description_t *units;
+
+ for (size = ctx->alloc_units; size < 2 * (n + ctx->num_units + 1); size <<= 1);
+
+ units = (pcilib_unit_description_t*)realloc(ctx->units, size * sizeof(pcilib_unit_description_t));
+ if (!units) return PCILIB_ERROR_MEMORY;
+
+ ctx->units = units;
+ ctx->alloc_units = size;
+
+ ctx->model_info.units = units;
+ }
+
+ memcpy(ctx->units + ctx->num_units, desc, n * sizeof(pcilib_unit_description_t));
+ memset(ctx->units + ctx->num_units + n, 0, sizeof(pcilib_unit_description_t));
+
+ ctx->num_units += n;
+
+ return 0;
+}
diff --git a/pcilib/unit.h b/pcilib/unit.h
new file mode 100644
index 0000000..9c62ff3
--- /dev/null
+++ b/pcilib/unit.h
@@ -0,0 +1,36 @@
+#ifndef _PCILIB_UNIT_H
+#define _PCILIB_UNIT_H
+
+#include <pcilib.h>
+
+#define PCILIB_UNIT_INVALID ((pcilib_unit_t)-1)
+#define PCILIB_MAX_TRANSFORMS_PER_UNIT 16 /**< Limits number of supported transforms per unit */
+
+typedef struct pcilib_unit_context_s *pcilib_unit_context_t;
+
+/**
+ * unit transformation routines
+ */
+typedef struct {
+ char *unit; /**< Name of the resulting unit */
+ char *transform; /**< String, similar to view formula, explaining transform to this unit */
+} pcilib_unit_transform_t;
+
+typedef struct {
+ char *name; /**< Unit name */
+ pcilib_unit_transform_t transforms[PCILIB_MAX_TRANSFORMS_PER_UNIT + 1]; /**< Transforms to other units */
+} pcilib_unit_description_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *desc);
+pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *unit);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _PCILIB_UNIT_H */
diff --git a/pcilib/view.c b/pcilib/view.c
new file mode 100644
index 0000000..1179808
--- /dev/null
+++ b/pcilib/view.c
@@ -0,0 +1,74 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "pci.h"
+#include "pcilib.h"
+#include "view.h"
+#include "error.h"
+
+
+pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *view) {
+ pcilib_view_t i;
+
+ for(i = 0; ctx->views[i]; i++) {
+ if (!strcasecmp(ctx->views[i]->name, view))
+ return i;
+ }
+
+ return PCILIB_VIEW_INVALID;
+}
+
+
+
+int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc) {
+ size_t i;
+ void *ptr;
+
+ if (!n) {
+ // No padding between array elements
+ ptr = (void*)desc;
+ while (1) {
+ const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
+ if (v->name) n++;
+ else break;
+ ptr += v->api->description_size;
+ }
+ }
+
+ if ((ctx->num_views + n + 1) > ctx->alloc_views) {
+ size_t size;
+ pcilib_view_description_t **views;
+ for (size = ctx->alloc_views; size < 2 * (n + ctx->num_views + 1); size<<=1);
+
+ views = (pcilib_view_description_t**)realloc(ctx->views, size * sizeof(pcilib_view_description_t*));
+ if (!views) return PCILIB_ERROR_MEMORY;
+
+ ctx->views = views;
+ ctx->alloc_views = size;
+
+ ctx->model_info.views = (const pcilib_view_description_t**)views;
+ }
+
+ // No padding between array elements
+ ptr = (void*)desc;
+ for (i = 0; i < n; i++) {
+ const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr;
+ ctx->views[ctx->num_views + i] = (pcilib_view_description_t*)malloc(v->api->description_size);
+ if (!ctx->views[ctx->num_views + i]) {
+ size_t j;
+ for (j = 0; j < i; j++)
+ free(ctx->views[ctx->num_views + j]);
+ ctx->views[ctx->num_views] = NULL;
+ pcilib_error("Error allocating %zu bytes of memory for the view description", v->api->description_size);
+ return PCILIB_ERROR_MEMORY;
+ }
+ memcpy(ctx->views[ctx->num_views + i], v, v->api->description_size);
+ ptr += v->api->description_size;
+ }
+ ctx->views[ctx->num_views + i] = NULL;
+ ctx->num_views += n;
+
+ return 0;
+}
diff --git a/pcilib/view.h b/pcilib/view.h
new file mode 100644
index 0000000..7a78a1d
--- /dev/null
+++ b/pcilib/view.h
@@ -0,0 +1,40 @@
+#ifndef _PCILIB_VIEW_H
+#define _PCILIB_VIEW_H
+
+#include <pcilib.h>
+#include <pcilib/unit.h>
+
+#define PCILIB_VIEW_INVALID ((pcilib_view_t)-1)
+
+//typedef void *pcilib_view_context_t;
+typedef struct pcilib_view_context_s *pcilib_view_context_t;
+
+typedef struct {
+ pcilib_version_t version;
+ size_t description_size;
+ pcilib_view_context_t (*init)(pcilib_t *ctx);
+ void (*free)(pcilib_t *ctx, pcilib_view_context_t *view);
+ int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, const pcilib_register_value_t *regval, pcilib_data_type_t viewval_type, size_t viewval_size, void *viewval);
+ int (*write_to_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, pcilib_data_type_t viewval_type, size_t viewval_size, const void *viewval);
+} pcilib_view_api_description_t;
+
+typedef struct {
+ const pcilib_view_api_description_t *api;
+ pcilib_data_type_t type; /**< The default data type returned by operation, PCILIB_VIEW_TYPE_STRING is supported by all operations */
+ const char *unit; /**< Returned unit (if any) */
+ const char *name; /**< Name of the view */
+ const char *description; /**< Short description */
+} pcilib_view_description_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc);
+pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *view);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PCILIB_VIEW_H */
diff --git a/pcilib/views.c b/pcilib/views.c
deleted file mode 100644
index f15aeb4..0000000
--- a/pcilib/views.c
+++ /dev/null
@@ -1,382 +0,0 @@
-#include <string.h>
-#include "pci.h"
-#include "pcilib.h"
-#include <Python.h>
-#include "views.h"
-#include "error.h"
-#include <strings.h>
-#include <stdlib.h>
-
-/**
- * this function calls the python script and the function "evaluate" in it to evaluate the given formula
- *@param[in] the formula to be evaluated
- *@return the integer value of the evaluated formula (maybe go to float instead)
- */
-static pcilib_register_value_t
-pcilib_view_eval_formula(char* formula){
-
- /* initialization of python interpreter*/
- Py_Initialize();
-
- /*compilation of the formula as python string*/
- PyCodeObject* code=(PyCodeObject*)Py_CompileString(formula,"test",Py_eval_input);
- PyObject* main_module = PyImport_AddModule("__parser__");
- PyObject* global_dict = PyModule_GetDict(main_module);
- PyObject* local_dict = PyDict_New();
- /*evaluation of formula*/
- PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict);
- double c=PyFloat_AsDouble(obj);
-
- /* close interpreter*/
- Py_Finalize();
- pcilib_register_value_t value=(pcilib_register_value_t)c;
- return value;
-}
-
-
-/**
- *
- */
-static char*
-pcilib_view_compute_formula(pcilib_t* ctx, char* formula,char* reg_value_string){
- char *src=(char*)formula;
- char *reg,*regend;
- char *dst=malloc(6*strlen(src)*sizeof(char));
- char temp[66];
- pcilib_register_value_t value;
- int offset=0;
-
- /*we get recursively all registers of string , and if they are not equel to '@reg', then we get their value and put it in formula*/
- while(1){
- reg = strchr(src, '@');
- if (!reg) {
- strcpy(dst+offset, src);
- break;
- }
- regend = strchr(reg + 1, '@');
- if (!regend){
- pcilib_error("formula corresponding is malformed");
- return NULL;
- }
- strncpy(dst+offset, src, reg - src);
- offset+=reg-src;
- *regend = 0;
- /* Now (reg + 1) contains the proper register name, you can compare
-it to reg/value and either get the value of current register or the
-specified one. Add it to the register*/
- if(!(strcasecmp(reg+1,"value")) || !(strcasecmp(reg+1,"reg")) || !(strcasecmp(reg+1,"self"))){
- strncpy(dst+offset,reg_value_string,strlen(reg_value_string));
- offset+=strlen(reg_value_string);
- }else{
- pcilib_read_register(ctx, NULL,reg+1,&value);
- sprintf(temp,"%i",value);
- strncpy(dst+offset,temp,strlen(temp));
- offset+=strlen(temp);
- }
- src = regend + 1;
- }
- return dst;
-}
-
-
-
-
-static int
-pcilib_view_apply_formula(pcilib_t* ctx, char* formula, pcilib_register_value_t* reg_value)
-{
-
- char reg_value_string[66]; /* to register reg_value as a string, need to check the length*/
- sprintf(reg_value_string,"%u",*reg_value);
- formula=pcilib_view_compute_formula(ctx,formula,reg_value_string);
-
- if(!(formula)){
- pcilib_error("computing of formula failed");
- return PCILIB_ERROR_INVALID_DATA;
- }
-
- /* evaluation of the formula*/
- *reg_value= pcilib_view_eval_formula(formula);
- return 0;
-}
-
-/**
- * function to apply a unit for the views of type formula
- *@param[in] view - the view we want to get the units supported
- *@param[in] unit - the requested unit in which we want to get the value
- *@param[in,out] value - the number that needs to get transformed
- */
-static void
-pcilib_view_apply_unit(pcilib_transform_unit_t unit_desc, const char* unit,pcilib_register_value_t* value){
- char* formula;
-
- formula=malloc(strlen(unit_desc.transform_formula)*sizeof(char));
- strcpy(formula,unit_desc.transform_formula);
- pcilib_view_apply_formula(NULL,formula, value);
-
- free(formula);
-}
-
-
-
-int pcilib_read_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, size_t value_size, void *value)
-{
- int i,j,k,err=0;
- pcilib_register_value_t temp_value;
-
- /* we get the index of the register to find the corresponding register context*/
- if((i=pcilib_find_register(ctx,bank,regname))==PCILIB_REGISTER_INVALID){
- pcilib_error("can't get the index of the register %s", regname);
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- /* we get the value of the register, as we will apply the view on it*/
- err=pcilib_read_register_by_id(ctx,i,&temp_value);
- if(err){
- pcilib_error("can't read the register %s value before applying views : error %i",regname);
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
-
- for(j=0;ctx->register_ctx[i].views[j].name;j++){
- if(!(strcasecmp("name",(char*)unit))){/*if we asked for the unit "name"*/
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters,NULL/*the command name*/,0,&temp_value,value_size,value);
- if(err){
- pcilib_error("can't read from the register with the enum view");
- return PCILIB_ERROR_FAILED;
- }
- return 0;
- }else if(!(strcasecmp(ctx->register_ctx[i].views[j].base_unit.name,(char*)unit))){/*in this case we asked for the name of the view in unit*/
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters,(char*)unit, 0, &temp_value,0,&(ctx->register_ctx[i].views[j]));
- if(err){
- pcilib_error("can't read from the register with the formula view %s", unit);
- return PCILIB_ERROR_FAILED;
- }
- *(pcilib_register_value_t*)value=temp_value;
- return 0;
- }else{
- for(k=0;ctx->register_ctx[i].views[j].base_unit.transforms[k].name;k++){
- if(!(strcasecmp(ctx->register_ctx[i].views[j].base_unit.transforms[k].name,(char*)unit))){
- ctx->register_ctx[i].views[j].base_unit.transforms[k].name
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters,(char*)unit, 0, &temp_value,0,&(ctx->register_ctx[i].views[j]));
- /***wrong***/ pcilib_view_apply_unit(ctx->register_ctx[i].views[j].base_unit.transforms[k].name,unit,(pcilib_register_value_t*)value);
- if(err){
- pcilib_error("can't write to the register with the formula view %s", unit);
- return PCILIB_ERROR_FAILED;
- }
- *(pcilib_register_value_t*)value=temp_value;
- return 0;
- }
- }
- }
- }
-
- pcilib_error("the view asked and the register do not correspond");
- return PCILIB_ERROR_NOTAVAILABLE;
-}
-
-
-/**
- * function to write to a register using a view
- */
-int pcilib_write_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, size_t value_size,void* value){
- int i,j,k;
- pcilib_register_value_t temp_value;
- int err;
- int next=1,ok=0;
-
- /* we get the index of the register to find the corresponding register context*/
- if((i=pcilib_find_register(ctx,bank,regname))==PCILIB_REGISTER_INVALID){
- pcilib_error("can't get the index of the register %s", regname);
- return PCILIB_ERROR_INVALID_REQUEST;
- }
-
- for(j=0;ctx->register_ctx[i].views[j].name;j++){
- if(!(strcasecmp((char*)unit,"name"))){/*if we asked for the unit "name"*/
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters,NULL,1,&temp_value,0,value);
- if(err){
- pcilib_error("can't write to the register with the enum view");
- return PCILIB_ERROR_FAILED;
- }
- ok=1;
- break;
- }else if(!(strcasecmp(ctx->register_ctx[i].views[j].base_unit.name,(char*)unit))){/*in this case we asked for then name of the view in unit*/
- //temp_value=*(pcilib_register_value_t*)value /*the value to put in the register*/;
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters, (char*)unit, 1, &temp_value,0,&(ctx->register_ctx[i].views[j]));
- if(err){
- pcilib_error("can't write to the register with the formula view %s", unit);
- return PCILIB_ERROR_FAILED;
- }
- ok=1;
- break;
- }else{
- for(k=0;ctx->register_ctx[i].views[j].base_unit.transforms[k].name;k++){
- if(!(strcasecmp(ctx->register_ctx[i].views[j].base_unit.transforms[k].name,(char*)unit))){
- pcilib_view_apply_unit(ctx->register_ctx[i].views[j].base_unit.transforms[k].name,unit,(pcilib_register_value_t*)value);
- err=ctx->register_ctx[i].views[j].op(ctx,ctx->register_ctx[i].views[j].parameters, (char*)unit, 1, &temp_value,0,&(ctx->register_ctx[i].views[j]));
- if(err){
- pcilib_error("can't write to the register with the formula view %s", unit);
- return PCILIB_ERROR_FAILED;
- }
- next=0;
- ok=1;
- break;
- }
- }
- if(next==0)break;
- }
- }
-
- if(ok==1) {
- pcilib_write_register(ctx,bank,regname,temp_value);
- printf("value %i written in register\n",temp_value);
- return 0;
- }
-
- pcilib_error("the view asked and the register do not correspond");
- return PCILIB_ERROR_NOTAVAILABLE;
-}
-
-/**
- * always : viewval=view params=view params
- * write: name=enum command regval:the value corresponding to the command
- */
-int operation_enum(pcilib_t *ctx, void *params, char* unit, int view2reg, pcilib_register_value_t *regval, size_t viewval_size, void* viewval){
- int j,k;
- if(view2reg==1){
- for(j=0; ((pcilib_enum_t*)(params))[j].name;j++){
- if(!(strcasecmp(((pcilib_enum_t*)(params))[j].name,(char*)viewval))){
- *regval=((pcilib_enum_t*)(params))[j].value;
- return 0;
- }
- }
- }else if (view2reg==0){
- for(j=0; ((pcilib_enum_t*)(params))[j].name;j++){
- if (*regval<=((pcilib_enum_t*)(params))[j].max && *regval>=((pcilib_enum_t*)(params))[j].min){
- if(viewval_size<strlen(((pcilib_enum_t*)(params))[j].name)){
- pcilib_error("the string to contain the enum command is too tight");
- return PCILIB_ERROR_MEMORY;
- }
- strncpy((char*)viewval,((pcilib_enum_t*)(params))[j].name, strlen(((pcilib_enum_t*)(params))[j].name));
- k=strlen(((pcilib_enum_t*)(params))[j].name);
- ((char*)viewval)[k]='\0';
- return 0;
- }
- }
- }
- return PCILIB_ERROR_INVALID_REQUEST;
-}
-
-/**
- * pârams: view params unit=unit wanted regval:value before formula/after formula viewval=view
- */
-int operation_formula(pcilib_t *ctx, void *params, char* unit, int view2reg, pcilib_register_value_t *regval, size_t viewval_size, void* viewval){
- int j=0;
- pcilib_register_value_t value=0;
- char* formula=NULL;
-
- if(view2reg==0){
- if(!(strcasecmp(unit,((pcilib_view_t*)viewval)->base_unit.name))){
- formula=malloc(sizeof(char)*strlen(((pcilib_formula_t*)params)->read_formula));
- if(!(formula)){
- pcilib_error("can't allocate memory for the formula");
- return PCILIB_ERROR_MEMORY;
- }
- strncpy(formula,((pcilib_formula_t*)params)->read_formula,strlen(((pcilib_formula_t*)params)->read_formula));
- pcilib_view_apply_formula(ctx,formula,regval);
- return 0;
- }
-
- for(j=0; ((pcilib_view_t*)viewval)->base_unit.transforms[j].name;j++){
- if(!(strcasecmp(((pcilib_view_t*)viewval)->base_unit.transforms[j].name,unit))){
- /* when we have found the correct view of type formula, we apply the formula, that get the good value for return*/
- formula=malloc(sizeof(char)*strlen(((pcilib_formula_t*)params)->read_formula));
- if(!(formula)){
- pcilib_error("can't allocate memory for the formula");
- return PCILIB_ERROR_MEMORY;
- }
- strncpy(formula,((pcilib_formula_t*)params)->read_formula,strlen(((pcilib_formula_t*)params)->read_formula));
- pcilib_view_apply_formula(ctx,formula, regval);
- // pcilib_view_apply_unit(((pcilib_view_t*)viewval)->base_unit.transforms[j],unit,regval);
- return 0;
- }
- }
- }else if(view2reg==1){
- if(!(strcasecmp(unit, ((pcilib_view_t*)viewval)->base_unit.name))){
- formula=malloc(sizeof(char)*strlen(((pcilib_formula_t*)params)->write_formula));
- strncpy(formula,((pcilib_formula_t*)params)->write_formula,strlen(((pcilib_formula_t*)params)->write_formula));
- pcilib_view_apply_formula(ctx,formula,regval);
- return 0;
- }
-
- for(j=0;((pcilib_view_t*)viewval)->base_unit.transforms[j].name;j++){
- if(!(strcasecmp(((pcilib_view_t*)viewval)->base_unit.transforms[j].name,unit))){
- /* when we have found the correct view of type formula, we apply the formula, that get the good value for return*/
- formula=malloc(sizeof(char)*strlen(((pcilib_formula_t*)params)->write_formula));
- strncpy(formula,((pcilib_formula_t*)params)->write_formula,strlen((( pcilib_formula_t*)params)->write_formula));
- //pcilib_view_apply_unit(((pcilib_view_t*)viewval)->base_unit.transforms[j],unit,regval);
- pcilib_view_apply_formula(ctx,formula,regval);
- /* we maybe need some error checking there , like temp_value >min and <max*/
- return 0;
- }
- }
- }
- free(formula);
- return PCILIB_ERROR_INVALID_REQUEST;
-}
-
-
-/**
- * function to populate ctx views, as we could do for registers or banks
- */
-int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_t* views) {
-
- pcilib_view_t *views2;
- size_t size;
-
- if (!n) {
- for (n = 0; views[n].name; n++);
- }
-
- if ((ctx->num_views + n + 1) > ctx->alloc_views) {
- for (size = ctx->alloc_views; size < 2 * (n + ctx->num_views + 1); size<<=1);
-
- views2 = (pcilib_view_t*)realloc(ctx->views, size * sizeof(pcilib_view_t));
- if (!views2) return PCILIB_ERROR_MEMORY;
-
- ctx->views = views2;
- ctx->alloc_views = size;
- }
-
- memcpy(ctx->views + ctx->num_views, views, n * sizeof(pcilib_view_t));
- memset(ctx->views + ctx->num_views + n, 0, sizeof(pcilib_view_t));
-
- ctx->num_views += n;
- return 0;
-}
-
-int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_t* units) {
-
- pcilib_unit_t *units2;
- size_t size;
-
- if (!n) {
- for (n = 0; units[n].name[0]; n++);
- }
-
- if ((ctx->num_units + n + 1) > ctx->alloc_units) {
- for (size = ctx->alloc_units; size < 2 * (n + ctx->num_units + 1); size<<=1);
-
- units2 = (pcilib_unit_t*)realloc(ctx->units, size * sizeof(pcilib_unit_t));
- if (!units2) return PCILIB_ERROR_MEMORY;
-
- ctx->units = units2;
- ctx->alloc_units = size;
- }
-
- memcpy(ctx->units + ctx->num_units, units, n * sizeof(pcilib_unit_t));
- memset(ctx->units + ctx->num_units + n, 0, sizeof(pcilib_unit_t));
-
- ctx->num_units += n;
-
- return 0;
-}
diff --git a/pcilib/views.h b/pcilib/views.h
deleted file mode 100644
index c44393d..0000000
--- a/pcilib/views.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef _PCILIB_VIEWS_H
-#define _PCILIB_VIEWS_H
-
-#include "pcilib.h"
-
-#define PCILIB_MAX_TRANSFORMS_PER_UNIT 16
-
-typedef struct pcilib_transform_unit_s pcilib_transform_unit_t;
-
-typedef struct pcilib_unit_s pcilib_unit_t;
-
-typedef struct pcilib_enum_s pcilib_enum_t;
-
-typedef struct pcilib_view_s pcilib_view_t;
-
-typedef struct pcilib_formula_s pcilib_formula_t;
-
-typedef int (*pcilib_view_operation_t)(pcilib_t *ctx, void *params, char* string, int read_or_write, pcilib_register_value_t *regval, size_t viewval_size, void* viewval);
-
-/**
- * type to save a transformation unit in the pcitool program
- */
-struct pcilib_transform_unit_s{
- char *name;
- char *transform_formula;
-};
-
-/**
- * type to save a unit in the pcitool programm
- */
-struct pcilib_unit_s{
- char* name;
- pcilib_transform_unit_t transforms[PCILIB_MAX_TRANSFORMS_PER_UNIT];
-};
-
-/**
- * new type to define an enum view
- */
-struct pcilib_enum_s {
- const char *name; /**<corresponding string to value*/
- pcilib_register_value_t value, min, max;
-};
-
-struct pcilib_formula_s{
- char* read_formula;
- char* write_formula;
-};
-
-struct pcilib_view_s{
- const char* name;
- const char* description;
- pcilib_view_operation_t op;
- void* parameters;
- pcilib_unit_t base_unit;
-};
-
-/**
- * function to read a register using a view
- */
-int pcilib_read_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, size_t value_size, void *value);
-
-/**
- * function to write to a register using a view
- */
-int pcilib_write_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, size_t value_size, void *value);
-
-int operation_enum(pcilib_t *ctx, void *params, char* name, int view2reg, pcilib_register_value_t *regval, size_t viewval_size, void* viewval);
-
-int operation_formula(pcilib_t *ctx, void *params, char* unit, int view2reg, pcilib_register_value_t *regval, size_t viewval_size, void* viewval);
-
-int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_t* views);
-
-
-/**
- * function to populate the ctx with units
- */
-int pcilib_add_units(pcilib_t* ctx, size_t n, const pcilib_unit_t* units);
-
-
-
-#endif
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 31b9926..c431b73 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -39,18 +39,25 @@
#include "register.h"
#include "xml.h"
#include "error.h"
-#include "views.h"
+#include "view.h"
+#include "views/enum.h"
+#include "views/transform.h"
-#define BANKS_PATH ((xmlChar*)"/model/banks/bank/bank_description") /**< path to complete nodes of banks.*/
-//#define REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register") /**< all standard registers nodes.*/
-//#define BIT_REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register/registers_bits/register_bits") /**< all bits registers nodes.*/
-#define REGISTERS_PATH ((xmlChar*)"../registers/register") /**< all standard registers nodes.*/
-#define BIT_REGISTERS_PATH ((xmlChar*)"./registers_bits/register_bits") /**< all bits registers nodes.*/
-#define VIEWS_PATH ((xmlChar*)"/model/views/view") /**< path to complete nodes of views.*/
-#define UNITS_PATH ((xmlChar*)"/model/units/unit") /**< path to complete nodes of units.*/
+#define BANKS_PATH ((xmlChar*)"/model/bank") /**< path to complete nodes of banks */
+#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 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 */
-static char *pcilib_xml_bank_default_format = "0x%lx";
+
+
+static const char *pcilib_xml_bank_default_format = "0x%lx";
+static const char *pcilib_xml_enum_view_unit = "name";
typedef struct {
pcilib_register_description_t base;
@@ -63,7 +70,7 @@ static xmlNodePtr pcilib_xml_get_parent_bank_node(xmlDocPtr doc, xmlNodePtr node
bank_node = node->parent->parent;
// bank_description is always a first node according to the XSD schema
return xmlFirstElementChild(bank_node);
-
+
}
static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr node) {
@@ -71,150 +78,105 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr
}
*/
-/**
- * get the associated unit of a view
- * this function is maybe completekly useless : we need to decide if we iterate directly in ctx or n view when we want to apply a unit. (in the second choice of course keep it).
- */
-static void
-pcilib_get_unit_of_view(pcilib_t* ctx,pcilib_view_t* myview, char* base_unit){
- int j;
- if((strcasecmp(base_unit,"name"))){
- for(j=0;ctx->units[j].name;j++){
- if(!(strcasecmp(base_unit,ctx->units[j].name))){
- myview->base_unit=ctx->units[j];
- break;
- }
- }
- }
-}
-
-/**
- * get the associated views of a register, to fill its register context
- */
-static int
-pcilib_get_associated_views(pcilib_t* ctx, const char* reg_name,xmlXPathContextPtr xpath,pcilib_register_t id,int mode){
-
- /* i find this solution pretty elegant, but what about perf?*/
- char* VIEWS_NAME_PATH_BITS="/model/banks/bank/registers/register[./name=\"%s\"]/registers_bits/register_bits/views/view";
- char* VIEWS_NAME_PATH="/model/banks/bank/registers/register[./name=\"%s\"]/views/view";
- char* path;
- xmlXPathObjectPtr nodes;
- xmlNodeSetPtr nodeset;
- char* view_name;
-
- /*we get first the nodes corresponding to the given register*/
- if(mode==1) path=malloc(strlen(VIEWS_NAME_PATH)+strlen(reg_name));
- else path=malloc(strlen(VIEWS_NAME_PATH_BITS)+strlen(reg_name));
- if(!(path)){
- pcilib_error("can't allocate memory for getting path to get associated views of %s",reg_name);
- return PCILIB_ERROR_MEMORY;
- }
-
- if(mode==1) sprintf(path,VIEWS_NAME_PATH,reg_name);
- else sprintf(path,VIEWS_NAME_PATH_BITS,reg_name);
- nodes = xmlXPathEvalExpression((xmlChar*)path, xpath);
- nodeset = nodes->nodesetval;
- ctx->register_ctx[id].views=malloc(sizeof(pcilib_view_t));
- if(!(ctx->register_ctx[id].views)){
- pcilib_error("error allocating memory for enum views in register context %i",id);
- return PCILIB_ERROR_MEMORY;
- }
+static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) {
+ xmlAttr *cur;
+ char *value, *name;
- if (!xmlXPathNodeSetIsEmpty(nodeset)) {
- int i,k,l=0;
- /*if we correctly get a nodeset, then we iterate through the nodeset to get all views, using their names*/
- for (i = 0; i < nodeset->nodeNr; i++) {
- view_name=(char*)nodeset->nodeTab[i]->children->content;
- /* if the view name obtained is for an enum view, we get all pcilib_enum_t corresponding to the register*/
- for(k=0; ctx->views[k].name; k++){
- if(!(strcasecmp(view_name, ctx->views[k].name))){
- ctx->register_ctx[id].views=realloc(ctx->register_ctx[id].views,(l+1)*sizeof(pcilib_view_t));
- ctx->register_ctx[id].views[l]=ctx->views[k];
- l++;
- }
- }
- }
- ctx->register_ctx[id].views=realloc(ctx->register_ctx[id].views,(l+1)*sizeof(pcilib_view_t));
- ctx->register_ctx[id].views[l].name=NULL;
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if(!cur->children) continue;
+ if(!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+ if (!strcasecmp(name, "name")) {
+ desc->name = value;
+ } else if (!strcasecmp(name, "view")) {
+ desc->view = value;
+ }
}
-
- xmlXPathFreeObject(nodes);
- free(path);
+
+ if (!desc->name)
+ desc->name = desc->view;
+
return 0;
}
-
-static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc, int* views_ok) {
+static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc) {
+ int err;
pcilib_register_description_t *desc = (pcilib_register_description_t*)xml_desc;
- xmlNodePtr cur;
+ xmlXPathObjectPtr nodes;
+ xmlNodeSetPtr nodeset;
+
+ xmlAttrPtr cur;
char *value, *name;
char *endptr;
- for (cur = node->children; cur != NULL; cur = cur->next) {
- if (!cur->children) continue;
- if (!xmlNodeIsText(cur->children)) continue;
-
- name = (char*)cur->name;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
value = (char*)cur->children->content;
if (!value) continue;
-
+
if (!strcasecmp((char*)name, "address")) {
- uintptr_t addr = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid address (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ uintptr_t addr = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid address (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc->addr = addr;
} else if(!strcasecmp(name, "offset")) {
- int offset = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) {
- pcilib_error("Invalid offset (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ int offset = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) {
+ pcilib_error("Invalid offset (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc->offset = (pcilib_register_size_t)offset;
} else if (!strcasecmp(name,"size")) {
- int size = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) {
- pcilib_error("Invalid size (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ int size = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) {
+ pcilib_error("Invalid size (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc->bits = (pcilib_register_size_t)size;
} else if (!strcasecmp(name, "default")) {
- pcilib_register_value_t val = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid default value (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ pcilib_register_value_t val = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid default value (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc->defvalue = val;
} else if (!strcasecmp(name,"min")) {
- pcilib_register_value_t min = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- xml_desc->min = min;
+ pcilib_register_value_t min = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ xml_desc->min = min;
} else if (!strcasecmp(name, "max")) {
- pcilib_register_value_t max = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- xml_desc->max = max;
+ pcilib_register_value_t max = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ xml_desc->max = max;
} else if (!strcasecmp((char*)name,"rwmask")) {
if (!strcasecmp(value, "all")) {
desc->rwmask = PCILIB_REGISTER_ALL_BITS;
} else if (!strcasecmp(value, "none")) {
desc->rwmask = 0;
} else {
- uintptr_t mask = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid mask (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- desc->rwmask = mask;
- }
+ uintptr_t mask = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid mask (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ desc->rwmask = mask;
+ }
} else if (!strcasecmp(name, "mode")) {
if (!strcasecmp(value, "R")) {
desc->mode = PCILIB_REGISTER_R;
@@ -229,113 +191,138 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript
} else if (!strcasecmp(value, "W1C")) {
desc->mode = PCILIB_REGISTER_W1C;
} else {
- pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
+ pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
}
} else if (!strcasecmp(name, "type")) {
if (!strcasecmp(value, "fifo")) {
desc->type = PCILIB_REGISTER_FIFO;
} else {
- pcilib_error("Invalid register type (%s) is specified in the XML register description", value);
- return PCILIB_ERROR_INVALID_DATA;
+ pcilib_error("Invalid register type (%s) is specified in the XML register description", value);
+ return PCILIB_ERROR_INVALID_DATA;
}
} else if (!strcasecmp(name,"name")) {
desc->name = value;
} else if (!strcasecmp(name,"description")) {
desc->description = value;
}
- else if (!strcasecmp(name,"views")) {
- *views_ok=1;
+ }
+
+ xpath->node = node;
+ nodes = xmlXPathEvalExpression(REGISTER_VIEWS_PATH, xpath);
+ xpath->node = NULL;
+
+ if (!nodes) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTER_VIEWS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", REGISTER_VIEWS_PATH);
+ return PCILIB_ERROR_FAILED;
+ }
+
+
+ nodeset = nodes->nodesetval;
+ if (!xmlXPathNodeSetIsEmpty(nodeset)) {
+ int i;
+
+ desc->views = (pcilib_view_reference_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t));
+ if (!desc->views) {
+ xmlXPathFreeObject(nodes);
+ pcilib_error("Failed to allocate %zu bytes of memory to store supported register views", (nodeset->nodeNr + 1) * sizeof(char*));
+ return PCILIB_ERROR_MEMORY;
}
+
+ memset(desc->views, 0, (nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t));
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_parse_view_reference(ctx, doc, nodeset->nodeTab[i], &desc->views[i]);
+ if (err) {
+ xmlXPathFreeObject(nodes);
+ return err;
+ }
+ }
}
+ xmlXPathFreeObject(nodes);
return 0;
}
static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
int err;
- int views_ok=0;
xmlXPathObjectPtr nodes;
xmlNodeSetPtr nodeset;
pcilib_xml_register_description_t desc = {{0}};
pcilib_xml_register_description_t fdesc;
-
+
pcilib_register_t reg;
desc.base.bank = ctx->banks[bank].addr;
desc.base.rwmask = PCILIB_REGISTER_ALL_BITS;
desc.base.mode = PCILIB_REGISTER_R;
desc.base.type = PCILIB_REGISTER_STANDARD;
-
- err = pcilib_xml_parse_register(ctx, &desc, doc, node, &ctx->banks[bank],&views_ok);
+
+ err = pcilib_xml_parse_register(ctx, &desc, xpath, doc, node, &ctx->banks[bank]);
if (err) {
- pcilib_error("Error (%i) parsing an XML register", err);
- return err;
+ pcilib_error("Error (%i) parsing an XML register", err);
+ return err;
}
-
+
err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &desc.base, &reg);
if (err) {
- pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name);
- return err;
+ if (desc.base.views) free(desc.base.views);
+ pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name);
+ return err;
}
- ctx->register_ctx[reg].xml = node;
+ ctx->register_ctx[reg].xml = node;
ctx->register_ctx[reg].min = desc.min;
ctx->register_ctx[reg].max = desc.max;
-
- /* if the register had a node of type views, then we compute its associated registers. I do that here as i need the index for register context*/
- if(views_ok){
- err=pcilib_get_associated_views(ctx,desc.base.name,xpath,reg,1);
- if(err) pcilib_warning("can't get correctly the associated views of the register %s",desc.base.name);
- }
+ ctx->register_ctx[reg].views = desc.base.views;
+
xpath->node = node;
nodes = xmlXPathEvalExpression(BIT_REGISTERS_PATH, xpath);
xpath->node = NULL;
-
+
if (!nodes) {
- xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlErrorPtr xmlerr = xmlGetLastError();
- if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message);
- else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH);
- return PCILIB_ERROR_FAILED;
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH);
+ return PCILIB_ERROR_FAILED;
}
nodeset = nodes->nodesetval;
if (!xmlXPathNodeSetIsEmpty(nodeset)) {
- int i;
-
- for (i = 0; i < nodeset->nodeNr; i++) {
- views_ok=0;
- memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t));
-
- fdesc.base.bank = desc.base.bank;
- fdesc.base.addr = desc.base.addr;
- fdesc.base.mode = desc.base.mode;
- fdesc.base.rwmask = desc.base.rwmask;
- fdesc.base.type = PCILIB_REGISTER_BITS;
-
- err = pcilib_xml_parse_register(ctx, &fdesc, doc, nodeset->nodeTab[i], &ctx->banks[bank],&views_ok);
- if (err) {
- pcilib_error("Error parsing field in the XML register %s", desc.base.name);
- continue;
- }
-
- err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, &reg);
- if (err) {
- pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name);
- continue;
- }
-
- ctx->register_ctx[reg].xml = nodeset->nodeTab[i];
- ctx->register_ctx[reg].min = fdesc.min;
- ctx->register_ctx[reg].max = fdesc.max;
- if(views_ok){
- err=pcilib_get_associated_views(ctx, desc.base.name,xpath,reg,0);
- if(err) pcilib_warning("can't get correctly the associated views of the register %s",fdesc.base.name);
- }
- }
+ int i;
+
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t));
+
+ fdesc.base.bank = desc.base.bank;
+ fdesc.base.addr = desc.base.addr;
+ fdesc.base.mode = desc.base.mode;
+ fdesc.base.rwmask = desc.base.rwmask;
+ fdesc.base.type = PCILIB_REGISTER_BITS;
+
+ err = pcilib_xml_parse_register(ctx, &fdesc, xpath, doc, nodeset->nodeTab[i], &ctx->banks[bank]);
+ if (err) {
+ pcilib_error("Error parsing field in the XML register %s", desc.base.name);
+ continue;
+ }
+
+ err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, &reg);
+ if (err) {
+ if (fdesc.base.views) free(fdesc.base.views);
+ pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name);
+ continue;
+ }
+
+ ctx->register_ctx[reg].xml = nodeset->nodeTab[i];
+ ctx->register_ctx[reg].min = fdesc.min;
+ ctx->register_ctx[reg].max = fdesc.max;
+ ctx->register_ctx[reg].views = fdesc.base.views;
+ }
}
xmlXPathFreeObject(nodes);
@@ -344,11 +331,11 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank
static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
int err;
-
+
int override = 0;
pcilib_register_bank_description_t desc = {0};
pcilib_register_bank_t bank;
- xmlNodePtr cur;
+ xmlAttrPtr cur;
char *value, *name;
char *endptr;
@@ -365,70 +352,70 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
desc.endianess = PCILIB_HOST_ENDIAN;
desc.raw_endianess = PCILIB_HOST_ENDIAN;
- // iterate through all children, representing bank properties, to fill the structure
- for (cur = node->children; cur != NULL; cur = cur->next) {
- if (!cur->children) continue;
- if (!xmlNodeIsText(cur->children)) continue;
-
- name = (char*)cur->name;
+ // iterate through all children, representing bank properties, to fill the structure
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
value = (char*)cur->children->content;
if (!value) continue;
-
+
if (!strcasecmp(name, "bar")) {
- char bar = value[0]-'0';
- if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) {
- pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ char bar = value[0]-'0';
+ if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) {
+ pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.bar = (pcilib_bar_t)bar;
override = 1;
} else if (!strcasecmp(name,"size")) {
- long size = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)||(size<=0)) {
- pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ long size = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)||(size<=0)) {
+ pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.size = (size_t)size;
override = 1;
} else if (!strcasecmp(name,"protocol")) {
- pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value);
- if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) {
- pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_NOTSUPPORTED;
- }
- desc.protocol = ctx->protocols[protocol].addr;
+ pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value);
+ if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) {
+ pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+ desc.protocol = ctx->protocols[protocol].addr;
override = 1;
} else if (!strcasecmp(name,"address")) {
- uintptr_t addr = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ uintptr_t addr = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.read_addr = addr;
desc.write_addr = addr;
override = 1;
} else if (!strcasecmp(name,"read_address")) {
- uintptr_t addr = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ uintptr_t addr = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.read_addr = addr;
override = 1;
} else if (!strcasecmp(name,"write_address")) {
- uintptr_t addr = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ uintptr_t addr = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.write_addr = addr;
override = 1;
} else if(strcasecmp((char*)name,"word_size")==0) {
- int access = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) {
- pcilib_error("Invalid word size (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
+ int access = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) {
+ pcilib_error("Invalid word size (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
desc.access = access;
override = 1;
} else if (!strcasecmp(name,"endianess")) {
@@ -436,8 +423,8 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
else if (!strcasecmp(value,"big")) desc.endianess = PCILIB_BIG_ENDIAN;
else if (!strcasecmp(value,"host")) desc.endianess = PCILIB_HOST_ENDIAN;
else {
- pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value);
- return PCILIB_ERROR_INVALID_DATA;
+ pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
}
override = 1;
} else if (!strcasecmp(name,"format")) {
@@ -449,7 +436,7 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
desc.description = value;
override = 1;
} else if (!strcasecmp((char*)name,"override")) {
- override = 1;
+ override = 1;
}
}
@@ -461,30 +448,237 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
ctx->xml.bank_nodes[bank] = node;
if (ctx->bank_ctx[bank]) {
- ctx->bank_ctx[bank]->xml = node;
+ ctx->bank_ctx[bank]->xml = node;
}
xpath->node = node;
nodes = xmlXPathEvalExpression(REGISTERS_PATH, xpath);
xpath->node = NULL;
-
+
if (!nodes) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message);
- else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH);
- return PCILIB_ERROR_FAILED;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH);
+ return PCILIB_ERROR_FAILED;
}
nodeset = nodes->nodesetval;
if (!xmlXPathNodeSetIsEmpty(nodeset)) {
- int i;
- for (i = 0; i < nodeset->nodeNr; i++) {
- err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]);
- if (err) pcilib_error("Error creating XML registers for bank %s", desc.name);
+ int i;
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]);
+ if (err) pcilib_error("Error creating XML registers for bank %s", desc.name);
+ }
+ }
+ xmlXPathFreeObject(nodes);
+
+ return 0;
+}
+
+static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_view_description_t *desc) {
+ xmlAttrPtr cur;
+ const char *value, *name;
+
+ desc->type = PCILIB_TYPE_STRING;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+ if (!value) continue;
+
+ if (!strcasecmp(name, "name")) {
+ desc->name = value;
+ } else if (!strcasecmp((char*)name, "description")) {
+ desc->description = value;
+ } else if (!strcasecmp((char*)name, "unit")) {
+ desc->unit = value;
+ } else if (!strcasecmp((char*)name, "type")) {
+ if (!strcasecmp(value, "string")) desc->type = PCILIB_TYPE_STRING;
+ else if (!strcasecmp(value, "float")) desc->type = PCILIB_TYPE_DOUBLE;
+ else if (!strcasecmp(value, "int")) desc->type = PCILIB_TYPE_LONG;
+ else {
+ pcilib_error("Invalid type (%s) of register view is specified in the XML bank description", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
+ int err;
+ xmlAttrPtr cur;
+ const char *value, *name;
+
+ pcilib_transform_view_description_t desc = {0};
+
+ desc.base.api = &pcilib_enum_view_xml_api;
+
+ err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc);
+ if (err) return err;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+ if (!value) continue;
+
+ if (!strcasecmp(name, "read_from_register")) {
+ desc.read_from_reg = value;
+ } else if (!strcasecmp(name, "write_to_register")) {
+ desc.write_to_reg = value;
+ }
+ }
+
+
+ return pcilib_add_views(ctx, 1, (pcilib_view_description_t*)&desc);
+}
+
+
+static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_value_name_t *desc) {
+ xmlAttr *cur;
+ char *value, *name;
+ char *endptr;
+
+ int min_set = 0, max_set = 0;
+ pcilib_register_value_t val;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if(!cur->children) continue;
+ if(!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+
+ if (!strcasecmp(name, "name")) {
+ desc->name = value;
+ } else if (!strcasecmp(name, "value")) {
+ val = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid enum value (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ desc->value = val;
+ } else if (!strcasecmp(name, "min")) {
+ val = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid enum min-value (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ desc->min = val;
+ min_set = 1;
+ } else if (!strcasecmp(name, "max")) {
+ val = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid enum max-value (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ desc->max = val;
+ max_set = 1;
}
}
+
+ if ((!min_set)&&(!max_set)) {
+ desc->min = desc->value;
+ desc->max = desc->value;
+ } else if (max_set) {
+ desc->min = 0;
+ } else if (min_set) {
+ desc->max = (pcilib_register_value_t)-1;
+ }
+
+ if ((desc->min > desc->max)||(desc->value < desc->min)||(desc->value > desc->max)) {
+ pcilib_error("Invalid enum configuration (min: %lu, max: %lu, value: %lu)", desc->min, desc->max, desc->value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+
+ return 0;
+}
+
+static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
+ int i;
+ int err;
+
+ xmlXPathObjectPtr nodes;
+ xmlNodeSetPtr nodeset;
+
+ pcilib_enum_view_description_t desc = {0};
+
+ desc.base.unit = pcilib_xml_enum_view_unit;
+ desc.base.api = &pcilib_enum_view_xml_api;
+
+ err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc);
+ if (err) return err;
+
+
+ xpath->node = node;
+ nodes = xmlXPathEvalExpression(ENUM_ELEMENTS_PATH, xpath);
+ xpath->node = NULL;
+
+ if (!nodes) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", ENUM_ELEMENTS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", ENUM_ELEMENTS_PATH);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ nodeset = nodes->nodesetval;
+ if (xmlXPathNodeSetIsEmpty(nodeset)) {
+ xmlXPathFreeObject(nodes);
+ pcilib_error("No names is defined for enum view (%s)", desc.base.name);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+
+ desc.names = (pcilib_value_name_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_value_name_t));
+ if (!desc.names) {
+ xmlXPathFreeObject(nodes);
+ pcilib_error("No names is defined for enum view (%s)", desc.base.name);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+
+
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_parse_value_name(ctx, xpath, doc, nodeset->nodeTab[i], &desc.names[i]);
+ if (err) {
+ xmlXPathFreeObject(nodes);
+ free(desc.names);
+ return err;
+ }
+ }
+ memset(&desc.names[nodeset->nodeNr], 0, sizeof(pcilib_value_name_t));
+
xmlXPathFreeObject(nodes);
+
+ err = pcilib_add_views(ctx, 1, (pcilib_view_description_t*)&desc);
+ if (err) free(desc.names);
+ return err;
+}
+
+static int pcilib_xml_parse_unit_transform(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_unit_transform_t *desc) {
+ xmlAttrPtr cur;
+ char *value, *name;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+
+ if (!strcasecmp(name, "unit")) {
+ desc->unit = value;
+ } else if (!strcasecmp(name, "transform")) {
+ desc->transform = value;
+ }
+ }
+
return 0;
}
@@ -496,171 +690,60 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
*@param[in] node - the node representing the unit
*@return an error code: 0 if evrythinh is ok
*/
-static int
-pcilib_xml_create_unit(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
+static int pcilib_xml_create_unit(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
int err;
-
- pcilib_unit_t desc = {0};
- xmlNodePtr cur;
- char *value, *name, *value2;
- xmlAttr *attr;
- int i=0;
+ pcilib_unit_description_t desc = {0};
- /* we get the attribute type of the view node*/
- attr=node->properties;
- value=(char*)attr->children->content;
- desc.name=value;
-
- for (cur = node->children; cur != NULL; cur = cur->next) {
- if (!cur->children) continue;
- if (!xmlNodeIsText(cur->children)) continue;
-
- name = (char*)cur->name;
+ xmlXPathObjectPtr nodes;
+ xmlNodeSetPtr nodeset;
+
+ xmlAttrPtr cur;
+ char *value, *name;
+
+ for (cur = node->properties; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
value = (char*)cur->children->content;
- attr= cur->properties;
- value2=(char*)attr->children->content;
- if (!value || !attr) continue;
-
- if (!strcasecmp(name, "convert_unit")) {
- desc.transforms[i].name=value2;
- desc.transforms[i].transform_formula=value;
- i++;
+ if (!strcasecmp(name, "name")) {
+ desc.name = value;
}
}
- err = pcilib_add_units(ctx, 1, &desc);
- if (err) {
- pcilib_error("Error adding unit (%s) specified in the XML", desc.name);
- return err;
- }
-
- return 0;
-}
+ xpath->node = node;
+ nodes = xmlXPathEvalExpression(UNIT_TRANSFORMS_PATH, xpath);
+ xpath->node = NULL;
-/**
- * function that create a view from a view node, and populate ctx views list
- */
-static int pcilib_xml_create_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
- int err;
-
- pcilib_view_t desc={0};
- xmlNodePtr cur;
- char *value, *name;
- char *endptr;
- xmlAttr *attr;
- int i=0;
- int ok_min=0, ok_max=0;
+ if (!nodes) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", UNIT_TRANSFORMS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", UNIT_TRANSFORMS_PATH);
+ return PCILIB_ERROR_FAILED;
+ }
- desc.description="default description";
+ nodeset = nodes->nodesetval;
+ if (!xmlXPathNodeSetIsEmpty(nodeset)) {
+ int i;
- /* we get the attribute type of the view node*/
- attr=node->properties;
- value=(char*)attr->children->content;
- /* regarding the architecture, i decided to follow what has been done for registers and banks. but without the context*/
- /*if the view is of type enum, we get recursively its properties and then populate ctx enum views*/
- if(!(strcasecmp(value,"enum"))){
- desc.op=&operation_enum;
- desc.parameters=malloc(sizeof(pcilib_enum_t));
- desc.base_unit.name="name";
- for (cur = node->children; cur != NULL; cur = cur->next) {
- if (!cur->children) continue;
- if (!xmlNodeIsText(cur->children)) continue;
-
- name = (char*)cur->name;
- value = (char*)cur->children->content;
- if (!value) continue;
-
- if (!(strcasecmp((char*)name,"name"))) {
- desc.name = value;
-
- }else if (!(strcasecmp((char*)name,"description"))) {
- desc.description = value;
-
- }else if (!(strcasecmp((char*)name,"enum"))) {
- desc.parameters=realloc(desc.parameters,(i+1)*sizeof(pcilib_enum_t));
- ((pcilib_enum_t*)(desc.parameters))[i].name=value;
-
- /* we need to iterate through the different attributes of an enum node to get all properties*/
- for(attr=cur->properties; attr!=NULL;attr=attr->next){
- if(!attr->children) continue;
- if(!xmlNodeIsText(attr->children)) continue;
-
- name=(char*)attr->name;
- value=(char*)attr->children->content;
-
- if(!(strcasecmp(name,"value"))){
- pcilib_register_value_t dat_value = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid value (%s) is specified in the XML enum node", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- ((pcilib_enum_t*)(desc.parameters))[i].value=dat_value;
- }else if(!(strcasecmp(name,"min"))){
- pcilib_register_value_t dat_min = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid min (%s) is specified in the XML enum node", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- ((pcilib_enum_t*)(desc.parameters))[i].min=dat_min;
- ok_min=1;
- }else if(!(strcasecmp(name,"max"))){
- pcilib_register_value_t dat_max = strtol(value, &endptr, 0);
- if ((strlen(endptr) > 0)) {
- pcilib_error("Invalid max (%s) is specified in the XML enum node", value);
- return PCILIB_ERROR_INVALID_DATA;
- }
- ((pcilib_enum_t*)(desc.parameters))[i].max=dat_max;
- ok_max=1;
- }
- if(ok_min==0) ((pcilib_enum_t*)(desc.parameters))[i].min=((pcilib_enum_t*)(desc.parameters))[i].value;
- if(ok_max==0) ((pcilib_enum_t*)(desc.parameters))[i].max=((pcilib_enum_t*)(desc.parameters))[i].value;
-
- }
- i++;
+ if (nodeset->nodeNr > PCILIB_MAX_TRANSFORMS_PER_UNIT) {
+ xmlXPathFreeObject(nodes);
+ pcilib_error("Too many transforms for unit %s are defined, only %lu are supported", desc.name, PCILIB_MAX_TRANSFORMS_PER_UNIT);
+ return PCILIB_ERROR_INVALID_DATA;
}
- }
- err=pcilib_add_views(ctx,1,&desc);
- if (err) {
- pcilib_error("Error (%i) adding a new enum view (%s) to the pcilib_t", err, desc.name);
- return err;
- }
-
- /* we do the same here but for a iew of type formula if the attribute gives formula*/
- }else if(!(strcasecmp(value,"formula"))){
- desc.op=&operation_formula;
- desc.parameters=malloc(sizeof(pcilib_formula_t));
- for (cur = node->children; cur != NULL; cur = cur->next) {
- if (!cur->children) continue;
- if (!xmlNodeIsText(cur->children)) continue;
- name = (char*)cur->name;
- value = (char*)cur->children->content;
-
- if (!value) continue;
-
- if (!(strcasecmp((char*)name,"name"))) {
- desc.name = value;
- }else if (!(strcasecmp((char*)name,"read_from_register"))) {
- ((pcilib_formula_t*)(desc.parameters))->read_formula=value;
- }else if (!(strcasecmp((char*)name,"write_to_register"))) {
- ((pcilib_formula_t*)(desc.parameters))->write_formula=value;
- }else if (!(strcasecmp((char*)name,"description"))) {
- desc.description=value;
- }else if (!(strcasecmp((char*)name,"unit"))){
- desc.base_unit.name=value;
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_parse_unit_transform(ctx, xpath, doc, nodeset->nodeTab[i], &desc.transforms[i]);
+ if (err) {
+ xmlXPathFreeObject(nodes);
+ return err;
+ }
}
- }
-
- err=pcilib_add_views(ctx,1,&desc);
- if (err) {
- pcilib_error("Error (%i) adding a new formula view (%s) to the pcilib_t", err, desc.name);
- return err;
- }
-
}
-
- return 0;
+ xmlXPathFreeObject(nodes);
+
+ return pcilib_add_units(ctx, 1, &desc);
}
@@ -672,97 +755,108 @@ static int pcilib_xml_create_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
* @param[in] pci the pcilib_t running, which will be filled
*/
static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathContextPtr xpath) {
- xmlXPathObjectPtr bank_nodes,views_nodes, units_nodes;
+ int err;
+ xmlXPathObjectPtr bank_nodes = NULL, transform_nodes = NULL, enum_nodes = NULL, unit_nodes = NULL;
xmlNodeSetPtr nodeset;
int i;
- xmlErrorPtr xmlerr;
-
- units_nodes=xmlXPathEvalExpression(UNITS_PATH,xpath);
- if(!units_nodes){
- goto views;
- }
-
- nodeset=units_nodes->nodesetval;
- if(!xmlXPathNodeSetIsEmpty(nodeset)){
- for(i=0;i < nodeset->nodeNr; i++){
- pcilib_xml_create_unit(ctx,xpath,doc,nodeset->nodeTab[i]);
- }
- }
- xmlXPathFreeObject(units_nodes);
- views:
- views_nodes=xmlXPathEvalExpression(VIEWS_PATH,xpath);
- if(!views_nodes){
- goto banks;
+ bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath);
+ if (bank_nodes) transform_nodes = xmlXPathEvalExpression(TRANSFORM_VIEWS_PATH, xpath);
+ if (transform_nodes) enum_nodes = xmlXPathEvalExpression(ENUM_VIEWS_PATH, xpath);
+ if (enum_nodes) unit_nodes = xmlXPathEvalExpression(UNITS_PATH, xpath);
+
+ if (!unit_nodes) {
+ const unsigned char *expr = (enum_nodes?UNITS_PATH:(transform_nodes?ENUM_VIEWS_PATH:(bank_nodes?TRANSFORM_VIEWS_PATH:BANKS_PATH)));
+
+ if (enum_nodes) xmlXPathFreeObject(enum_nodes);
+ if (transform_nodes) xmlXPathFreeObject(transform_nodes);
+ if (bank_nodes) xmlXPathFreeObject(bank_nodes);
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", expr, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", expr);
+ return PCILIB_ERROR_FAILED;
}
-
- nodeset=views_nodes->nodesetval;
- if(!xmlXPathNodeSetIsEmpty(nodeset)){
- for(i=0;i < nodeset->nodeNr; i++){
- pcilib_xml_create_view(ctx,xpath,doc,nodeset->nodeTab[i]);
- }
+
+ nodeset = unit_nodes->nodesetval;
+ if(!xmlXPathNodeSetIsEmpty(nodeset)) {
+ for(i=0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_create_unit(ctx, xpath, doc, nodeset->nodeTab[i]);
+ if (err) pcilib_error("Error (%i) creating unit", err);
+ }
}
- xmlXPathFreeObject(views_nodes);
- banks:
- bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath);
- if (!bank_nodes) {
- xmlerr = xmlGetLastError();
- if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BANKS_PATH, xmlerr->code, xmlerr->message);
- else pcilib_error("Failed to parse XPath expression %s", BANKS_PATH);
- return PCILIB_ERROR_FAILED;
+ nodeset = transform_nodes->nodesetval;
+ if (!xmlXPathNodeSetIsEmpty(nodeset)) {
+ for(i=0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_create_transform_view(ctx, xpath, doc, nodeset->nodeTab[i]);
+ if (err) pcilib_error("Error (%i) creating register transform", err);
+ }
}
+ nodeset = enum_nodes->nodesetval;
+ if (!xmlXPathNodeSetIsEmpty(nodeset)) {
+ for(i=0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_create_enum_view(ctx, xpath, doc, nodeset->nodeTab[i]);
+ if (err) pcilib_error("Error (%i) creating register enum", err);
+ }
+ }
nodeset = bank_nodes->nodesetval;
if (!xmlXPathNodeSetIsEmpty(nodeset)) {
- for (i = 0; i < nodeset->nodeNr; i++) {
- pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]);
- }
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ err = pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]);
+ if (err) pcilib_error("Error (%i) creating bank", err);
+ }
}
+
+
+ xmlXPathFreeObject(unit_nodes);
+ xmlXPathFreeObject(enum_nodes);
+ xmlXPathFreeObject(transform_nodes);
xmlXPathFreeObject(bank_nodes);
+
return 0;
}
static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
int err;
-
+
xmlSchemaParserCtxtPtr ctxt;
/** we first parse the xsd file for AST with validation*/
ctxt = xmlSchemaNewParserCtxt(xsd_filename);
if (!ctxt) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
- else pcilib_error("Failed to create a parser for XML schemas");
- return PCILIB_ERROR_FAILED;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to create a parser for XML schemas");
+ return PCILIB_ERROR_FAILED;
}
-
+
ctx->xml.schema = xmlSchemaParse(ctxt);
if (!ctx->xml.schema) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- xmlSchemaFreeParserCtxt(ctxt);
- if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
- else pcilib_error("Failed to parse XML schema");
- return PCILIB_ERROR_INVALID_DATA;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlSchemaFreeParserCtxt(ctxt);
+ if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XML schema");
+ return PCILIB_ERROR_INVALID_DATA;
}
-
+
xmlSchemaFreeParserCtxt(ctxt);
ctx->xml.validator = xmlSchemaNewValidCtxt(ctx->xml.schema);
if (!ctx->xml.validator) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- 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;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ 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;
}
-
+
err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE);
if (err) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- 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;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ 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;
}
return 0;
@@ -776,46 +870,46 @@ static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *nam
full_name = (char*)alloca(strlen(path) + strlen(name) + 2);
if (!name) {
- pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
- return PCILIB_ERROR_MEMORY;
+ pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
+ return PCILIB_ERROR_MEMORY;
}
sprintf(full_name, "%s/%s", path, name);
doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0);
if (!doc) {
- xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.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 PCILIB_ERROR_INVALID_DATA;
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.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 PCILIB_ERROR_INVALID_DATA;
}
err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
if (err) {
- xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.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);
- return PCILIB_ERROR_VERIFY;
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.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);
+ return PCILIB_ERROR_VERIFY;
}
xpath = xmlXPathNewContext(doc);
if (!xpath) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- xmlFreeDoc(doc);
- if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
- else pcilib_error("Error creating XPath context for %s", full_name);
- return PCILIB_ERROR_FAILED;
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlFreeDoc(doc);
+ if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error creating XPath context for %s", full_name);
+ return PCILIB_ERROR_FAILED;
}
- // This can only partially fail... Therefore we need to keep XML and just return the error...
+ // This can only partially fail... Therefore we need to keep XML and just return the error...
err = pcilib_xml_process_document(ctx, doc, xpath);
if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
- xmlFreeDoc(doc);
+ xmlFreeDoc(doc);
xmlXPathFreeContext(xpath);
- pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
- return PCILIB_ERROR_TOOBIG;
+ pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
+ return PCILIB_ERROR_TOOBIG;
}
ctx->xml.docs[ctx->xml.num_files] = doc;
@@ -833,8 +927,6 @@ int pcilib_process_xml(pcilib_t *ctx, const char *location) {
struct dirent *file = NULL;
char *model_dir, *model_path;
- int i,j;
-
model_dir = getenv("PCILIB_MODEL_DIR");
if (!model_dir) model_dir = PCILIB_MODEL_DIR;
@@ -847,27 +939,14 @@ int pcilib_process_xml(pcilib_t *ctx, const char *location) {
if (!rep) return PCILIB_ERROR_NOTFOUND;
while ((file = readdir(rep)) != NULL) {
- 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;
-
- err = pcilib_xml_load_file(ctx, model_path, file->d_name);
- if (err) pcilib_error("Error processing XML file %s", file->d_name);
- }
-
- for(i=0;i<ctx->num_views;i++){
- pcilib_get_unit_of_view(ctx,&(ctx->views[i]),ctx->views[i].base_unit.name);
- }
-
- for(i=0;i<ctx->num_reg;i++){
- if(!(ctx->register_ctx[i].views)) continue;
- for(j=0;j<ctx->num_views;j++){
- if(!(ctx->register_ctx[i].views[j].name)) break;
- if(ctx->register_ctx[i].views[j].name){
- pcilib_get_unit_of_view(ctx,&(ctx->register_ctx[i].views[j]),ctx->register_ctx[i].views[j].base_unit.name);
- }
- }
+ 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;
+
+ err = pcilib_xml_load_file(ctx, model_path, file->d_name);
+ if (err) pcilib_error("Error processing XML file %s", file->d_name);
}
+
closedir(rep);
return 0;
@@ -896,16 +975,16 @@ int pcilib_init_xml(pcilib_t *ctx, const char *model) {
sprintf(xsd_path, "%s/model.xsd", model_dir);
if (stat(xsd_path, &st)) {
- pcilib_info("XML models are not present");
- return PCILIB_ERROR_NOTFOUND;
+ pcilib_info("XML models are not present");
+ return PCILIB_ERROR_NOTFOUND;
}
ctx->xml.parser = xmlNewParserCtxt();
if (!ctx->xml.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 PCILIB_ERROR_FAILED;
+ 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 PCILIB_ERROR_FAILED;
}
err = pcilib_xml_load_xsd(ctx, xsd_path);
@@ -923,44 +1002,44 @@ void pcilib_free_xml(pcilib_t *ctx) {
memset(ctx->xml.bank_nodes, 0, sizeof(ctx->xml.bank_nodes));
for (i = 0; i < ctx->num_banks; i++) {
- if (ctx->bank_ctx[i])
- ctx->bank_ctx[i]->xml = NULL;
+ if (ctx->bank_ctx[i])
+ ctx->bank_ctx[i]->xml = NULL;
}
-
+
for (i = 0; i < ctx->num_reg; i++) {
- ctx->register_ctx[i].xml = NULL;
+ ctx->register_ctx[i].xml = NULL;
}
-
+
for (i = 0; i < ctx->xml.num_files; i++) {
- if (ctx->xml.docs[i]) {
- xmlFreeDoc(ctx->xml.docs[i]);
- ctx->xml.docs[i] = NULL;
- }
- if (ctx->xml.xpath[i]) {
- xmlXPathFreeContext(ctx->xml.xpath[i]);
- ctx->xml.xpath[i] = NULL;
- }
+ if (ctx->xml.docs[i]) {
+ xmlFreeDoc(ctx->xml.docs[i]);
+ ctx->xml.docs[i] = NULL;
+ }
+ if (ctx->xml.xpath[i]) {
+ xmlXPathFreeContext(ctx->xml.xpath[i]);
+ ctx->xml.xpath[i] = NULL;
+ }
}
ctx->xml.num_files = 0;
if (ctx->xml.validator) {
- xmlSchemaFreeValidCtxt(ctx->xml.validator);
- ctx->xml.validator = NULL;
+ xmlSchemaFreeValidCtxt(ctx->xml.validator);
+ ctx->xml.validator = NULL;
}
-
+
if (ctx->xml.schema) {
- xmlSchemaFree(ctx->xml.schema);
- ctx->xml.schema = NULL;
-
+ xmlSchemaFree(ctx->xml.schema);
+ ctx->xml.schema = NULL;
+
}
if (ctx->xml.parser) {
- xmlFreeParserCtxt(ctx->xml.parser);
- ctx->xml.parser = NULL;
+ xmlFreeParserCtxt(ctx->xml.parser);
+ ctx->xml.parser = NULL;
}
-/*
- xmlSchemaCleanupTypes();
- xmlCleanupParser();
- xmlMemoryDump();
-*/
+ /*
+ xmlSchemaCleanupTypes();
+ xmlCleanupParser();
+ xmlMemoryDump();
+ */
}