/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to pcilib/xml.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-09-10 03:08:04 UTC
  • mfrom: (277.2.17 test_xml)
  • Revision ID: csa@suren.me-20150910030804-djti3wcmk4yubhp7
Initial integration of XML support

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
9
 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.
 
10
 
 
11
 In case the performance is not good enough, please consider the following : hard code of formulas
 
12
 */
 
13
#define _XOPEN_SOURCE 700
 
14
#define _BSD_SOURCE
 
15
#define _DEFAULT_SOURCE
 
16
 
 
17
#include <stdlib.h>
 
18
#include <stdio.h>
 
19
#include <string.h>
 
20
#include <strings.h>
 
21
#include <dirent.h>
 
22
#include <errno.h>
 
23
#include <alloca.h>
 
24
#include <unistd.h>
 
25
#include <sys/types.h>
 
26
#include <sys/stat.h>
 
27
 
 
28
 
 
29
#include <libxml/xmlschemastypes.h>
 
30
#include <libxml/tree.h>
 
31
#include <libxml/parser.h>
 
32
#include <libxml/xpath.h>
 
33
#include <libxml/xpathInternals.h>
 
34
 
 
35
#include "config.h"
 
36
 
 
37
#include "pci.h"
 
38
#include "bank.h"
 
39
#include "register.h"
 
40
#include "xml.h"
 
41
#include "error.h"
 
42
 
 
43
#define BANKS_PATH ((xmlChar*)"/model/banks/bank/bank_description")                                             /**< path to complete nodes of banks.*/
 
44
//#define REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register")                                     /**< all standard registers nodes.*/
 
45
//#define BIT_REGISTERS_PATH ((xmlChar*)"/model/banks/bank/registers/register/registers_bits/register_bits")    /**< all bits registers nodes.*/
 
46
#define REGISTERS_PATH ((xmlChar*)"../registers/register")                      /**< all standard registers nodes.*/
 
47
#define BIT_REGISTERS_PATH ((xmlChar*)"./registers_bits/register_bits")         /**< all bits registers nodes.*/
 
48
 
 
49
static char *pcilib_xml_bank_default_format = "0x%lx";
 
50
 
 
51
typedef struct {
 
52
    pcilib_register_description_t base;
 
53
    pcilib_register_value_t min, max;
 
54
} pcilib_xml_register_description_t;
 
55
 
 
56
/*
 
57
static xmlNodePtr pcilib_xml_get_parent_bank_node(xmlDocPtr doc, xmlNodePtr node) {
 
58
    xmlNodePtr bank_node;
 
59
    bank_node = node->parent->parent;
 
60
        // bank_description is always a first node according to the XSD schema
 
61
    return xmlFirstElementChild(bank_node);
 
62
    
 
63
}
 
64
 
 
65
static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr node) {
 
66
    return node->parent->parent;
 
67
}
 
68
*/
 
