diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2015-09-24 04:28:45 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2015-09-24 04:28:45 +0200 |
commit | 08a01723af9cd52c078d5ca6c38c34d375b39fa0 (patch) | |
tree | 6eadea9c67f4bb56a9e4ee09f4982efaf61deece | |
parent | 924adedb2928f5657c6668f606dbb3294b3c45da (diff) | |
parent | ae7f83a7948d8c3760f8019899a45e6ec90c2c6a (diff) | |
download | pcitool-08a01723af9cd52c078d5ca6c38c34d375b39fa0.tar.gz pcitool-08a01723af9cd52c078d5ca6c38c34d375b39fa0.tar.bz2 pcitool-08a01723af9cd52c078d5ca6c38c34d375b39fa0.tar.xz pcitool-08a01723af9cd52c078d5ca6c38c34d375b39fa0.zip |
Finalyze XML support and provide initial support for views (only descriptions so far)
-rw-r--r-- | CMakeLists.txt | 9 | ||||
-rw-r--r-- | docs/ToDo | 18 | ||||
-rwxr-xr-x | misc/xml/format.sh | 8 | ||||
-rw-r--r-- | misc/xml/format.xsl | 44 | ||||
-rw-r--r-- | misc/xml/update_to_new_format.xsl | 118 | ||||
-rw-r--r-- | pcilib/CMakeLists.txt | 12 | ||||
-rw-r--r-- | pcilib/lock.c | 32 | ||||
-rw-r--r-- | pcilib/lock.h | 79 | ||||
-rw-r--r-- | pcilib/locking.c | 28 | ||||
-rw-r--r-- | pcilib/locking.h | 58 | ||||
-rw-r--r-- | pcilib/model.h | 3 | ||||
-rw-r--r-- | pcilib/pci.c | 45 | ||||
-rw-r--r-- | pcilib/pci.h | 31 | ||||
-rw-r--r-- | pcilib/pcilib.h | 11 | ||||
-rw-r--r-- | pcilib/register.h | 16 | ||||
-rw-r--r-- | pcilib/unit.c | 49 | ||||
-rw-r--r-- | pcilib/unit.h | 36 | ||||
-rw-r--r-- | pcilib/view.c | 74 | ||||
-rw-r--r-- | pcilib/view.h | 40 | ||||
-rw-r--r-- | pcilib/xml.c | 885 | ||||
-rw-r--r-- | pcitool/cli.c | 108 | ||||
-rw-r--r-- | protocols/software.c | 44 | ||||
-rw-r--r-- | protocols/software.h | 43 | ||||
-rw-r--r-- | views/CMakeLists.txt | 11 | ||||
-rw-r--r-- | views/enum.c | 47 | ||||
-rw-r--r-- | views/enum.h | 23 | ||||
-rw-r--r-- | views/transform.c | 71 | ||||
-rw-r--r-- | views/transform.h | 17 | ||||
-rw-r--r-- | xml/model.xsd | 248 | ||||
-rw-r--r-- | xml/references.xsd | 50 | ||||
-rw-r--r-- | xml/test/camera.xml | 647 | ||||
-rw-r--r-- | xml/types.xsd | 208 |
32 files changed, 1978 insertions, 1135 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c4c0d8..bc922c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,11 +33,19 @@ SET(ENV{PKG_CONFIG_PATH} "${LIB_INSTALL_DIR}/pkgconfig:$ENV{PKG_CONFIG_PATH}") find_package(PkgConfig REQUIRED) find_package(Threads REQUIRED) +find_package(PythonLibs REQUIRED) set(EXTRA_SYSTEM_LIBS -lrt) check_include_files(stdatomic.h HAVE_STDATOMIC_H) +find_path(UTHASH_INCLUDE_DIRS uthash.h PATH_SUFFIXES uthash) +if (UTHASH_INCLUDE_DIRS) + message ("uthash is found at ${UTHASH_INCLUDE_DIRS}") +else (UTHASH_INCLUDE_DIRS) + message (FATAL_ERROR "uthash is not found...") +endif (UTHASH_INCLUDE_DIRS) + pkg_check_modules(LIBXML2 libxml-2.0 REQUIRED) #Check in sibling directory @@ -66,6 +74,7 @@ set(PCILIB_DEBUG_DIR "." CACHE PATH "Directory to write debug information") add_subdirectory(dma) add_subdirectory(protocols) +add_subdirectory(views) add_subdirectory(pcilib) add_subdirectory(pcitool) add_subdirectory(apps) @@ -1,6 +1,9 @@ High Priority (we would need it for IPE Camera) ============= - 1. Allow overriding of registers and banks (performance?). + 1. Join multiple XML files and on error use simplified XSD scheme on all files to find the file causing error + 2. Universal tree-style api to access the independent views, frontend all registers as well (pci -l /register; pci -r /register/reg1; pci -r /sensor/width;) Unit is path of the view /view[:unit] or just /unit for register vies + 3. Information on bank and the view values in the pci -i <reg> + 4. Integrate hash tables for views, units, and registers Normal Priority (it would make just few things a bit easier) =============== @@ -10,13 +13,12 @@ Normal Priority (it would make just few things a bit easier) Low Priority (only as generalization for other projects) ============ - 1. XML configurations describing registers (and DMA engines?) - 2. Access register/bank/lock lookups using hash tables - 3. Support for Network Registers and Network DMA - 4. Define a syntax for register dependencies / delays (?) - 5. Use pthread_condition_t instead of polling - 6. Support FIFO reads/writes from/to registers - 7. We managed kmem performance using next kmem prediction, but it is still wise to provide additionally a binary tree for faster search + 1. Shall we allow overriding of registers? + 2. Support for Network Registers and Network DMA + 3. Define a syntax for register dependencies / delays (?) + 4. Use pthread_condition_t instead of polling + 5. Support FIFO reads/writes from/to registers + 6. We managed kmem performance using next kmem prediction, but it is still wise to provide additionally a binary tree for faster search Performance =========== diff --git a/misc/xml/format.sh b/misc/xml/format.sh new file mode 100755 index 0000000..c522f44 --- /dev/null +++ b/misc/xml/format.sh @@ -0,0 +1,8 @@ +#! /bin/bash + +if [ -z "$1" ]; then + echo "Usage: $0 [ xml_file ]" + exit 0 +fi + +cat $1 | xmllint -format - | xsltproc format.xsl - diff --git a/misc/xml/format.xsl b/misc/xml/format.xsl new file mode 100644 index 0000000..92abcbb --- /dev/null +++ b/misc/xml/format.xsl @@ -0,0 +1,44 @@ +<?xml version="1.0"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:template match="register|field"> + <xsl:if test="local-name() = 'field'"> + <xsl:value-of select="preceding-sibling::text()"/> + </xsl:if> + + <xsl:element name="{local-name()}"> + <xsl:apply-templates select="@*"/> + <xsl:for-each select="view"> + <xsl:copy> + <xsl:apply-templates select="@*"/> + </xsl:copy> + </xsl:for-each> + <xsl:apply-templates select="field"/> + <xsl:if test="field"> + <xsl:value-of select="text()[last()]"/> + </xsl:if> + </xsl:element> + </xsl:template> + + <xsl:template match="//model/bank|//model/transform|//model/enum|//model/unit"> + <xsl:value-of select="preceding-sibling::text()"/> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="model"> + <xsl:copy> + <xsl:apply-templates select="bank"/> + <xsl:apply-templates select="transform"/> + <xsl:apply-templates select="enum"/> + <xsl:apply-templates select="unit"/> + <xsl:value-of select="text()[last()]"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> +</xsl:stylesheet> diff --git a/misc/xml/update_to_new_format.xsl b/misc/xml/update_to_new_format.xsl new file mode 100644 index 0000000..b92f780 --- /dev/null +++ b/misc/xml/update_to_new_format.xsl @@ -0,0 +1,118 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="banks"> + <xsl:apply-templates select="@*|node()"/> + </xsl:template> + <xsl:template match="views"> + <xsl:apply-templates select="@*|node()"/> + </xsl:template> + <xsl:template match="units"> + <xsl:apply-templates select="@*|node()"/> + </xsl:template> + + <xsl:template match="bank"> + <bank> + <xsl:for-each select="bank_description/*"> + <xsl:attribute name="{name()}"> + <xsl:value-of select="text()"/> + </xsl:attribute> + </xsl:for-each> + + <xsl:apply-templates select="registers/*"/> + </bank> + </xsl:template> + + <xsl:template match="bank_description"> + </xsl:template> + + <xsl:template match="register_bits"> + <field> + <xsl:for-each select="*"> + <xsl:if test="name() = 'views'"> + <xsl:apply-templates select="view"/> + </xsl:if> + <xsl:if test="name() != 'views'"> + <xsl:attribute name="{name()}"> + <xsl:value-of select="text()"/> + </xsl:attribute> + </xsl:if> + </xsl:for-each> + </field> + </xsl:template> + + <xsl:template match="register"> + <register> + <xsl:for-each select="*"> + <xsl:if test="name() = 'registers_bits'"> + <xsl:apply-templates select="register_bits"/> + </xsl:if> + <xsl:if test="name() = 'views'"> + <xsl:apply-templates select="view"/> + </xsl:if> + <xsl:if test="name() != 'registers_bits' and name() != 'views'"> + <xsl:attribute name="{name()}"> + <xsl:value-of select="text()"/> + </xsl:attribute> + </xsl:if> + </xsl:for-each> + </register> + </xsl:template> + + <xsl:template match="enum"> + <name> + <xsl:attribute name="name"> + <xsl:value-of select="text()"/> + </xsl:attribute> + <xsl:apply-templates select="@*"/> + </name> + </xsl:template> + + <xsl:template match="view[@type]"> + <xsl:if test="@type = 'formula'"> + <transform> + <xsl:for-each select="*"> + <xsl:attribute name="{name()}"> + <xsl:value-of select="text()"/> + </xsl:attribute> + </xsl:for-each> + </transform> + </xsl:if> + <xsl:if test="@type = 'enum'"> + <enum> + <xsl:for-each select="*"> + <xsl:if test="name() != 'enum'"> + <xsl:attribute name="{name()}"> + <xsl:value-of select="text()"/> + </xsl:attribute> + </xsl:if> + </xsl:for-each> + <xsl:apply-templates select="enum"/> + </enum> + </xsl:if> + </xsl:template> + + <xsl:template match="view"> + <view> + <xsl:attribute name="name"><xsl:value-of select="text()"/></xsl:attribute> + </view> + </xsl:template> + + <xsl:template match="convert_unit"> + <transform> + <xsl:attribute name="unit"><xsl:value-of select="@value"/></xsl:attribute> + <xsl:attribute name="transform"><xsl:value-of select="text()"/></xsl:attribute> + </transform> + </xsl:template> + + <xsl:template match="unit"> + <unit> + <xsl:apply-templates select="@*"/> + <xsl:apply-templates select="convert_unit"/> + </unit> + </xsl:template> + + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> +</xsl:stylesheet> diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index 8b11d60..beaa253 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -4,12 +4,14 @@ include_directories( ${CMAKE_SOURCE_DIR}/pcilib ${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 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 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}) -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} @@ -19,6 +21,6 @@ install(FILES pcilib.h DESTINATION include ) -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 +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 03a2377..9e7cda2 100644 --- a/pcilib/lock.c +++ b/pcilib/lock.c @@ -18,22 +18,21 @@ #include "lock.h" #include "pci.h" - +/** + * structure to define a lock + */ struct pcilib_lock_s { - pthread_mutex_t mutex; - pcilib_lock_flags_t flags; + 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; + 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; + volatile uint32_t refs; /**< approximate number of processes that hold the lock initialized, may desynchronize on crashes */ #endif /* HAVE_STDATOMIC_H */ - char name[]; + char name[]; /**< lock identifier */ }; -/** - * this function initialize a new semaphore in the kernel if it's not already initialized given the key that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore - */ int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char *lock_id) { int err; pthread_mutexattr_t attr; @@ -53,11 +52,13 @@ int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char return PCILIB_ERROR_FAILED; } + /* we declare the mutex as possibly shared amongst different processes*/ if ((err = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED))!=0) { pcilib_error("Can't configure a shared mutex attribute, errno %i", errno); return PCILIB_ERROR_FAILED; } + /* we set the mutex as robust, so it would be automatically unlocked if the application crash*/ if ((flags&PCILIB_LOCK_FLAG_PERSISTENT)==0) { if ((err = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST))!=0) { pcilib_error("Can't configure a robust mutex attribute, errno: %i", errno); @@ -78,9 +79,6 @@ int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char } -/* - * we uninitialize a mutex and set its name to 0 pointed by lock_ctx with this function. setting name to is the real destroying operation, but we need to unitialize the lock to initialize it again after - */ void pcilib_free_lock(pcilib_lock_t *lock) { int err; @@ -134,9 +132,6 @@ const char *pcilib_lock_get_name(pcilib_lock_t *lock) { return NULL; } -/* - * this function will take the lock for the semaphore pointed by semId - */ int pcilib_lock_custom(pcilib_lock_t *lock, pcilib_lock_flags_t flags, pcilib_timeout_t timeout) { int err; @@ -149,12 +144,15 @@ int pcilib_lock_custom(pcilib_lock_t *lock, pcilib_lock_flags_t flags, pcilib_ti switch (timeout) { case PCILIB_TIMEOUT_INFINITE: + /* the process will be hold till it can gain acquire the lock*/ err = pthread_mutex_lock(&lock->mutex); break; case PCILIB_TIMEOUT_IMMEDIATE: + /* the function returns immediatly if it can't acquire the lock*/ err = pthread_mutex_trylock(&lock->mutex); break; default: + /* the process will be hold till it can acquire the lock and timeout is not reached*/ clock_gettime(CLOCK_REALTIME, &tm); tm.tv_nsec += 1000 * (timeout%1000000); if (tm.tv_nsec < 1000000000) @@ -171,6 +169,7 @@ int pcilib_lock_custom(pcilib_lock_t *lock, pcilib_lock_flags_t flags, pcilib_ti switch (err) { case EOWNERDEAD: + /*in the case an application with a lock acquired crashes, this lock becomes inconsistent. we have so to make it consistent again to use it again.*/ err = pthread_mutex_consistent(&lock->mutex); if (err) { pcilib_error("Failed to mark mutex as consistent, errno %i", err); @@ -195,9 +194,6 @@ int pcilib_try_lock(pcilib_lock_t* lock) { return pcilib_lock_custom(lock, PCILIB_LOCK_FLAGS_DEFAULT, PCILIB_TIMEOUT_IMMEDIATE); } -/** - * this function will unlock the semaphore pointed by lock_ctx. - */ void pcilib_unlock(pcilib_lock_t *lock) { int err; diff --git a/pcilib/lock.h b/pcilib/lock.h index 9ffe4cf..e3a5b02 100644 --- a/pcilib/lock.h +++ b/pcilib/lock.h @@ -1,29 +1,31 @@ /** * @file lock.h - * @skip author zilio nicolas, nicolas.zilio@hotmail.fr * @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 and that with more than 10 locks/unlocks, pthread is better in performance, so that should suits more to the final pcitool program. + * @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. + * * 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 a name, which corresponds to a register or processus. The iterations like searching a lock are done on names. + * 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. */ #ifndef _PCILIB_LOCK_H #define _PCILIB_LOCK_H -#define PCILIB_LOCK_SIZE 128 /**< size of one lock, determine so the size of the protocol_name in the way locks are registered. 40 bytes are necessary for the mutex structure, so we have a protocol name of length LOCK_SIZE-40*/ +#define PCILIB_LOCK_SIZE 128 /**< size of one lock. indeed, as we can't allocate easily on the fly memory in the kernel, fixed size have been chosen. determines so the size of the identifier name in the way locks are registered. 40 bytes are necessary for the mutex structure, so we have an id name of length LOCK_SIZE-40*/ #include <pcilib.h> /** - * type that defines possible flags when locking a lock by calling pcilib_lock + * type that defines possible flags for a lock, defining how a lock should be handled by the locking functions */ typedef enum { PCILIB_LOCK_FLAGS_DEFAULT = 0, /**< Default flags */ - PCILIB_LOCK_FLAG_UNLOCKED = 1, /**< Perform operation unlocked (protected by global flock during initialization of locking subsystem) */ + PCILIB_LOCK_FLAG_UNLOCKED = 1, /**< Perform operations unlocked, thus without taking care of the lock (protected by global flock during initialization of locking subsystem) */ PCILIB_LOCK_FLAG_PERSISTENT = 2 /**< Do not create robust mutexes, but preserve the lock across application launches */ } pcilib_lock_flags_t; +/** structure defining a lock*/ typedef struct pcilib_lock_s pcilib_lock_t; @@ -32,70 +34,87 @@ extern "C" { #endif /** - * this function initialize a new semaphore in the kernel given a name that corresponds to a specific processus if the semaphore is not already initialized given the name that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore. - * @param[in] lock - pointer to lock to initialize - * @param[in] flags - flags + *this function initializes a lock, by setting correctly its property given the flags associated. + * @param[in,out] lock - pointer to lock to initialize + * @param[in] flags - flags: if it's set to two, then not a robust mutex is created * @param[in] lock_id - lock identificator * @return error code or 0 on success */ int pcilib_init_lock(pcilib_lock_t *lock, pcilib_lock_flags_t flags, const char *lock_id); /** - * this function uninitialize a lock in kernel memory and set the corresponding name to 0 - * @param[in] lock_ctx the pointer that points to the lock. + * this function will unref the defined lock. Any subsequent tries to lock it without reinitializaing it will fail. + * @param[in,out] lock_ctx - the pointer that points to the lock. */ void pcilib_free_lock(pcilib_lock_t *lock_ctx); - +/** + * this function gives the identifier name associated to a lock in the kernel space + * @param[in] loc - pointer to the lock we want the name + * @return string corresponding to the name + */ const char *pcilib_lock_get_name(pcilib_lock_t *lock); /** - * Increment reference count. Not thread/process safe unless system supports stdatomic (gcc 4.9+). - * In this case, the access should be synchronized by the caller - * @param[in] lock - pointer to initialized lock + * Increment reference count(number of processes that may access the given lock). + * Not thread/process safe unless system supports stdatomic (gcc 4.9+). In this case, the access should be synchronized by the caller. + * @param[in,out] lock - pointer to initialized lock */ void pcilib_lock_ref(pcilib_lock_t *lock); /** - * Decrement reference count. Not thread/process safe unless system supports stdatomic (gcc 4.9+). - * In this case, the access should be synchronized by the caller - * @param[in] lock - pointer to initialized lock + * Decrement reference count(number of processes that may access the given lock). + * Not thread/process safe unless system supports stdatomic (gcc 4.9+). In this case, the access should be synchronized by the caller + * @param[in,out] lock - pointer to initialized lock */ void pcilib_lock_unref(pcilib_lock_t *lock); /** - * Return _approximate_ number of lock references. The crashed applications will may not unref. - * @param[in] lock - pointer to initialized lock + * Return _approximate_ number of lock references as the crashed applications will may not unref. + * @param[in,out] lock - pointer to initialized lock + * @return the number of lock refs */ size_t pcilib_lock_get_refs(pcilib_lock_t *lock); +/** + * gets the flags associated to the given lock + * @param[in] lock - the lock we want to know the flags + * @return value of the flag associated + */ pcilib_lock_flags_t pcilib_lock_get_flags(pcilib_lock_t *lock); /** - * this function will take a lock for the mutex pointed by lock - * @param[in] lock the pointer to the mutex - * @param[in] flags define the type of lock wanted - * @param[in] timeout defines timeout + * this function will call different locking functions to acquire the given lock. Given the flags, it is thus possible to: + * 1) the process requesting the lock will be held till it can acquire it + * 2)the lock is tried to be acquired, if the lock can be acquired then it is, if not, then the function returns immediatly and the lock is not taken at all + * 3) same than previous, but it's possible to define a waiting time to acquire the lock before returning + * + * @param[in] lock - the pointer to the mutex + * @param[in] flags - define the type of lock wanted + * @param[in] timeout - the waiting time if asked, before the function returns without having obtained the lock, in micro seconds + * @return error code or 0 for correctness */ int pcilib_lock_custom(pcilib_lock_t* lock, pcilib_lock_flags_t flags, pcilib_timeout_t timeout); /** - * this function will take a lock for the mutex pointed by lock - * @param[in] lock the pointer to the mutex + * function to acquire a lock, and wait till the lock can be acquire + * @param[in] lock - the pointer to the mutex + * @return error code or 0 for correctness */ int pcilib_lock(pcilib_lock_t* lock); /** - * this function will try to take a lock for the mutex pointed by lock - * @param[in] lock the pointer to the mutex + * this function will try to take a lock for the mutex pointed by lockfunction to acquire a lock, but that returns immediatly if the lock can't be acquired on first try + * @param[in] lock - the pointer to the mutex + * @return error code or 0 for correctness */ int pcilib_try_lock(pcilib_lock_t* lock); /** - * this function will unlock the lock pointed by lock - * @param[in] lock the integer that points to the semaphore + * this function unlocks the lock pointed by lock + * @param[in] lock - the integer that points to the semaphore */ void pcilib_unlock(pcilib_lock_t* lock); diff --git a/pcilib/locking.c b/pcilib/locking.c index f384ca4..71f204e 100644 --- a/pcilib/locking.c +++ b/pcilib/locking.c @@ -21,10 +21,12 @@ int pcilib_init_locking(pcilib_t* ctx) { pcilib_kmem_reuse_state_t reused; assert(PCILIB_LOCK_PAGES * PCILIB_KMEM_PAGE_SIZE >= PCILIB_MAX_LOCKS * PCILIB_LOCK_SIZE); - + + /*protection against multiple creations of kernel space*/ err = pcilib_lock_global(ctx); if (err) return err; + /* by default, this kernel space is persistent and will be reused, in order to avoid the big initialization times for robust mutexes each time we run pcitool*/ ctx->locks.kmem = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, PCILIB_LOCK_PAGES, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_LOCKS,0), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); if (!ctx->locks.kmem) { pcilib_unlock_global(ctx); @@ -46,6 +48,7 @@ int pcilib_init_locking(pcilib_t* ctx) { } } + /* the lock that has been used for the creation of kernel space is declared unlocked, has we shouldnot use it anymore*/ ctx->locks.locking = pcilib_get_lock(ctx, PCILIB_LOCK_FLAG_UNLOCKED, "locking"); pcilib_unlock_global(ctx); @@ -59,7 +62,7 @@ int pcilib_init_locking(pcilib_t* ctx) { } /* - * this functions destroy all locks and then free the kernel memory allocated for them + * this function free the kernel memory allocated for them and destroys locks by setting memory to 0 */ void pcilib_free_locking(pcilib_t *ctx) { if (ctx->locks.locking) @@ -75,7 +78,7 @@ void pcilib_free_locking(pcilib_t *ctx) { int pcilib_lock_global(pcilib_t *ctx) { int err; - /* we flock() to make sure to not have two initialization in the same time (possible long time to init) */ + /* we flock() on the board's device file to make sure to not have two initialization in the same time (possible long time to init) */ if ((err = flock(ctx->handle, LOCK_EX))==-1) { pcilib_error("Can't get flock on device file"); return PCILIB_ERROR_FAILED; @@ -105,7 +108,7 @@ pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const c pcilib_lock_t *lock; char buffer[PCILIB_LOCK_SIZE]; - + /* we construct the complete lock_id given the parameters of the function*/ va_list pa; va_start(pa, lock_id); ret = vsnprintf(buffer, PCILIB_LOCK_SIZE, lock_id, pa); @@ -115,7 +118,9 @@ pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const c pcilib_error("Failed to construct the lock id, probably arguments does not match the format string (%s)...", lock_id); return NULL; } - + + + /* we iterate through locks to see if there is one already with the same name*/ // Would be nice to have hash here for (i = 0; i < PCILIB_MAX_LOCKS; i++) { lock = pcilib_get_lock_by_id(ctx, i); @@ -141,6 +146,7 @@ pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const c } } #endif /* ! HAVE_STDATOMIC_H */ + /* if yes, we increment its ref variable*/ pcilib_lock_ref(lock); #ifndef HAVE_STDATOMIC_H if ((flags&PCILIB_LOCK_FLAG_UNLOCKED)==0) @@ -192,6 +198,7 @@ pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const c return NULL; } + /* if the lock did not exist before, then we create it*/ err = pcilib_init_lock(lock, flags, buffer); if (err) { @@ -229,11 +236,11 @@ void pcilib_return_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, pcilib_lock_t } -/** - * Destroy all existing locks. This is unsafe call as this and other running applications - * will still have all initialized lock pointers. It is user responsibility to issue this - * command when no other application is running. - */ +/* + * Destroy all existing locks. This is unsafe call as this and other running applications + * will still have all initialized lock pointers. It is user responsibility to issue this + * command when no other application is running. + */ int pcilib_destroy_all_locks(pcilib_t *ctx, int force) { int err; pcilib_lock_id_t i; @@ -269,6 +276,7 @@ int pcilib_destroy_all_locks(pcilib_t *ctx, int force) { return 0; } + /* if we run in non-forced case, then if it may be still processes that can have access to the locks, they are not destroyed*/ if (!force) { for (i = 0; i < PCILIB_MAX_LOCKS; i++) { pcilib_lock_t *lock = pcilib_get_lock_by_id(ctx, i); diff --git a/pcilib/locking.h b/pcilib/locking.h index ccacd63..5e4c6e9 100644 --- a/pcilib/locking.h +++ b/pcilib/locking.h @@ -1,5 +1,5 @@ /** - * @file lock_global.h + * @file locking.h * @brief this file is the header file for functions that touch all locks allocated for software registers. * @details for more details about implementation choice, please read the file lock.h */ @@ -14,30 +14,78 @@ #include <pcilib/kmem.h> #include <pcilib/lock.h> -typedef uint32_t pcilib_lock_id_t; +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; + +/** + * 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 other locks */ -// 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 extern "C" { #endif +/** + *this function gets the kernel space for the locks : if this space have been already initialized, then the previous space is returned. If not, the space is created. this function has to be protected, in order to avoid the simultaneous creation of 2 kernel spaces. For that, we use pcilib_lock_global. + *@param[in,out] ctx - the pcilib_t structure running, getting filled with a ref to locks' kernel space + */ int pcilib_init_locking(pcilib_t *ctx); + +/** + *this function cleans the memory from all locks : the kernel space is freed, and locks references in pcilib_t are destroyed by setting memory to 0 + *@param[in,out] ctx - the pcilib_t structure running + */ void pcilib_free_locking(pcilib_t *ctx); +/** + * this function use flock locking mechanism on the ALPS platform device file, to make sure to not create two kernel spaces for locks + *@param[in,out] ctx - the pcilib_t structure running + */ int pcilib_lock_global(pcilib_t *ctx); + +/** + *function to remove the lock created by flock on the ALPS platform device file + *@param[in,out] ctx - the pcilib_t structure running + */ void pcilib_unlock_global(pcilib_t *ctx); +/** + * this function returns the lock at the index in the kernel space equal to id + *@param[in] ctx - the pcilib_t structure running + *@param[in] id - the index of the lock + *@return the lock structure corresponding + */ pcilib_lock_t *pcilib_get_lock_by_id(pcilib_t *ctx, pcilib_lock_id_t id); +/** + *this function verify if the lock requested exists in the kernel space. If yes, then nothing is done, else we create the lock in the kernel space. This function also gives the number of processes that may request the lock afterwards, including the one that just created it. + *@param[in] ctx - the pcilib_t structure running + *@param[in] flags - the flag defining the property of the lock + *@param[in@ lock_id - the identifier name for the lock + *@return the corresponding lock, or a new one if it did not exist before + */ pcilib_lock_t *pcilib_get_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, const char *lock_id, ...); + +/** + *this function is to decrement the variable in a lock containing the number of processes that may access to this lock(refs) + *@param[in] ctx - the pcilib_t structure running + *@param[in] flags - the flag defining the property of the lock + *@param[in] lock - pointer to the lock we want to modify + */ void pcilib_return_lock(pcilib_t *ctx, pcilib_lock_flags_t flags, pcilib_lock_t *lock); +/** + * this function destroy all the locks that have been created(unref the locks + set memory to 0), and so is used when we want to clean properly the kernel space. If force is set to 1, then we don't care about other processes that may request locks. If not, if there is locks that may be requested by other processes, then the operation is stopped. Of course, destroying locks that may be requested by other processes results in an undefined behaviour. Thus, it is user responsibility to issue this command with force set to 1 + *@param[in,out] ctx - the pcilib_t structure running + *@param[in] force - should the operation be forced or not + * @return error code : 0 if everything was ok + */ int pcilib_destroy_all_locks(pcilib_t *ctx, int force); 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 b7dcbcd..5c25473 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -139,16 +139,23 @@ 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_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_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; } + 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)); @@ -191,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) { @@ -350,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; @@ -370,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); @@ -389,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 00528e1..ab80101 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -8,11 +8,15 @@ #define PCILIB_DMA_SKIP_TIMEOUT 1000000 /**< us */ #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_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" @@ -26,6 +30,7 @@ #include "export.h" #include "locking.h" #include "xml.h" +#include "view.h" typedef struct { uint8_t max_link_speed, link_speed; @@ -33,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 */ @@ -62,7 +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 */ - 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) */ @@ -75,6 +99,11 @@ 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 */ 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 e7cbae9..74eeb12 100644 --- a/pcilib/register.h +++ b/pcilib/register.h @@ -24,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 */ @@ -37,17 +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_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/xml.c b/pcilib/xml.c index 73a3deb..c431b73 100644 --- a/pcilib/xml.c +++ b/pcilib/xml.c @@ -39,14 +39,25 @@ #include "register.h" #include "xml.h" #include "error.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.*/ -static char *pcilib_xml_bank_default_format = "0x%lx"; +#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 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; @@ -59,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) { @@ -67,76 +78,105 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr } */ -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) { +static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) { + xmlAttr *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, "name")) { + desc->name = value; + } else if (!strcasecmp(name, "view")) { + desc->view = value; + } + } + + 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, 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; @@ -151,15 +191,15 @@ 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; @@ -168,82 +208,121 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript } } + 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; - 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]); + + 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, ®); 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; + 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++) { - 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]); - 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, ®); - 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; - } + 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, ®); + 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); @@ -252,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; @@ -273,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")) { @@ -344,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")) { @@ -357,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; } } @@ -369,31 +448,302 @@ 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; + } + + 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); + } + } + 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; +} + +/** + * function to create a unit from a unit xml node, then populating ctx with it + *@param[in,out] ctx - the pcilib_t running + *@param[in] xpath - the xpath context of the unis xml file + *@param[in] doc - the AST of the unit xml file + *@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) { + int err; + + pcilib_unit_description_t desc = {0}; + + 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; + if (!strcasecmp(name, "name")) { + desc.name = value; + } + } + + xpath->node = node; + nodes = xmlXPathEvalExpression(UNIT_TRANSFORMS_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", UNIT_TRANSFORMS_PATH, xmlerr->code, xmlerr->message); + else pcilib_error("Failed to parse XPath expression %s", UNIT_TRANSFORMS_PATH); + return PCILIB_ERROR_FAILED; } nodeset = nodes->nodesetval; if (!xmlXPathNodeSetIsEmpty(nodeset)) { int 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; + } + 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); + err = pcilib_xml_parse_unit_transform(ctx, xpath, doc, nodeset->nodeTab[i], &desc.transforms[i]); + if (err) { + xmlXPathFreeObject(nodes); + return err; + } } } xmlXPathFreeObject(nodes); - return 0; + return pcilib_add_units(ctx, 1, &desc); } @@ -405,69 +755,108 @@ static int pcilib_xml_create_bank(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; + int err; + xmlXPathObjectPtr bank_nodes = NULL, transform_nodes = NULL, enum_nodes = NULL, unit_nodes = NULL; xmlNodeSetPtr nodeset; + int i; - bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath); - if (!bank_nodes) { - xmlErrorPtr 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; + 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 = 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); + } + } + + 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)) { - int i; - 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; @@ -481,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; @@ -550,12 +939,12 @@ 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); + 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); @@ -586,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); @@ -613,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(); + */ } diff --git a/pcitool/cli.c b/pcitool/cli.c index c3663d2..d140b98 100644 --- a/pcitool/cli.c +++ b/pcitool/cli.c @@ -192,7 +192,7 @@ static struct option long_options[] = { {"output", required_argument, 0, OPT_OUTPUT }, {"timeout", required_argument, 0, OPT_TIMEOUT }, {"iterations", required_argument, 0, OPT_ITERATIONS }, - {"info", no_argument, 0, OPT_INFO }, + {"info", optional_argument, 0, OPT_INFO }, {"list", no_argument, 0, OPT_LIST }, {"reset", no_argument, 0, OPT_RESET }, {"benchmark", optional_argument, 0, OPT_BENCHMARK }, @@ -257,7 +257,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { "Usage:\n" " %s <mode> [options] [hex data]\n" " Modes:\n" -" -i - Device Info\n" +" -i [target] - Device or Register (target) Info\n" " -l[l] - List (detailed) Data Banks & Registers\n" " -r <addr|reg|dmaX> - Read Data/Register\n" " -w <addr|reg|dmaX> - Write Data/Register\n" @@ -572,7 +572,90 @@ void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const } } -void Info(pcilib_t *handle, const pcilib_model_description_t *model_info) { +void RegisterInfo(pcilib_t *handle, pcilib_register_t reg) { + int err; + pcilib_register_value_t val; + + const pcilib_model_description_t *model_info = pcilib_get_model_description(handle); + const pcilib_register_description_t *r = &model_info->registers[reg]; + pcilib_register_bank_t bank = pcilib_find_register_bank_by_addr(handle, r->bank); + const pcilib_register_bank_description_t *b = &model_info->banks[bank]; + + err = pcilib_read_register_by_id(handle, reg, &val); + + + printf("%s/%s\n", b->name, r->name); + printf(" Current value: "); + if (err) printf("error %i", err); + else printf(b->format, val); + + if (r->mode&PCILIB_REGISTER_W) { + printf(" (default: "); + printf(b->format, r->defvalue); + printf(")"); + } + printf("\n"); + + printf(" Address : 0x%x [%u:%u]\n", r->addr, r->offset, r->offset + r->bits); + printf(" Access : "); + if ((r->mode&PCILIB_REGISTER_RW) == 0) printf("-"); + if (r->mode&PCILIB_REGISTER_R) printf("R"); + if (r->mode&PCILIB_REGISTER_W) printf("W"); + if (r->mode&PCILIB_REGISTER_W1C) printf("/reset"); + if (r->mode&PCILIB_REGISTER_W1I) printf("/invert"); + printf("\n"); + + + if (r->description) + printf(" Description : %s\n", r->description); + + if (r->views) { + int i; + printf("\nSupported Views:\n"); + for (i = 0; r->views[i].name; i++) { + pcilib_view_t view = pcilib_find_view_by_name(handle, r->views[i].view); + if (view == PCILIB_VIEW_INVALID) continue; + + const pcilib_view_description_t *v = model_info->views[view]; + + printf(" View %s (", r->views[i].name); + switch (v->type) { + case PCILIB_TYPE_STRING: + printf("char*"); + break; + case PCILIB_TYPE_DOUBLE: + printf("double"); + break; + default: + printf("unknown"); + } + printf(")\n"); + + if (v->unit) { + pcilib_unit_t unit = pcilib_find_unit_by_name(handle, v->unit); + + printf(" Supported units: %s", v->unit); + + if (unit != PCILIB_UNIT_INVALID) { + int j; + const pcilib_unit_description_t *u = &model_info->units[unit]; + + for (j = 0; u->transforms[j].unit; j++) + printf(", %s", u->transforms[j].unit); + } + printf("\n"); + } + + if (v->description) + printf(" Description : %s\n", v->description); + } + } + + +// printf("Type: %s". r->rw +} + +void Info(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *target) { int i, j; DIR *dir; void *plugin; @@ -595,9 +678,20 @@ void Info(pcilib_t *handle, const pcilib_model_description_t *model_info) { if (board_info) printf(" Interrupt - Pin: %i, Line: %i\n", board_info->interrupt_pin, board_info->interrupt_line); + printf("\n"); + + if (target) { + pcilib_register_t reg; + + reg = pcilib_find_register(handle, NULL, target); + if (reg != PCILIB_REGISTER_INVALID) + return RegisterInfo(handle, reg); + + Error(" No register %s is found", target); + } + List(handle, model_info, (char*)-1, 0); - printf("\n"); printf("Available models:\n"); dir = opendir(path); @@ -2656,6 +2750,7 @@ int main(int argc, char **argv) { const char *dma_channel = NULL; const char *use = NULL; const char *lock = NULL; + const char *info_target = NULL; size_t block = (size_t)-1; pcilib_irq_type_t irq_type = PCILIB_IRQ_TYPE_ALL; pcilib_irq_hw_source_t irq_source = PCILIB_IRQ_SOURCE_DEFAULT; @@ -2693,6 +2788,9 @@ int main(int argc, char **argv) { case OPT_INFO: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + if (optarg) info_target = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) info_target = argv[optind++]; + mode = MODE_INFO; break; case OPT_LIST: @@ -3328,7 +3426,7 @@ int main(int argc, char **argv) { switch (mode) { case MODE_INFO: - Info(handle, model_info); + Info(handle, model_info, info_target); break; case MODE_LIST: List(handle, model_info, bank, details); diff --git a/protocols/software.c b/protocols/software.c index 55f62e8..55ed647 100644 --- a/protocols/software.c +++ b/protocols/software.c @@ -12,33 +12,21 @@ typedef struct pcilib_software_register_bank_context_s pcilib_software_register_bank_context_t; +/** + * structure defining the context of software registers + */ struct pcilib_software_register_bank_context_s { - pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers */ - + pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers */ pcilib_kmem_handle_t *kmem; /**< the kernel memory for software registers */ void *addr; /**< the virtual adress of the allocated kernel memory*/ }; -/** - * pcilib_software_registers_close - * this function clear the kernel memory space that could have been allocated for software registers - * @param[in] bank_ctx the bank context running that we get from the initialisation function - */ void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx) { if (((pcilib_software_register_bank_context_t*)bank_ctx)->kmem) pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE); free(bank_ctx); } -/** - * pcilib_software_registers_open - * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. It the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used - * @param[in] ctx the pcilib_t structure running - * @param[in] bank the bank index that will permits to get the bank we want registers from - * @param[in] model not used - * @param[in] args not used - * @return a bank context with the adress of the kernel space memory related to it - */ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pcilib_register_bank_t bank, const char* model, const void *args) { int err; pcilib_software_register_bank_context_t *bank_ctx; @@ -59,6 +47,7 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc return NULL; } + /*we get a lock to protect the creation of the kernel space for software registers against multiple creations*/ lock = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "softreg/%s", bank_desc->name); if (!lock) { pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); @@ -74,7 +63,7 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc return NULL; } - + /*creation of the kernel space*/ handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank_desc->addr), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); if (!handle) { pcilib_unlock(lock); @@ -98,7 +87,8 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); return NULL; } - + + /* here we fill the software registers with their default value*/ for (i = 0; ctx->model_info.registers[i].name != NULL; i++) { if ((ctx->model_info.registers[i].bank == ctx->banks[bank].addr)&&(ctx->model_info.registers[i].type == PCILIB_REGISTER_STANDARD)) { *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue; @@ -112,15 +102,6 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc return (pcilib_register_bank_context_t*)bank_ctx; } -/** - * pcilib_software_registers_read - * this function read the value of a said register in the kernel space - * @param[in] ctx the pcilib_t structure runnning - * @param[in] bank_ctx the bank context that was returned by the initialisation function - * @param[in] addr the adress of the register we want to read - * @param[out] value the value of the register - * @return 0 in case of success - */ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value){ if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) { pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); @@ -132,15 +113,6 @@ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t return 0; } -/** - * pcilib_software_registers_write - * this function write the said value to a said register in the kernel space - * @param[in] ctx the pcilib_t structure runnning - * @param[in] bank_ctx the bank context that was returned by the initialisation function - * @param[in] addr the adress of the register we want to write in - * @param[out] value the value we want to write in the register - * @return 0 in case of success - */ int pcilib_software_registers_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t value) { if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) { pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); diff --git a/protocols/software.h b/protocols/software.h index d066cd6..484e344 100644 --- a/protocols/software.h +++ b/protocols/software.h @@ -1,7 +1,6 @@ /** * @file software.h - * @skip author nicolas zilio, nicolas.zilio@hotmail.fr - * @brief header file for implementation of the protocol with software registers allocated in the main memory. + * @brief header file for implementation of the protocol with software registers allocated in the kernel space, for parameters sharing between concurrent pcitool instances */ #ifndef _PCILIB_SOFTWARE_H @@ -13,44 +12,44 @@ /** * this function initialize the kernel space memory for the use of software register. it initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. If the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used - * @param[in] ctx the pcilib_t structure running - * @param[in] bank the bank index that will permits to get the bank we want registers from - * @param[in] model not used - * @param[in] args not used - * @return a bank context with the adress of the kernel space memory related to it + * @param[in] - ctx the pcilib_t structure running + * @param[in] - bank the bank index that will permits to get the bank we want registers from + * @param[in] - model not used + * @param[in] - args not used + * @return a bank context with the adress of the kernel space memory related to it, as we could have for BAR */ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pcilib_register_bank_t bank, const char* model, const void *args); /** - * this function clear the kernel memory space that could have been allocated for software registers. - * @param[in] ctx the pcilib_t structure runnning - * @param[in] bank_ctx the bank context running that we get from the initialisation function + * this function clear the kernel memory space that could have been allocated for software registers and the bank context that correspond to it too + * @param[in] ctx - the pcilib_t structure runnning + * @param[in] bank_ctx - the bank context running that we get from the initialisation function */ void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx); /** * this function read the value of a said register in the kernel space. - * @param[in] ctx the pcilib_t structure runnning - * @param[in] bank_ctx the bank context that was returned by the initialisation function - * @param[in] addr the adress of the register we want to read - * @param[out] value the value of the register - * @return 0 in case of success + * @param[in] - ctx the pcilib_t structure runnning + * @param[in] - bank_ctx the bank context that was returned by the initialisation function + * @param[in] - addr the adress of the register we want to read + * @param[out] - value the value of the register + * @return error code : 0 in case of success */ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t* bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value); /** - * this function write the said value to a said register in the kernel space - * @param[in] ctx the pcilib_t structure runnning - * @param[in] bank_ctx the bank context that was returned by the initialisation function - * @param[in] addr the adress of the register we want to write in - * @param[out] value the value we want to write in the register - * @return 0 in case of success + * this function write the given value to a given register in the kernel space + * @param[in] ctx - the pcilib_t structure runnning + * @param[in] bank_ctx - the bank context that was returned by the initialisation function + * @param[in] addr - the adress of the register we want to write in + * @param[in] value - the value we want to write in the register + * @return error code : 0 in case of success */ int pcilib_software_registers_write(pcilib_t *ctx,pcilib_register_bank_context_t* bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t value); #ifdef _PCILIB_EXPORT_C /** - * new protocol addition to the protocol api. + * software protocol addition to the protocol api. */ const pcilib_register_protocol_api_description_t pcilib_register_software_protocol_api = { PCILIB_VERSION, pcilib_software_registers_open, pcilib_software_registers_close,pcilib_software_registers_read, pcilib_software_registers_write }; /**< we add there the protocol to the list of possible protocols*/ diff --git a/views/CMakeLists.txt b/views/CMakeLists.txt new file mode 100644 index 0000000..fa50abf --- /dev/null +++ b/views/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/pcilib + ${CMAKE_BINARY_DIR}/pcilib + ${LIBXML2_INCLUDE_DIRS} +) + +set(HEADERS ${HEADERS} enum.h transform.h) + +add_library(views STATIC enum.c transform.c) diff --git a/views/enum.c b/views/enum.c new file mode 100644 index 0000000..a222971 --- /dev/null +++ b/views/enum.c @@ -0,0 +1,47 @@ +#define _PCILIB_VIEW_ENUM_C + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include "version.h" +#include "model.h" +#include "enum.h" + +static void pcilib_enum_view_free(pcilib_t *ctx, pcilib_view_context_t *view) { +} + +static int pcilib_enum_view_read(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) { +/* 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;*/ +} + +static int pcilib_enum_view_write(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) { +/* 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; + } + }*/ +} + +const pcilib_view_api_description_t pcilib_enum_view_static_api = + { PCILIB_VERSION, sizeof(pcilib_enum_view_description_t), NULL, NULL, pcilib_enum_view_read, pcilib_enum_view_write }; +const pcilib_view_api_description_t pcilib_enum_view_xml_api = + { PCILIB_VERSION, sizeof(pcilib_enum_view_description_t), NULL, pcilib_enum_view_free, pcilib_enum_view_read, pcilib_enum_view_write }; diff --git a/views/enum.h b/views/enum.h new file mode 100644 index 0000000..eb90810 --- /dev/null +++ b/views/enum.h @@ -0,0 +1,23 @@ +#ifndef _PCILIB_VIEW_ENUM_H +#define _PCILIB_VIEW_ENUM_H + +#include <pcilib.h> +#include <pcilib/view.h> + +typedef struct { + pcilib_register_value_t value, min, max; /**< the value or value-range for which the name is defined, while wrtiting the name the value will be used even if range is specified */ + const char *name; /**< corresponding string to value */ +} pcilib_value_name_t; + +typedef struct { + pcilib_view_description_t base; + pcilib_value_name_t *names; +} pcilib_enum_view_description_t; + + +#ifndef _PCILIB_VIEW_ENUM_C +extern const pcilib_view_api_description_t pcilib_enum_view_static_api; +extern const pcilib_view_api_description_t pcilib_enum_view_xml_api; +#endif /* _PCILIB_VIEW_ENUM_C */ + +#endif /* _PCILIB_VIEW_ENUM_H */ diff --git a/views/transform.c b/views/transform.c new file mode 100644 index 0000000..54ae2c1 --- /dev/null +++ b/views/transform.c @@ -0,0 +1,71 @@ +#define _PCILIB_VIEW_TRANSFORM_C + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +#include "version.h" +#include "model.h" +#include "transform.h" + + +static int pcilib_transform_view_read(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 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; + } + }*/ +} + +static int pcilib_transform_view_write(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) { +/* 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;*/ +} + + +const pcilib_view_api_description_t pcilib_transform_view_api = + { PCILIB_VERSION, sizeof(pcilib_transform_view_description_t), NULL, NULL, pcilib_transform_view_read, pcilib_transform_view_write }; diff --git a/views/transform.h b/views/transform.h new file mode 100644 index 0000000..f474552 --- /dev/null +++ b/views/transform.h @@ -0,0 +1,17 @@ +#ifndef _PCILIB_VIEW_TRANSFORM_H +#define _PCILIB_VIEW_TRANSFORM_H + +#include <pcilib.h> +#include <pcilib/view.h> + +typedef struct { + pcilib_view_description_t base; + const char *read_from_reg; /**< Formula explaining how to convert the register value to the view value */ + const char *write_to_reg; /**< Formula explaining how to convert from the view value to the register value */ +} pcilib_transform_view_description_t; + +#ifndef _PCILIB_VIEW_TRANSFORM_C +const pcilib_view_api_description_t pcilib_transform_view_api; +#endif /* _PCILIB_VIEW_TRANSFORM_C */ + +#endif /* _PCILIB_VIEW_TRANSFORM_H */ diff --git a/xml/model.xsd b/xml/model.xsd index 5febd1a..1440032 100644 --- a/xml/model.xsd +++ b/xml/model.xsd @@ -1,241 +1,15 @@ <?xml version="1.0" encoding="ISO-8859-1"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> - - <xsd:element name="model"> - <xsd:complexType> - <xsd:sequence> - <xsd:element name="banks" type="banks_type"/> - <xsd:element name="views" type="views_type" minOccurs="0" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - <xsd:key name="Registerkey"> - <xsd:selector xpath="views/view/name"/> - <xsd:field xpath="."/> - </xsd:key> - <xsd:keyref refer="Registerkey" name="RegisterkeyRef"> - <xsd:selector xpath="banks/bank/registers/register/views/view"/> - <xsd:field xpath="."/> - </xsd:keyref> - <xsd:key name="Registerbitskey"> - <xsd:selector xpath="views/view/name"/> - <xsd:field xpath="."/> - </xsd:key> - <xsd:keyref refer="Registerbitskey" name="RegisterbitskeyRef"> - <xsd:selector xpath="banks/bank/registers/register/registers_bits/register_bits/views/view"/> - <xsd:field xpath="."/> - </xsd:keyref> - </xsd:element> - - - <xsd:complexType name="views_type"> - <xsd:sequence> - <xsd:element name="view" type="view_type" maxOccurs="unbounded"/> - </xsd:sequence> - </xsd:complexType> - - - <xsd:complexType name="banks_type"> - <xsd:sequence> - <xsd:element name="bank" type="banktype" minOccurs="1" maxOccurs="12"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="banktype"> - <xsd:sequence> - <xsd:element name="bank_description" type="bank_description_t"/> - <xsd:element name="registers" type="registerstype" minOccurs="0" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="bank_description_t"> - <xsd:sequence> - <xsd:element name="bar" type="bar_type"/> - <xsd:element name="size" type="hexa_and_integer64_t"/> - <xsd:element name="protocol" type="xsd:string"/> - <xsd:element name="read_address" type="hex64_t"/> - <xsd:element name="write_address" type="hex64_t"/> - <xsd:element name="word_size" type="uint8_t"/> - <xsd:element name="endianess" type="endianess_type"/> - <xsd:element name="format" type="xsd:string"/> - <xsd:element name="name" type="xsd:string"/> - <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - - - <xsd:complexType name="registerstype"> - <xsd:sequence> - <xsd:element name="register" type="register_type" minOccurs="0" maxOccurs="256"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="register_type"> - <xsd:sequence> - <xsd:element name="address" type="hexa_and_integer32_t"/> - <xsd:element name="offset" type="uint8_t"/> - <xsd:element name="size" type="uint8_t"/> - <xsd:element name="default" type="hexa_and_integer32_t"/> - <xsd:element name="rwmask" type="rwmask_type"/> - <xsd:element name="mode" type="pcilib_register_mode_t"/> - <xsd:element name="name" type="xsd:string"/> - <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1"/> - <xsd:element name="views" type="reg_to_views_type" minOccurs="0" maxOccurs="1"/> - <xsd:element name="registers_bits" type="registers_bits_type" minOccurs="0" maxOccurs="1"/> - <xsd:element name="value_min" type="hexa_and_integer32_t" minOccurs="0" maxOccurs="1"/> - <xsd:element name="value_max" type="hexa_and_integer32_t" minOccurs="0" maxOccurs="1"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="registers_bits_type"> - <xsd:sequence> - <xsd:element name="register_bits" type="register_bits_type" minOccurs="1" maxOccurs="32"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="reg_to_views_type"> - <xsd:sequence> - <xsd:element name="view" type="xsd:string" minOccurs="1" maxOccurs="unbounded"/> - </xsd:sequence> - </xsd:complexType> - - <xsd:complexType name="register_bits_type"> - <xsd:sequence> - <xsd:element name="offset" type="uint8_t"/> - <xsd:element name="size" type="uint8_t"/> - <xsd:element name="mode" type="pcilib_register_mode_t"/> - <xsd:element name="name" type="xsd:string"/> - <xsd:element name="description" type="xsd:string" minOccurs="0" maxOccurs="1"/> - <xsd:element name="views" type="reg_to_views_type" minOccurs="0" maxOccurs="1"/> - </xsd:sequence> - - </xsd:complexType> - - <xsd:simpleType name="uint8_t"> - <xsd:restriction base="xsd:integer"> - <xsd:minInclusive value="0"/> - <xsd:maxInclusive value="255"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="size_t"> - <xsd:restriction base="xsd:integer"> - <xsd:minInclusive value="0"/> - <xsd:maxInclusive value="18446744073709551615"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="uintptr_t"> - <xsd:restriction base="xsd:integer"> - <xsd:minInclusive value="0"/> - <xsd:maxInclusive value="18446744073709551615"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="uint32_t"> - <xsd:restriction base="xsd:integer"> - <xsd:minInclusive value="0"/> - <xsd:maxInclusive value="4294967295"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="pcilib_register_mode_t"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="R"/> - <xsd:enumeration value="W"/> - <xsd:enumeration value="RW"/> - <xsd:enumeration value="W1C"/> - <xsd:enumeration value="RW1C"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="bank_adress_type"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="bank 0"/> - <xsd:enumeration value="bank 1"/> - <xsd:enumeration value="bank 2"/> - <xsd:enumeration value="bank 3"/> - <xsd:enumeration value="DMA bank"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="endianess_type"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="little"/> - <xsd:enumeration value="big"/> - <xsd:enumeration value="host"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="bar_type"> - <xsd:restriction base="xsd:integer"> - <xsd:enumeration value="0"/> - <xsd:enumeration value="1"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="space_adress_type"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="write adress"/> - <xsd:enumeration value="read adress"/> - <xsd:enumeration value="space adress"/> - <xsd:enumeration value="0"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="rwmask_type"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="all"/> - <xsd:enumeration value="0"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="hexa_and_integer32_t"> - <xsd:union memberTypes="uint32_t hex32_t"/> - </xsd:simpleType> - - <xsd:simpleType name="hex32_t"> - <xsd:restriction base="xsd:string"> - <xsd:pattern value="0x([a-fA-F0-9]){0,8}"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:simpleType name="hexa_and_integer64_t"> - <xsd:union memberTypes="size_t hex64_t"/> - </xsd:simpleType> - - <xsd:simpleType name="hex64_t"> - <xsd:restriction base="xsd:string"> - <xsd:pattern value="0x([a-fA-F0-9]){0,16}"/> - </xsd:restriction> - </xsd:simpleType> - - <xsd:complexType name="view_type"> - <xsd:sequence> - <xsd:element name="name" type="xsd:ID"/> - <xsd:element name="unit" type="xsd:string" minOccurs="0" maxOccurs="1"/> - <xsd:element name="read_from_register" type="xsd:string" minOccurs="0" maxOccurs="1"/> - <xsd:element name="write_to_register" type="xsd:string" minOccurs="0" maxOccurs="1"/> - <xsd:element name="enum" type="enum_t" minOccurs="0" maxOccurs="unbounded"/> - <xsd:element name="description" type="xsd:string"/> - </xsd:sequence> - <xsd:attribute name="type" type="viewtype_type" use="required"/> - </xsd:complexType> - - <xsd:complexType name="enum_t"> - <xsd:simpleContent> - <xsd:extension base="xsd:string"> - <xsd:attribute name="value" type="hexa_and_integer64_t" use="required"/> - <xsd:attribute name="min" type="hexa_and_integer64_t"/> - <xsd:attribute name="max" type="hexa_and_integer64_t"/> - </xsd:extension> - </xsd:simpleContent> - </xsd:complexType> + <xsd:include schemaLocation="types.xsd"/> - <xsd:simpleType name="viewtype_type"> - <xsd:restriction base="xsd:string"> - <xsd:enumeration value="enum"/> - <xsd:enumeration value="formula"/> - </xsd:restriction> - </xsd:simpleType> - + <xsd:element name="model"> + <xsd:complexType> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="bank" type="pcilib_bank_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="transform" type="pcilib_transform_view_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="enum" type="pcilib_enum_view_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="unit" type="pcilib_unit_t" minOccurs="0" maxOccurs="unbounded" /> + </xsd:choice> + </xsd:complexType> + </xsd:element> </xsd:schema> diff --git a/xml/references.xsd b/xml/references.xsd new file mode 100644 index 0000000..810913c --- /dev/null +++ b/xml/references.xsd @@ -0,0 +1,50 @@ +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + <xsd:include schemaLocation="types.xsd"/> + + <xsd:element name="model"> + <xsd:complexType> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="bank" type="pcilib_bank_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="transform" type="pcilib_transform_view_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="enum" type="pcilib_enum_view_t" minOccurs="0" maxOccurs="unbounded"> + <xsd:key name="pcilib_value_name_key"> + <xsd:selector xpath="name" /> + <xsd:field xpath="@value" /> + </xsd:key> + </xsd:element> + <xsd:element name="unit" type="pcilib_unit_t" minOccurs="0" maxOccurs="unbounded"> + <xsd:key name="pcilib_unit_transform_key"> + <xsd:selector xpath="transform" /> + <xsd:field xpath="@unit" /> + </xsd:key> + </xsd:element> + </xsd:choice> + </xsd:complexType> + + <xsd:key name="pcilib_bank_key"> + <xsd:selector xpath="bank" /> + <xsd:field xpath="@name" /> + </xsd:key> + <xsd:key name="pcilib_register_key"> + <xsd:selector xpath="bank/register|bank/register/field" /> + <xsd:field xpath="@name" /> + </xsd:key> + <xsd:key name="pcilib_view_key"> + <xsd:selector xpath="transform|enum" /> + <xsd:field xpath="@name" /> + </xsd:key> + <xsd:key name="pcilib_unit_key"> + <xsd:selector xpath="unit" /> + <xsd:field xpath="@name" /> + </xsd:key> + + <xsd:keyref name="pcilib_register_view_ref" refer="pcilib_view_key"> + <xsd:selector xpath="bank/register/view|bank/register/field/view" /> + <xsd:field xpath="@view" /> + </xsd:keyref> + <xsd:keyref name="pcilib_unit_ref" refer="pcilib_unit_key"> + <xsd:selector xpath="transform|enum" /> + <xsd:field xpath="@unit" /> + </xsd:keyref> + </xsd:element> +</xsd:schema> diff --git a/xml/test/camera.xml b/xml/test/camera.xml index 5b486ee..2169bd2 100644 --- a/xml/test/camera.xml +++ b/xml/test/camera.xml @@ -1,494 +1,157 @@ -<?xml version="1.0" encoding="ISO-8859-1"?> +<?xml version="1.0"?> <model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - <banks> - <bank> - <bank_description> - <bar>0</bar> - <size>0x0200</size> - <protocol>software_registers</protocol> - <read_address>0x9000</read_address> - <write_address>0x9000</write_address> - <word_size>32</word_size> - <endianess>little</endianess> - <format>0x%lx</format> - <name>software</name> - <description>IPECamera Registers</description> - </bank_description> - <registers> - <register> - <address>0x00</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>spi_conf_input</name> - </register> - <register> - <address>0x10</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>spi_conf_output</name> - </register> - <register> - <address>0x20</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>spi_clk_speed</name> - </register> - <register> - <address>0x30</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>firmware_info</name> - <registers_bits> - <register_bits> - <offset>0</offset> - <size>8</size> - <mode>R</mode> - <name>firmware_version</name> - </register_bits> - <register_bits> - <offset>8</offset> - <size>1</size> - <mode>R</mode> - <name>firmware_bitmode</name> - </register_bits> - <register_bits> - <offset>12</offset> - <size>2</size> - <mode>R</mode> - <name>adc_resolution</name> - </register_bits> - <register_bits> - <offset>16</offset> - <size>2</size> - <mode>R</mode> - <name>output_mode</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0x40</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>control</name> - <registers_bits> - <register_bits> - <offset>31</offset> - <size>1</size> - <mode>R</mode> - <name>freq</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0x50</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>status</name> - </register> - <register> - <address>0x54</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>status2</name> - </register> - <register> - <address>0x58</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>status3</name> - </register> - <register> - <address>0x5c</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>fr_status</name> - </register> - <register> - <address>0x70</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>start_address</name> - </register> - <register> - <address>0x74</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>end_address</name> - </register> - <register> - <address>0x78</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>rd_address</name> - </register> - <register> - <address>0xa0</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>fr_param1</name> - <registers_bits> - <register_bits> - <offset>0</offset> - <size>10</size> - <mode>RW</mode> - <name>fr_skip_lines</name> - </register_bits> - <register_bits> - <offset>10</offset> - <size>11</size> - <mode>RW</mode> - <name>fr_num_lines</name> - </register_bits> - <register_bits> - <offset>21</offset> - <size>11</size> - <mode>RW</mode> - <name>fr_start_address</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0xb0</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>all</rwmask> - <mode>RW</mode> - <name>fr_param2</name> - <registers_bits> - <register_bits> - <offset>0</offset> - <size>11</size> - <mode>RW</mode> - <name>fr_threshold_start_line</name> - </register_bits> - <register_bits> - <offset>16</offset> - <size>10</size> - <mode>RW</mode> - <name>fr_area_lines</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0xc0</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>skiped_lines</name> - </register> - <register> - <address>0xd0</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>all</rwmask> - <mode>RW</mode> - <name>fr_thresholds</name> - </register> - <register> - <address>0xd0</address> - <offset>0</offset> - <size>10</size> - <default>0</default> - <rwmask>all</rwmask> - <mode>RW</mode> - <name>fr_pixel_thr</name> - </register> - <register> - <address>0xd0</address> - <offset>10</offset> - <size>11</size> - <default>0</default> - <rwmask>all</rwmask> - <mode>RW</mode> - <name>fr_num_pixel_thr</name> - </register> - <register> - <address>0xd0</address> - <offset>21</offset> - <size>11</size> - <default>0</default> - <rwmask>all</rwmask> - <mode>RW</mode> - <name>fr_num_lines_thr</name> - </register> - <register> - <address>0x100</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>rawdata_pkt_addr</name> - </register> - <register> - <address>0x110</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>temperature_info</name> - <registers_bits> - <register_bits> - <offset>0</offset> - <size>16</size> - <mode>R</mode> - <name>sensor_temperature</name> - <views> - <view>formuu1</view> - <view>formuu2</view> - <view>enumm2</view> - </views> - </register_bits> - <register_bits> - <offset>16</offset> - <size>3</size> - <mode>R</mode> - <name>sensor_temperature_alarms</name> - </register_bits> - <register_bits> - <offset>19</offset> - <size>10</size> - <mode>RW</mode> - <name>fpga_temperature</name> - <views> - <view>formuu1</view> - <view>enumm1</view> - </views> - </register_bits> - <register_bits> - <offset>29</offset> - <size>3</size> - <mode>R</mode> - <name>fpga_temperature_alarms</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0x120</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>num_lines</name> - </register> - <register> - <address>0x130</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>start_line</name> - </register> - <register> - <address>0x140</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>exp_time</name> - </register> - <register> - <address>0x150</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>motor</name> - <registers_bits> - <register_bits> - <offset>0</offset> - <size>5</size> - <mode>RW</mode> - <name>motor_phi</name> - </register_bits> - <register_bits> - <offset>5</offset> - <size>5</size> - <mode>RW</mode> - <name>motor_z</name> - </register_bits> - <register_bits> - <offset>10</offset> - <size>5</size> - <mode>RW</mode> - <name>motor_y</name> - </register_bits> - <register_bits> - <offset>15</offset> - <size>5</size> - <mode>RW</mode> - <name>motor_x</name> - </register_bits> - <register_bits> - <offset>20</offset> - <size>8</size> - <mode>R</mode> - <name>adc_gain</name> - </register_bits> - </registers_bits> - </register> - <register> - <address>0x160</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>write_status</name> - </register> - <register> - <address>0x170</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>num_triggers</name> - </register> - <register> - <address>0x180</address> - <offset>0</offset> - <size>32</size> - <default>0x280</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>trigger_period</name> - <views> - <view>enumm2</view> - </views> - </register> - <register> - <address>0x190</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>temperature_sample_period</name> - </register> - <register> - <address>0x1a0</address> - <offset>0</offset> - <size>32</size> - <default>0x64</default> - <rwmask>0</rwmask> - <mode>RW</mode> - <name>ddr_max_frames</name> - </register> - <register> - <address>0x1b0</address> - <offset>0</offset> - <size>32</size> - <default>0</default> - <rwmask>0</rwmask> - <mode>R</mode> - <name>ddr_num_frames</name> - </register> - </registers> - </bank> - <bank> - <bank_description> - <bar>0</bar> - <size>0x0200</size> - <protocol>default</protocol> - <read_address>0x0</read_address> - <write_address>0x0</write_address> - <word_size>32</word_size> - <endianess>little</endianess> - <format>0x%lx</format> - <name>dma</name> - <description>DMA Registers</description> - </bank_description> - </bank> - </banks> - <views> - <view type="formula"> - <name>formuu1</name> - <unit>C</unit> - <read_from_register>(503975./1024000)*@reg - 27315./100</read_from_register> - <write_to_register>(@value + 27315./100)*(102400./503975)</write_to_register> -<description>formula to get real fpga temperature from the fpga_temperature register in decimal</description> - </view> - <view type="enum"> - <name>enumm1</name> - <enum value="0x100" min="0x2" max="0x300">high</enum> - <enum value="0x010">low</enum> - <description>enum towards temperatures register</description> - </view> - <view type="formula"> - <name>formuu2</name> - <unit>C</unit> - <read_from_register>((1./4)*(@reg - 1200)) if @freq==0 else ((3./10)*(@reg - 1000))</read_from_register> - <write_to_register>4*@value + 1200 if @freq==0 else (10./3)*@value + 1000</write_to_register> - <description>formula to get real sensor temperature from the sensor_temperature register in decimal</description> - </view> - <view type="enum"> - <name>enumm2</name> - <enum value="0x120">high</enum> - <enum value="0x010" min="0x00" max="0x020">low</enum> - <description>enum towards sensor_temperature register</description> - </view> - <view type="formula"> - <name>formuu3</name> - <unit>us</unit> - <read_from_register>(@reg+(43./100))*129./(40*1000000)if @freq==0 else (@reg+(43./100))*129./(48*1000000)</read_from_register> - <write_to_register>@value/129.*(40*1000000) - 43./100 if @freq==0 else @value/129.*(48*1000000) - 43./100</write_to_register> - <description>formula to get real exposure time from the cmosis_exp_time register in decimal</description> - </view> - <view type="enum"> - <name>enumm3</name> - <enum value="0x000">short</enum> - <enum value="0x010">mid</enum> - <enum value="0x100" min="0x0F0">long</enum> - <description>enum towards cmosis_exp_register register</description> - </view> - </views> + <bank bar="0" size="128" protocol="software_registers" read_address="0x9010" write_address="0x9000" word_size="8" endianess="little" format="%lu" name="cmosis" description="CMOSIS CMV2000 Registers"> + <register address="1" offset="0" size="16" default="1088" rwmask="0" mode="RW" name="cmosis_number_lines" description="test"/> + <register address="3" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start1"/> + <register address="5" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start2"/> + <register address="7" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start3"/> + <register address="9" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start4"/> + <register address="11" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start5"/> + <register address="13" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start6"/> + <register address="15" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start7"/> + <register address="17" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start8"/> + <register address="19" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines1"/> + <register address="21" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines2"/> + <register address="23" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines3"/> + <register address="25" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines4"/> + <register address="27" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines5"/> + <register address="29" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines6"/> + <register address="31" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines7"/> + <register address="33" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines8"/> + <register address="35" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_s"/> + <register address="37" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_a"/> + <register address="39" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_color"/> + <register address="40" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_image_flipping"/> + <register address="41" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_exp_flags"/> + <register address="42" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time"><view view="formuu3"/><view view="enumm3"/></register> + <register address="45" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step"/> + <register address="48" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp1"/> + <register address="51" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp2"/> + <register address="54" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes"/> + <register address="55" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq"/> + <register address="56" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time2"/> + <register address="59" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step2"/> + <register address="68" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes2"/> + <register address="69" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq2"/> + <register address="70" offset="0" size="16" default="1" rwmask="0" mode="RW" name="cmosis_number_frames"/> + <register address="72" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_output_mode"/> + <register address="78" offset="0" size="12" default="85" rwmask="0" mode="RW" name="cmosis_training_pattern"/> + <register address="80" offset="0" size="18" default="0x3FFFF" rwmask="0" mode="RW" name="cmosis_channel_en"/> + <register address="82" offset="0" size="3" default="7" rwmask="0" mode="RW" name="cmosis_special_82"/> + <register address="89" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow2"/> + <register address="90" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow3"/> + <register address="100" offset="0" size="14" default="16260" rwmask="0" mode="RW" name="cmosis_offset"/> + <register address="102" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_pga"/> + <register address="103" offset="0" size="8" default="32" rwmask="0" mode="RW" name="cmosis_adc_gain"/> + <register address="111" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_bit_mode"/> + <register address="112" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_adc_resolution"/> + <register address="115" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_special_115"/> + </bank> + <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x9000" write_address="0x9000" word_size="32" endianess="little" format="0x%lx" name="fpga" description="IPECamera Registers"> + <register address="0x00" offset="0" size="32" default="0" rwmask="0" mode="RW" name="spi_conf_input"/> + <register address="0x10" offset="0" size="32" default="0" rwmask="0" mode="R" name="spi_conf_output"/> + <register address="0x20" offset="0" size="32" default="0" rwmask="0" mode="RW" name="spi_clk_speed"/> + <register address="0x30" offset="0" size="32" default="0" rwmask="0" mode="R" name="firmware_info"> + <field offset="0" size="8" mode="R" name="firmware_version"/> + <field offset="8" size="1" mode="R" name="firmware_bitmode"/> + <field offset="12" size="2" mode="R" name="adc_resolution"/> + <field offset="16" size="2" mode="R" name="output_mode"/> + </register> + <register address="0x40" offset="0" size="32" default="0" rwmask="0" mode="RW" name="control"> + <field offset="31" size="1" mode="R" name="freq"/> + </register> + <register address="0x50" offset="0" size="32" default="0" rwmask="0" mode="R" name="status"/> + <register address="0x54" offset="0" size="32" default="0" rwmask="0" mode="R" name="status2"/> + <register address="0x58" offset="0" size="32" default="0" rwmask="0" mode="R" name="status3"/> + <register address="0x5c" offset="0" size="32" default="0" rwmask="0" mode="R" name="fr_status"/> + <register address="0x70" offset="0" size="32" default="0" rwmask="0" mode="R" name="start_address"/> + <register address="0x74" offset="0" size="32" default="0" rwmask="0" mode="R" name="end_address"/> + <register address="0x78" offset="0" size="32" default="0" rwmask="0" mode="R" name="rd_address"/> + <register address="0xa0" offset="0" size="32" default="0" rwmask="0" mode="R" name="fr_param1"> + <field offset="0" size="10" mode="RW" name="fr_skip_lines"/> + <field offset="10" size="11" mode="RW" name="fr_num_lines"/> + <field offset="21" size="11" mode="RW" name="fr_start_address"/> + </register> + <register address="0xb0" offset="0" size="32" default="0" rwmask="all" mode="RW" name="fr_param2"> + <field offset="0" size="11" mode="RW" name="fr_threshold_start_line"/> + <field offset="16" size="10" mode="RW" name="fr_area_lines"/> + </register> + <register address="0xc0" offset="0" size="32" default="0" rwmask="0" mode="R" name="skiped_lines"/> + <register address="0xd0" offset="0" size="32" default="0" rwmask="all" mode="RW" name="fr_thresholds"/> + <register address="0xd0" offset="0" size="10" default="0" rwmask="all" mode="RW" name="fr_pixel_thr"/> + <register address="0xd0" offset="10" size="11" default="0" rwmask="all" mode="RW" name="fr_num_pixel_thr"/> + <register address="0xd0" offset="21" size="11" default="0" rwmask="all" mode="RW" name="fr_num_lines_thr"/> + <register address="0x100" offset="0" size="32" default="0" rwmask="0" mode="RW" name="rawdata_pkt_addr"/> + <register address="0x110" offset="0" size="32" default="0" rwmask="0" mode="R" name="temperature_info"> + <field offset="0" size="16" mode="R" name="sensor_temperature"><view view="formuu1"/><view view="formuu2"/><view view="enumm2"/></field> + <field offset="16" size="3" mode="R" name="sensor_temperature_alarms"/> + <field offset="19" size="10" mode="RW" name="fpga_temperature"><view view="formuu1"/><view view="enumm1"/></field> + <field offset="29" size="3" mode="R" name="fpga_temperature_alarms"/> + </register> + <register address="0x120" offset="0" size="32" default="0" rwmask="0" mode="R" name="num_lines"/> + <register address="0x130" offset="0" size="32" default="0" rwmask="0" mode="R" name="start_line"/> + <register address="0x140" offset="0" size="32" default="0" rwmask="0" mode="R" name="exp_time"/> + <register address="0x150" offset="0" size="32" default="0" rwmask="0" mode="RW" name="motor"> + <field offset="0" size="5" mode="RW" name="motor_phi"/> + <field offset="5" size="5" mode="RW" name="motor_z"/> + <field offset="10" size="5" mode="RW" name="motor_y"/> + <field offset="15" size="5" mode="RW" name="motor_x"/> + <field offset="20" size="8" mode="R" name="adc_gain"/> + </register> + <register address="0x160" offset="0" size="32" default="0" rwmask="0" mode="R" name="write_status"/> + <register address="0x170" offset="0" size="32" default="0" rwmask="0" mode="RW" name="num_triggers"/> + <register address="0x180" offset="0" size="32" default="0x280" rwmask="0" mode="RW" name="trigger_period"><view view="enumm2"/></register> + <register address="0x190" offset="0" size="32" default="0" rwmask="0" mode="R" name="temperature_sample_period"/> + <register address="0x1a0" offset="0" size="32" default="0x64" rwmask="0" mode="RW" name="ddr_max_frames"/> + <register address="0x1b0" offset="0" size="32" default="0" rwmask="0" mode="R" name="ddr_num_frames"/> + </bank> + <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x0" write_address="0x0" word_size="32" endianess="little" format="0x%lx" name="dma" description="DMA Registers"/> + <transform name="formuu1" unit="C" read_from_register="(503975./1024000)*$value - 27315./100" write_to_register="($value + 27315./100)*(102400./503975)" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/> + <transform name="formuu2" unit="C" read_from_register="((1./4)*($value - 1200)) if $freq==0 else ((3./10)*($value - 1000))" write_to_register="4*$value + 1200 if $freq==0 else (10./3)*$value + 1000" description="formula to get real sensor temperature from the sensor_temperature register in decimal"/> + <transform name="formuu3" unit="us" read_from_register="($value+(43./100))*129./(40*1000000)if $freq==0 else ($value+(43./100))*129./(48*1000000)" write_to_register="$value/129.*(40*1000000) - 43./100 if $freq==0 else $value/129.*(48*1000000) - 43./100" description="formula to get real exposure time from the cmosis_exp_time register in decimal"/> + <enum name="enumm1" description="enum towards temperatures register"> + <name name="high" value="0x100" min="0x2" max="0x300"/> + <name name="low" value="0x010"/> + </enum> + <enum name="enumm2" description="enum towards sensor_temperature register"> + <name name="high" value="0x120"/> + <name name="low" value="0x010" min="0x00" max="0x020"/> + </enum> + <enum name="enumm3" description="enum towards cmosis_exp_register register"> + <name name="short" value="0x000"/> + <name name="mid" value="0x010"/> + <name name="long" value="0x100" min="0x0F0"/> + </enum> + <unit name="C"> + <transform unit="K" transform="$value+273.15"/> + <transform unit="F" transform="$value*(9./5)+32"/> + </unit> + <unit name="K"> + <transform unit="C" transform="$value-273.15"/> + <transform unit="F" transform="($value-273.15)*(9./5)+32"/> + </unit> + <unit name="F"> + <transform unit="C" transform="($value-32)*5./9"/> + <transform unit="K" transform="($value+273.15-32)*5./9"/> + </unit> + <unit name="s"> + <transform unit="ms" transform="$value*1000"/> + <transform unit="us" transform="$value*1000000"/> + <transform unit="ns" transform="$value*1000000000"/> + </unit> + <unit name="ms"> + <transform unit="s" transform="$value/1000"/> + <transform unit="us" transform="$value*1000"/> + <transform unit="ns" transform="$value*1000000"/> + </unit> + <unit name="us"> + <transform unit="s" transform="$value/1000000"/> + <transform unit="ms" transform="$value/1000"/> + <transform unit="ns" transform="$value*1000"/> + </unit> + <unit name="ns"> + <transform unit="s" transform="$value/1000000000"/> + <transform unit="ms" transform="$value/1000000"/> + <transform unit="us" transform="$value/1000"/> + </unit> </model> diff --git a/xml/types.xsd b/xml/types.xsd new file mode 100644 index 0000000..6edb35e --- /dev/null +++ b/xml/types.xsd @@ -0,0 +1,208 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> + + <xsd:complexType name="pcilib_bank_t"> + <xsd:choice minOccurs="0" maxOccurs="unbounded"> + <xsd:element name="register" type="pcilib_register_t" minOccurs="0" maxOccurs="unbounded" /> + </xsd:choice> + <xsd:attribute name="protocol" type="xsd:string" default="default" /> + <xsd:attribute name="bar" type="pcilib_bar_t" /> + <xsd:attribute name="address" type="uintptr_t" /> + <xsd:attribute name="read_address" type="uintptr_t" /> + <xsd:attribute name="write_address" type="uintptr_t" /> + <xsd:attribute name="size" type="size_t" default="4096" /> + <xsd:attribute name="word_size" type="uint8_t" default="32" /> + <xsd:attribute name="endianess" type="pcilib_endianess_t" default="host" /> + <xsd:attribute name="format" type="xsd:string" default="0x%lx" /> + <xsd:attribute name="name" type="xsd:ID" use="required" /> + <xsd:attribute name="description" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_register_t"> + <xsd:sequence> + <xsd:element name="view" type="pcilib_view_reference_t" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="field" type="pcilib_register_field_t" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="address" type="uint64_t" use="required" /> + <xsd:attribute name="offset" type="uint8_t" default="0" /> + <xsd:attribute name="size" type="uint8_t" default="32" /> + <xsd:attribute name="default" type="pcilib_register_value_t" default="0" /> + <xsd:attribute name="min" type="pcilib_register_value_t" /> + <xsd:attribute name="max" type="pcilib_register_value_t"/> + <xsd:attribute name="rwmask" type="pcilib_rwmask_t" default="all" /> + <xsd:attribute name="mode" type="pcilib_register_mode_t" default="R" /> + <xsd:attribute name="name" type="xsd:ID" use="required"/> + <xsd:attribute name="description" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_register_field_t"> + <xsd:sequence> + <xsd:element name="view" type="pcilib_view_reference_t" minOccurs="0" maxOccurs="unbounded" /> + </xsd:sequence> + <xsd:attribute name="offset" type="uint8_t"/> + <xsd:attribute name="size" type="uint8_t"/> + <xsd:attribute name="mode" type="pcilib_register_mode_t"/> + <xsd:attribute name="name" type="xsd:ID" use="required" /> + <xsd:attribute name="description" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_view_reference_t"> + <xsd:attribute name="view" type="xsd:string" use="required" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_view_t"> + <xsd:attribute name="name" type="xsd:ID" use="required" /> + <xsd:attribute name="unit" type="xsd:string" /> + <xsd:attribute name="type" type="pcilib_data_type_t" /> + <xsd:attribute name="visible" type="bool_t" default="0" /> + <xsd:attribute name="description" type="xsd:string" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_transform_view_t"> + <xsd:complexContent> + <xsd:extension base="pcilib_view_t"> + <xsd:attribute name="read_from_register" type="xsd:string" /> + <xsd:attribute name="write_to_register" type="xsd:string" /> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="pcilib_enum_view_t"> + <xsd:complexContent> + <xsd:extension base="pcilib_view_t"> + <xsd:choice minOccurs="1" maxOccurs="unbounded"> + <xsd:element name="name" type="pcilib_value_name_t" minOccurs="1" maxOccurs="unbounded" /> + </xsd:choice> + </xsd:extension> + </xsd:complexContent> + </xsd:complexType> + + <xsd:complexType name="pcilib_value_name_t"> + <xsd:attribute name="value" type="pcilib_register_value_t" use="required" /> + <xsd:attribute name="min" type="pcilib_register_value_t" /> + <xsd:attribute name="max" type="pcilib_register_value_t" /> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + + <xsd:complexType name="pcilib_unit_t"> + <xsd:sequence> + <xsd:element name="transform" type="pcilib_unit_transform_t" minOccurs="0" maxOccurs="unbounded"/> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:ID" use="required"/> + <xsd:attribute name="title" type="xsd:string"/> + </xsd:complexType> + + <xsd:complexType name="pcilib_unit_transform_t"> + <xsd:attribute name="transform" type="xsd:string" use="required" /> + <xsd:attribute name="unit" type="xsd:string" use="required"/> + </xsd:complexType> + + <xsd:simpleType name="bool_t"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="1"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="dec8_t"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="255"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="hex8_t"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0x([a-fA-F0-9]){1,2}"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="uint8_t"> + <xsd:union memberTypes="dec8_t hex8_t"/> + </xsd:simpleType> + <xsd:simpleType name="dec32_t"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="4294967295"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="hex32_t"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0x([a-fA-F0-9]){1,8}"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="uint32_t"> + <xsd:union memberTypes="dec32_t hex32_t"/> + </xsd:simpleType> + <xsd:simpleType name="dec64_t"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="18446744073709551615"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="hex64_t"> + <xsd:restriction base="xsd:string"> + <xsd:pattern value="0x([a-fA-F0-9]){1,16}"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="uint64_t"> + <xsd:union memberTypes="dec64_t hex64_t"/> + </xsd:simpleType> + <xsd:simpleType name="size_t"> + <xsd:restriction base="uint64_t"/> + </xsd:simpleType> + <xsd:simpleType name="uintptr_t"> + <xsd:restriction base="hex64_t"/> + </xsd:simpleType> + + <xsd:simpleType name="pcilib_register_value_t"> + <xsd:restriction base="uint32_t"/> + </xsd:simpleType> + <xsd:simpleType name="pcilib_bar_t"> + <xsd:restriction base="xsd:integer"> + <xsd:minInclusive value="0"/> + <xsd:maxInclusive value="5"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_bank_address_t"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="0"/> + <xsd:enumeration value="1"/> + <xsd:enumeration value="2"/> + <xsd:enumeration value="3"/> + <xsd:enumeration value="dma0"/> + <xsd:enumeration value="dma1"/> + <xsd:enumeration value="dma2"/> + <xsd:enumeration value="dma3"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_register_mode_t"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="R"/> + <xsd:enumeration value="W"/> + <xsd:enumeration value="RW"/> + <xsd:enumeration value="W1C"/> + <xsd:enumeration value="RW1C"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_data_type_t"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="string"/> + <xsd:enumeration value="float"/> + <xsd:enumeration value="int"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_endianess_t"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="little"/> + <xsd:enumeration value="big"/> + <xsd:enumeration value="host"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_rwmask_keywords_t"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="all"/> + </xsd:restriction> + </xsd:simpleType> + <xsd:simpleType name="pcilib_rwmask_t"> + <xsd:union memberTypes="pcilib_rwmask_keywords_t pcilib_register_value_t"/> + </xsd:simpleType> +</xsd:schema> |