diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2015-10-18 03:47:47 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2015-10-18 03:47:47 +0200 |
commit | c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd (patch) | |
tree | 53971a137e5d0e32ad7219f1d2fd01559c0a6ff3 /pcilib | |
parent | 2e9457b666a303fab83aa17e33624f39de9a1dd7 (diff) | |
download | pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.gz pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.bz2 pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.xz pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.zip |
Support properties of arbitrary type
Diffstat (limited to 'pcilib')
-rw-r--r-- | pcilib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | pcilib/bank.c | 35 | ||||
-rw-r--r-- | pcilib/bank.h | 54 | ||||
-rw-r--r-- | pcilib/error.h | 1 | ||||
-rw-r--r-- | pcilib/pci.c | 8 | ||||
-rw-r--r-- | pcilib/pci.h | 10 | ||||
-rw-r--r-- | pcilib/pcilib.h | 65 | ||||
-rw-r--r-- | pcilib/property.c | 207 | ||||
-rw-r--r-- | pcilib/property.h | 30 | ||||
-rw-r--r-- | pcilib/register.c | 67 | ||||
-rw-r--r-- | pcilib/register.h | 34 | ||||
-rw-r--r-- | pcilib/unit.c | 41 | ||||
-rw-r--r-- | pcilib/unit.h | 39 | ||||
-rw-r--r-- | pcilib/value.c | 1 | ||||
-rw-r--r-- | pcilib/view.c | 100 | ||||
-rw-r--r-- | pcilib/view.h | 36 | ||||
-rw-r--r-- | pcilib/xml.c | 7 |
17 files changed, 612 insertions, 127 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index 3fc789e..5d84ddc 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -8,8 +8,8 @@ include_directories( ${UTHASH_INCLUDE_DIRS} ) -set(HEADERS pcilib.h pci.h export.h value.h bar.h fifo.h model.h bank.h register.h view.h unit.h xml.h py.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 value.c bar.c fifo.c model.c bank.c register.c view.c unit.c xml.c py.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c ) +set(HEADERS pcilib.h pci.h export.h value.h bar.h fifo.h model.h bank.h register.h view.h property.h unit.h xml.h py.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 value.c bar.c fifo.c model.c bank.c register.c view.c unit.c property.c xml.c py.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) diff --git a/pcilib/bank.c b/pcilib/bank.c index 24ddf1f..ec38c82 100644 --- a/pcilib/bank.c +++ b/pcilib/bank.c @@ -19,6 +19,7 @@ int pcilib_init_register_banks(pcilib_t *ctx) { int err; + size_t start = ctx->num_banks_init; err = pcilib_map_register_space(ctx); if (err) return err; @@ -33,6 +34,7 @@ int pcilib_init_register_banks(pcilib_t *ctx) { const char *name = ctx->banks[ctx->num_banks_init].name; if (!name) name = "unnamed"; pcilib_error("Invalid register protocol address (%u) is specified for bank %i (%s)", ctx->banks[ctx->num_banks_init].protocol, ctx->banks[ctx->num_banks_init].addr, name); + pcilib_free_register_banks(ctx, start); return PCILIB_ERROR_INVALID_BANK; } @@ -46,8 +48,10 @@ int pcilib_init_register_banks(pcilib_t *ctx) { } else bank_ctx = (pcilib_register_bank_context_t*)malloc(sizeof(pcilib_register_bank_context_t)); - if (!bank_ctx) + if (!bank_ctx) { + pcilib_free_register_banks(ctx, start); return PCILIB_ERROR_FAILED; + } bank_ctx->bank = ctx->banks + ctx->num_banks_init; bank_ctx->api = bapi; @@ -58,10 +62,10 @@ int pcilib_init_register_banks(pcilib_t *ctx) { return 0; } -void pcilib_free_register_banks(pcilib_t *ctx) { +void pcilib_free_register_banks(pcilib_t *ctx, pcilib_register_bank_t start) { size_t i; - for (i = 0; i < ctx->num_banks_init; i++) { + for (i = start; i < ctx->num_banks_init; i++) { const pcilib_register_protocol_api_description_t *bapi = ctx->bank_ctx[i]->api; if (ctx->bank_ctx[i]) { @@ -74,14 +78,16 @@ void pcilib_free_register_banks(pcilib_t *ctx) { } } - ctx->num_banks_init = 0; + ctx->num_banks_init = start; } int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_bank_description_t *banks, pcilib_register_bank_t *ids) { + int err; size_t i; pcilib_register_bank_t bank; size_t dyn_banks = ctx->dyn_banks; size_t num_banks = ctx->num_banks; + size_t cur_banks = num_banks; if (!n) { for (n = 0; banks[n].access; n++); @@ -90,11 +96,6 @@ int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t f if ((ctx->num_banks + n + 1) > PCILIB_MAX_REGISTER_BANKS) return PCILIB_ERROR_TOOBIG; -/* - memcpy(ctx->banks + ctx->num_banks, banks, n * sizeof(pcilib_register_bank_description_t)); - ctx->num_banks += n; -*/ - for (i = 0; i < n; i++) { // Try to find if the bank is already existing... bank = pcilib_find_register_bank_by_name(ctx, banks[i].name); @@ -111,6 +112,7 @@ int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t f pcilib_error("The bank %s is already existing and override flag is not set", banks[i].name); else pcilib_error("The bank with address 0x%lx is already existing and override flag is not set", banks[i].addr); + memset(ctx->banks + ctx->num_banks, 0, sizeof(pcilib_register_bank_description_t)); return PCILIB_ERROR_EXIST; } @@ -122,17 +124,22 @@ int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t f dyn_banks++; } } - + ctx->num_banks = num_banks; - ctx->dyn_banks = dyn_banks; // If banks are already initialized, we need to re-run the initialization code - // DS: Locking is currently missing if (ctx->reg_bar_mapped) { ctx->reg_bar_mapped = 0; - return pcilib_init_register_banks(ctx); + err = pcilib_init_register_banks(ctx); + if (err) { + ctx->num_banks = cur_banks; + memset(ctx->banks + ctx->num_banks, 0, sizeof(pcilib_register_bank_description_t)); + return err; + } } - + + ctx->dyn_banks = dyn_banks; + return 0; } diff --git a/pcilib/bank.h b/pcilib/bank.h index 602fa67..39dd79c 100644 --- a/pcilib/bank.h +++ b/pcilib/bank.h @@ -96,14 +96,64 @@ struct pcilib_register_bank_context_s { extern "C" { #endif - // we don't copy strings, they should be statically allocated +/** + * Initalizes context of register banks. This is an internal function and will + * be called automatically when new register banks are added. On error no new + * banks are initalized + * @param[in,out] ctx - pcilib context + * @return - error or 0 on success + */ int pcilib_init_register_banks(pcilib_t *ctx); -void pcilib_free_register_banks(pcilib_t *ctx); +/** + * Destroys contexts of register banks. This is an internal function and will + * be called during clean-up. + * @param[in,out] ctx - pcilib context + * @param[in] start - specifies first bank to clean (used to clean only part of the banks to keep the defined state if pcilib_init_register_banks has failed) + */ +void pcilib_free_register_banks(pcilib_t *ctx, pcilib_register_bank_t start); + + +/** + * Use this function to add new register banks into the model or override configuration + * of the existing banks. The function will copy the context of banks structure, but name, + * description, and other strings in the structure are considered to have static duration + * and will not be copied. On error no new banks are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] flags - instructs if existing banks should be reported as error (default), overriden or ignored + * @param[in] n - number of banks to initialize. It is OK to pass 0 if banks variable is NULL terminated (last member of banks array have all members set to 0) + * @param[in] banks - bank descriptions + * @param[out] ids - if specified will contain the ids of the newly registered and overriden banks + * @return - error or 0 on success + */ int pcilib_add_register_banks(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_bank_description_t *banks, pcilib_register_bank_t *ids); + +/** + * Use this function to add new register protocols into the model. It is error to re-register + * already registered protocols. The function will copy the context of banks structure, but name, + * description, and other strings in the structure are considered to have static duration + * and will not be copied. On error no new protocols are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] flags - not used + * @param[in] n - number of protocols to initialize. It is OK to pass 0 if protocols variable is NULL terminated (last member of protocols array have all members set to 0) + * @param[in] protocols - protocol descriptions + * @param[out] ids - if specified will contain the ids of the newly registered protocols + * @return - error or 0 on success + */ int pcilib_add_register_protocols(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_protocol_description_t *protocols, pcilib_register_protocol_t *ids); + +/** + * Use this function to add new register ranges into the model. It is error register + * overlapping registered ranges. On error no new ranges are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] flags - not used + * @param[in] n - number of protocols to initialize. It is OK to pass 0 if protocols variable is NULL terminated. + * @param[in] ranges - range descriptions + * @return - error or 0 on success + */ int pcilib_add_register_ranges(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_range_t *ranges); + pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank); pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname); pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank); diff --git a/pcilib/error.h b/pcilib/error.h index 4ac0967..a9f4c0b 100644 --- a/pcilib/error.h +++ b/pcilib/error.h @@ -26,6 +26,7 @@ enum { PCILIB_ERROR_OUTOFRANGE = ERANGE, PCILIB_ERROR_NOTAVAILABLE = ENAVAIL, PCILIB_ERROR_NOTINITIALIZED = EBADFD, + PCILIB_ERROR_NOTPERMITED = EPERM, PCILIB_ERROR_TOOBIG = EFBIG, PCILIB_ERROR_OVERWRITTEN = ESTALE, PCILIB_ERROR_BUSY = EBUSY, diff --git a/pcilib/pci.c b/pcilib/pci.c index 4a0e79c..ae892a2 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -383,7 +383,7 @@ void pcilib_close(pcilib_t *ctx) { pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, ctx->dma_wlock[dma]); } - pcilib_free_register_banks(ctx); + pcilib_free_register_banks(ctx, 0); if (ctx->event_plugin) pcilib_plugin_close(ctx->event_plugin); @@ -414,16 +414,16 @@ void pcilib_close(pcilib_t *ctx) { if (ctx->units) { - pcilib_clean_units(ctx); + pcilib_clean_units(ctx, 0); free(ctx->units); } if (ctx->views) { - pcilib_clean_views(ctx); + pcilib_clean_views(ctx, 0); free(ctx->views); } - pcilib_clean_registers(ctx); + pcilib_clean_registers(ctx, 0); if (ctx->register_ctx) free(ctx->register_ctx); diff --git a/pcilib/pci.h b/pcilib/pci.h index caefe44..8f05ddf 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -40,16 +40,6 @@ typedef struct { } pcilib_pcie_link_info_t; -typedef struct { - const char *name; /**< Register name */ - pcilib_register_t reg; /**< Register index */ - 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) */ - UT_hash_handle hh; -} pcilib_register_context_t; - struct pcilib_s { int handle; /**< file handle of device */ diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h index 5c1ca70..e4fdf6d 100644 --- a/pcilib/pcilib.h +++ b/pcilib/pcilib.h @@ -41,6 +41,12 @@ typedef enum { } pcilib_endianess_t; typedef enum { + PCILIB_ACCESS_R = 1, /**< getting property is allowed */ + PCILIB_ACCESS_W = 2, /**< setting property is allowed */ + PCILIB_ACCESS_RW = 3 +} pcilib_access_mode_t; + +typedef enum { PCILIB_TYPE_INVALID = 0, /**< uninitialized */ PCILIB_TYPE_DEFAULT = 0, /**< default type */ PCILIB_TYPE_STRING = 1, /**< char* */ @@ -74,14 +80,14 @@ typedef enum { } pcilib_dma_flags_t; typedef enum { - PCILIB_STREAMING_STOP = 0, /**< stop streaming */ - PCILIB_STREAMING_CONTINUE = 1, /**< wait the default DMA timeout for a new data */ - PCILIB_STREAMING_WAIT = 2, /**< wait the specified timeout for a new data */ - PCILIB_STREAMING_CHECK = 3, /**< do not wait for the data, bail out imideatly if no data ready */ - PCILIB_STREAMING_FAIL = 4, /**< fail if data is not available on timeout */ - PCILIB_STREAMING_REQ_FRAGMENT = 5, /**< only fragment of a packet is read, wait for next fragment and fail if no data during DMA timeout */ - PCILIB_STREAMING_REQ_PACKET = 6, /**< wait for next packet and fail if no data during the specified timeout */ - PCILIB_STREAMING_TIMEOUT_MASK = 3 /**< mask specifying all timeout modes */ + PCILIB_STREAMING_STOP = 0, /**< stop streaming */ + PCILIB_STREAMING_CONTINUE = 1, /**< wait the default DMA timeout for a new data */ + PCILIB_STREAMING_WAIT = 2, /**< wait the specified timeout for a new data */ + PCILIB_STREAMING_CHECK = 3, /**< do not wait for the data, bail out imideatly if no data ready */ + PCILIB_STREAMING_FAIL = 4, /**< fail if data is not available on timeout */ + PCILIB_STREAMING_REQ_FRAGMENT = 5, /**< only fragment of a packet is read, wait for next fragment and fail if no data during DMA timeout */ + PCILIB_STREAMING_REQ_PACKET = 6, /**< wait for next packet and fail if no data during the specified timeout */ + PCILIB_STREAMING_TIMEOUT_MASK = 3 /**< mask specifying all timeout modes */ } pcilib_streaming_action_t; typedef enum { @@ -104,23 +110,38 @@ typedef struct { pcilib_event_info_flags_t flags; /**< flags */ } pcilib_event_info_t; +typedef enum { + PCILIB_LIST_FLAGS_DEFAULT = 0, + PCILIB_LIST_FLAG_CHILDS = 1 /**< Request all sub-elements or indicated that sub-elements are available */ +} pcilib_list_flags_t; + typedef struct { - pcilib_value_type_t type; - const char *unit; - const char *format; + pcilib_value_type_t type; /**< Current data type */ + const char *unit; /**< Units (if known) */ + const char *format; /**< requested printf format (may enforce using output in hex form) */ union { - long ival; - double fval; - const char *sval; + long ival; /**< The value if type = PCILIB_TYPE_LONG */ + double fval; /**< The value if type = PCILIB_TYPE_DOUBLE */ + const char *sval; /**< The value if type = PCILIB_TYPE_STRING, the pointer may point to static location or reference actual string in str or data */ }; // This is a private part - size_t size; - void *data; - char str[16]; + size_t size; /**< Size of the data */ + void *data; /**< Arbitrary data, for instance actual string referenced by the sval */ + char str[16]; /**< Used for shorter strings converted from integer/float types */ } pcilib_value_t; +typedef struct { + const char *name; /**< Name of the property view */ + const char *path; /**< Full path to the property */ + const char *description; /**< Short description */ + pcilib_value_type_t type; /**< The default data type or PCILIB_TYPE_INVALID if directory */ + pcilib_access_mode_t mode; /**< Specifies if the view is read/write-only */ + pcilib_list_flags_t flags; /**< Indicates if have sub-folders, etc. */ + const char *unit; /**< Returned unit (if any) */ +} pcilib_property_info_t; + #define PCILIB_BAR_DETECT ((pcilib_bar_t)-1) #define PCILIB_BAR_INVALID ((pcilib_bar_t)-1) @@ -218,6 +239,8 @@ int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_regi int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value); 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_value_t *value); +int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, const pcilib_value_t *value); void pcilib_clean_value(pcilib_t *ctx, pcilib_value_t *val); int pcilib_copy_value(pcilib_t *ctx, pcilib_value_t *dst, const pcilib_value_t *src); @@ -228,12 +251,14 @@ int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *value, co double pcilib_get_value_as_float(pcilib_t *ctx, const pcilib_value_t *val, int *err); long pcilib_get_value_as_int(pcilib_t *ctx, const pcilib_value_t *val, int *err); pcilib_register_value_t pcilib_get_value_as_register_value(pcilib_t *ctx, const pcilib_value_t *val, int *err); - int pcilib_convert_value_unit(pcilib_t *ctx, pcilib_value_t *val, const char *unit_name); int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_type_t type); -int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_value_t *value); -int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, const pcilib_value_t *value); +pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *branch, pcilib_list_flags_t flags); +void pcilib_free_property_info(pcilib_t *ctx, pcilib_property_info_t *info); +int pcilib_get_property(pcilib_t *ctx, const char *prop, pcilib_value_t *val); +int pcilib_set_property(pcilib_t *ctx, const char *prop, const pcilib_value_t *val); + 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/property.c b/pcilib/property.c new file mode 100644 index 0000000..23c92d1 --- /dev/null +++ b/pcilib/property.c @@ -0,0 +1,207 @@ +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> + +#include <views/register.h> + +#include "pci.h" +#include "bank.h" +#include "view.h" +#include "register.h" +#include "property.h" + +#include "tools.h" +#include "error.h" + +int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers) { + int err; + + pcilib_register_t i; + pcilib_view_t cur_view = ctx->num_views; + pcilib_view_context_t *view_ctx; + + if (!n) + return PCILIB_ERROR_INVALID_ARGUMENT; + + + for (i = 0; i < n; i++) { + pcilib_access_mode_t mode = 0; + + pcilib_register_view_description_t v; + pcilib_register_bank_description_t *b = &ctx->banks[banks[i]]; + + char *view_name = malloc(strlen(registers[i].name) + strlen(b->name) + 13); + if (!view_name) { + pcilib_clean_views(ctx, cur_view); + return PCILIB_ERROR_MEMORY; + } + + sprintf(view_name, "/registers/%s/%s", b->name, registers[i].name); + + if ((registers[i].views)&&(registers[i].views[0].view)) { + pcilib_view_t view = pcilib_find_view_by_name(ctx, registers[i].views[0].view); + if (view == PCILIB_VIEW_INVALID) return PCILIB_ERROR_NOTFOUND; + + memcpy(&v, ctx->views[view], sizeof(pcilib_view_description_t)); + v.view = registers[i].views[0].name; + + if (ctx->views[view]->api->read_from_reg) mode |= PCILIB_ACCESS_R; + if (ctx->views[view]->api->write_to_reg) mode |= PCILIB_ACCESS_W; + mode &= ctx->views[view]->mode; + } else { + v.base.type = PCILIB_TYPE_LONG; + mode = PCILIB_ACCESS_RW; + } + + v.base.api = &pcilib_register_view_api; + v.base.name = view_name; + v.base.description = registers[i].description; + v.base.mode = registers[i].mode&mode; + v.reg = registers[i].name; + v.bank = b->name; + + err = pcilib_add_views(ctx, 1, (pcilib_view_description_t*)&v); + if (err) { + free(view_name); + pcilib_clean_views(ctx, cur_view); + return err; + } + + view_ctx = pcilib_find_view_context_by_name(ctx, v.base.name); + view_ctx->flags |= PCILIB_VIEW_FLAG_PROPERTY; + } + + return 0; +} + +pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *branch, pcilib_list_flags_t flags) { + int err = 0; + + size_t pos = 0; + size_t name_offset = 0; + pcilib_view_context_t *view_ctx, *view_tmp; + pcilib_property_info_t *info = (pcilib_property_info_t*)malloc((ctx->num_views + 1) * sizeof(pcilib_property_info_t)); + + struct dir_hash_s { + char *name; + UT_hash_handle hh; + } *dir_hash = NULL, *dir, *dir_tmp; + + if (branch) { + name_offset = strlen(branch); + if (branch[name_offset - 1] != '/') name_offset++; + } + + // Find all folders + HASH_ITER(hh, ctx->view_hash, view_ctx, view_tmp) { + const pcilib_view_description_t *v = ctx->views[view_ctx->view]; + const char *subname = v->name + name_offset; + const char *suffix; + + if (!(view_ctx->flags&PCILIB_VIEW_FLAG_PROPERTY)) continue; + if ((branch)&&(strncasecmp(branch, v->name, strlen(branch)))) continue; + + suffix = strchr(subname, '/'); + if (suffix) { + char *name = strndup(v->name, suffix - v->name); + if (!name) { + err = PCILIB_ERROR_MEMORY; + break; + } + + HASH_FIND_STR(dir_hash, name + name_offset, dir); + if (dir) { + free(name); + continue; + } + + + dir = (struct dir_hash_s*)malloc(sizeof(struct dir_hash_s)); + if (!dir) { + err = PCILIB_ERROR_MEMORY; + break; + } + + dir->name = name; + + HASH_ADD_KEYPTR(hh, dir_hash, dir->name + name_offset, strlen(dir->name + name_offset), dir); + } + } + + HASH_ITER(hh, ctx->view_hash, view_ctx, view_tmp) { + const pcilib_view_description_t *v = ctx->views[view_ctx->view]; + const char *subname = v->name + name_offset; + + if (!(view_ctx->flags&PCILIB_VIEW_FLAG_PROPERTY)) continue; + if ((branch)&&(strncasecmp(branch, v->name, strlen(branch)))) continue; + + if (!strchr(subname, '/')) { + pcilib_view_context_t *found_view; + + char *path = strdup(v->name); + if (!path) { + err = PCILIB_ERROR_MEMORY; + break; + } + char *name = strrchr(v->name, '/'); + if (name) name++; + else name = path; + + HASH_FIND_STR(dir_hash, name, found_view); + + info[pos++] = (pcilib_property_info_t) { + .name = name, + .path = path, + .description = v->description, + .type = v->type, + .mode = v->mode, + .unit = v->unit, + .flags = (found_view?PCILIB_LIST_FLAG_CHILDS:0) + }; + + if (found_view) HASH_DEL(dir_hash, found_view); + } + } + + HASH_ITER(hh, dir_hash, dir, dir_tmp) { + char *name = strrchr(dir->name, '/'); + if (name) name++; + else name = dir->name; + + info[pos++] = (pcilib_property_info_t) { + .name = name, + .path = dir->name, + .type = PCILIB_TYPE_INVALID, + .flags = PCILIB_LIST_FLAG_CHILDS + }; + } + + HASH_CLEAR(hh, dir_hash); + + memset(&info[pos], 0, sizeof(pcilib_property_info_t)); + + if (err) { + pcilib_free_property_info(ctx, info); + return NULL; + } + + return info; +} + +void pcilib_free_property_info(pcilib_t *ctx, pcilib_property_info_t *info) { + int i; + + for (i = 0; info[i].path; i++) + free((char*)info[i].path); + free(info); +} + +int pcilib_get_property(pcilib_t *ctx, const char *prop, pcilib_value_t *val) { + return pcilib_read_register_view(ctx, NULL, NULL, prop, val); +} + +int pcilib_set_property(pcilib_t *ctx, const char *prop, const pcilib_value_t *val) { + return pcilib_write_register_view(ctx, NULL, NULL, prop, val); +} diff --git a/pcilib/property.h b/pcilib/property.h new file mode 100644 index 0000000..bec11c8 --- /dev/null +++ b/pcilib/property.h @@ -0,0 +1,30 @@ +#ifndef _PCILIB_PROPERTY_H +#define _PCILIB_PROPERTY_H + +#ifdef __cplusplus +extern "C" { +#endif +/** + * This is internal function used to add property view for all model registers. It is automatically + * called from pcilib_add_registers and should not be called by the users. On error no new views are + * initalized. + * @param[in,out] ctx - pcilib context + * @param[in] n - number of views to initialize. + * @param[in] banks - array containing a bank id for each of the considered registers + * @param[in] desc - register descriptions + * @return - error or 0 on success + */ +int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *desc); + +#ifdef __cplusplus +} +#endif + +#endif /* _PCILIB_PROPERTY_H */ + + + + + +// free'd by user. Do we need it? + diff --git a/pcilib/register.c b/pcilib/register.c index 3a60800..30505ae 100644 --- a/pcilib/register.c +++ b/pcilib/register.c @@ -11,22 +11,28 @@ #include <arpa/inet.h> #include <errno.h> #include <assert.h> +#include <alloca.h> #include "pci.h" #include "bank.h" #include "tools.h" #include "error.h" - +#include "property.h" int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_description_t *registers, pcilib_register_t *ids) { // DS: Overrride existing registers // Registers identified by addr + offset + size + type or name - + int err; + size_t size; pcilib_register_t i; + pcilib_register_description_t *regs; pcilib_register_context_t *reg_ctx; - size_t size; + + pcilib_register_bank_t bank = PCILIB_REGISTER_BANK_INVALID; + pcilib_register_bank_addr_t bank_addr = (pcilib_register_bank_addr_t)-1; + pcilib_register_bank_t *banks; if (!n) { for (n = 0; registers[n].bits; n++); @@ -59,13 +65,43 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, ctx->alloc_reg = size; } + banks = (pcilib_register_bank_t*)alloca(n * sizeof(pcilib_register_bank_t)); + if (!banks) return PCILIB_ERROR_MEMORY; + + for (i = 0; i < n; i++) { + if (registers[i].bank != bank_addr) { + bank_addr = registers[i].bank; + bank = pcilib_find_register_bank_by_addr(ctx, bank_addr); + if (bank == PCILIB_REGISTER_BANK_INVALID) { + pcilib_error("Invalid bank address (0x%lx) is specified for register %s", bank_addr, registers[i].name); + return PCILIB_ERROR_INVALID_BANK; + } + } + +/* + // No hash so far, will iterate. + pcilib_register_t reg = pcilib_find_register(ctx, ctx->banks[bank].name, registers[i].name); + if (reg != PCILIB_REGISTER_INVALID) { + pcilib_error("Register %s is already defined in the model", registers[i].name); + return PCILIB_ERROR_EXIST; + } +*/ + + banks[i] = bank; + } + + err = pcilib_add_register_properties(ctx, n, banks, registers); + if (err) return err; + for (i = 0; i < n; i++) { pcilib_register_context_t *cur = &ctx->register_ctx[ctx->num_reg + i]; + cur->reg = ctx->num_reg + i; cur->name = registers[i].name; + cur->bank = banks[i]; HASH_ADD_KEYPTR(hh, ctx->reg_hash, cur->name, strlen(cur->name), cur); } - + memcpy(ctx->registers + ctx->num_reg, registers, n * sizeof(pcilib_register_description_t)); memset(ctx->registers + ctx->num_reg + n, 0, sizeof(pcilib_register_description_t)); @@ -78,26 +114,35 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, ctx->num_reg += n; - return 0; } -void pcilib_clean_registers(pcilib_t *ctx) { +void pcilib_clean_registers(pcilib_t *ctx, pcilib_register_t start) { pcilib_register_t reg; + pcilib_register_context_t *reg_ctx, *tmp; + + if (start) { + HASH_ITER(hh, ctx->reg_hash, reg_ctx, tmp) { + if (reg_ctx->reg >= start) { + HASH_DEL(ctx->reg_hash, reg_ctx); + } + } + } else { + HASH_CLEAR(hh, ctx->reg_hash); + } - HASH_CLEAR(hh, ctx->reg_hash); - for (reg = 0; reg < ctx->num_reg; reg++) { + for (reg = start; reg < ctx->num_reg; reg++) { if (ctx->register_ctx[reg].views) free(ctx->register_ctx[reg].views); } if (ctx->registers) - memset(ctx->registers, 0, sizeof(pcilib_register_description_t)); + memset(&ctx->registers[start], 0, sizeof(pcilib_register_description_t)); if (ctx->register_ctx) - memset(ctx->register_ctx, 0, ctx->alloc_reg * sizeof(pcilib_register_context_t)); + memset(&ctx->register_ctx[start], 0, (ctx->alloc_reg - start) * sizeof(pcilib_register_context_t)); - ctx->num_reg = 0; + ctx->num_reg = start; } static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) { diff --git a/pcilib/register.h b/pcilib/register.h index 95f52cc..e2e8508 100644 --- a/pcilib/register.h +++ b/pcilib/register.h @@ -1,6 +1,8 @@ #ifndef _PCILIB_REGISTER_H #define _PCILIB_REGISTER_H +#include <uthash.h> + #include <pcilib.h> #include <pcilib/bank.h> @@ -49,13 +51,43 @@ typedef struct { pcilib_view_reference_t *views; /**< List of supported views for this register */ } pcilib_register_description_t; +typedef struct { + const char *name; /**< Register name */ + pcilib_register_t reg; /**< Register index */ + 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) */ + UT_hash_handle hh; +} pcilib_register_context_t; #ifdef __cplusplus extern "C" { #endif +/** + * Use this function to add new registers into the model. Currently, it is considered a error + * to re-add already defined register. If it will turn out to be useful to redefine some registers + * from the model, it may change in the future. However, we should think how to treat bit-registers + * in this case. The function will copy the context of registers structure, but name, + * description, and other strings in the structure are considered to have static duration + * and will not be copied. On error no new registers are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] flags - not used now, but in future may instruct if existing registers should be reported as error (default), overriden or ignored + * @param[in] n - number of registers to initialize. It is OK to pass 0 if registers array is NULL terminated (last member of the array have all members set to 0) + * @param[in] registers - register descriptions + * @param[out] ids - if specified will contain the ids of the newly registered and overriden registers + * @return - error or 0 on success + */ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags, size_t n, const pcilib_register_description_t *registers, pcilib_register_t *ids); -void pcilib_clean_registers(pcilib_t *ctx); + +/** + * Destroys data associated with registers. This is an internal function and will + * be called during clean-up. + * @param[in,out] ctx - pcilib context + * @param[in] start - specifies first register to clean (used to clean only part of the registers to keep the defined state if pcilib_add_registers has failed) + */ +void pcilib_clean_registers(pcilib_t *ctx, pcilib_register_t start); #ifdef __cplusplus } diff --git a/pcilib/unit.c b/pcilib/unit.c index 0295120..99ece99 100644 --- a/pcilib/unit.c +++ b/pcilib/unit.c @@ -35,11 +35,19 @@ int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *d // ToDo: Check if exists... for (i = 0; i < n; i++) { + pcilib_unit_t unit = pcilib_find_unit_by_name(ctx, desc[i].name); + if (unit != PCILIB_UNIT_INVALID) { + pcilib_clean_units(ctx, ctx->num_units); + pcilib_error("Unit %s is already defined in the model", desc[i].name); + return PCILIB_ERROR_EXIST; + } + pcilib_unit_context_t *unit_ctx = (pcilib_unit_context_t*)malloc(sizeof(pcilib_unit_context_t)); if (!unit_ctx) { - err = PCILIB_ERROR_MEMORY; - break; + pcilib_clean_units(ctx, ctx->num_units); + return PCILIB_ERROR_MEMORY; } + memset(unit_ctx, 0, sizeof(pcilib_unit_context_t)); unit_ctx->unit = ctx->num_units + i; unit_ctx->name = desc[i].name; @@ -48,24 +56,26 @@ int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *d memcpy(ctx->units + ctx->num_units + i, &desc[i], sizeof(pcilib_unit_description_t)); } - memset(ctx->units + ctx->num_units + i, 0, sizeof(pcilib_unit_description_t)); - ctx->num_units += i; + ctx->num_units += n; + memset(ctx->units + ctx->num_units, 0, sizeof(pcilib_unit_description_t)); return err; } -void pcilib_clean_units(pcilib_t *ctx) { +void pcilib_clean_units(pcilib_t *ctx, pcilib_unit_t start) { pcilib_unit_context_t *s, *tmp; if (ctx->unit_hash) { HASH_ITER(hh, ctx->unit_hash, s, tmp) { - HASH_DEL(ctx->unit_hash, s); - free(s); + if (s->unit >= start) { + HASH_DEL(ctx->unit_hash, s); + free(s); + } } } - memset(ctx->units, 0, sizeof(pcilib_unit_description_t)); - ctx->num_units = 0; + memset(&ctx->units[start], 0, sizeof(pcilib_unit_description_t)); + ctx->num_units = start; } pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *name) { @@ -105,13 +115,18 @@ pcilib_unit_transform_t *pcilib_find_transform_by_unit_names(pcilib_t *ctx, cons return NULL; } -int pcilib_transform_unit(pcilib_t *ctx, pcilib_unit_transform_t *trans, pcilib_value_t *value) { +int pcilib_transform_unit(pcilib_t *ctx, const pcilib_unit_transform_t *trans, pcilib_value_t *value) { int err; - err = pcilib_py_eval_string(ctx, trans->transform, value); - if (err) return err; + if (trans->transform) { + err = pcilib_py_eval_string(ctx, trans->transform, value); + if (err) return err; + + value->unit = trans->unit; + } else if (trans->unit) { + value->unit = trans->unit; + } - value->unit = trans->unit; return 0; } diff --git a/pcilib/unit.h b/pcilib/unit.h index 3e49174..2351f26 100644 --- a/pcilib/unit.h +++ b/pcilib/unit.h @@ -35,14 +35,47 @@ struct pcilib_unit_context_s { extern "C" { #endif +/** + * Use this function to add new unit definitions into the model. It is error to re-register + * already registered unit. The function will copy the context of unit description, but name, + * transform, and other strings in the structure are considered to have static duration + * and will not be copied. On error no new units are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] n - number of units to initialize. It is OK to pass 0 if protocols variable is NULL terminated (last member of protocols array have all members set to 0) + * @param[in] desc - unit descriptions + * @return - error or 0 on success + */ int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *desc); -void pcilib_clean_units(pcilib_t *ctx); + +/** + * Destroys data associated with units. This is an internal function and will + * be called during clean-up. + * @param[in,out] ctx - pcilib context + * @param[in] start - specifies first unit to clean (used to clean only part of the units to keep the defined state if pcilib_add_units has failed) + */ +void pcilib_clean_units(pcilib_t *ctx, pcilib_unit_t start); pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *unit); pcilib_unit_transform_t *pcilib_find_transform_by_unit_names(pcilib_t *ctx, const char *from, const char *to); - // value is modified -int pcilib_transform_unit(pcilib_t *ctx, pcilib_unit_transform_t *trans, pcilib_value_t *value); +/** + * Converts value to the requested units. It is error to convert values with unspecified units. + * This is internal function, use pcilib_value_convert_value_unit instead. + * @param[in,out] ctx - pcilib context + * @param[in] trans - the requested unit transform + * @param[in,out] value - the value to be converted (changed on success) + * @return - error or 0 on success + */ +int pcilib_transform_unit(pcilib_t *ctx, const pcilib_unit_transform_t *trans, pcilib_value_t *value); + +/** + * Converts value to the requested units. It is error to convert values with unspecified units. + * This is internal function, use pcilib_value_convert_value_unit instead. + * @param[in,out] ctx - pcilib context + * @param[in] name - specifies the requested unit of the value + * @param[in,out] value - the value to be converted (changed on success) + * @return - error or 0 on success + */ int pcilib_transform_unit_by_name(pcilib_t *ctx, const char *to, pcilib_value_t *value); diff --git a/pcilib/value.c b/pcilib/value.c index 42e7993..4264759 100644 --- a/pcilib/value.c +++ b/pcilib/value.c @@ -267,5 +267,6 @@ int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_t return PCILIB_ERROR_NOTSUPPORTED; } + val->type = type; return 0; } diff --git a/pcilib/view.c b/pcilib/view.c index f00e483..8df5fc4 100644 --- a/pcilib/view.c +++ b/pcilib/view.c @@ -11,7 +11,6 @@ #include "value.h" int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc) { - int err = 0; size_t i; void *ptr; @@ -44,55 +43,68 @@ int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *d ptr = (void*)desc; for (i = 0; i < n; i++) { const pcilib_view_description_t *v = (const pcilib_view_description_t*)ptr; + pcilib_view_description_t *cur; pcilib_view_context_t *view_ctx; - ctx->views[ctx->num_views + i] = (pcilib_view_description_t*)malloc(v->api->description_size); - if (!ctx->views[ctx->num_views + i]) { - err = PCILIB_ERROR_MEMORY; - break; + pcilib_view_t view = pcilib_find_view_by_name(ctx, v->name); + if (view != PCILIB_VIEW_INVALID) { + pcilib_clean_views(ctx, ctx->num_views); + pcilib_error("View %s is already defined in the model", v->name); + return PCILIB_ERROR_EXIST; + } + + cur = (pcilib_view_description_t*)malloc(v->api->description_size); + if (!cur) { + pcilib_clean_views(ctx, ctx->num_views); + return PCILIB_ERROR_MEMORY; } if (v->api->init) view_ctx = v->api->init(ctx); else { view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t)); - memset(view_ctx, 0, sizeof(pcilib_view_context_t)); + if (view_ctx) memset(view_ctx, 0, sizeof(pcilib_view_context_t)); } - view_ctx->view = ctx->num_views + i; - view_ctx->name = v->name; - if (!view_ctx) { - free(ctx->views[ctx->num_views + i]); - err = PCILIB_ERROR_MEMORY; - break; + free(cur); + pcilib_clean_views(ctx, ctx->num_views); + return PCILIB_ERROR_FAILED; } + memcpy(cur, v, v->api->description_size); + view_ctx->view = ctx->num_views + i; + view_ctx->name = v->name; + HASH_ADD_KEYPTR(hh, ctx->view_hash, view_ctx->name, strlen(view_ctx->name), view_ctx); - memcpy(ctx->views[ctx->num_views + i], v, v->api->description_size); + ctx->views[ctx->num_views + i] = cur; + ptr += v->api->description_size; } - ctx->views[ctx->num_views + i] = NULL; - ctx->num_views += i; - return err; + ctx->views[ctx->num_views + n] = NULL; + ctx->num_views += n; + + return 0; } -void pcilib_clean_views(pcilib_t *ctx) { +void pcilib_clean_views(pcilib_t *ctx, pcilib_view_t start) { pcilib_view_t i; pcilib_view_context_t *view_ctx, *tmp; - if (ctx->unit_hash) { + if (ctx->view_hash) { HASH_ITER(hh, ctx->view_hash, view_ctx, tmp) { const pcilib_view_description_t *v = ctx->views[view_ctx->view]; - HASH_DEL(ctx->view_hash, view_ctx); - if (v->api->free) v->api->free(ctx, view_ctx); - else free(view_ctx); + if (view_ctx->view >= start) { + HASH_DEL(ctx->view_hash, view_ctx); + if (v->api->free) v->api->free(ctx, view_ctx); + else free(view_ctx); + } } } - for (i = 0; ctx->views[i]; i++) { + for (i = start; ctx->views[i]; i++) { if (ctx->views[i]->api->free_description) { ctx->views[i]->api->free_description(ctx, ctx->views[i]); } else { @@ -100,8 +112,8 @@ void pcilib_clean_views(pcilib_t *ctx) { } } - ctx->views[0] = NULL; - ctx->num_views = 0; + ctx->views[start] = NULL; + ctx->num_views = start; } pcilib_view_context_t *pcilib_find_view_context_by_name(pcilib_t *ctx, const char *name) { @@ -117,8 +129,6 @@ pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *name) { return PCILIB_VIEW_INVALID; } - - pcilib_view_context_t *pcilib_find_register_view_context_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name) { pcilib_view_t i; pcilib_register_context_t *regctx = &ctx->register_ctx[reg]; @@ -191,7 +201,7 @@ typedef struct { pcilib_unit_transform_t *trans; } pcilib_view_configuration_t; -static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, const char *regname, const char *view_cname, int write_direction, pcilib_view_configuration_t *cfg) { +static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, const char *regname, const char *view_cname, const char *unit_cname, int write_direction, pcilib_view_configuration_t *cfg) { int err = 0; pcilib_view_t view; pcilib_view_context_t *view_ctx; @@ -199,17 +209,21 @@ static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, con pcilib_register_t reg = PCILIB_REGISTER_INVALID; char *view_name = alloca(strlen(view_cname) + 1); - char *unit_name; + const char *unit_name; strcpy(view_name, view_cname); - unit_name = strchr(view_name, ':'); - if (unit_name) { - *unit_name = 0; - unit_name++; + if (unit_cname) unit_name = unit_cname; + else { + unit_name = strchr(view_name, ':'); + if (unit_name) { + *(char*)unit_name = 0; + unit_name++; + } } + if (regname) { reg = pcilib_find_register(ctx, bank, regname); if (reg == PCILIB_REGISTER_INVALID) { @@ -244,7 +258,7 @@ static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, con } // No transform is required - if (!trans->transform) trans = NULL; + if ((trans)&&(!trans->transform)) trans = NULL; cfg->reg = reg; cfg->view = view_ctx; @@ -261,7 +275,7 @@ int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regna pcilib_view_configuration_t cfg; pcilib_register_value_t regvalue = 0; - err = pcilib_detect_view_configuration(ctx, bank, regname, view, 0, &cfg); + err = pcilib_detect_view_configuration(ctx, bank, regname, view, NULL, 0, &cfg); if (err) return err; v = ctx->views[cfg.view->view]; @@ -271,6 +285,11 @@ int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regna return PCILIB_ERROR_NOTSUPPORTED; } + if ((v->mode & PCILIB_REGISTER_R) == 0) { + pcilib_error("The view (%s) does not allow reading from the register", view); + return PCILIB_ERROR_NOTPERMITED; + } + if (regname) { err = pcilib_read_register_by_id(ctx, cfg.reg, ®value); if (err) { @@ -290,6 +309,10 @@ int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regna return err; } + if (v->unit) { + val->unit = v->unit; + } + if (cfg.trans) { err = pcilib_transform_unit(ctx, cfg.trans, val); if (err) return err; @@ -307,16 +330,21 @@ int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regn pcilib_view_configuration_t cfg; pcilib_register_value_t regvalue = 0; - err = pcilib_detect_view_configuration(ctx, bank, regname, view, 1, &cfg); + err = pcilib_detect_view_configuration(ctx, bank, regname, view, valarg->unit, 1, &cfg); if (err) return err; v = ctx->views[cfg.view->view]; if (!v->api->write_to_reg) { - pcilib_error("The view (%s) does not support reading from the register", view); + pcilib_error("The view (%s) does not support writting to the register", view); return PCILIB_ERROR_NOTSUPPORTED; } + if ((v->mode & PCILIB_REGISTER_W) == 0) { + pcilib_error("The view (%s) does not allow writting to the register", view); + return PCILIB_ERROR_NOTPERMITED; + } + err = pcilib_copy_value(ctx, &val, valarg); if (err) return err; diff --git a/pcilib/view.h b/pcilib/view.h index 9d3d32d..6287942 100644 --- a/pcilib/view.h +++ b/pcilib/view.h @@ -16,19 +16,19 @@ typedef enum { } pcilib_view_flags_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); - void (*free_description)(pcilib_t *ctx, pcilib_view_description_t *view); - int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t regval, pcilib_value_t *val); - int (*write_to_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, const pcilib_value_t *val); + pcilib_version_t version; /**< Version */ + size_t description_size; /**< The actual size of the description */ + pcilib_view_context_t *(*init)(pcilib_t *ctx); /**< Optional function which should allocated context used by read/write functions */ + void (*free)(pcilib_t *ctx, pcilib_view_context_t *view); /**< Optional function which should clean context */ + void (*free_description)(pcilib_t *ctx, pcilib_view_description_t *view); /**< Optional function which shoud clean required parts of the extended description if non-static memory was used to initialize it */ + int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t regval, pcilib_value_t *val); /**< Function which computes view value based on the passed the register value (view-based properties should not use register value) */ + int (*write_to_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, const pcilib_value_t *val); /**< Function which computes register value based on the passed value (view-based properties are not required to set the register value) */ } pcilib_view_api_description_t; struct pcilib_view_description_s { const pcilib_view_api_description_t *api; pcilib_value_type_t type; /**< The default data type returned by operation, PCILIB_VIEW_TYPE_STRING is supported by all operations */ - pcilib_view_flags_t flags; /**< Flags specifying type of the view */ + pcilib_access_mode_t mode; /**< Specifies if the view is read/write-only */ const char *unit; /**< Returned unit (if any) */ const char *name; /**< Name of the view */ const char *description; /**< Short description */ @@ -37,6 +37,7 @@ struct pcilib_view_description_s { struct pcilib_view_context_s { const char *name; pcilib_view_t view; + pcilib_view_flags_t flags; /**< Flags specifying type of the view */ UT_hash_handle hh; }; @@ -44,8 +45,25 @@ struct pcilib_view_context_s { extern "C" { #endif +/** + * Use this function to add new view definitions into the model. It is error to re-register + * already registered view. The function will copy the context of unit description, but name, + * transform, and other strings in the structure are considered to have static duration + * and will not be copied. On error no new views are initalized. + * @param[in,out] ctx - pcilib context + * @param[in] n - number of views to initialize. It is OK to pass 0 if protocols variable is NULL terminated (last member of protocols array have all members set to 0) + * @param[in] desc - view descriptions + * @return - error or 0 on success + */ int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc); -void pcilib_clean_views(pcilib_t *ctx); + +/** + * Destroys data associated with views. This is an internal function and will + * be called during clean-up. + * @param[in,out] ctx - pcilib context + * @param[in] start - specifies first view to clean (used to clean only part of the views to keep the defined state if pcilib_add_views has failed) + */ +void pcilib_clean_views(pcilib_t *ctx, pcilib_view_t start); pcilib_view_context_t *pcilib_find_view_context_by_name(pcilib_t *ctx, const char *view); pcilib_view_context_t *pcilib_find_register_view_context_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name); diff --git a/pcilib/xml.c b/pcilib/xml.c index 25ffbfe..4df0d2d 100644 --- a/pcilib/xml.c +++ b/pcilib/xml.c @@ -479,8 +479,6 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc 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; @@ -517,6 +515,7 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp pcilib_transform_view_description_t desc = {0}; desc.base.api = &pcilib_transform_view_api; + desc.base.type = PCILIB_TYPE_DOUBLE; err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc); if (err) return err; @@ -531,8 +530,10 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp if (!strcasecmp(name, "read_from_register")) { desc.read_from_reg = value; + if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_R; } else if (!strcasecmp(name, "write_to_register")) { desc.write_to_reg = value; + if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_W; } } @@ -610,8 +611,10 @@ static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, pcilib_enum_view_description_t desc = {0}; + desc.base.type = PCILIB_TYPE_STRING; desc.base.unit = pcilib_xml_enum_view_unit; desc.base.api = &pcilib_enum_view_xml_api; + desc.base.mode = PCILIB_ACCESS_RW; err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc); if (err) return err; |