69
 
 
70
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) {
 
71
    pcilib_register_description_t *desc = (pcilib_register_description_t*)xml_desc;
 
72
 
 
73
    xmlNodePtr cur;
 
74
    char *value, *name;
 
75
    char *endptr;
 
76
 
 
77
    for (cur = node->children; cur != NULL; cur = cur->next) {
 
78
        if (!cur->children) continue;
 
79
        if (!xmlNodeIsText(cur->children)) continue;
 
80
        
 
81
        name = (char*)cur->name;
 
82
        value = (char*)cur->children->content;
 
83
        if (!value) continue;
 
84
        
 
85
        if (!strcasecmp((char*)name, "address")) {
 
86
            uintptr_t addr = strtol(value, &endptr, 0);
 
87
            if ((strlen(endptr) > 0)) {
 
88
                pcilib_error("Invalid address (%s) is specified in the XML register description", value);
 
89
                return PCILIB_ERROR_INVALID_DATA;
 
90
            }
 
91
            desc->addr = addr;
 
92
        } else if(!strcasecmp(name, "offset")) {
 
93
            int offset = strtol(value, &endptr, 0);
 
94
            if ((strlen(endptr) > 0)||(offset < 0)||(offset > (8 * sizeof(pcilib_register_value_t)))) {
 
95
                pcilib_error("Invalid offset (%s) is specified in the XML register description", value);
 
96
                return PCILIB_ERROR_INVALID_DATA;
 
97
            }
 
98
            desc->offset = (pcilib_register_size_t)offset;
 
99
        } else if (!strcasecmp(name,"size")) {
 
100
            int size = strtol(value, &endptr, 0);
 
101
            if ((strlen(endptr) > 0)||(size <= 0)||(size > (8 * sizeof(pcilib_register_value_t)))) {
 
102
                pcilib_error("Invalid size (%s) is specified in the XML register description", value);
 
103
                return PCILIB_ERROR_INVALID_DATA;
 
104
            }
 
105
            desc->bits = (pcilib_register_size_t)size;
 
106
        } else if (!strcasecmp(name, "default")) {
 
107
            pcilib_register_value_t val  = strtol(value, &endptr, 0);
 
108
            if ((strlen(endptr) > 0)) {
 
109
                pcilib_error("Invalid default value (%s) is specified in the XML register description", value);
 
110
                return PCILIB_ERROR_INVALID_DATA;
 
111
            }
 
112
            desc->defvalue = val;
 
113
        } else if (!strcasecmp(name,"min")) {
 
114
            pcilib_register_value_t min = strtol(value, &endptr, 0);
 
115
            if ((strlen(endptr) > 0)) {
 
116
                pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
 
117
                return PCILIB_ERROR_INVALID_DATA;
 
118
            }
 
119
            xml_desc->min = min;
 
120
        } else if (!strcasecmp(name, "max")) {
 
121
            pcilib_register_value_t max = strtol(value, &endptr, 0);
 
122
            if ((strlen(endptr) > 0)) {
 
123
                pcilib_error("Invalid minimum value (%s) is specified in the XML register description", value);
 
124
                return PCILIB_ERROR_INVALID_DATA;
 
125
            }
 
126
            xml_desc->max = max;
 
127
        } else if (!strcasecmp((char*)name,"rwmask")) {
 
128
            if (!strcasecmp(value, "all")) {
 
129
                desc->rwmask = PCILIB_REGISTER_ALL_BITS;
 
130
            } else if (!strcasecmp(value, "none")) {
 
131
                desc->rwmask = 0;
 
132
            } else {
 
133
                uintptr_t mask = strtol(value, &endptr, 0);
 
134
                if ((strlen(endptr) > 0)) {
 
135
                    pcilib_error("Invalid mask (%s) is specified in the XML register description", value);
 
136
                    return PCILIB_ERROR_INVALID_DATA;
 
137
                }
 
138
                desc->rwmask = mask;
 
139
            }
 
140
        } else if (!strcasecmp(name, "mode")) {
 
141
            if (!strcasecmp(value, "R")) {
 
142
                desc->mode = PCILIB_REGISTER_R;
 
143
            } else if (!strcasecmp(value, "W")) {
 
144
                desc->mode = PCILIB_REGISTER_W;
 
145
            } else if (!strcasecmp(value, "RW")) {
 
146
                desc->mode = PCILIB_REGISTER_RW;
 
147
            } else if (!strcasecmp(value, "W")) {
 
148
                desc->mode = PCILIB_REGISTER_W;
 
149
            } else if (!strcasecmp(value, "RW1C")) {
 
150
                desc->mode = PCILIB_REGISTER_RW1C;
 
151
            } else if (!strcasecmp(value, "W1C")) {
 
152
                desc->mode = PCILIB_REGISTER_W1C;
 
153
            } else {
 
154
                pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
 
155
                return PCILIB_ERROR_INVALID_DATA;
 
156
            }
 
157
        } else if (!strcasecmp(name, "type")) {
 
158
            if (!strcasecmp(value, "fifo")) {
 
159
                desc->type = PCILIB_REGISTER_FIFO;
 
160
            } else {
 
161
                pcilib_error("Invalid register type (%s) is specified in the XML register description", value);
 
162
                return PCILIB_ERROR_INVALID_DATA;
 
163
            }
 
164
        } else if (!strcasecmp(name,"name")) {
 
165
            desc->name = value;
 
166
        } else if (!strcasecmp(name,"description")) {
 
167
            desc->description = value;
 
168
        }
 
169
    }
 
170
 
 
171
    return 0;
 
172
}
 
