From 55255f2ce3a2234850249efcabd9ba32d0a89a9c Mon Sep 17 00:00:00 2001
From: "Suren A. Chilingaryan" <csa@suren.me>
Date: Mon, 19 Oct 2015 15:58:46 +0200
Subject: Support computed (property-based) registers

---
 pcilib/bank.h     |  6 +++--
 pcilib/export.c   |  9 +++++++-
 pcilib/export.h   |  2 ++
 pcilib/property.c | 34 +++++++++++++++++++++++++++--
 pcilib/property.h | 20 +++++++++++++++--
 pcilib/register.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++--------
 pcilib/register.h |  7 +++---
 pcilib/view.c     | 18 +++++++++++++++
 pcilib/view.h     |  4 +++-
 pcilib/xml.c      | 38 +++++++++++++++++++++++++++-----
 10 files changed, 177 insertions(+), 26 deletions(-)

(limited to 'pcilib')

diff --git a/pcilib/bank.h b/pcilib/bank.h
index ba149b9..2f90321 100644
--- a/pcilib/bank.h
+++ b/pcilib/bank.h
@@ -8,13 +8,15 @@
 #define PCILIB_REGISTER_BANK1 			1
 #define PCILIB_REGISTER_BANK2 			2
 #define PCILIB_REGISTER_BANK3 			3
-#define PCILIB_REGISTER_BANK_DMA		64					/**< First BANK address to be used by DMA engines */
-#define PCILIB_REGISTER_BANK_DMACONF		65					/**< DMA configuration in the software registers */
+#define PCILIB_REGISTER_BANK_PROPERTY           64                                      /**< Registers abstracting properties and other computed registers */
+#define PCILIB_REGISTER_BANK_DMA		96					/**< First BANK address to be used by DMA engines */
+#define PCILIB_REGISTER_BANK_DMACONF		96					/**< DMA configuration in the software registers */
 #define PCILIB_REGISTER_BANK_DYNAMIC		128					/**< First BANK address to map dynamic XML configuration */
 #define PCILIB_REGISTER_PROTOCOL_INVALID	((pcilib_register_protocol_t)-1)
 #define PCILIB_REGISTER_PROTOCOL0		0					/**< First PROTOCOL address to be used in the event engine */
 #define PCILIB_REGISTER_PROTOCOL_DEFAULT	64					/**< Default memmap based protocol */
 #define PCILIB_REGISTER_PROTOCOL_SOFTWARE	65					/**< Software registers */
+#define PCILIB_REGISTER_PROTOCOL_PROPERTY       66                                      /**< Protocol to access registers interfacing properties */
 #define PCILIB_REGISTER_PROTOCOL_DMA		96					/**< First PROTOCOL address to be used by DMA engines */
 #define PCILIB_REGISTER_PROTOCOL_DYNAMIC	128					/**< First PROTOCOL address to be used by plugins */
 
diff --git a/pcilib/export.c b/pcilib/export.c
index ffb1c4b..8e1a7d2 100644
--- a/pcilib/export.c
+++ b/pcilib/export.c
@@ -10,13 +10,20 @@ const char *pcilib_data_types[] = { "default", "string", "double", "long" };
 
 #include "protocols/default.h"
 #include "protocols/software.h"
+#include "protocols/property.h"
 
 const pcilib_register_protocol_description_t pcilib_protocols[] = {
     { PCILIB_REGISTER_PROTOCOL_DEFAULT, &pcilib_default_protocol_api, NULL, NULL, "default", "" },
-    { PCILIB_REGISTER_PROTOCOL_SOFTWARE, &pcilib_register_software_protocol_api, NULL, NULL, "software_registers", "" },
+    { PCILIB_REGISTER_PROTOCOL_SOFTWARE, &pcilib_software_protocol_api, NULL, NULL, "software_registers", "" },
+    { PCILIB_REGISTER_PROTOCOL_PROPERTY, &pcilib_property_protocol_api, NULL, NULL, "property_registers", "" },
     { 0 }
 };
 
