xml.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112
  1. /**
  2. * @file pcilib_xml.c
  3. * @version 1.0
  4. *
  5. * @brief this file is the main source file for the implementation of dynamic registers using xml and several funtionalities for the "pci-tool" line command tool from XML files. the xml part has been implemented using libxml2
  6. *
  7. * @details registers and banks nodes are parsed using xpath expression, but their properties is get by recursively getting all properties nodes. In this sense, if a property changes, the algorithm has to be changed, but if it's registers or banks nodes, just the xpath expression modification should be enough.
  8. Libxml2 considers blank spaces within the XML as node natively and this code as been produced considering blank spaces in the XML files. In case XML files would not contain blank spaces anymore, please change the code.
  9. In case the performance is not good enough, please consider the following : hard code of formulas
  10. */
  11. #define _XOPEN_SOURCE 700
  12. #define _BSD_SOURCE
  13. #define _DEFAULT_SOURCE
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <strings.h>
  18. #include <dirent.h>
  19. #include <errno.h>
  20. #include <alloca.h>
  21. #include <unistd.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <libxml/xmlschemastypes.h>
  25. #include <libxml/tree.h>
  26. #include <libxml/parser.h>
  27. #include <libxml/xpath.h>
  28. #include <libxml/xpathInternals.h>
  29. #include "config.h"
  30. #include "pci.h"
  31. #include "bank.h"
  32. #include "register.h"
  33. #include "xml.h"
  34. #include "error.h"
  35. #include "view.h"
  36. #include "views/enum.h"
  37. #include "views/transform.h"
  38. #define BANKS_PATH ((xmlChar*)"/model/bank") /**< path to complete nodes of banks */
  39. #define REGISTERS_PATH ((xmlChar*)"./register") /**< all standard registers nodes */
  40. #define BIT_REGISTERS_PATH ((xmlChar*)"./field") /**< all bits registers nodes */
  41. #define REGISTER_VIEWS_PATH ((xmlChar*)"./view") /**< supported register & field views */
  42. #define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
  43. #define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum") /**< path to complete nodes of views */
  44. #define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") /**< all elements in the enum */
  45. #define UNITS_PATH ((xmlChar*)"/model/unit") /**< path to complete nodes of units */
  46. #define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
  47. static const char *pcilib_xml_bank_default_format = "0x%lx";
  48. static const char *pcilib_xml_enum_view_unit = "name";
  49. typedef struct {
  50. pcilib_register_description_t base;
  51. pcilib_register_value_range_t range;
  52. } pcilib_xml_register_description_t;
  53. /*
  54. static xmlNodePtr pcilib_xml_get_parent_bank_node(xmlDocPtr doc, xmlNodePtr node) {
  55. xmlNodePtr bank_node;
  56. bank_node = node->parent->parent;
  57. // bank_description is always a first node according to the XSD schema
  58. return xmlFirstElementChild(bank_node);
  59. }
  60. static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr node) {
  61. return node->parent->parent;
  62. }
  63. */
  64. static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) {
  65. xmlAttr *cur;
  66. char *value, *name;
  67. for (cur = node->properties; cur != NULL; cur = cur->next) {
  68. if(!cur->children) continue;
  69. if(!xmlNodeIsText(cur->children)) continue;
  70. name = (char*)cur->name;
  71. value = (char*)cur->children->content;
  72. if (!strcasecmp(name, "name")) {
  73. desc->name = value;
  74. } else if (!strcasecmp(name, "view")) {
  75. desc->view = value;
  76. }
  77. }
  78. if (!desc->name)
  79. desc->name = desc->view;
  80. return 0;
  81. }
  82. static int pcilib_xml_parse_register(pcilib_t *ctx, pcilib_xml_register_description_t *xml_desc, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_bank_description_t *bdesc) {
  83. int err;
  84. pcilib_register_description_t *desc = (pcilib_register_description_t*)xml_desc;
  85. xmlXPathObjectPtr nodes;
  86. xmlNodeSetPtr nodeset;
  87. xmlAttrPtr cur;
  88. char *value, *name;
  89. char *endptr;
  90. for (cur = node->properties; cur != NULL; cur = cur->next) {
  91. if (!cur->children) continue;
  92. if (!xmlNodeIsText(cur->children)) continue;
  93. name = (char*)cur->name;
  94. value = (char*)cur->children->content;
  95. if (!value) continue;
  96. if (!strcasecmp((char*)name, "address")) {
  97. uintptr_t addr = strtol(value, &endptr, 0);
  98. if ((strlen(endptr) > 0)) {
  99. pcilib_error("Invalid address (%s) is specified in the XML register description", value);
  100. return PCILIB_ERROR_INVALID_DATA;
  101. }
  102. desc->addr = addr;
  103. } else if(!strcasecmp(name, "offset")) {
  104. int offset = strtol(value, &endptr, 0);
  105. if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) {
  106. pcilib_error("Invalid offset (%s) is specified in the XML register description", value);
  107. return PCILIB_ERROR_INVALID_DATA;
  108. }
  109. desc->offset = (pcilib_register_size_t)offset;
  110. } else if (!strcasecmp(name,"size")) {
  111. int size = strtol(value, &endptr, 0);
  112. if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) {
  113. pcilib_error("Invalid size (%s) is specified in the XML register description", value);
  114. return PCILIB_ERROR_INVALID_DATA;
  115. }
  116. desc->bits = (pcilib_register_size_t)size;
  117. } else if (!strcasecmp(name, "default")) {
  118. pcilib_register_value_t val = strtol(value, &endptr, 0);
  119. if ((strlen(endptr) > 0)) {
  120. pcilib_error("Invalid default value (%s) is specified in the XML register description", value);
  121. return PCILIB_ERROR_INVALID_DATA;
  122. }
  123. desc->defvalue = val;
  124. } else if (!strcasecmp(name,"min")) {
  125. pcilib_register_value_t min = strtol(value, &endptr, 0);
  126. if ((strlen(endptr) > 0)) {
  127. pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
  128. return PCILIB_ERROR_INVALID_DATA;
  129. }
  130. xml_desc->range.min = min;
  131. } else if (!strcasecmp(name, "max")) {
  132. pcilib_register_value_t max = strtol(value, &endptr, 0);
  133. if ((strlen(endptr) > 0)) {
  134. pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
  135. return PCILIB_ERROR_INVALID_DATA;
  136. }
  137. xml_desc->range.max = max;
  138. } else if (!strcasecmp((char*)name,"rwmask")) {
  139. if (!strcasecmp(value, "all")) {
  140. desc->rwmask = PCILIB_REGISTER_ALL_BITS;
  141. } else if (!strcasecmp(value, "none")) {
  142. desc->rwmask = 0;
  143. } else {
  144. uintptr_t mask = strtol(value, &endptr, 0);
  145. if ((strlen(endptr) > 0)) {
  146. pcilib_error("Invalid mask (%s) is specified in the XML register description", value);
  147. return PCILIB_ERROR_INVALID_DATA;
  148. }
  149. desc->rwmask = mask;
  150. }
  151. } else if (!strcasecmp(name, "mode")) {
  152. if (!strcasecmp(value, "R")) {
  153. desc->mode = PCILIB_REGISTER_R;
  154. } else if (!strcasecmp(value, "W")) {
  155. desc->mode = PCILIB_REGISTER_W;
  156. } else if (!strcasecmp(value, "RW")) {
  157. desc->mode = PCILIB_REGISTER_RW;
  158. } else if (!strcasecmp(value, "RW1C")) {
  159. desc->mode = PCILIB_REGISTER_RW1C;
  160. } else if (!strcasecmp(value, "W1C")) {
  161. desc->mode = PCILIB_REGISTER_W1C;
  162. } else if (!strcasecmp(value, "RW1I")) {
  163. desc->mode = PCILIB_REGISTER_RW1I;
  164. } else if (!strcasecmp(value, "W1I")) {
  165. desc->mode = PCILIB_REGISTER_W1I;
  166. } else if (!strcasecmp(value, "-")) {
  167. desc->mode = 0;
  168. } else {
  169. pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
  170. return PCILIB_ERROR_INVALID_DATA;
  171. }
  172. } else if (!strcasecmp(name, "type")) {
  173. if (!strcasecmp(value, "fifo")) {
  174. desc->type = PCILIB_REGISTER_FIFO;
  175. } else {
  176. pcilib_error("Invalid register type (%s) is specified in the XML register description", value);
  177. return PCILIB_ERROR_INVALID_DATA;
  178. }
  179. } else if (!strcasecmp(name,"name")) {
  180. desc->name = value;
  181. } else if (!strcasecmp(name,"description")) {
  182. desc->description = value;
  183. }
  184. }
  185. xpath->node = node;
  186. nodes = xmlXPathEvalExpression(REGISTER_VIEWS_PATH, xpath);
  187. xpath->node = NULL;
  188. if (!nodes) {
  189. xmlErrorPtr xmlerr = xmlGetLastError();
  190. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTER_VIEWS_PATH, xmlerr->code, xmlerr->message);
  191. else pcilib_error("Failed to parse XPath expression %s", REGISTER_VIEWS_PATH);
  192. return PCILIB_ERROR_FAILED;
  193. }
  194. nodeset = nodes->nodesetval;
  195. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  196. int i;
  197. desc->views = (pcilib_view_reference_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t));
  198. if (!desc->views) {
  199. xmlXPathFreeObject(nodes);
  200. pcilib_error("Failed to allocate %zu bytes of memory to store supported register views", (nodeset->nodeNr + 1) * sizeof(char*));
  201. return PCILIB_ERROR_MEMORY;
  202. }
  203. memset(desc->views, 0, (nodeset->nodeNr + 1) * sizeof(pcilib_view_reference_t));
  204. for (i = 0; i < nodeset->nodeNr; i++) {
  205. err = pcilib_xml_parse_view_reference(ctx, doc, nodeset->nodeTab[i], &desc->views[i]);
  206. if (err) {
  207. xmlXPathFreeObject(nodes);
  208. return err;
  209. }
  210. }
  211. }
  212. xmlXPathFreeObject(nodes);
  213. return 0;
  214. }
  215. static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
  216. int err;
  217. xmlXPathObjectPtr nodes;
  218. xmlNodeSetPtr nodeset;
  219. pcilib_xml_register_description_t desc = {{0}};
  220. pcilib_xml_register_description_t fdesc;
  221. pcilib_register_t reg;
  222. desc.base.bank = ctx->banks[bank].addr;
  223. desc.base.rwmask = PCILIB_REGISTER_ALL_BITS;
  224. desc.base.mode = PCILIB_REGISTER_R;
  225. desc.base.type = PCILIB_REGISTER_STANDARD;
  226. err = pcilib_xml_parse_register(ctx, &desc, xpath, doc, node, &ctx->banks[bank]);
  227. if (err) {
  228. pcilib_error("Error (%i) parsing an XML register", err);
  229. return err;
  230. }
  231. err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &desc.base, &reg);
  232. if (err) {
  233. if (desc.base.views) free(desc.base.views);
  234. pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name);
  235. return err;
  236. }
  237. ctx->register_ctx[reg].xml = node;
  238. memcpy(&ctx->register_ctx[reg].range, &desc.range, sizeof(pcilib_register_value_range_t));
  239. ctx->register_ctx[reg].views = desc.base.views;
  240. xpath->node = node;
  241. nodes = xmlXPathEvalExpression(BIT_REGISTERS_PATH, xpath);
  242. xpath->node = NULL;
  243. if (!nodes) {
  244. xmlErrorPtr xmlerr = xmlGetLastError();
  245. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message);
  246. else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH);
  247. return PCILIB_ERROR_FAILED;
  248. }
  249. nodeset = nodes->nodesetval;
  250. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  251. int i;
  252. for (i = 0; i < nodeset->nodeNr; i++) {
  253. memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t));
  254. fdesc.base.bank = desc.base.bank;
  255. fdesc.base.addr = desc.base.addr;
  256. fdesc.base.mode = desc.base.mode;
  257. fdesc.base.rwmask = desc.base.rwmask;
  258. fdesc.base.type = PCILIB_REGISTER_BITS;
  259. err = pcilib_xml_parse_register(ctx, &fdesc, xpath, doc, nodeset->nodeTab[i], &ctx->banks[bank]);
  260. if (err) {
  261. pcilib_error("Error parsing field in the XML register %s", desc.base.name);
  262. continue;
  263. }
  264. err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, &reg);
  265. if (err) {
  266. if (fdesc.base.views) free(fdesc.base.views);
  267. pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name);
  268. continue;
  269. }
  270. ctx->register_ctx[reg].xml = nodeset->nodeTab[i];
  271. memcpy(&ctx->register_ctx[reg].range, &fdesc.range, sizeof(pcilib_register_value_range_t));
  272. ctx->register_ctx[reg].views = fdesc.base.views;
  273. }
  274. }
  275. xmlXPathFreeObject(nodes);
  276. return 0;
  277. }
  278. static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
  279. int err;
  280. int override = 0;
  281. pcilib_register_bank_description_t desc = {0};
  282. pcilib_register_bank_t bank;
  283. xmlAttrPtr cur;
  284. char *value, *name;
  285. char *endptr;
  286. xmlXPathObjectPtr nodes;
  287. xmlNodeSetPtr nodeset;
  288. desc.format = pcilib_xml_bank_default_format;
  289. desc.addr = PCILIB_REGISTER_BANK_DYNAMIC;
  290. desc.bar = PCILIB_BAR_NOBAR;
  291. desc.size = 0x1000;
  292. desc.protocol = PCILIB_REGISTER_PROTOCOL_DEFAULT;
  293. desc.access = 32;
  294. desc.endianess = PCILIB_HOST_ENDIAN;
  295. desc.raw_endianess = PCILIB_HOST_ENDIAN;
  296. // iterate through all children, representing bank properties, to fill the structure
  297. for (cur = node->properties; cur != NULL; cur = cur->next) {
  298. if (!cur->children) continue;
  299. if (!xmlNodeIsText(cur->children)) continue;
  300. name = (char*)cur->name;
  301. value = (char*)cur->children->content;
  302. if (!value) continue;
  303. if (!strcasecmp(name, "bar")) {
  304. char bar = value[0]-'0';
  305. if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) {
  306. pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value);
  307. return PCILIB_ERROR_INVALID_DATA;
  308. }
  309. desc.bar = (pcilib_bar_t)bar;
  310. override = 1;
  311. } else if (!strcasecmp(name,"size")) {
  312. long size = strtol(value, &endptr, 0);
  313. if ((strlen(endptr) > 0)||(size<=0)) {
  314. pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value);
  315. return PCILIB_ERROR_INVALID_DATA;
  316. }
  317. desc.size = (size_t)size;
  318. override = 1;
  319. } else if (!strcasecmp(name,"protocol")) {
  320. pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value);
  321. if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) {
  322. pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value);
  323. return PCILIB_ERROR_NOTSUPPORTED;
  324. }
  325. desc.protocol = ctx->protocols[protocol].addr;
  326. override = 1;
  327. } else if (!strcasecmp(name,"address")) {
  328. uintptr_t addr = strtol(value, &endptr, 0);
  329. if ((strlen(endptr) > 0)) {
  330. pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
  331. return PCILIB_ERROR_INVALID_DATA;
  332. }
  333. desc.read_addr = addr;
  334. desc.write_addr = addr;
  335. override = 1;
  336. } else if (!strcasecmp(name,"read_address")) {
  337. uintptr_t addr = strtol(value, &endptr, 0);
  338. if ((strlen(endptr) > 0)) {
  339. pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
  340. return PCILIB_ERROR_INVALID_DATA;
  341. }
  342. desc.read_addr = addr;
  343. override = 1;
  344. } else if (!strcasecmp(name,"write_address")) {
  345. uintptr_t addr = strtol(value, &endptr, 0);
  346. if ((strlen(endptr) > 0)) {
  347. pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
  348. return PCILIB_ERROR_INVALID_DATA;
  349. }
  350. desc.write_addr = addr;
  351. override = 1;
  352. } else if(strcasecmp((char*)name,"word_size")==0) {
  353. int access = strtol(value, &endptr, 0);
  354. if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) {
  355. pcilib_error("Invalid word size (%s) is specified in the XML bank description", value);
  356. return PCILIB_ERROR_INVALID_DATA;
  357. }
  358. desc.access = access;
  359. override = 1;
  360. } else if (!strcasecmp(name,"endianess")) {
  361. if (!strcasecmp(value,"little")) desc.endianess = PCILIB_LITTLE_ENDIAN;
  362. else if (!strcasecmp(value,"big")) desc.endianess = PCILIB_BIG_ENDIAN;
  363. else if (!strcasecmp(value,"host")) desc.endianess = PCILIB_HOST_ENDIAN;
  364. else {
  365. pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value);
  366. return PCILIB_ERROR_INVALID_DATA;
  367. }
  368. override = 1;
  369. } else if (!strcasecmp(name,"format")) {
  370. desc.format = value;
  371. override = 1;
  372. } else if (!strcasecmp((char*)name,"name")) {
  373. desc.name = value;
  374. } else if (!strcasecmp((char*)name,"description")) {
  375. desc.description = value;
  376. override = 1;
  377. } else if (!strcasecmp((char*)name,"override")) {
  378. override = 1;
  379. }
  380. }
  381. err = pcilib_add_register_banks(ctx, override?PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE:PCILIB_MODEL_MODIFICATION_FLAG_SKIP_EXISTING, 1, &desc, &bank);
  382. if (err) {
  383. pcilib_error("Error adding register bank (%s) specified in the XML bank description", desc.name);
  384. return err;
  385. }
  386. ctx->xml.bank_nodes[bank] = node;
  387. if (ctx->bank_ctx[bank]) {
  388. ctx->bank_ctx[bank]->xml = node;
  389. }
  390. xpath->node = node;
  391. nodes = xmlXPathEvalExpression(REGISTERS_PATH, xpath);
  392. xpath->node = NULL;
  393. if (!nodes) {
  394. xmlErrorPtr xmlerr = xmlGetLastError();
  395. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message);
  396. else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH);
  397. return PCILIB_ERROR_FAILED;
  398. }
  399. nodeset = nodes->nodesetval;
  400. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  401. int i;
  402. for (i = 0; i < nodeset->nodeNr; i++) {
  403. err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]);
  404. if (err) pcilib_error("Error creating XML registers for bank %s", desc.name);
  405. }
  406. }
  407. xmlXPathFreeObject(nodes);
  408. return 0;
  409. }
  410. static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_view_description_t *desc) {
  411. xmlAttrPtr cur;
  412. const char *value, *name;
  413. for (cur = node->properties; cur != NULL; cur = cur->next) {
  414. if (!cur->children) continue;
  415. if (!xmlNodeIsText(cur->children)) continue;
  416. name = (char*)cur->name;
  417. value = (char*)cur->children->content;
  418. if (!value) continue;
  419. if (!strcasecmp(name, "name")) {
  420. // Overriden by path
  421. if (desc->name) continue;
  422. if (*value == '/')
  423. desc->flags |= PCILIB_VIEW_FLAG_PROPERTY;
  424. desc->name = value;
  425. } else if (!strcasecmp(name, "path")) {
  426. desc->name = value;
  427. desc->flags |= PCILIB_VIEW_FLAG_PROPERTY;
  428. } else if (!strcasecmp(name, "register")) {
  429. desc->regname = value;
  430. desc->flags |= PCILIB_VIEW_FLAG_REGISTER;
  431. } else if (!strcasecmp((char*)name, "description")) {
  432. desc->description = value;
  433. } else if (!strcasecmp((char*)name, "unit")) {
  434. desc->unit = value;
  435. } else if (!strcasecmp((char*)name, "type")) {
  436. if (!strcasecmp(value, "string")) desc->type = PCILIB_TYPE_STRING;
  437. else if (!strcasecmp(value, "float")) desc->type = PCILIB_TYPE_DOUBLE;
  438. else if (!strcasecmp(value, "int")) desc->type = PCILIB_TYPE_LONG;
  439. else {
  440. pcilib_error("Invalid type (%s) of register view is specified in the XML bank description", value);
  441. return PCILIB_ERROR_INVALID_DATA;
  442. }
  443. } else if (!strcasecmp(name, "mode")) {
  444. if (!strcasecmp(value, "R")) {
  445. desc->mode = PCILIB_REGISTER_R;
  446. } else if (!strcasecmp(value, "W")) {
  447. desc->mode = PCILIB_REGISTER_W;
  448. } else if (!strcasecmp(value, "RW")) {
  449. desc->mode = PCILIB_REGISTER_RW;
  450. } else if (!strcasecmp(value, "-")) {
  451. desc->mode = 0;
  452. } else {
  453. pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
  454. return PCILIB_ERROR_INVALID_DATA;
  455. }
  456. }
  457. }
  458. return 0;
  459. }
  460. static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
  461. int err;
  462. xmlAttrPtr cur;
  463. const char *value, *name;
  464. pcilib_view_context_t *view_ctx;
  465. pcilib_access_mode_t mode = 0;
  466. pcilib_transform_view_description_t desc = {0};
  467. desc.base.api = &pcilib_transform_view_api;
  468. desc.base.type = PCILIB_TYPE_DOUBLE;
  469. desc.base.mode = PCILIB_ACCESS_RW;
  470. err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc);
  471. if (err) return err;
  472. for (cur = node->properties; cur != NULL; cur = cur->next) {
  473. if (!cur->children) continue;
  474. if (!xmlNodeIsText(cur->children)) continue;
  475. name = (char*)cur->name;
  476. value = (char*)cur->children->content;
  477. if (!value) continue;
  478. if (!strcasecmp(name, "read_from_register")) {
  479. if (desc.base.flags&PCILIB_VIEW_FLAG_PROPERTY) {
  480. if (strstr(value, "$value")) {
  481. pcilib_error("Invalid transform specified in XML property (%s). The properties can't reference $value (%s)", desc.base.name, value);
  482. return PCILIB_ERROR_INVALID_DATA;
  483. }
  484. }
  485. desc.read_from_reg = value;
  486. if ((value)&&(*value)) mode |= PCILIB_ACCESS_R;
  487. } else if (!strcasecmp(name, "write_to_register")) {
  488. if (desc.base.flags&PCILIB_VIEW_FLAG_PROPERTY) {
  489. if (strstr(value, "$value")) {
  490. pcilib_error("Invalid transform specified in XML property (%s). The properties can't reference $value (%s)", desc.base.name, value);
  491. return PCILIB_ERROR_INVALID_DATA;
  492. }
  493. }
  494. desc.write_to_reg = value;
  495. if ((value)&&(*value)) mode |= PCILIB_ACCESS_W;
  496. }
  497. }
  498. desc.base.mode &= mode;
  499. err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx);
  500. if (err) return err;
  501. view_ctx->xml = node;
  502. return 0;
  503. }
  504. static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_value_name_t *desc) {
  505. xmlAttr *cur;
  506. char *value, *name;
  507. char *endptr;
  508. int min_set = 0, max_set = 0;
  509. pcilib_register_value_t val;
  510. for (cur = node->properties; cur != NULL; cur = cur->next) {
  511. if(!cur->children) continue;
  512. if(!xmlNodeIsText(cur->children)) continue;
  513. name = (char*)cur->name;
  514. value = (char*)cur->children->content;
  515. if (!strcasecmp(name, "name")) {
  516. desc->name = value;
  517. } else if (!strcasecmp(name, "description")) {
  518. desc->description = value;
  519. } else if (!strcasecmp(name, "value")) {
  520. val = strtol(value, &endptr, 0);
  521. if ((strlen(endptr) > 0)) {
  522. pcilib_error("Invalid enum value (%s) is specified in the XML enum node", value);
  523. return PCILIB_ERROR_INVALID_DATA;
  524. }
  525. desc->value = val;
  526. } else if (!strcasecmp(name, "min")) {
  527. val = strtol(value, &endptr, 0);
  528. if ((strlen(endptr) > 0)) {
  529. pcilib_error("Invalid enum min-value (%s) is specified in the XML enum node", value);
  530. return PCILIB_ERROR_INVALID_DATA;
  531. }
  532. desc->min = val;
  533. min_set = 1;
  534. } else if (!strcasecmp(name, "max")) {
  535. val = strtol(value, &endptr, 0);
  536. if ((strlen(endptr) > 0)) {
  537. pcilib_error("Invalid enum max-value (%s) is specified in the XML enum node", value);
  538. return PCILIB_ERROR_INVALID_DATA;
  539. }
  540. desc->max = val;
  541. max_set = 1;
  542. }
  543. }
  544. if ((!min_set)&&(!max_set)) {
  545. desc->min = desc->value;
  546. desc->max = desc->value;
  547. } else if (max_set) {
  548. desc->min = 0;
  549. } else if (min_set) {
  550. desc->max = (pcilib_register_value_t)-1;
  551. }
  552. if ((desc->min > desc->max)||(desc->value < desc->min)||(desc->value > desc->max)) {
  553. pcilib_error("Invalid enum configuration (min: %lu, max: %lu, value: %lu)", desc->min, desc->max, desc->value);
  554. return PCILIB_ERROR_INVALID_DATA;
  555. }
  556. return 0;
  557. }
  558. static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
  559. int i;
  560. int err;
  561. xmlXPathObjectPtr nodes;
  562. xmlNodeSetPtr nodeset;
  563. pcilib_view_context_t *view_ctx;
  564. pcilib_enum_view_description_t desc = {0};
  565. desc.base.type = PCILIB_TYPE_STRING;
  566. desc.base.unit = pcilib_xml_enum_view_unit;
  567. desc.base.api = &pcilib_enum_view_xml_api;
  568. desc.base.mode = PCILIB_ACCESS_RW;
  569. err = pcilib_xml_parse_view(ctx, xpath, doc, node, (pcilib_view_description_t*)&desc);
  570. if (err) return err;
  571. xpath->node = node;
  572. nodes = xmlXPathEvalExpression(ENUM_ELEMENTS_PATH, xpath);
  573. xpath->node = NULL;
  574. if (!nodes) {
  575. xmlErrorPtr xmlerr = xmlGetLastError();
  576. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", ENUM_ELEMENTS_PATH, xmlerr->code, xmlerr->message);
  577. else pcilib_error("Failed to parse XPath expression %s", ENUM_ELEMENTS_PATH);
  578. return PCILIB_ERROR_FAILED;
  579. }
  580. nodeset = nodes->nodesetval;
  581. if (xmlXPathNodeSetIsEmpty(nodeset)) {
  582. xmlXPathFreeObject(nodes);
  583. pcilib_error("No names is defined for enum view (%s)", desc.base.name);
  584. return PCILIB_ERROR_INVALID_DATA;
  585. }
  586. desc.names = (pcilib_register_value_name_t*)malloc((nodeset->nodeNr + 1) * sizeof(pcilib_register_value_name_t));
  587. if (!desc.names) {
  588. xmlXPathFreeObject(nodes);
  589. pcilib_error("No names is defined for enum view (%s)", desc.base.name);
  590. return PCILIB_ERROR_INVALID_DATA;
  591. }
  592. for (i = 0; i < nodeset->nodeNr; i++) {
  593. err = pcilib_xml_parse_value_name(ctx, xpath, doc, nodeset->nodeTab[i], &desc.names[i]);
  594. if (err) {
  595. xmlXPathFreeObject(nodes);
  596. free(desc.names);
  597. return err;
  598. }
  599. }
  600. memset(&desc.names[nodeset->nodeNr], 0, sizeof(pcilib_register_value_name_t));
  601. xmlXPathFreeObject(nodes);
  602. err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx);
  603. if (err) {
  604. free(desc.names);
  605. return err;
  606. }
  607. view_ctx->xml = node;
  608. return 0;
  609. }
  610. static int pcilib_xml_parse_unit_transform(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_unit_transform_t *desc) {
  611. xmlAttrPtr cur;
  612. char *value, *name;
  613. for (cur = node->properties; cur != NULL; cur = cur->next) {
  614. if (!cur->children) continue;
  615. if (!xmlNodeIsText(cur->children)) continue;
  616. name = (char*)cur->name;
  617. value = (char*)cur->children->content;
  618. if (!strcasecmp(name, "unit")) {
  619. desc->unit = value;
  620. } else if (!strcasecmp(name, "transform")) {
  621. desc->transform = value;
  622. }
  623. }
  624. return 0;
  625. }
  626. /**
  627. * function to create a unit from a unit xml node, then populating ctx with it
  628. *@param[in,out] ctx - the pcilib_t running
  629. *@param[in] xpath - the xpath context of the unis xml file
  630. *@param[in] doc - the AST of the unit xml file
  631. *@param[in] node - the node representing the unit
  632. *@return an error code: 0 if evrythinh is ok
  633. */
  634. static int pcilib_xml_create_unit(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
  635. int err;
  636. pcilib_unit_description_t desc = {0};
  637. xmlXPathObjectPtr nodes;
  638. xmlNodeSetPtr nodeset;
  639. xmlAttrPtr cur;
  640. char *value, *name;
  641. for (cur = node->properties; cur != NULL; cur = cur->next) {
  642. if (!cur->children) continue;
  643. if (!xmlNodeIsText(cur->children)) continue;
  644. name = (char*)cur->name;
  645. value = (char*)cur->children->content;
  646. if (!strcasecmp(name, "name")) {
  647. desc.name = value;
  648. }
  649. }
  650. xpath->node = node;
  651. nodes = xmlXPathEvalExpression(UNIT_TRANSFORMS_PATH, xpath);
  652. xpath->node = NULL;
  653. if (!nodes) {
  654. xmlErrorPtr xmlerr = xmlGetLastError();
  655. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", UNIT_TRANSFORMS_PATH, xmlerr->code, xmlerr->message);
  656. else pcilib_error("Failed to parse XPath expression %s", UNIT_TRANSFORMS_PATH);
  657. return PCILIB_ERROR_FAILED;
  658. }
  659. nodeset = nodes->nodesetval;
  660. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  661. int i;
  662. if (nodeset->nodeNr > PCILIB_MAX_TRANSFORMS_PER_UNIT) {
  663. xmlXPathFreeObject(nodes);
  664. pcilib_error("Too many transforms for unit %s are defined, only %lu are supported", desc.name, PCILIB_MAX_TRANSFORMS_PER_UNIT);
  665. return PCILIB_ERROR_INVALID_DATA;
  666. }
  667. for (i = 0; i < nodeset->nodeNr; i++) {
  668. err = pcilib_xml_parse_unit_transform(ctx, xpath, doc, nodeset->nodeTab[i], &desc.transforms[i]);
  669. if (err) {
  670. xmlXPathFreeObject(nodes);
  671. return err;
  672. }
  673. }
  674. }
  675. xmlXPathFreeObject(nodes);
  676. return pcilib_add_units(ctx, 1, &desc);
  677. }
  678. /** pcilib_xml_initialize_banks
  679. *
  680. * function to create the structures to store the banks from the AST
  681. * @see pcilib_xml_create_bank
  682. * @param[in] doc the AST of the xml file.
  683. * @param[in] pci the pcilib_t running, which will be filled
  684. */
  685. static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathContextPtr xpath) {
  686. int err;
  687. xmlXPathObjectPtr bank_nodes = NULL, transform_nodes = NULL, enum_nodes = NULL, unit_nodes = NULL;
  688. xmlNodeSetPtr nodeset;
  689. int i;
  690. bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath);
  691. if (bank_nodes) transform_nodes = xmlXPathEvalExpression(TRANSFORM_VIEWS_PATH, xpath);
  692. if (transform_nodes) enum_nodes = xmlXPathEvalExpression(ENUM_VIEWS_PATH, xpath);
  693. if (enum_nodes) unit_nodes = xmlXPathEvalExpression(UNITS_PATH, xpath);
  694. if (!unit_nodes) {
  695. const unsigned char *expr = (enum_nodes?UNITS_PATH:(transform_nodes?ENUM_VIEWS_PATH:(bank_nodes?TRANSFORM_VIEWS_PATH:BANKS_PATH)));
  696. if (enum_nodes) xmlXPathFreeObject(enum_nodes);
  697. if (transform_nodes) xmlXPathFreeObject(transform_nodes);
  698. if (bank_nodes) xmlXPathFreeObject(bank_nodes);
  699. xmlErrorPtr xmlerr = xmlGetLastError();
  700. if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", expr, xmlerr->code, xmlerr->message);
  701. else pcilib_error("Failed to parse XPath expression %s", expr);
  702. return PCILIB_ERROR_FAILED;
  703. }
  704. nodeset = unit_nodes->nodesetval;
  705. if(!xmlXPathNodeSetIsEmpty(nodeset)) {
  706. for(i=0; i < nodeset->nodeNr; i++) {
  707. err = pcilib_xml_create_unit(ctx, xpath, doc, nodeset->nodeTab[i]);
  708. if (err) pcilib_error("Error (%i) creating unit", err);
  709. }
  710. }
  711. nodeset = transform_nodes->nodesetval;
  712. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  713. for(i=0; i < nodeset->nodeNr; i++) {
  714. err = pcilib_xml_create_transform_view(ctx, xpath, doc, nodeset->nodeTab[i]);
  715. if (err) pcilib_error("Error (%i) creating register transform", err);
  716. }
  717. }
  718. nodeset = enum_nodes->nodesetval;
  719. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  720. for(i=0; i < nodeset->nodeNr; i++) {
  721. err = pcilib_xml_create_enum_view(ctx, xpath, doc, nodeset->nodeTab[i]);
  722. if (err) pcilib_error("Error (%i) creating register enum", err);
  723. }
  724. }
  725. nodeset = bank_nodes->nodesetval;
  726. if (!xmlXPathNodeSetIsEmpty(nodeset)) {
  727. for (i = 0; i < nodeset->nodeNr; i++) {
  728. err = pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]);
  729. if (err) pcilib_error("Error (%i) creating bank", err);
  730. }
  731. }
  732. xmlXPathFreeObject(unit_nodes);
  733. xmlXPathFreeObject(enum_nodes);
  734. xmlXPathFreeObject(transform_nodes);
  735. xmlXPathFreeObject(bank_nodes);
  736. return 0;
  737. }
  738. static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
  739. int err;
  740. xmlSchemaParserCtxtPtr ctxt;
  741. /** we first parse the xsd file for AST with validation*/
  742. ctxt = xmlSchemaNewParserCtxt(xsd_filename);
  743. if (!ctxt) {
  744. xmlErrorPtr xmlerr = xmlGetLastError();
  745. if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
  746. else pcilib_error("Failed to create a parser for XML schemas");
  747. return PCILIB_ERROR_FAILED;
  748. }
  749. ctx->xml.schema = xmlSchemaParse(ctxt);
  750. if (!ctx->xml.schema) {
  751. xmlErrorPtr xmlerr = xmlGetLastError();
  752. xmlSchemaFreeParserCtxt(ctxt);
  753. if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
  754. else pcilib_error("Failed to parse XML schema");
  755. return PCILIB_ERROR_INVALID_DATA;
  756. }
  757. xmlSchemaFreeParserCtxt(ctxt);
  758. ctx->xml.validator = xmlSchemaNewValidCtxt(ctx->xml.schema);
  759. if (!ctx->xml.validator) {
  760. xmlErrorPtr xmlerr = xmlGetLastError();
  761. if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
  762. else pcilib_error("Failed to create a validation context");
  763. return PCILIB_ERROR_FAILED;
  764. }
  765. err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE);
  766. if (err) {
  767. xmlErrorPtr xmlerr = xmlGetLastError();
  768. if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);
  769. else pcilib_error("Failed to configure the validation context to populate default attributes");
  770. return PCILIB_ERROR_FAILED;
  771. }
  772. return 0;
  773. }
  774. static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
  775. int err;
  776. char *full_name;
  777. xmlDocPtr doc;
  778. xmlXPathContextPtr xpath;
  779. full_name = (char*)alloca(strlen(path) + strlen(name) + 2);
  780. if (!name) {
  781. pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
  782. return PCILIB_ERROR_MEMORY;
  783. }
  784. sprintf(full_name, "%s/%s", path, name);
  785. doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0);
  786. if (!doc) {
  787. xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
  788. if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
  789. else pcilib_error("Error parsing %s", full_name);
  790. return PCILIB_ERROR_INVALID_DATA;
  791. }
  792. err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
  793. if (err) {
  794. xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
  795. xmlFreeDoc(doc);
  796. if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
  797. else pcilib_error("Error validating %s", full_name);
  798. return PCILIB_ERROR_VERIFY;
  799. }
  800. xpath = xmlXPathNewContext(doc);
  801. if (!xpath) {
  802. xmlErrorPtr xmlerr = xmlGetLastError();
  803. xmlFreeDoc(doc);
  804. if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
  805. else pcilib_error("Error creating XPath context for %s", full_name);
  806. return PCILIB_ERROR_FAILED;
  807. }
  808. // This can only partially fail... Therefore we need to keep XML and just return the error...
  809. err = pcilib_xml_process_document(ctx, doc, xpath);
  810. if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
  811. xmlFreeDoc(doc);
  812. xmlXPathFreeContext(xpath);
  813. pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
  814. return PCILIB_ERROR_TOOBIG;
  815. }
  816. ctx->xml.docs[ctx->xml.num_files] = doc;
  817. ctx->xml.xpath[ctx->xml.num_files] = xpath;
  818. ctx->xml.num_files++;
  819. return err;
  820. }
  821. int pcilib_process_xml(pcilib_t *ctx, const char *location) {
  822. int err;
  823. DIR *rep;
  824. struct dirent *file = NULL;
  825. char *model_dir, *model_path;
  826. model_dir = getenv("PCILIB_MODEL_DIR");
  827. if (!model_dir) model_dir = PCILIB_MODEL_DIR;
  828. model_path = (char*)alloca(strlen(model_dir) + strlen(location) + 2);
  829. if (!model_path) return PCILIB_ERROR_MEMORY;
  830. sprintf(model_path, "%s/%s", model_dir, location);
  831. rep = opendir(model_path);
  832. if (!rep) return PCILIB_ERROR_NOTFOUND;
  833. while ((file = readdir(rep)) != NULL) {
  834. size_t len = strlen(file->d_name);
  835. if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
  836. if (file->d_type != DT_REG) continue;
  837. err = pcilib_xml_load_file(ctx, model_path, file->d_name);
  838. if (err) pcilib_error("Error processing XML file %s", file->d_name);
  839. }
  840. closedir(rep);
  841. return 0;
  842. }
  843. /** pcilib_init_xml
  844. * this function will initialize the registers and banks from the xml files
  845. * @param[in,out] ctx the pciilib_t running that gets filled with structures
  846. * @param[in] model the current model of ctx
  847. * @return an error code
  848. */
  849. int pcilib_init_xml(pcilib_t *ctx, const char *model) {
  850. int err;
  851. char *model_dir;
  852. char *xsd_path;
  853. struct stat st;
  854. model_dir = getenv("PCILIB_MODEL_DIR");
  855. if (!model_dir) model_dir = PCILIB_MODEL_DIR;
  856. xsd_path = (char*)alloca(strlen(model_dir) + 16);
  857. if (!xsd_path) return PCILIB_ERROR_MEMORY;
  858. sprintf(xsd_path, "%s/model.xsd", model_dir);
  859. if (stat(xsd_path, &st)) {
  860. pcilib_info("XML models are not present");
  861. return PCILIB_ERROR_NOTFOUND;
  862. }
  863. ctx->xml.parser = xmlNewParserCtxt();
  864. if (!ctx->xml.parser) {
  865. xmlErrorPtr xmlerr = xmlGetLastError();
  866. if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message);
  867. else pcilib_error("Failed to create an XML parser context");
  868. return PCILIB_ERROR_FAILED;
  869. }
  870. err = pcilib_xml_load_xsd(ctx, xsd_path);
  871. if (err) return err;
  872. return pcilib_process_xml(ctx, model);
  873. }
  874. /** pcilib_free_xml
  875. * this function free the xml parts of the pcilib_t running, and some libxml ashes
  876. * @param[in] pci the pcilib_t running
  877. */
  878. void pcilib_free_xml(pcilib_t *ctx) {
  879. int i;
  880. memset(ctx->xml.bank_nodes, 0, sizeof(ctx->xml.bank_nodes));
  881. for (i = 0; i < ctx->num_banks; i++) {
  882. if (ctx->bank_ctx[i])
  883. ctx->bank_ctx[i]->xml = NULL;
  884. }
  885. for (i = 0; i < ctx->num_reg; i++) {
  886. ctx->register_ctx[i].xml = NULL;
  887. }
  888. for (i = 0; i < ctx->xml.num_files; i++) {
  889. if (ctx->xml.docs[i]) {
  890. xmlFreeDoc(ctx->xml.docs[i]);
  891. ctx->xml.docs[i] = NULL;
  892. }
  893. if (ctx->xml.xpath[i]) {
  894. xmlXPathFreeContext(ctx->xml.xpath[i]);
  895. ctx->xml.xpath[i] = NULL;
  896. }
  897. }
  898. ctx->xml.num_files = 0;
  899. if (ctx->xml.validator) {
  900. xmlSchemaFreeValidCtxt(ctx->xml.validator);
  901. ctx->xml.validator = NULL;
  902. }
  903. if (ctx->xml.schema) {
  904. xmlSchemaFree(ctx->xml.schema);
  905. ctx->xml.schema = NULL;
  906. }
  907. if (ctx->xml.parser) {
  908. xmlFreeParserCtxt(ctx->xml.parser);
  909. ctx->xml.parser = NULL;
  910. }
  911. /*
  912. xmlSchemaCleanupTypes();
  913. xmlCleanupParser();
  914. xmlMemoryDump();
  915. */
  916. }
  917. int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val) {
  918. xmlAttr *prop;
  919. xmlChar *str;
  920. prop = xmlHasProp(node, BAD_CAST attr);
  921. if ((!prop)||(!prop->children)) return PCILIB_ERROR_NOTFOUND;
  922. str = prop->children->content;
  923. return pcilib_set_value_from_static_string(ctx, val, (const char*)str);
  924. }