173
 
 
174
static int pcilib_xml_create_register(pcilib_t *ctx, pcilib_register_bank_t bank, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
 
175
    int err;
 
176
    
 
177
    xmlXPathObjectPtr nodes;
 
178
    xmlNodeSetPtr nodeset;
 
179
 
 
180
    pcilib_xml_register_description_t desc = {{0}};
 
181
    pcilib_xml_register_description_t fdesc;
 
182
    
 
183
    pcilib_register_t reg;
 
184
    
 
185
    desc.base.bank = ctx->banks[bank].addr;
 
186
    desc.base.rwmask = PCILIB_REGISTER_ALL_BITS;
 
187
    desc.base.mode = PCILIB_REGISTER_R;
 
188
    desc.base.type = PCILIB_REGISTER_STANDARD;
 
189
    
 
190
    err = pcilib_xml_parse_register(ctx, &desc, doc, node, &ctx->banks[bank]);
 
191
    if (err) {
 
192
        pcilib_error("Error (%i) parsing an XML register", err);
 
193
        return err;
 
194
    }
 
195
    
 
196
    err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &desc.base, &reg);
 
197
    if (err) {
 
198
        pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, desc.base.name);
 
199
        return err;
 
200
    }
 
201
 
 
202
    ctx->register_ctx[reg].xml = node;    
 
203
    ctx->register_ctx[reg].min = desc.min;
 
204
    ctx->register_ctx[reg].max = desc.max;
 
205
 
 
206
    xpath->node = node;
 
207
    nodes = xmlXPathEvalExpression(BIT_REGISTERS_PATH, xpath);
 
208
    xpath->node = NULL;
 
209
    
 
210
    if (!nodes) {
 
211
        xmlErrorPtr xmlerr = xmlGetLastError();
 
212
 
 
213
        if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BIT_REGISTERS_PATH, xmlerr->code, xmlerr->message);
 
214
        else pcilib_error("Failed to parse XPath expression %s", BIT_REGISTERS_PATH);
 
215
        return PCILIB_ERROR_FAILED;
 
216
    }
 
217
 
 
218
    nodeset = nodes->nodesetval;
 
219
    if (!xmlXPathNodeSetIsEmpty(nodeset)) {
 
220
        int i;
 
221
        
 
222
        for (i = 0; i < nodeset->nodeNr; i++) {
 
223
            memset(&fdesc, 0, sizeof(pcilib_xml_register_description_t));
 
224
 
 
225
            fdesc.base.bank = desc.base.bank;
 
226
            fdesc.base.addr = desc.base.addr;
 
227
            fdesc.base.mode = desc.base.mode;
 
228
            fdesc.base.rwmask = desc.base.rwmask;
 
229
            fdesc.base.type = PCILIB_REGISTER_BITS;
 
230
            
 
231
            err = pcilib_xml_parse_register(ctx, &fdesc, doc, nodeset->nodeTab[i], &ctx->banks[bank]);
 
232
            if (err) {
 
233
                pcilib_error("Error parsing field in the XML register %s", desc.base.name);
 
234
                continue;
 
235
            }
 
236
            
 
237
            err = pcilib_add_registers(ctx, PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE, 1, &fdesc.base, &reg);
 
238
            if (err) {
 
239
                pcilib_error("Error (%i) adding a new XML register (%s) to the model", err, fdesc.base.name);
 
240
                continue;
 
241
            }
 
242
            
 
243
            ctx->register_ctx[reg].xml = nodeset->nodeTab[i];
 
244
            ctx->register_ctx[reg].min = fdesc.min;
 
245
            ctx->register_ctx[reg].max = fdesc.max;
 
246
        }
 
247
    }
 
