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 | |
| parent | 2e9457b666a303fab83aa17e33624f39de9a1dd7 (diff) | |
| download | pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.gz pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.bz2 pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.tar.xz pcitool-c8628b2a715a7cfaaccbd7e403cd1c6c76b918cd.zip  | |
Support properties of arbitrary type
| -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 | ||||
| -rw-r--r-- | pcitool/cli.c | 210 | ||||
| -rw-r--r-- | views/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | views/enum.c | 2 | ||||
| -rw-r--r-- | views/register.c | 65 | ||||
| -rw-r--r-- | views/register.h | 19 | 
22 files changed, 871 insertions, 168 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; diff --git a/pcitool/cli.c b/pcitool/cli.c index 867b65e..2956306 100644 --- a/pcitool/cli.c +++ b/pcitool/cli.c @@ -77,8 +77,10 @@ typedef enum {      MODE_BENCHMARK,      MODE_READ,      MODE_READ_REGISTER, +    MODE_READ_PROPERTY,      MODE_WRITE,      MODE_WRITE_REGISTER, +    MODE_WRITE_PROPERTY,      MODE_RESET,      MODE_GRAB,      MODE_START_DMA, @@ -193,7 +195,7 @@ static struct option long_options[] = {      {"timeout",			required_argument, 0, OPT_TIMEOUT },      {"iterations",		required_argument, 0, OPT_ITERATIONS },      {"info",			optional_argument, 0, OPT_INFO }, -    {"list",			no_argument, 0, OPT_LIST }, +    {"list",			optional_argument, 0, OPT_LIST },      {"reset",			no_argument, 0, OPT_RESET },      {"benchmark",		optional_argument, 0, OPT_BENCHMARK },      {"read",			optional_argument, 0, OPT_READ }, @@ -258,7 +260,7 @@ void Usage(int argc, char *argv[], const char *format, ...) {  " %s <mode> [options] [hex data]\n"  "  Modes:\n"  "   -i [target]			- Device or Register (target) Info\n" -"   -l[l]			- List (detailed) Data Banks & Registers\n" +"   -l[l] [bank|/branch]	- List (detailed) Data Banks & Registers\n"  "   -r <addr|dmaX|reg[/unit]>	- Read Data/Register\n"  "   -w <addr|dmaX|reg[/unit]>	- Write Data/Register\n"  "   --benchmark <barX|dmaX>	- Performance Evaluation\n" @@ -406,6 +408,79 @@ int RegisterCompare(const void *aptr, const void *bptr, void *registers) {      return 0;  } +void ListProperties(pcilib_t *handle, const char *branch, int details) { +    int i; +    pcilib_property_info_t *props; + +    props = pcilib_get_property_list(handle, branch, 0); +    if (!props) Error("Error getting properties"); + +    if (props[0].path) { +        printf("Properties: \n"); + +        for (i = 0; props[i].path; i++) { +            const char *mode; +            const char *type; + +            switch (props[i].type) { +                case PCILIB_TYPE_LONG: +                    type = "int    "; +                    break; +                case PCILIB_TYPE_DOUBLE: +                    type = "float  "; +                    break; +                case PCILIB_TYPE_STRING: +                    type = "string "; +                    break; +                case PCILIB_TYPE_INVALID: +                    type = NULL; +                    break; +                default: +                    type = "unknown"; +            } +             +            switch (props[i].mode) { +                case PCILIB_ACCESS_RW: +                    mode = "RW"; +                    break; +                case PCILIB_ACCESS_R: +                    mode = "R "; +                    break; +                case PCILIB_ACCESS_W: +                    mode = "W "; +                    break; +                default: +                    mode = "  "; +            } + +            if (type) +                printf(" (%s %s) ", type, mode); +            else +                printf(" %12s", ""); + +            if (props[i].flags&PCILIB_LIST_FLAG_CHILDS) +                printf(" + "); +            else +                printf("   "); + +	    if (details > 0) { +	        printf("%s", props[i].name); +	        if ((props[i].description)&&(props[i].description[0])) { +		    printf(": %s", props[i].description); +	        } +	    } else { +	        printf("%s", props[i].path); +	    } +	    printf("\n"); +        } + +        printf("\n"); + +        pcilib_free_property_info(handle, props); +    } + +} +  void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, int details) {      int i, j, k;      const pcilib_register_bank_description_t *banks; @@ -415,7 +490,7 @@ void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const      const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);      const pcilib_dma_description_t *dma_info = pcilib_get_dma_description(handle); -     +      for (i = 0; i < PCILIB_MAX_BARS; i++) {  	if (board_info->bar_length[i] > 0) {  	    printf(" BAR %d - ", i); @@ -470,7 +545,7 @@ void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const      if ((bank)&&(bank != (char*)-1)) banks = NULL;      else banks = model_info->banks; -     +      if (banks) {  	printf("Banks: \n");  	for (i = 0; banks[i].access; i++) { @@ -543,6 +618,8 @@ void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const  	printf("\n");      } +    ListProperties(handle, "/", details); +      if (bank == (char*)-1) events = NULL;      else {  	events = model_info->events; @@ -1126,7 +1203,7 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_ -int ReadRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, const char *unit) { +int ReadRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, const char *view, const char *unit) {      int i;      int err;      const char *format; @@ -1139,19 +1216,37 @@ int ReadRegister(pcilib_t *handle, const pcilib_model_description_t *model_info,  	// Adding DMA registers      pcilib_get_dma_description(handle); -    if (reg) { -        pcilib_register_t regid = pcilib_find_register(handle, bank, reg); - -        if (unit) { +    if (reg||view) { +        if (view) {              pcilib_value_t val = {0}; -            err = pcilib_read_register_view(handle, bank, reg, unit, &val); -            if (err) Error("Error reading view %s of register %s", unit, reg); +            if (reg) { +                err = pcilib_read_register_view(handle, bank, reg, view, &val); +                if (err) Error("Error reading view %s of register %s", view, reg); +            } else { +                err = pcilib_get_property(handle, view, &val); +                if (err) Error("Error reading property %s", view); +            } +            if (unit) { +                err = pcilib_convert_value_unit(handle, &val, unit); +                if (err) { +                    if (reg) Error("Error converting view %s of register %s to unit %s", view, reg, unit); +                    else Error("Error converting property %s to unit %s", view, unit); +                } +            } +                          err = pcilib_convert_value_type(handle, &val, PCILIB_TYPE_STRING); -            if (err) Error("Error converting view %s of register %s to string", unit, reg); +            if (err) { +                if (reg) Error("Error converting view %s of register %s to string", view); +                else Error("Error converting property %s to string", view); +            } -            printf("%s = %s\n", reg, val.sval); +            printf("%s = %s", (reg?reg:view), val.sval); +            if ((val.unit)&&(strcasecmp(val.unit, "name"))) +                printf(" %s", val.unit); +            printf("\n");          } else { +            pcilib_register_t regid = pcilib_find_register(handle, bank, reg);              bank_id = pcilib_find_register_bank_by_addr(handle, model_info->registers[regid].bank);              format = model_info->banks[bank_id].format;              if (!format) format = "%lu"; @@ -1362,14 +1457,12 @@ int WriteRegisterRange(pcilib_t *handle, const pcilib_model_description_t *model  } -int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, const char *unit, char **data) { +int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, const char *view, const char *unit, char **data) {      int err = 0;      pcilib_value_t val = {0};      pcilib_register_value_t value, verify; -    pcilib_register_t regid = pcilib_find_register(handle, bank, reg); -    if (regid == PCILIB_REGISTER_INVALID) Error("Can't find register (%s) from bank (%s)", reg, bank?bank:"autodetected");  /*      pcilib_register_bank_t bank_id; @@ -1384,11 +1477,23 @@ int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info      err = pcilib_set_value_from_static_string(handle, &val, *data);      if (err) Error("Error (%i) setting value", err); -    if (unit) { -        err = pcilib_write_register_view(handle, bank, reg, unit, &val); -        if (err) Error("Error writting view %s of register %s", unit, reg); -        printf("%s is written\n ", reg); +    if (view) { +        if (unit) +            val.unit = unit; + +        if (reg) { +            err = pcilib_write_register_view(handle, bank, reg, view, &val); +            if (err) Error("Error writting view %s of register %s", view, reg); +            printf("%s is written\n ", reg); +        } else { +            err = pcilib_set_property(handle, view, &val); +            if (err) Error("Error setting property %s", view); +            printf("%s is written\n ", view); +        }      } else { +        pcilib_register_t regid = pcilib_find_register(handle, bank, reg); +        if (regid == PCILIB_REGISTER_INVALID) Error("Can't find register (%s) from bank (%s)", reg, bank?bank:"autodetected"); +          value = pcilib_get_value_as_register_value(handle, &val, &err);          if (err) Error("Error (%i) parsing data value (%s)", *data); @@ -2758,6 +2863,7 @@ int main(int argc, char **argv) {      pcilib_bar_t bar = PCILIB_BAR_DETECT;      const char *addr = NULL;      const char *reg = NULL; +    const char *view = NULL;      const char *unit = NULL;      const char *bank = NULL;      char **data = NULL; @@ -2767,6 +2873,7 @@ int main(int argc, char **argv) {      const char *use = NULL;      const char *lock = NULL;      const char *info_target = NULL; +    const char *list_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; @@ -2813,6 +2920,9 @@ int main(int argc, char **argv) {  		if (mode == MODE_LIST) details++;  		else if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); +		if (optarg) list_target = optarg; +		else if ((optind < argc)&&(argv[optind][0] != '-')) list_target = argv[optind++]; +  		mode = MODE_LIST;  	    break;  	    case OPT_RESET: @@ -3302,17 +3412,25 @@ int main(int argc, char **argv) {  		num_offset = dma_channel + 3;  		itmp -= 3;  	    } -	     +  	    if (bank) {  		if (strncmp(num_offset, bank, itmp)) Usage(argc, argv, "Conflicting DMA channels are specified in mode parameter (%s) and bank parameter (%s)", dma_channel, bank);  	    } -		  +   	    if (!isnumber_n(num_offset, itmp))  		 Usage(argc, argv, "Invalid DMA channel (%s) is specified", dma_channel);  	    dma = atoi(num_offset);  	}       break; +     case MODE_LIST: +	if (bank&&list_target) { +	    if (strcmp(list_target, bank))  +		Usage(argc, argv, "Conflicting banks are specified in list parameter (%s) and bank parameter (%s)", list_target, bank); +	} else if (bank) { +	    list_target = bank; +	} +     break;       default:          if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied");      } @@ -3359,24 +3477,35 @@ int main(int argc, char **argv) {  		}  	    }  	} else { -            unit = strchr(addr, '/'); -            if (!unit) unit = strchr(addr, ':'); -            if (unit) { -                char *reg_name; -                size_t reg_size = strlen(addr) - strlen(unit); -                reg_name = alloca(reg_size + 1); -                memcpy(reg_name, addr, reg_size); -                reg_name[reg_size] = 0; -                reg = reg_name; -                unit++; +            view = strchr(addr, '/'); +            unit = strchr((view?view:addr), ':'); + +            if (view||unit) { +                size_t reg_size = strlen(addr) - strlen(view?view:unit); +                if (reg_size) reg = strndupa(addr, reg_size); +                else reg = NULL; + +                if ((reg)&&(view)) view++; +                if (unit) unit++; + +                if (view&&unit) { +                    view = strndupa(view, strlen(view) - strlen(unit) - 1); +                } else if ((reg)&&(unit)) { +                    view = unit; +                    unit = NULL; +                }              } else {                  reg = addr;              } -	    if (pcilib_find_register(handle, bank, reg) == PCILIB_REGISTER_INVALID) { -	        Usage(argc, argv, "Invalid address (%s) is specified", addr); +            if (reg) { +	        if (pcilib_find_register(handle, bank, reg) == PCILIB_REGISTER_INVALID) { +	            Usage(argc, argv, "Invalid address (%s) is specified", addr); +	        } else { +		    ++mode; +	        }  	    } else { -		++mode; +	        mode += 2;  	    }  	}       } @@ -3458,7 +3587,10 @@ int main(int argc, char **argv) {          Info(handle, model_info, info_target);       break;       case MODE_LIST: -        List(handle, model_info, bank, details); +        if ((list_target)&&(*list_target == '/')) +            ListProperties(handle, list_target, details); +        else +            List(handle, model_info, list_target, details);       break;       case MODE_BENCHMARK:          Benchmark(handle, amode, dma, bar, start, size_set?size:0, access, iterations); @@ -3475,14 +3607,16 @@ int main(int argc, char **argv) {  	}       break;       case MODE_READ_REGISTER: -        if ((reg)||(!addr)) ReadRegister(handle, model_info, bank, reg, unit); +     case MODE_READ_PROPERTY: +        if ((reg)||(view)||(!addr)) ReadRegister(handle, model_info, bank, reg, view, unit);  	else ReadRegisterRange(handle, model_info, bank, start, addr_shift, size, ofile);       break;       case MODE_WRITE:  	WriteData(handle, amode, dma, bar, start, size, access, endianess, data, verify);       break;       case MODE_WRITE_REGISTER: -        if (reg) WriteRegister(handle, model_info, bank, reg, unit, data); +     case MODE_WRITE_PROPERTY: +        if (reg||view) WriteRegister(handle, model_info, bank, reg, view, unit, data);  	else WriteRegisterRange(handle, model_info, bank, start, addr_shift, size, data);       break;       case MODE_RESET: diff --git a/views/CMakeLists.txt b/views/CMakeLists.txt index 646a982..0e0c20b 100644 --- a/views/CMakeLists.txt +++ b/views/CMakeLists.txt @@ -8,6 +8,6 @@ include_directories(      ${UTHASH_INCLUDE_DIRS}  ) -set(HEADERS ${HEADERS} enum.h transform.h) +set(HEADERS ${HEADERS} enum.h transform.h register.h) -add_library(views STATIC enum.c transform.c) +add_library(views STATIC enum.c transform.c register.c) diff --git a/views/enum.c b/views/enum.c index d712c71..e049c43 100644 --- a/views/enum.c +++ b/views/enum.c @@ -34,7 +34,7 @@ static int pcilib_enum_view_read(pcilib_t *ctx, pcilib_view_context_t *view_ctx,              return pcilib_set_value_from_static_string(ctx, val, v->names[i].name);      } -    return pcilib_set_value_from_int(ctx, val, regval); +    return pcilib_set_value_from_register_value(ctx, val, regval);  }  static int pcilib_enum_view_write(pcilib_t *ctx, pcilib_view_context_t *view_ctx, pcilib_register_value_t *regval, const pcilib_value_t *val) { diff --git a/views/register.c b/views/register.c new file mode 100644 index 0000000..8256a4a --- /dev/null +++ b/views/register.c @@ -0,0 +1,65 @@ +#define _PCILIB_VIEW_ENUM_C + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +#include <uthash.h> + +#include "error.h" +#include "version.h" +#include "model.h" +#include "enum.h" +#include "view.h" +#include "value.h" +#include "register.h" + + +static void pcilib_register_view_free(pcilib_t *ctx, pcilib_view_description_t *view) { +    if (view->name) +        free((void*)view->name); +    free(view); +} + +static int pcilib_register_view_read(pcilib_t *ctx, pcilib_view_context_t *view_ctx, pcilib_register_value_t dummy, pcilib_value_t *val) { +    int err; + +    const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); +    pcilib_register_view_description_t *v = (pcilib_register_view_description_t*)(model_info->views[view_ctx->view]); + +    if (v->view) { +        return pcilib_read_register_view(ctx, v->bank, v->reg, v->view, val); +    } else { +        pcilib_register_value_t regval; + +        err = pcilib_read_register(ctx, v->bank, v->reg, ®val); +        if (err) return err; + +        return pcilib_set_value_from_register_value(ctx, val, regval); +    } +} + +static int pcilib_register_view_write(pcilib_t *ctx, pcilib_view_context_t *view_ctx, pcilib_register_value_t *dummy, const pcilib_value_t *val) { +    int err; + +    const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); +    pcilib_register_view_description_t *v = (pcilib_register_view_description_t*)(model_info->views[view_ctx->view]); + +    if (v->view) { +        return pcilib_write_register_view(ctx, v->bank, v->reg, v->view, val); +    } else { +        pcilib_register_value_t regval; + +        regval = pcilib_get_value_as_register_value(ctx, val, &err); +        if (err) return err; + +        return pcilib_write_register(ctx, v->bank, v->reg, regval); +    } + +    return err; +} + +const pcilib_view_api_description_t pcilib_register_view_api = +  { PCILIB_VERSION, sizeof(pcilib_register_view_description_t), NULL, NULL, pcilib_register_view_free,  pcilib_register_view_read,  pcilib_register_view_write }; diff --git a/views/register.h b/views/register.h new file mode 100644 index 0000000..e527846 --- /dev/null +++ b/views/register.h @@ -0,0 +1,19 @@ +#ifndef _PCILIB_VIEW_REGISTER_H +#define _PCILIB_VIEW_REGISTER_H + +#include <pcilib.h> +#include <pcilib/view.h> + +typedef struct { +    pcilib_view_description_t base; +    const char *view; +    const char *reg; +    const char *bank; +} pcilib_register_view_description_t; + + +#ifndef _PCILIB_VIEW_REGISTER_C +extern const pcilib_view_api_description_t pcilib_register_view_api; +#endif /* _PCILIB_VIEW_REGISTER_C */ + +#endif /* _PCILIB_VIEW_REGISTER_H */  | 
