diff options
Diffstat (limited to 'pcilib/xml.c')
| -rw-r--r-- | pcilib/xml.c | 196 | 
1 files changed, 185 insertions, 11 deletions
| diff --git a/pcilib/xml.c b/pcilib/xml.c index b980a83..467c9c7 100644 --- a/pcilib/xml.c +++ b/pcilib/xml.c @@ -49,12 +49,11 @@  #define REGISTERS_PATH ((xmlChar*)"./register")		 			/**< all standard registers nodes */  #define BIT_REGISTERS_PATH ((xmlChar*)"./field") 				/**< all bits registers nodes */  #define REGISTER_VIEWS_PATH ((xmlChar*)"./view") 				/**< supported register & field views */ -#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform")		/**< path to complete nodes of views */ +#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform")			/**< path to complete nodes of views */  #define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum")	 			/**< path to complete nodes of views */  #define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") 				/**< all elements in the enum */  #define UNITS_PATH ((xmlChar*)"/model/unit")	 				/**< path to complete nodes of units */ -#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") 			/**< all transforms of the unit */ - +#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform")				/**< all transforms of the unit */  static const char *pcilib_xml_bank_default_format = "0x%lx"; @@ -892,7 +891,7 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon      return 0;  } -static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) { +static int pcilib_xml_load_xsd_file(pcilib_t *ctx, const char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) {      int err;      xmlSchemaParserCtxtPtr ctxt; @@ -923,6 +922,7 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema      *validator  = xmlSchemaNewValidCtxt(*schema);      if (!*validator) {          xmlErrorPtr xmlerr = xmlGetLastError(); +	xmlSchemaFree(*schema); *schema = NULL;          if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);          else pcilib_error("Failed to create a validation context");          return PCILIB_ERROR_FAILED; @@ -931,6 +931,8 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema      err = xmlSchemaSetValidOptions(*validator, XML_SCHEMA_VAL_VC_I_CREATE);      if (err) {          xmlErrorPtr xmlerr = xmlGetLastError(); +	xmlSchemaFreeValidCtxt(*validator); *validator = NULL; +	xmlSchemaFree(*schema); *schema = NULL;          if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);          else pcilib_error("Failed to configure the validation context to populate default attributes");          return PCILIB_ERROR_FAILED; @@ -939,8 +941,87 @@ static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchema      return 0;  } +/* +static xmlDocPtr pcilib_xml_load_xml_file(pcilib_t *ctx, const char *xsd_filename, const char *xml_filename) { +    int err; +    xmlDocPtr doc; +    xmlSchemaPtr schema; +    xmlSchemaValidCtxtPtr validator; +    xmlParserCtxtPtr parser; + +    err = pcilib_xml_load_xsd_file(ctx, xsd_filename, &schema, &validator); +    if (err) { +	pcilib_error("Error (%i) parsing the devices schema (%s)", err, xsd_filename); +	return NULL; +    } -static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) { +    parser = xmlNewParserCtxt(); +    if (!parser) { +        xmlErrorPtr xmlerr = xmlGetLastError(); +	xmlSchemaFree(schema); +	xmlSchemaFreeValidCtxt(validator); +        if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message); +        else pcilib_error("Failed to create an XML parser context"); +        return NULL; +    } + +    doc = xmlCtxtReadFile(parser, xml_filename, NULL, 0); +    if (!doc) { +        xmlErrorPtr xmlerr = xmlGetLastError(); +	xmlFreeParserCtxt(parser); +	xmlSchemaFree(schema); +	xmlSchemaFreeValidCtxt(validator); +	if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", xml_filename, xmlerr->code, xmlerr->message); +        else pcilib_error("Error parsing %s", xml_filename); +	return NULL; +    } +     +    err = xmlSchemaValidateDoc(validator, doc); +    if (err) { +        xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser); +	xmlFreeDoc(doc); +	xmlFreeParserCtxt(parser); +	xmlSchemaFree(schema); +	xmlSchemaFreeValidCtxt(validator); +        if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", xml_filename, xmlerr->code, xmlerr->message); +        else pcilib_error("Error validating %s", xml_filename); +        return NULL; +    } + +    xmlFreeParserCtxt(parser); +    xmlSchemaFree(schema); +    xmlSchemaFreeValidCtxt(validator); + +    return doc; +} +*/ + +static xmlXPathObjectPtr pcilib_xml_eval_xpath_expression(pcilib_t *ctx, xmlDocPtr doc, const xmlChar *query) { +    xmlXPathContextPtr xpath; +    xmlXPathObjectPtr nodes; + +    xpath = xmlXPathNewContext(doc); +    if (!xpath) { +        xmlErrorPtr xmlerr = xmlGetLastError(); +        if (xmlerr) pcilib_error("xmlXpathNewContext reported error %d - %s", xmlerr->code, xmlerr->message); +        else pcilib_error("Error creating XPath context"); +        return NULL; +    } + +    nodes = xmlXPathEvalExpression(query, xpath); +    if (!nodes) { +        xmlErrorPtr xmlerr = xmlGetLastError(); +	xmlXPathFreeContext(xpath); +        if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", query, xmlerr->code, xmlerr->message); +        else pcilib_error("Failed to parse XPath expression %s", query); +        return NULL; +    } + +    xmlXPathFreeContext(xpath); +    return nodes; +} + +static int pcilib_xml_load_xsd(pcilib_t *ctx, const char *model_dir) {      int err;      struct stat st; @@ -969,7 +1050,7 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) { -static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) { +static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, xmlParserCtxtPtr parser, xmlSchemaValidCtxtPtr validator, const char *path, const char *name) {      int err;      char *full_name;      xmlDocPtr doc; @@ -982,17 +1063,17 @@ static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const cha      sprintf(full_name, "%s/%s", path, name); -    doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0); +    doc = xmlCtxtReadFile(parser, full_name, NULL, 0);      if (!doc) { -        xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); +        xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser);          if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);          else pcilib_error("Error parsing %s", full_name);          return NULL;      } -    err = xmlSchemaValidateDoc(ctx->xml.parts_validator, doc); +    err = xmlSchemaValidateDoc(validator, doc);      if (err) { -        xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser); +        xmlErrorPtr xmlerr = xmlCtxtGetLastError(parser);          xmlFreeDoc(doc);          if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);          else pcilib_error("Error validating %s", full_name); @@ -1002,6 +1083,11 @@ static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const cha      return doc;  } +static xmlDocPtr pcilib_xml_load_model_file(pcilib_t *ctx, const char *path, const char *name) { +    return pcilib_xml_load_file(ctx, ctx->xml.parser, ctx->xml.parts_validator, path, name); +} + +  static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const char *location) {      int err; @@ -1039,7 +1125,7 @@ static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const c          if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;          if (file->d_type != DT_REG) continue; -        newdoc = pcilib_xml_load_file(ctx, model_path, file->d_name); +        newdoc = pcilib_xml_load_model_file(ctx, model_path, file->d_name);          if (!newdoc) {              pcilib_error("Error processing XML file %s", file->d_name);              continue; @@ -1190,3 +1276,91 @@ void pcilib_free_xml(pcilib_t *ctx) {          xmlMemoryDump();      */  } + + +char *pcilib_detect_xml_model(pcilib_t *ctx, unsigned int vendor_id, unsigned int device_id) { +    int err; +    char *model = NULL; +    xmlSchemaPtr schema;  				/**< Pointer to the parsed xsd schema */ +    xmlSchemaValidCtxtPtr validator;       		/**< Pointer to the XML validation context */ +    xmlParserCtxtPtr parser;				/**< Pointer to the XML parser context */ + +    DIR *rep; +    struct dirent *file = NULL; +    struct stat st; +    const char *data_dir; +    char *xsd_path, *xml_path; + +    xmlXPathObjectPtr nodes; +    xmlChar xpath_query[64]; + +    xmlStrPrintf(xpath_query, sizeof(xpath_query), (xmlChar*)"/devices/device[@vendor=%x and @device=%x]/@model", vendor_id, device_id); + +    data_dir = getenv("PCILIB_DATA_DIR"); +    if (!data_dir) data_dir = PCILIB_DATA_DIR; + +    xsd_path = (char*)alloca(strlen(data_dir) + 32); +    xml_path = (char*)alloca(strlen(data_dir) + 32); +    if ((!xsd_path)||(!xml_path)) { +	pcilib_error("Error allocating stack memory"); +	return NULL; +    } + +    sprintf(xsd_path, "%s/devices.xsd", data_dir); +    sprintf(xml_path, "%s/devices", data_dir); +    if (stat(xsd_path, &st)||stat(xml_path, &st)) { +        pcilib_info("No XML devices are defined, missing devices schema or list"); +        return NULL; +    } + +    parser = xmlNewParserCtxt(); +    if (!parser) { +        xmlErrorPtr xmlerr = xmlGetLastError(); +        if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message); +        else pcilib_error("Failed to create an XML parser context"); +        return NULL; +    } + +    err = pcilib_xml_load_xsd_file(ctx, xsd_path, &schema, &validator); +    if (err) { +	xmlFreeParserCtxt(parser); +	pcilib_error("Error (%i) parsing the device schema (%s)", err, xsd_path); +	return NULL; +    } + +    rep = opendir(xml_path); +    if (!rep) goto cleanup; + +    while ((model == NULL)&&((file = readdir(rep)) != NULL)) { +	xmlDocPtr doc; +         +        size_t len = strlen(file->d_name); +        if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue; +        if (file->d_type != DT_REG) continue; + +	doc = pcilib_xml_load_file(ctx, parser, validator, xml_path, file->d_name); +	if (!doc) continue; + +	nodes = pcilib_xml_eval_xpath_expression(ctx, doc, xpath_query); +	if (!nodes) { +	    xmlFreeDoc(doc); +	    continue; +	} + +	if (!xmlXPathNodeSetIsEmpty(nodes->nodesetval)) { +	    xmlNodePtr node = nodes->nodesetval->nodeTab[0]; +	    model = strdup((char*)node->children->content); +	} + +	xmlXPathFreeObject(nodes); +	xmlFreeDoc(doc); +    } +    closedir(rep); + +cleanup:     +    xmlSchemaFree(schema); +    xmlSchemaFreeValidCtxt(validator); +    xmlFreeParserCtxt(parser); + +    return model; +} | 