248
    xmlXPathFreeObject(nodes);
 
249
 
 
250
    return 0;
 
251
}
 
252
 
 
253
static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node) {
 
254
    int err;
 
255
    
 
256
    int override = 0;
 
257
    pcilib_register_bank_description_t desc = {0};
 
258
    pcilib_register_bank_t bank;
 
259
    xmlNodePtr cur;
 
260
    char *value, *name;
 
261
    char *endptr;
 
262
 
 
263
    xmlXPathObjectPtr nodes;
 
264
    xmlNodeSetPtr nodeset;
 
265
 
 
266
 
 
267
    desc.format = pcilib_xml_bank_default_format;
 
268
    desc.addr = PCILIB_REGISTER_BANK_DYNAMIC;
 
269
    desc.bar = PCILIB_BAR_NOBAR;
 
270
    desc.size = 0x1000;
 
271
    desc.protocol = PCILIB_REGISTER_PROTOCOL_DEFAULT;
 
272
    desc.access = 32;
 
273
    desc.endianess = PCILIB_HOST_ENDIAN;
 
274
    desc.raw_endianess = PCILIB_HOST_ENDIAN;
 
275
 
 
276
        // iterate through all children, representing bank properties, to fill the structure
 
277
    for (cur = node->children; cur != NULL; cur = cur->next) {
 
278
        if (!cur->children) continue;
 
279
        if (!xmlNodeIsText(cur->children)) continue;
 
280
        
 
281
        name = (char*)cur->name;
 
282
        value = (char*)cur->children->content;
 
283
        if (!value) continue;
 
284
        
 
285
        if (!strcasecmp(name, "bar")) {
 
286
            char bar = value[0]-'0';
 
287
            if ((strlen(value) != 1)||(bar < 0)||(bar > 5)) {
 
288
                pcilib_error("Invalid BAR (%s) is specified in the XML bank description", value);
 
289
                return PCILIB_ERROR_INVALID_DATA;
 
290
            }
 
291
            desc.bar = (pcilib_bar_t)bar;
 
292
            override = 1;
 
293
        } else if (!strcasecmp(name,"size")) {
 
294
            long size = strtol(value, &endptr, 0);
 
295
            if ((strlen(endptr) > 0)||(size<=0)) {
 
296
                pcilib_error("Invalid bank size (%s) is specified in the XML bank description", value);
 
297
                return PCILIB_ERROR_INVALID_DATA;
 
298
            }
 
299
            desc.size = (size_t)size;
 
300
            override = 1;
 
301
        } else if (!strcasecmp(name,"protocol")) {
 
302
            pcilib_register_protocol_t protocol = pcilib_find_register_protocol_by_name(ctx, value);
 
303
            if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) {
 
304
                pcilib_error("Unsupported protocol (%s) is specified in the XML bank description", value);
 
305
                return PCILIB_ERROR_NOTSUPPORTED;
 
306
            }
 
307
            desc.protocol = ctx->protocols[protocol].addr;
 
308
            override = 1;
 
309
        } else if (!strcasecmp(name,"address")) {
 
310
            uintptr_t addr = strtol(value, &endptr, 0);
 
311
            if ((strlen(endptr) > 0)) {
 
312
                pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
 
313
                return PCILIB_ERROR_INVALID_DATA;
 
314
            }
 
315
            desc.read_addr = addr;
 
316
            desc.write_addr = addr;
 
317
            override = 1;
 
318
        } else if (!strcasecmp(name,"read_address")) {
 
319
            uintptr_t addr = strtol(value, &endptr, 0);
 
320
            if ((strlen(endptr) > 0)) {
 
321
                pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
 
322
                return PCILIB_ERROR_INVALID_DATA;
 
323
            }
 
324
            desc.read_addr = addr;
 
325
            override = 1;
 
326
        } else if (!strcasecmp(name,"write_address")) {
 
327
            uintptr_t addr = strtol(value, &endptr, 0);
 
328
            if ((strlen(endptr) > 0)) {
 
329
                pcilib_error("Invalid address (%s) is specified in the XML bank description", value);
 
330
                return PCILIB_ERROR_INVALID_DATA;
 
331
            }
 
332
            desc.write_addr = addr;
 
333
            override = 1;
 
334
        } else if(strcasecmp((char*)name,"word_size")==0) {
 
335
            int access = strtol(value, &endptr, 0);
 
336
            if ((strlen(endptr) > 0)||(access%8)||(access<=0)||(access>(8 * sizeof(pcilib_register_value_t)))) {
 
337
                pcilib_error("Invalid word size (%s) is specified in the XML bank description", value);
 
338
                return PCILIB_ERROR_INVALID_DATA;
 
339
            }
 
340
            desc.access = access;
 
341
            override = 1;
 
342
        } else if (!strcasecmp(name,"endianess")) {
 
343
            if (!strcasecmp(value,"little")) desc.endianess = PCILIB_LITTLE_ENDIAN;
 
344
            else if (!strcasecmp(value,"big")) desc.endianess = PCILIB_BIG_ENDIAN;
 
345
            else if (!strcasecmp(value,"host")) desc.endianess = PCILIB_HOST_ENDIAN;
 
346
            else {
 
347
                pcilib_error("Invalid endianess (%s) is specified in the XML bank description", value);
 
348
                return PCILIB_ERROR_INVALID_DATA;        
 
349
            }
 
350
            override = 1;
 
351
        } else if (!strcasecmp(name,"format")) {
 
352
            desc.format = value;
 
353
            override = 1;
 
354
        } else if (!strcasecmp((char*)name,"name")) {
 
355
            desc.name = value;
 
356
        } else if (!strcasecmp((char*)name,"description")) {
 
357
            desc.description = value;
 
358
            override = 1;
 
359
        } else if (!strcasecmp((char*)name,"override")) {
 
360
            override = 1;
 
361
        }
 
362
    }
 