+const pcilib_register_bank_description_t pcilib_property_register_bank = 
+    { PCILIB_REGISTER_BANK_PROPERTY, PCILIB_REGISTER_PROTOCOL_PROPERTY, PCILIB_BAR_NOBAR, 0, 0, 32, 0, PCILIB_HOST_ENDIAN, PCILIB_HOST_ENDIAN, "%lu", "property", "Computed registers interfacing properties"};
+
+
+
 #include "dma/nwl.h"
 #include "dma/ipe.h"
 
diff --git a/pcilib/export.h b/pcilib/export.h
index 6fb08c3..7d3ff35 100644
--- a/pcilib/export.h
+++ b/pcilib/export.h
@@ -13,6 +13,8 @@ extern const pcilib_dma_description_t pcilib_dma[];
 
 extern const pcilib_register_protocol_api_description_t pcilib_default_protocol_api;
 
+extern const pcilib_register_bank_description_t pcilib_property_register_bank;
+
 extern const pcilib_dma_description_t pcilib_ipedma;
 extern const pcilib_dma_description_t pcilib_nwldma;
 
diff --git a/pcilib/property.c b/pcilib/property.c
index 276360a..1a20de1 100644
--- a/pcilib/property.c
+++ b/pcilib/property.c
@@ -15,7 +15,34 @@
 #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 pcilib_add_registers_from_properties(pcilib_t *ctx, size_t n, pcilib_view_context_t* const *view_ctx, pcilib_view_description_t* const *v) {
+    pcilib_view_t i;
+    pcilib_register_t pos = 0;
+    pcilib_register_description_t regs[n];
+
+    for (i = 0; i < n; i++) {
+        if ((v[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) continue;
+
+        regs[pos++] = (pcilib_register_description_t){
+            .addr = view_ctx[i]->view,
+            .bits = 8 * sizeof(pcilib_register_value_t),
+            .mode = v[i]->mode,
+            .type = PCILIB_REGISTER_PROPERTY,
+            .bank = PCILIB_REGISTER_BANK_PROPERTY,
+            .name = (v[i]->regname?v[i]->regname:v[i]->name),
+            .description = v[i]->description
+        };
+    }
+
+    if (pos)
+        return pcilib_add_registers(ctx, 0, pos, regs, NULL);
+
+    return 0;
+}
+
+
+int pcilib_add_properties_from_registers(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers) {
     int err;
 
     pcilib_register_t i;
@@ -26,12 +53,15 @@ int pcilib_add_register_properties(pcilib_t *ctx, size_t n, const pcilib_registe
 
 
     for (i = 0; i < n; i++) {
+        char *view_name;
         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 (registers[i].type == PCILIB_REGISTER_PROPERTY) continue;
+
+        view_name = malloc(strlen(registers[i].name) + strlen(b->name) + 13);
         if (!view_name) {
             pcilib_clean_views(ctx, cur_view);
             return PCILIB_ERROR_MEMORY;
diff --git a/pcilib/property.h b/pcilib/property.h
index bec11c8..75ec053 100644
--- a/pcilib/property.h
+++ b/pcilib/property.h
@@ -5,7 +5,7 @@
 extern "C" {
 #endif
 /**
- * This is internal function used to add property view for all model registers. It is automatically
+ * This is an 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
@@ -14,7 +14,23 @@ extern "C" {
  * @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);
+int pcilib_add_properties_from_registers(pcilib_t *ctx, size_t n, const pcilib_register_bank_t *banks, const pcilib_register_description_t *registers);
+
+
+/**
+ * To reduce number of required interfaces, some of the property views may be also mapped into the 
+ * model as registers. The client application, then, is able to use either register or property APIs
+ * to access them. This is an internal function which processes the supplied views, finds which views
+ * have to be mapped in the register space, and finally pushes corresponding registers into the model.
+ * The function is automatically called from pcilib_add_views and should never be called by the user. 
+ * On error no new registers are added.
+ * @param[in,out] ctx - pcilib context
+ * @param[in] n - number of views to analyze. 
+ * @param[in] view_ctx - views to analyze
+ * @param[in] view - array of pointers to corresponding view descriptions
+ * @return - error or 0 on success
+ */
+int pcilib_add_registers_from_properties(pcilib_t *ctx, size_t n, pcilib_view_context_t* const *view_ctx, pcilib_view_description_t* const *view);
 
 #ifdef __cplusplus
 }
diff --git a/pcilib/register.c b/pcilib/register.c
index 08af871..a166bbd 100644
--- a/pcilib/register.c
+++ b/pcilib/register.c
@@ -74,8 +74,17 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags,
             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;
+                    // We need to add a bank first in this case
+                if (registers[i].type == PCILIB_REGISTER_PROPERTY) {
+                    err = pcilib_add_register_banks(ctx, 0, 1, &pcilib_property_register_bank, &bank);
+                } else {
+                    err = PCILIB_ERROR_INVALID_BANK;
+                }
+
+                if (err) {
+                    pcilib_error("Invalid bank address (0x%lx) is specified for register %s", bank_addr, registers[i].name);
+                    return err;
+                }
             }
         }
 
@@ -91,7 +100,7 @@ int pcilib_add_registers(pcilib_t *ctx, pcilib_model_modification_flags_t flags,
         banks[i] = bank;
     }
 
-    err = pcilib_add_register_properties(ctx, n, banks, registers);
+    err = pcilib_add_properties_from_registers(ctx, n, banks, registers);
     if (err) return err;
 
     for (i = 0; i < n; i++) {
@@ -148,7 +157,9 @@ void pcilib_clean_registers(pcilib_t *ctx, pcilib_register_t 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) {
     int err;
+
     size_t i;
+    size_t space_size;
 
     pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank];
     const pcilib_register_protocol_api_description_t *bapi = bctx->api;
@@ -163,14 +174,31 @@ static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_ba
 	return PCILIB_ERROR_NOTSUPPORTED;
     }
 
-    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+    if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) space_size = ctx->num_views;
+    else space_size = b->size;
+
+    if (((addr + n) > space_size)||(((addr + n) == space_size)&&(bits))) {
 	if ((b->format)&&(strchr(b->format, 'x')))
-	    pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	    pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, space_size);
 	else 
-	    pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	    pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, space_size);
 	return PCILIB_ERROR_OUTOFRANGE;
     }
 
