summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pcilib/CMakeLists.txt7
-rw-r--r--pcilib/pci.h5
-rw-r--r--pcilib/views.c67
-rw-r--r--pcilib/views.h16
-rw-r--r--pcilib/xml.c239
5 files changed, 324 insertions, 10 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt
index f75d7de..48363f6 100644
--- a/pcilib/CMakeLists.txt
+++ b/pcilib/CMakeLists.txt
@@ -8,9 +8,10 @@ include_directories(
)
set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h
-xml.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h
-debug.h env.h version.h config.h views.h)
-add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c xml.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c views.c)
+views.h xml.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h
+debug.h env.h version.h config.h )
+add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c
+register.c views.c xml.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c )
target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT}
${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS} ${EXTRA_SYSTEM_LIBS}
${LIBXML2_LIBRARIES} ${PYTHON_LIBRARIES})
diff --git a/pcilib/pci.h b/pcilib/pci.h
index 00528e1..657c335 100644
--- a/pcilib/pci.h
+++ b/pcilib/pci.h
@@ -62,6 +62,8 @@ struct pcilib_s {
size_t num_banks, num_protocols, num_ranges; /**< Number of registered banks, protocols, and register ranges */
size_t num_engines; /**< Number of configured DMA engines */
size_t dyn_banks; /**< Number of configured dynamic banks */
+ size_t num_enum_views,alloc_enum_views; /**< Number of configured and allocated views of type enum*/
+ size_t num_formula_views,alloc_formula_views; /**< Number of configured and allocated views of type formula*/
pcilib_register_description_t *registers; /**< List of currently defined registers (from all sources) */
pcilib_register_bank_description_t banks[PCILIB_MAX_REGISTER_BANKS + 1]; /**< List of currently defined register banks (from all sources) */
@@ -81,6 +83,9 @@ struct pcilib_s {
struct pcilib_locking_s locks; /**< Context of locking subsystem */
struct pcilib_xml_s xml; /**< XML context */
+ pcilib_view_enum2_t* enum_views; /**< list of currently defined views of type enum*/
+ pcilib_view_formula_t* formula_views; /**< list of currently defined views of type formula*/
+
#ifdef PCILIB_FILE_IO
int file_io_handle;
#endif /* PCILIB_FILE_IO */
diff --git a/pcilib/views.c b/pcilib/views.c
index 38ce102..44392d9 100644
--- a/pcilib/views.c
+++ b/pcilib/views.c
@@ -2,7 +2,7 @@
#include "pci.h"
#include "pcilib.h"
#include <Python.h>
-#include "views.h"
+//#include "views.h"
#include "error.h"
#include <strings.h>
#include <stdlib.h>
@@ -329,3 +329,68 @@ int pcilib_write_view(pcilib_t *ctx, const char *bank, const char *regname, cons
pcilib_warning("the view asked and the register do not correspond");
return PCILIB_ERROR_NOTAVAILABLE;
}
+
+/**
+ * function to populate ctx enum views, as we could do for registers or banks
+ */
+int pcilib_add_views_enum(pcilib_t *ctx, size_t n, const pcilib_view_enum2_t* views) {
+
+ pcilib_view_enum2_t *views_enum;
+ size_t size;
+
+ if (!n) {
+ for (n = 0; views[n].enums_list[0].value; n++);
+ }
+
+ if ((ctx->num_enum_views + n + 1) > ctx->alloc_enum_views) {
+ for (size = ctx->alloc_enum_views; size < 2 * (n + ctx->num_enum_views + 1); size<<=1);
+
+ views_enum = (pcilib_view_enum2_t*)realloc(ctx->enum_views, size * sizeof(pcilib_view_enum2_t));
+ if (!views_enum) return PCILIB_ERROR_MEMORY;
+
+ ctx->enum_views = views_enum;
+ /* context + model part ????*/
+ ctx->alloc_enum_views = size;
+ }
+
+ memcpy(ctx->enum_views + ctx->num_enum_views, views, n * sizeof(pcilib_view_enum2_t));
+ memset(ctx->enum_views + ctx->num_enum_views + n, 0, sizeof(pcilib_view_enum2_t));
+
+ ctx->num_enum_views += n;
+
+
+ return 0;
+}
+
+
+/**
+ * function to populate ctx formula views, as we could do for registers or banks
+ */
+int pcilib_add_views_formula(pcilib_t *ctx, size_t n, const pcilib_view_formula_t* views) {
+
+ pcilib_view_formula_t *views_formula;
+ size_t size;
+
+ if (!n) {
+ for (n = 0; views[n].name[0]; n++);
+ }
+
+ if ((ctx->num_formula_views + n + 1) > ctx->alloc_formula_views) {
+ for (size = ctx->alloc_formula_views; size < 2 * (n + ctx->num_formula_views + 1); size<<=1);
+
+ views_formula = (pcilib_view_formula_t*)realloc(ctx->formula_views, size * sizeof(pcilib_view_formula_t));
+ if (!views_formula) return PCILIB_ERROR_MEMORY;
+
+ ctx->formula_views = views_formula;
+ /* context + model part?????*/
+ ctx->alloc_formula_views = size;
+ }
+
+ memcpy(ctx->formula_views + ctx->num_formula_views, views, n * sizeof(pcilib_view_formula_t));
+ memset(ctx->formula_views + ctx->num_formula_views + n, 0, sizeof(pcilib_view_formula_t));
+
+ ctx->num_formula_views += n;
+
+
+ return 0;
+}
diff --git a/pcilib/views.h b/pcilib/views.h
index bdae9f4..98e3dcd 100644
--- a/pcilib/views.h
+++ b/pcilib/views.h
@@ -7,6 +7,8 @@ typedef struct pcilib_view_enum_s pcilib_view_enum_t;
typedef struct pcilib_view_formula_s pcilib_view_formula_t;
+typedef struct pcilib_view_enum2_s pcilib_view_enum2_t;
+
/**
* new type to define an enum view
*/
@@ -17,6 +19,15 @@ struct pcilib_view_enum_s {
/**
+ * complete type for an enum view : name will be changed after with the previous one
+ */
+struct pcilib_view_enum2_s {
+ const char* name;
+ pcilib_view_enum_t* enums_list;
+};
+
+
+/**
* new type to define a formula view
*/
struct pcilib_view_formula_s {
@@ -36,4 +47,9 @@ int pcilib_read_view(pcilib_t *ctx, const char *bank, const char *regname, const
*/
int pcilib_write_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view/*, const char *unit*/, size_t value_size, void *value);
+int pcilib_add_views_enum(pcilib_t* ctx,size_t n, pcilib_view_enum2_t* views);
+
+int pcilib_add_views_formula(pcilib_t* ctx, size_t n, pcilib_view_formula_t* views);
+
+
#endif
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 73a3deb..852f319 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -39,12 +39,15 @@
#include "register.h"
#include "xml.h"
#include "error.h"
+#include "views.h"
#define BANKS_PATH ((xmlChar*)"/model/banks/bank/bank_description") /**< path to complete nodes of banks.*/
//#define REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register") /**< all standard registers nodes.*/
//#define BIT_REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register/registers_bits/register_bits") /**< all bits registers nodes.*/
#define REGISTERS_PATH ((xmlChar*)"../registers/register") /**< all standard registers nodes.*/
#define BIT_REGISTERS_PATH ((xmlChar*)"./registers_bits/register_bits") /**< all bits registers nodes.*/
+#define VIEWS_PATH ((xmlChar*)"/model/views/view") /**< path to complete nodes of views.*/
+
static char *pcilib_xml_bank_default_format = "0x%lx";
@@ -67,7 +70,74 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr
}
*/
-static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc) {
+
+/**
+ * get the associated views of a register, to fill its register context
+ */
+static int
+pcilib_get_associated_views(pcilib_t* ctx, const char* reg_name,xmlXPathContextPtr xpath,pcilib_register_t id){
+ char* VIEWS_NAME_PATH="/model/banks/bank/registers/register[@name=\"%s\"]/views/view";
+ char* path;
+ xmlXPathObjectPtr nodes;
+ xmlNodeSetPtr nodeset;
+ char* view_name;
+
+ /*we get first the nodes corresponding to the given register*/
+ path=malloc(strlen(VIEWS_NAME_PATH)+strlen(reg_name));
+ if(!(path)){
+ pcilib_error("can't allocate memory for getting path to get associated views of %s",reg_name);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ sprintf(path,VIEWS_NAME_PATH,reg_name);
+ nodes = xmlXPathEvalExpression((xmlChar*)path, xpath);
+ nodeset = nodes->nodesetval;
+
+ if (!xmlXPathNodeSetIsEmpty(nodeset)) {
+ int i,k,l;
+ /*if we correctly get a nodeset, then we iterate through the nodeset to get all views, using their names*/
+ for (i = 0; i < nodeset->nodeNr; i++) {
+ view_name=(char*)nodeset->nodeTab[i]->children->content;
+
+ /* if the view name obtained is for an enum view, we get all pcilib_view_enum_t corresponding to the register*/
+ for(k=0; ctx->enum_views[k].enums_list[0].value;k++){
+ if(!(strcasecmp(view_name, ctx->enum_views[k].name))){
+ ctx->register_ctx[id].enums=malloc(sizeof(pcilib_view_enum_t));
+
+ if(!(ctx->register_ctx[id].enums)){
+ pcilib_error("error allocating memory for enum views in register context %i",id);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ for(l=0; ctx->enum_views[k].enums_list[l].value;l++){
+ ctx->register_ctx[id].enums=realloc(ctx->register_ctx[id].enums,(l+1)*sizeof(pcilib_view_enum_t));
+ ctx->register_ctx[id].enums[l]=ctx->enum_views[k].enums_list[l];
+ }
+ }
+ }
+
+ /*here it is for formula, i assume we have only one formula view per register*/
+ for(k=0; ctx->formula_views[k].name[0];k++){
+ if(!(strcasecmp(view_name,ctx->formula_views[k].name))){
+ ctx->register_ctx[id].formulas=malloc(sizeof(pcilib_view_formula_t));
+ if(!(ctx->register_ctx[id].formulas)){
+ pcilib_error("error allocating memory for formula views in register context %i",id);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ ctx->register_ctx[id].formulas=&(ctx->formula_views[k]);
+ }
+ }
+
+ }
+ }
+
+ xmlXPathFreeObject(nodes);
+ return 0;
+}
+
+
+static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc, int* views_ok) {
pcilib_register_description_t *desc = (pcilib_register_description_t*)xml_desc;
xmlNodePtr cur;
@@ -166,6 +236,9 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript
} else if (!strcasecmp(name,"description")) {
desc->description = value;
}
+ else if (!strcasecmp(name,"views")) {
+ *views_ok=1;
+ }
}
return 0;
@@ -173,6 +246,7 @@ static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_descript
static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
int err;
+ int views_ok=0;
xmlXPathObjectPtr nodes;
xmlNodeSetPtr nodeset;
@@ -187,7 +261,7 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank
desc.base.mode = PCILIB_REGISTER_R;
desc.base.type = PCILIB_REGISTER_STANDARD;
- err = pcilib_xml_parse_register(ctx, &desc, doc, node, &ctx->banks[bank]);
+ err = pcilib_xml_parse_register(ctx, &desc, doc, node, &ctx->banks[bank],&views_ok);
if (err) {
pcilib_error("Error (%i) parsing an XML register", err);
return err;
@@ -202,6 +276,12 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank
ctx->register_ctx[reg].xml = node;
ctx->register_ctx[reg].min = desc.min;
ctx->register_ctx[reg].max = desc.max;
+
+ /* if the register had a node of type views, then we compute its associated registers. I do that here as i need the index for register context*/
+ if(views_ok){
+ err=pcilib_get_associated_views(ctx,desc.base.name,xpath,reg);
+ if(err) pcilib_warning("can't get correctly the associated views of the register %s",desc.base.name);
+ }
xpath->node = node;
nodes = xmlXPathEvalExpression(BIT_REGISTERS_PATH, xpath);
@@ -228,7 +308,7 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank
fdesc.base.rwmask = desc.base.rwmask;
fdesc.base.type = PCILIB_REGISTER_BITS;
- err = pcilib_xml_parse_register(ctx, &fdesc, doc, nodeset->nodeTab[i], &ctx->banks[bank]);
+ err = pcilib_xml_parse_register(ctx, &fdesc, doc, nodeset->nodeTab[i], &ctx->banks[bank],&views_ok);
if (err) {
pcilib_error("Error parsing field in the XML register %s", desc.base.name);
continue;
@@ -243,6 +323,10 @@ static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank
ctx->register_ctx[reg].xml = nodeset->nodeTab[i];
ctx->register_ctx[reg].min = fdesc.min;
ctx->register_ctx[reg].max = fdesc.max;
+ if(views_ok){
+ err=pcilib_get_associated_views(ctx, desc.base.name,xpath,reg);
+ if(err) pcilib_warning("can't get correctly the associated views of the register %s",fdesc.base.name);
+ }
}
}
xmlXPathFreeObject(nodes);
@@ -397,6 +481,131 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
}
+/**
+ * function that create a view from a view node, and populate ctx views list
+ */
+static int pcilib_xml_create_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
+ int err;
+
+ pcilib_view_enum2_t complete_enum_desc={0};
+ pcilib_view_enum_t enum_desc = {0};
+ pcilib_view_formula_t formula_desc= {0};
+ xmlNodePtr cur;
+ char *value, *name;
+ char *endptr;
+ xmlAttr *attr;
+ int i=0;
+
+ /*must i initialize? i think it's only needed if we want to include a description property*/
+ enum_desc.name="default";
+ enum_desc.value=0;
+ enum_desc.min=0;
+ enum_desc.max=0;
+
+ complete_enum_desc.name="default enum";
+ complete_enum_desc.enums_list=malloc(sizeof(pcilib_view_enum_t));
+ if(!(complete_enum_desc.enums_list)){
+ pcilib_error("can't allocate memory for the complete enum type");
+ return PCILIB_ERROR_MEMORY;
+ }
+ complete_enum_desc.enums_list[0]=enum_desc;
+
+ formula_desc.name="formula_default";
+ formula_desc.read_formula="@reg";
+ formula_desc.write_formula="@reg";
+
+ /* we get the attribute type of the view node*/
+ attr=node->properties;
+ value=(char*)attr->children->content;
+ /* regarding the architecture, i decided to follow what has been done for registers and banks. but without the context*/
+ /*if the view is of type enum, we get recursively its properties and then populate ctx enum views*/
+ if(!(strcasecmp(value,"enum"))){
+ for (cur = node->children; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+ if (!value) continue;
+
+ if (!(strcasecmp((char*)name,"name"))) {
+ complete_enum_desc.name = value;
+ }else if (!(strcasecmp((char*)name,"enum"))) {
+
+ complete_enum_desc.enums_list=realloc(complete_enum_desc.enums_list,(i+1)*sizeof(pcilib_view_enum_t));
+ complete_enum_desc.enums_list[i].name=value;
+
+ /* we need to iterate through the different attributes of an enum node to get all properties*/
+ for(attr=cur->properties; attr!=NULL;attr=attr->next){
+ if(!attr->children) continue;
+ if(!xmlNodeIsText(attr->children)) continue;
+
+ name=(char*)attr->name;
+ value=(char*)attr->children->content;
+
+ if(!(strcasecmp(name,"value"))){
+ pcilib_register_value_t dat_value = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid value (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ complete_enum_desc.enums_list[i].value=dat_value;
+ }else if(!(strcasecmp(name,"min"))){
+ pcilib_register_value_t dat_min = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid min (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+ complete_enum_desc.enums_list[i].min=dat_min;
+ }else if(!(strcasecmp(name,"max"))){
+ pcilib_register_value_t dat_max = strtol(value, &endptr, 0);
+ if ((strlen(endptr) > 0)) {
+ pcilib_error("Invalid max (%s) is specified in the XML enum node", value);
+ return PCILIB_ERROR_INVALID_DATA;
+ }
+
+ complete_enum_desc.enums_list[i].max=dat_max;
+ }
+ }
+ i++;
+ }
+ }
+ err=pcilib_add_views_enum(ctx,1,&complete_enum_desc);
+ if (err) {
+ pcilib_error("Error (%i) adding a new enum view (%s) to the pcilib_t", err, complete_enum_desc.name);
+ return err;
+ }
+
+ /* we do the same here but for a iew of type formula if the attribute gives formula*/
+ }else if(!(strcasecmp(value,"formula"))){
+ for (cur = node->children; cur != NULL; cur = cur->next) {
+ if (!cur->children) continue;
+ if (!xmlNodeIsText(cur->children)) continue;
+
+ name = (char*)cur->name;
+ value = (char*)cur->children->content;
+ if (!value) continue;
+
+ if (!(strcasecmp((char*)name,"name"))) {
+ formula_desc.name = value;
+ }else if (!(strcasecmp((char*)name,"read_from_register"))) {
+ formula_desc.read_formula=value;
+ }else if (!(strcasecmp((char*)name,"write_to_register"))) {
+ formula_desc.write_formula=value;
+ }
+ }
+ err=pcilib_add_views_formula(ctx,1,&formula_desc);
+ if (err) {
+ pcilib_error("Error (%i) adding a new formula view (%s) to the pcilib_t", err, formula_desc.name);
+ return err;
+ }
+
+ }
+
+ return 0;
+}
+
+
/** pcilib_xml_initialize_banks
*
* function to create the structures to store the banks from the AST
@@ -405,12 +614,14 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
* @param[in] pci the pcilib_t running, which will be filled
*/
static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathContextPtr xpath) {
- xmlXPathObjectPtr bank_nodes;
+ xmlXPathObjectPtr bank_nodes,views_nodes;
xmlNodeSetPtr nodeset;
+ int i;
+ xmlErrorPtr xmlerr;
bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath);
if (!bank_nodes) {
- xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlerr = xmlGetLastError();
if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BANKS_PATH, xmlerr->code, xmlerr->message);
else pcilib_error("Failed to parse XPath expression %s", BANKS_PATH);
return PCILIB_ERROR_FAILED;
@@ -419,13 +630,29 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon
nodeset = bank_nodes->nodesetval;
if (!xmlXPathNodeSetIsEmpty(nodeset)) {
- int i;
for (i = 0; i < nodeset->nodeNr; i++) {
pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]);
}
}
xmlXPathFreeObject(bank_nodes);
+
+ views_nodes=xmlXPathEvalExpression(VIEWS_PATH,xpath);
+ if(!views_nodes){
+ xmlerr = xmlGetLastError();
+ if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BANKS_PATH, xmlerr->code, xmlerr->message);
+ else pcilib_error("Failed to parse XPath expression %s", BANKS_PATH);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ nodeset=views_nodes->nodesetval;
+ if(!xmlXPathNodeSetIsEmpty(nodeset)){
+ for(i=0;i < nodeset->nodeNr; i++){
+ pcilib_xml_create_view(ctx,xpath,doc,nodeset->nodeTab[i]);
+ }
+ }
+ xmlXPathFreeObject(views_nodes);
+
return 0;
}