363
 
 
364
    err = pcilib_add_register_banks(ctx, override?PCILIB_MODEL_MODIFICATION_FLAG_OVERRIDE:PCILIB_MODEL_MODIFICATION_FLAG_SKIP_EXISTING, 1, &desc, &bank);
 
365
    if (err) {
 
366
        pcilib_error("Error adding register bank (%s) specified in the XML bank description", desc.name);
 
367
        return err;
 
368
    }
 
369
 
 
370
    ctx->xml.bank_nodes[bank] = node;
 
371
    if (ctx->bank_ctx[bank]) {
 
372
        ctx->bank_ctx[bank]->xml = node;
 
373
    }
 
374
 
 
375
    xpath->node = node;
 
376
    nodes = xmlXPathEvalExpression(REGISTERS_PATH, xpath);
 
377
    xpath->node = NULL;
 
378
    
 
379
    if (!nodes) {
 
380
        xmlErrorPtr xmlerr = xmlGetLastError();
 
381
        if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", REGISTERS_PATH, xmlerr->code, xmlerr->message);
 
382
        else pcilib_error("Failed to parse XPath expression %s", REGISTERS_PATH);
 
383
        return PCILIB_ERROR_FAILED;
 
384
    }
 
385
 
 
386
    nodeset = nodes->nodesetval;
 