+    if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) {
+        for (i = 0; i < (bits?(n+1):n); i++) {
+            if ((ctx->views[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) {
+                pcilib_error("Accessing invalid register %u (associated view does not provide register functionality)", addr + i);
+                return PCILIB_ERROR_INVALID_REQUEST;
+            }
+
+            if ((ctx->views[i]->mode&PCILIB_ACCESS_R) == 0) {
+                pcilib_error("Read access is not allowed to register %u", addr + i);
+                return PCILIB_ERROR_NOTPERMITED;
+            }
+        }
+    } 
+
     //err = pcilib_init_register_banks(ctx);
     //if (err) return err;
     
@@ -259,7 +287,9 @@ int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, p
 
 static int pcilib_write_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 rwmask, pcilib_register_value_t *buf) {
     int err;
+
     size_t i;
+    size_t space_size;
 
     pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank];
     const pcilib_register_protocol_api_description_t *bapi = bctx->api;
@@ -274,14 +304,31 @@ static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_b
 	return PCILIB_ERROR_NOTSUPPORTED;
     }
 
-    if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) {
+    if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) space_size = ctx->num_views;
+    else space_size = b->size;
+
+    if (((addr + n) > space_size)||(((addr + n) == space_size)&&(bits))) {
 	if ((b->format)&&(strchr(b->format, 'x')))
-	    pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	    pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, space_size);
 	else 
-	    pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size);
+	    pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, space_size);
 	return PCILIB_ERROR_OUTOFRANGE;
     }
 
+    if (b->protocol == PCILIB_REGISTER_PROTOCOL_PROPERTY) {
+        for (i = 0; i < (bits?(n+1):n); i++) {
+            if ((ctx->views[i]->flags&PCILIB_VIEW_FLAG_REGISTER) == 0) {
+                pcilib_error("Accessing invalid register %u (associated view does not provide register functionality)", addr + i);
+                return PCILIB_ERROR_INVALID_REQUEST;
+            }
+
+            if ((ctx->views[i]->mode&PCILIB_ACCESS_W) == 0) {
+                pcilib_error("Write access is not allowed to register %u", addr + i);
+                return PCILIB_ERROR_NOTPERMITED;
+            }
+        }
+    } 
+
     //err = pcilib_init_register_banks(ctx);
     //if (err) return err;
     