387
    if (!xmlXPathNodeSetIsEmpty(nodeset)) {
 
388
        int i;
 
389
        for (i = 0; i < nodeset->nodeNr; i++) {
 
390
            err = pcilib_xml_create_register(ctx, bank, xpath, doc, nodeset->nodeTab[i]);
 
391
            if (err) pcilib_error("Error creating XML registers for bank %s", desc.name);
 
392
        }
 
393
    }
 
394
    xmlXPathFreeObject(nodes);
 
395
 
 
396
    return 0;
 
397
}
 
398
 
 
399
 
 
400
/** pcilib_xml_initialize_banks
 
401
 *
 
402
 * function to create the structures to store the banks from the AST
 
403
 * @see pcilib_xml_create_bank
 
404
 * @param[in] doc the AST of the xml file.
 
405
 * @param[in] pci the pcilib_t running, which will be filled
 
406
 */
 
407
static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathContextPtr xpath) {
 
408
    xmlXPathObjectPtr bank_nodes;
 
409
    xmlNodeSetPtr nodeset;
 
410
 
 
411
    bank_nodes = xmlXPathEvalExpression(BANKS_PATH, xpath); 
 
412
    if (!bank_nodes) {
 
413
        xmlErrorPtr xmlerr = xmlGetLastError();
 
414
        if (xmlerr) pcilib_error("Failed to parse XPath expression %s, xmlXPathEvalExpression reported error %d - %s", BANKS_PATH, xmlerr->code, xmlerr->message);
 
415
        else pcilib_error("Failed to parse XPath expression %s", BANKS_PATH);
 
416
        return PCILIB_ERROR_FAILED;
 
417
    }
 
418
 
 
419
 
 
420
    nodeset = bank_nodes->nodesetval;
 
421
    if (!xmlXPathNodeSetIsEmpty(nodeset)) {
 
422
        int i;
 
423
        for (i = 0; i < nodeset->nodeNr; i++) {
 
424
            pcilib_xml_create_bank(ctx, xpath, doc, nodeset->nodeTab[i]);
 
425
        }
 
426
    }
 
427
    xmlXPathFreeObject(bank_nodes);
 
428
    
 
429
    return 0;
 
430
}
 
431
 
 
432
static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
 
433
    int err;
 
434
    
 
435
    xmlSchemaParserCtxtPtr ctxt;
 
436
 
 
437
    /** we first parse the xsd file for AST with validation*/
 
438
    ctxt = xmlSchemaNewParserCtxt(xsd_filename);
 
439
    if (!ctxt) {
 
440
        xmlErrorPtr xmlerr = xmlGetLastError();
 
441
        if (xmlerr) pcilib_error("xmlSchemaNewParserCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
 
442
        else pcilib_error("Failed to create a parser for XML schemas");
 
443
        return PCILIB_ERROR_FAILED;
 
444
    }
 
445
    
 
446
    ctx->xml.schema = xmlSchemaParse(ctxt);
 
447
    if (!ctx->xml.schema) {
 
448
        xmlErrorPtr xmlerr = xmlGetLastError();
 
449
        xmlSchemaFreeParserCtxt(ctxt);
 
450
        if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
 
451
        else pcilib_error("Failed to parse XML schema");
 
452
        return PCILIB_ERROR_INVALID_DATA;
 
453
    }
 
454
    
 
455
    xmlSchemaFreeParserCtxt(ctxt);
 
456
 
 
457
    ctx->xml.validator  = xmlSchemaNewValidCtxt(ctx->xml.schema);
 
458
    if (!ctx->xml.validator) {
 
459
        xmlErrorPtr xmlerr = xmlGetLastError();
 
460
        if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
 
461
        else pcilib_error("Failed to create a validation context");
 
462
        return PCILIB_ERROR_FAILED;
 
463
    }
 
464
    
 
465
    err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE);
 
466
    if (err) {
 
467
        xmlErrorPtr xmlerr = xmlGetLastError();
 
468
        if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);
 
469
        else pcilib_error("Failed to configure the validation context to populate default attributes");
 
470
        return PCILIB_ERROR_FAILED;
 
471
    }
 
472
 
 
473
    return 0;
 
474
}
 
475
 
 
476
static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
 
477
    int err;
 
478
    char *full_name;
 
479
    xmlDocPtr doc;
 
480
    xmlXPathContextPtr xpath;
 
481
 
 
482
    full_name = (char*)alloca(strlen(path) + strlen(name) + 2);
 
483
    if (!name) {
 
484
        pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
 
485
        return PCILIB_ERROR_MEMORY;
 
486
    }
 
487
 
 
488
    sprintf(full_name, "%s/%s", path, name);
 
489
 
 
490
    doc = xmlCtxtReadFile(ctx->xml.parser, full_name, NULL, 0);
 
491
    if (!doc) {
 
492
        xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
 
493
        if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
 
494
        else pcilib_error("Error parsing %s", full_name);
 
495
        return PCILIB_ERROR_INVALID_DATA;
 
496
    }
 
497
 
 
498
    err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
 
499
    if (err) {
 
500
        xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
 
501
        xmlFreeDoc(doc);
 
502
        if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
 
503
        else pcilib_error("Error validating %s", full_name);
 
504
        return PCILIB_ERROR_VERIFY;
 
505
    }
 
506
 
 
507
    xpath = xmlXPathNewContext(doc);
 
508
    if (!xpath) {
 
509
        xmlErrorPtr xmlerr = xmlGetLastError();
 
510
        xmlFreeDoc(doc);
 
511
        if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
 
512
        else pcilib_error("Error creating XPath context for %s", full_name);
 
513
        return PCILIB_ERROR_FAILED;
 
514
    }
 
515
 
 
516
        // This can only partially fail... Therefore we need to keep XML and just return the error...
 
517
    err = pcilib_xml_process_document(ctx, doc, xpath);
 
518
 
 
519
    if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
 
520
        xmlFreeDoc(doc);
 
521
        xmlXPathFreeContext(xpath);
 
522
        pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
 
523
        return PCILIB_ERROR_TOOBIG;
 
524
    }
 
525
 
 
526
    ctx->xml.docs[ctx->xml.num_files] = doc;
 
527
    ctx->xml.xpath[ctx->xml.num_files] = xpath;
 
528
    ctx->xml.num_files++;
 
529
 
 
530
    return err;
 
531
}
 
532
 
 
533
 
 
534
int pcilib_process_xml(pcilib_t *ctx, const char *location) {
 
535
    int err;
 
536
 
 
537
    DIR *rep;
 
538
    struct dirent *file = NULL;
 
539
    char *model_dir, *model_path;
 
540
 
 
541
    model_dir = getenv("PCILIB_MODEL_DIR");
 
542
    if (!model_dir) model_dir = PCILIB_MODEL_DIR;
 
543
 
 
544
    model_path = (char*)alloca(strlen(model_dir) + strlen(location) + 2);
 
545
    if (!model_path) return PCILIB_ERROR_MEMORY;
 
546
 
 
547
    sprintf(model_path, "%s/%s", model_dir, location);
 
548
 
 
549
    rep = opendir(model_path);
 
550
    if (!rep) return PCILIB_ERROR_NOTFOUND;
 
551
 
 
552
    while ((file = readdir(rep)) != NULL) {
 
553
        size_t len = strlen(file->d_name);
 
554
        if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
 
555
        if (file->d_type != DT_REG) continue;
 
556
        
 
557
        err = pcilib_xml_load_file(ctx, model_path, file->d_name);
 
558
        if (err) pcilib_error("Error processing XML file %s", file->d_name);
 
559
    }
 
560
 
 
561
    closedir(rep);
 
562
 
 
563
    return 0;
 
564
}
 
565
 
 
566
 
 
567
/** pcilib_init_xml
 
568
 * this function will initialize the registers and banks from the xml files
 
569
 * @param[in,out] ctx the pciilib_t running that gets filled with structures
 
570
 * @param[in] model the current model of ctx
 
571
 * @return an error code
 
572
 */
 