diff --git a/pcilib/register.h b/pcilib/register.h
index f3df309..0963b22 100644
--- a/pcilib/register.h
+++ b/pcilib/register.h
@@ -11,9 +11,10 @@
 
 
 typedef enum {
-    PCILIB_REGISTER_STANDARD = 0,
-    PCILIB_REGISTER_FIFO,
-    PCILIB_REGISTER_BITS
+    PCILIB_REGISTER_STANDARD = 0,               /**< Standard register */
+    PCILIB_REGISTER_FIFO,                       /**< FIFO register */
+    PCILIB_REGISTER_BITS,                       /**< Besides a big standard register, the register bit-fields may be described by bit registers */
+    PCILIB_REGISTER_PROPERTY                    /**< A special register bound to a property and gettings/setting it value through it */
 } pcilib_register_type_t;
 
 typedef struct {
diff --git a/pcilib/view.c b/pcilib/view.c
index d14e8aa..e31fdba 100644
--- a/pcilib/view.c
+++ b/pcilib/view.c
@@ -9,8 +9,11 @@
 #include "view.h"
 #include "error.h"
 #include "value.h"
+#include "property.h"
 
 int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc, pcilib_view_context_t **refs) {
+    int err;
+
     size_t i;
     void *ptr;
 
@@ -25,6 +28,11 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
         }
     }
 