573
int pcilib_init_xml(pcilib_t *ctx, const char *model) {
 
574
    int err;
 
575
 
 
576
    char *model_dir;
 
577
    char *xsd_path;
 
578
 
 
579
    struct stat st;
 
580
 
 
581
    model_dir = getenv("PCILIB_MODEL_DIR");
 
582
    if (!model_dir) model_dir = PCILIB_MODEL_DIR;
 
583
 
 
584
    xsd_path = (char*)alloca(strlen(model_dir) + 16);
 
585
    if (!xsd_path) return PCILIB_ERROR_MEMORY;
 
586
 
 
587
    sprintf(xsd_path, "%s/model.xsd", model_dir);
 
588
    if (stat(xsd_path, &st)) {
 
589
        pcilib_info("XML models are not present");
 
590
        return PCILIB_ERROR_NOTFOUND;
 
591
    }
 
592
 
 
593
    ctx->xml.parser = xmlNewParserCtxt();
 
594
    if (!ctx->xml.parser) {
 
595
        xmlErrorPtr xmlerr = xmlGetLastError();
 
596
        if (xmlerr) pcilib_error("xmlNewParserCtxt reported error %d (%s)", xmlerr->code, xmlerr->message);
 
597
        else pcilib_error("Failed to create an XML parser context");
 
598
        return PCILIB_ERROR_FAILED;
 
599
    }
 
600
 
 
601
    err = pcilib_xml_load_xsd(ctx, xsd_path);
 
602
    if (err) return err;
 
603
 
 
604
    return pcilib_process_xml(ctx, model);
 
605
}
 
606
 
 
607
/** pcilib_free_xml
 
608
 * this function free the xml parts of the pcilib_t running, and some libxml ashes
 
609
 * @param[in] pci the pcilib_t running
 
610
*/
 
611
void pcilib_free_xml(pcilib_t *ctx) {
 
612
    int i;
 
613
 
 
614
    memset(ctx->xml.bank_nodes, 0, sizeof(ctx->xml.bank_nodes));
 
615
    for (i = 0; i < ctx->num_banks; i++) {
 
616
        if (ctx->bank_ctx[i]) 
 
617
            ctx->bank_ctx[i]->xml = NULL;
 
618
    }
 
619
    
 
620
    for (i = 0; i < ctx->num_reg; i++) {
 
621
        ctx->register_ctx[i].xml = NULL;
 
622
    }
 
623
    
 
624
    for (i = 0; i < ctx->xml.num_files; i++) {
 
625
        if (ctx->xml.docs[i]) {
 
626
            xmlFreeDoc(ctx->xml.docs[i]);
 
627
            ctx->xml.docs[i] = NULL;
 
628
        }
 
629
        if (ctx->xml.xpath[i]) {
 
630
            xmlXPathFreeContext(ctx->xml.xpath[i]);
 
631
            ctx->xml.xpath[i] = NULL;
 
632
        }
 
633
    }
 
634
    ctx->xml.num_files = 0;
 
635
 
 
636
    if (ctx->xml.validator) {
 
637
        xmlSchemaFreeValidCtxt(ctx->xml.validator);
 
638
        ctx->xml.validator = NULL;
 
639
    }
 
640
    
 
641
    if (ctx->xml.schema) {
 
642
        xmlSchemaFree(ctx->xml.schema);
 
643
        ctx->xml.schema = NULL;
 
644
    
 
645
    }
 
646
 
 
647
    if (ctx->xml.parser) {
 
648
        xmlFreeParserCtxt(ctx->xml.parser);
 
649
        ctx->xml.parser = NULL;
 
650
    }
 
651
/*
 
652
    xmlSchemaCleanupTypes();
 
653
    xmlCleanupParser();
 
654
    xmlMemoryDump();
 
655
*/
 
656
}