+    if (!refs) {
+        refs = (pcilib_view_context_t**)alloca(n * sizeof(pcilib_view_context_t*));
+        if (!refs) return PCILIB_ERROR_MEMORY;
+    }
+
     if ((ctx->num_views + n + 1) > ctx->alloc_views) {
         size_t size;
 	pcilib_view_description_t **views;
@@ -48,6 +56,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
 
         pcilib_view_t view = pcilib_find_view_by_name(ctx, v->name);
         if (view != PCILIB_VIEW_INVALID) {
+            ctx->views[ctx->num_views + i] = NULL;
             pcilib_clean_views(ctx, ctx->num_views);
             pcilib_error("View %s is already defined in the model", v->name);
             return PCILIB_ERROR_EXIST;
@@ -55,6 +64,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
 
         cur = (pcilib_view_description_t*)malloc(v->api->description_size);
         if (!cur) {
+            ctx->views[ctx->num_views + i] = NULL;
             pcilib_clean_views(ctx, ctx->num_views);
             return PCILIB_ERROR_MEMORY;
         }
@@ -68,6 +78,7 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
 
         if (!view_ctx) {
             free(cur);
+            ctx->views[ctx->num_views + i] = NULL;
             pcilib_clean_views(ctx, ctx->num_views);
             return PCILIB_ERROR_FAILED;
         }
@@ -85,6 +96,13 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
     }
 
     ctx->views[ctx->num_views + n] = NULL;
+
+    err = pcilib_add_registers_from_properties(ctx, n, refs, ctx->views + ctx->num_views);
+    if (err) {
+        pcilib_clean_views(ctx, ctx->num_views);
+        return err;
+    }
+
     ctx->num_views += n;
 
     return 0;
diff --git a/pcilib/view.h b/pcilib/view.h
index ec775b7..33d4d96 100644
--- a/pcilib/view.h
+++ b/pcilib/view.h
@@ -12,7 +12,8 @@ typedef struct pcilib_view_context_s pcilib_view_context_t;
 typedef struct pcilib_view_description_s pcilib_view_description_t;
 
 typedef enum {
-    PCILIB_VIEW_FLAG_PROPERTY = 1                                               /**< Indicates that view does not depend on a value and is independent property */
+    PCILIB_VIEW_FLAG_PROPERTY = 1,                                              /**< Indicates that view does not depend on a value and is independent property */
+    PCILIB_VIEW_FLAG_REGISTER = 2                                               /**< Indicates that view does not depend on a value and should be mapped to the register space */
 } pcilib_view_flags_t;
 
 typedef struct {
@@ -32,6 +33,7 @@ struct pcilib_view_description_s {
     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 *regname;                                                        /**< Specifies the register name if the view should be mapped to register space */
     const char *description;			                                /**< Short description */
 };
 
diff --git a/pcilib/xml.c b/pcilib/xml.c
index b022fd8..1238ba8 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -184,12 +184,16 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript
                 desc->mode = PCILIB_REGISTER_W;
             } else if (!strcasecmp(value, "RW")) {
                 desc->mode = PCILIB_REGISTER_RW;
-            } else if (!strcasecmp(value, "W")) {
-                desc->mode = PCILIB_REGISTER_W;
             } else if (!strcasecmp(value, "RW1C")) {
                 desc->mode = PCILIB_REGISTER_RW1C;
             } else if (!strcasecmp(value, "W1C")) {
                 desc->mode = PCILIB_REGISTER_W1C;
+            } else if (!strcasecmp(value, "RW1I")) {
+                desc->mode = PCILIB_REGISTER_RW1I;
+            } else if (!strcasecmp(value, "W1I")) {
+                desc->mode = PCILIB_REGISTER_W1I;
+            } else if (!strcasecmp(value, "-")) {
+                desc->mode = 0;
             } else {
                 pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
                 return PCILIB_ERROR_INVALID_DATA;
@@ -487,11 +491,16 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
 
         if (!strcasecmp(name, "name")) {
                 // Overriden by path
-            if (!desc->name)
-                desc->name = value;
+            if (desc->name) continue;
+            if (*value == '/')
+	        desc->flags |= PCILIB_VIEW_FLAG_PROPERTY;
+            desc->name = value;
 	} else if (!strcasecmp(name, "path")) {
 	    desc->name = value;
 	    desc->flags |= PCILIB_VIEW_FLAG_PROPERTY;
+	} else if (!strcasecmp(name, "register")) {
+	    desc->regname = value;
+	    desc->flags |= PCILIB_VIEW_FLAG_REGISTER;
         } else if (!strcasecmp((char*)name, "description")) {
     	    desc->description = value;
         } else if (!strcasecmp((char*)name, "unit")) {
@@ -504,6 +513,19 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
                 pcilib_error("Invalid type (%s) of register view is specified in the XML bank description", value);
                 return PCILIB_ERROR_INVALID_DATA;
             }
+        } else if (!strcasecmp(name, "mode")) {
+            if (!strcasecmp(value, "R")) {
+                desc->mode = PCILIB_REGISTER_R;
+            } else if (!strcasecmp(value, "W")) {
+                desc->mode = PCILIB_REGISTER_W;
+            } else if (!strcasecmp(value, "RW")) {
+                desc->mode = PCILIB_REGISTER_RW;
+            } else if (!strcasecmp(value, "-")) {
+                desc->mode = 0;
+            } else {
+                pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
+                return PCILIB_ERROR_INVALID_DATA;
+            }
         }
     }
 
@@ -516,10 +538,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
     const char *value, *name;
     pcilib_view_context_t *view_ctx;
 
+    pcilib_access_mode_t mode = 0;
     pcilib_transform_view_description_t desc = {0};
 
     desc.base.api = &pcilib_transform_view_api;
     desc.base.type = PCILIB_TYPE_DOUBLE;
+    desc.base.mode = PCILIB_ACCESS_RW;
 
     err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc);
     if (err) return err;
@@ -540,7 +564,7 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
                 }
             }
             desc.read_from_reg = value;
-            if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_R;
+            if ((value)&&(*value)) mode |= PCILIB_ACCESS_R;
         } else if (!strcasecmp(name, "write_to_register")) {
             if (desc.base.flags&PCILIB_VIEW_FLAG_PROPERTY) {
                 if (strstr(value, "$value")) {
@@ -549,10 +573,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
                 }
             }
             desc.write_to_reg = value;
-            if ((value)&&(*value)) desc.base.mode |= PCILIB_ACCESS_W;
+            if ((value)&&(*value)) mode |= PCILIB_ACCESS_W;
         } 
     }
 
+    desc.base.mode &= mode;
+
     err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx);
     if (err) return err;
 
-- 
cgit v1.2.3