5
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
7
* @details this code was meant to be evolutive as the XML files evolute. In this meaning, most of the xml parsing is realized with XPath expressions(when it was possible), so that changing the xml xould result mainly in changing the XPAth pathes present in the header file. In a case of a change in xml file, variables that need to be changed other than xpathes, will be indicated in the description of the function.
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.
9
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.
11
In case the performance is not good enough, please consider the following : no more configuration file indicating where the files required are, hard code of formulas, and go to complete non evolutive code : get 1 access to xml file and context, and then make recursive descent to get all you need(investigation of libxml2 source code would be so needed to prove it's better to go recursive than just xpath).
11
In case the performance is not good enough, please consider the following : hard code of formulas
13
13
#define _XOPEN_SOURCE 700
62
/**pcilib_xml_get_bank_node_from_register_node
63
* this function get the bank xml node from a standards register xml node in the xml file
64
*@param[in] mynode the register node we want to know the bank
65
*@return the bank node
68
pcilib_xml_get_bank_node_from_register_node(xmlNodePtr mynode){
69
return xmlFirstElementChild(xmlFirstElementChild(mynode->parent->parent));
74
70
/** pcilib_xml_validate
75
71
* function to validate the xml file against the xsd
76
72
* @param[in] xml_filename path to the xml file
125
121
* @param[in] doc the AST of the xml file, used for used lixbml functions
128
pcilib_xml_create_bank(pcilib_register_bank_description_t *mybank, xmlNodePtr mynode, xmlDocPtr doc, pcilib_t* pci){
124
pcilib_xml_create_bank(pcilib_register_bank_description_t *mybank, xmlNodePtr mynode, xmlDocPtr doc, pcilib_t* pci, int err){
135
int k=0, name_found=0;
137
132
cur=mynode->children; /** we place ourselves in the childrens of the bank node*/
149
144
mybank->size=(size_t)strtol((char*)value,&ptr,0);
151
146
}else if(strcasecmp((char*)cur->name,"protocol")==0){
152
while(pci->protocols[k].name!=NULL){
153
if(strcasecmp(pci->protocols[k].name,(char*)value)==0){
154
mybank->protocol=pci->protocols[k].addr;
147
if((mybank->protocol=pcilib_find_register_protocol_by_name(pci,(char*)value))==PCILIB_REGISTER_PROTOCOL_INVALID){
148
mybank->protocol=PCILIB_REGISTER_PROTOCOL_DEFAULT;
160
151
}else if(strcasecmp((char*)cur->name,"read_address")==0){
192
183
if(bar_ok==0) mybank->bar=PCILIB_BAR_NOBAR;
194
while(pci->banks[k].name!=NULL){
195
if(strcasecmp(pci->banks[k].name,mybank->name)==0){
196
mybank->addr=pci->banks[k].addr;
185
k=(int)pcilib_find_register_bank_by_name(pci,mybank->name);
186
if(k==PCILIB_REGISTER_BANK_INVALID){
187
mybank->addr=PCILIB_REGISTER_BANK_DYNAMIC + pci->xml_ctx->nb_new_banks;
188
pci->xml_ctx->nb_new_banks++;
203
mybank->addr=PCILIB_REGISTER_BANK_DYNAMIC + i;
206
pci->xml_banks[k]=mynode;
191
else mybank->addr=pci->banks[k].addr;
194
pci->xml_ctx->xml_banks[k]=mynode;
198
sprintf(buffer,"%i",mybank->addr);
199
printf("buffer %s \n",buffer);
200
xmlNewChild(mynode,NULL, BAD_CAST "address", BAD_CAST buffer);
234
228
if(!(nodesetaddress)) return;
235
229
if(nodesetaddress->nodeNr==0) return;
237
pci->xml_banks=calloc(PCILIB_MAX_REGISTER_BANKS+1,sizeof(xmlNodePtr));
238
if(!(pci->xml_banks)) pcilib_error("can't create bank xml nodes for pcilib_t struct");
231
pci->xml_ctx->xml_banks=calloc(PCILIB_MAX_REGISTER_BANKS+1,sizeof(xmlNodePtr));
232
if(!(pci->xml_ctx->xml_banks)){
233
pcilib_error("can't create bank xml nodes for pcilib_t struct");
240
237
/** for each of the bank nodes, we create the associated structure, and push it in the pcilib environnement*/
241
238
for(i=0;i<nodesetaddress->nodeNr;i++){
242
239
mynode=nodesetaddress->nodeTab[i];
243
pcilib_xml_create_bank(&mybank,mynode,doc, pci);
240
pcilib_xml_create_bank(&mybank,mynode,doc, pci, err);
244
241
pcilib_add_register_banks(pci,1,&mybank);
267
264
* @param[in,out] registers the list of registers in : not ranged out: ranged.
268
265
* @param[in] size the number of registers.
270
void pcilib_xml_arrange_registers(pcilib_register_description_t *registers,int size){
268
pcilib_xml_arrange_registers(pcilib_register_description_t *registers,int size){
271
269
pcilib_register_description_t* temp;
272
270
temp=malloc(size*sizeof(pcilib_register_description_t));
273
271
qsort(registers,size,sizeof(pcilib_register_description_t),pcilib_xml_compare_registers);
275
/**pcilib_get_bank_address_from_register_node
276
*@param[in] node the current register node
279
pcilib_get_bank_address_from_register_node(xmlDocPtr doc, xmlNodePtr node){
280
xmlChar* temp= xmlNodeListGetString(doc,xmlGetLastChild(xmlFirstElementChild(node->parent->parent))->children,1);
277
285
/** pcilib_xml_create_register.
278
286
* this function create a register structure from a xml register node.
279
287
* @param[out] myregister the register we want to create
281
289
* @param[in] doc the AST of the xml file, required for some ibxml2 sub-fonctions
282
290
* @param[in] mynode the xml node to create register from
284
void pcilib_xml_create_register(pcilib_register_description_t *myregister,xmlNodePtr mynode, xmlDocPtr doc, xmlChar* type, pcilib_t* pci){
292
void pcilib_xml_create_register(pcilib_register_description_t *myregister,xmlNodePtr mynode, xmlDocPtr doc,pcilib_register_type_t type, pcilib_t* pci){
288
296
xmlChar *value=NULL;
289
xmlNodePtr bank=NULL;
292
299
/**we get the children of the register xml nodes, that contains the properties for it*/
300
307
if(strcasecmp((char*)cur->name,"address")==0){
301
308
myregister->addr=(pcilib_register_addr_t)strtol((char*)value,&ptr,0);
303
310
}else if(strcasecmp((char*)cur->name,"offset")==0){
304
311
myregister->offset=(pcilib_register_size_t)strtol((char*)value,&ptr,0);
353
360
/** make sure we don't get the description from previous registers*/
354
361
if(i==0) myregister->description=NULL;
357
363
/** we then get properties that can not be parsed as the previous ones*/
358
if(strcasecmp((char*)type,"standard")==0){
364
if((int)type==(int)type_standard){
359
365
myregister->type=PCILIB_REGISTER_STANDARD;
360
bank=pcilib_xml_get_bank_node_from_register_node(mynode);
362
value=xmlNodeListGetString(doc,bank->children,1);
363
if(strcasecmp((char*)bank->name,"name")==0){
371
while(pci->banks[k].name!=NULL){
372
printf("name %s\n",pci->banks[k].name);
373
if(strcasecmp(pci->banks[k].name,(char*)value)==0){
374
myregister->bank=pci->banks[k].addr;
381
}else if(strcasecmp((char*)type,"bits")==0){
366
myregister->bank=(pcilib_register_bank_addr_t)strtol((char*)pcilib_get_bank_address_from_register_node(doc,mynode),&ptr,0);
368
}else if((int)type==(int)type_bits){
382
369
myregister->type=PCILIB_REGISTER_BITS;
384
}else if(strcasecmp((char*)type,"fifo")==0){
371
}else if((int)type==(int)type_fifo){
385
372
/* not implemented yet*/ myregister->type=PCILIB_REGISTER_FIFO;
403
390
xmlXPathContextPtr context;
404
391
pcilib_register_description_t *registers=NULL;
405
392
pcilib_register_description_t myregister;
408
395
context= xmlXPathNewContext(doc);
409
396
if(!(context= xmlXPathNewContext(doc))){
418
405
if(nodesetaddress->nodeNr>0)registers=calloc(nodesetaddress->nodeNr+nodesetsubaddress->nodeNr,sizeof(pcilib_register_description_t));
421
pci->xml_registers=calloc(nodesetaddress->nodeNr+nodesetsubaddress->nodeNr,sizeof(xmlNodePtr));
422
if(!(pci->xml_registers)) pcilib_warning("can't create registers xml nodes in pcilib_t struct");
408
if(pci->xml_ctx->nb_registers==0)
409
pci->xml_ctx->xml_registers=calloc(nodesetaddress->nodeNr+nodesetsubaddress->nodeNr,sizeof(xmlNodePtr));
411
pci->xml_ctx->xml_registers=realloc(pci->xml_ctx->xml_registers,(pci->xml_ctx->nb_registers+nodesetaddress->nodeNr+nodesetsubaddress->nodeNr)*sizeof(xmlNodePtr));
413
if(!(pci->xml_ctx->xml_registers)){
414
pcilib_warning("can't create registers xml nodes in pcilib_t struct: memory allocation failed");
424
418
/** we then iterate through standard registers nodes to create registers structures*/
425
419
for(i=0;i<nodesetaddress->nodeNr;i++){
426
420
mynode=nodesetaddress->nodeTab[i];
427
pcilib_xml_create_register(&myregister,mynode,doc,(xmlChar*)"standard",pci);
421
pcilib_xml_create_register(&myregister,mynode,doc,type_standard,pci);
428
422
registers[i]=myregister;
429
pci->xml_registers[i]=mynode;
423
if(err==0) pci->xml_ctx->xml_registers[pci->xml_ctx->nb_registers+i]=mynode;
434
428
/** we then iterate through bits registers nodes to create registers structures*/
435
429
for(i=0;i<nodesetsubaddress->nodeNr;i++){
436
430
mynode=nodesetsubaddress->nodeTab[i];
437
pcilib_xml_create_register(&myregister,mynode->parent->parent,doc,(xmlChar*)"standard",pci);
438
pcilib_xml_create_register(&myregister,mynode,doc,(xmlChar*)"bits",pci);
431
pcilib_xml_create_register(&myregister,mynode->parent->parent,doc,type_standard,pci);
432
pcilib_xml_create_register(&myregister,mynode,doc,type_bits,pci);
439
433
registers[i+j]=myregister;
440
pci->xml_registers[i+j]=mynode;
434
if(err==0) pci->xml_ctx->xml_registers[pci->xml_ctx->nb_registers+i+j]=mynode;
443
437
/**we arrange the register for them to be well placed for pci-l*/
444
438
pcilib_xml_arrange_registers(registers,nodesetaddress->nodeNr+nodesetsubaddress->nodeNr);
445
439
/**we fille the pcilib_t struct*/
446
440
pcilib_add_registers(pci,nodesetaddress->nodeNr+nodesetsubaddress->nodeNr,registers);
441
pci->xml_ctx->nb_registers+=nodesetaddress->nodeNr+nodesetsubaddress->nodeNr;
469
464
/** we first get the env variable corresponding to the place of the xml files*/
470
465
path=getenv("PCILIB_MODEL_DIR");
472
pcilib_warning("can't find environment variable for xml files");
467
path=PCILIB_MODEL_DIR;
476
470
/** we then open the directory corresponding to the ctx model*/
478
472
sprintf(pwd,"%s%s/",path,model);
479
473
if((rep=opendir(pwd))==NULL){
480
474
pcilib_warning("could not open the directory for xml files: error %i\n",errno);
475
return PCILIB_ERROR_NOTINITIALIZED;
484
478
/** we iterate through the files of the directory, to get the xml files and the xsd file*/
498
492
if(line_xsd==NULL){
499
493
pcilib_warning("no xsd file found");
494
return PCILIB_ERROR_NOTINITIALIZED;
503
497
if(line[0]==NULL){
504
498
pcilib_warning("no xml file found");
499
return PCILIB_ERROR_NOTINITIALIZED;
508
502
/** for each xml file, we validate it, and get the registers and the banks*/
509
503
docs=malloc((i-1)*sizeof(xmlDocPtr));
504
ctx->xml_ctx=malloc(sizeof(pcilib_xml_context_t));
505
ctx->xml_ctx->docs=malloc(sizeof(xmlDocPtr)*(i-1));
506
ctx->xml_ctx->nb_registers=0;
507
ctx->xml_ctx->nb_new_banks=0;
509
if(!(ctx->xml_ctx) || !(ctx->xml_ctx->docs))
510
return PCILIB_ERROR_MEMORY;
510
513
for(k=0;k<i-1;k++){
511
514
if((err=pcilib_xml_validate(line[k],line_xsd))==0){
512
515
if((docs[k]=xmlParseFile(line[k]))){
513
516
pcilib_xml_initialize_banks(ctx,docs[k]);
514
pcilib_xml_initialize_registers(ctx,docs[k]);
516
else pcilib_error("xml document %s not parsed successdfullly\n",line[k]);
517
pcilib_xml_initialize_registers(ctx,docs[k]);
520
pcilib_error("xml document %s not parsed successdfullly\n",line[k]);
519
ctx->xml_context=malloc(sizeof(pcilib_xml_context_t));
520
ctx->xml_context->docs=malloc(sizeof(xmlDocPtr)*(i-1));
521
ctx->xml_context->docs=docs;
526
ctx->xml_ctx->docs=docs;
532
if(err_count>0) return PCILIB_ERROR_NOTINITIALIZED;
531
537
* this function free the xml parts of the pcilib_t running, and some libxml ashes
532
538
* @param[in] pci the pcilib_t running
534
void pcilib_clean_xml(pcilib_t* pci){
540
void pcilib_free_xml(pcilib_t* pci){
536
free(pci->xml_banks);
537
free(pci->xml_registers);
538
free(pci->xml_context);
542
free(pci->xml_ctx->xml_banks);
543
free(pci->xml_ctx->xml_registers);
544
pci->xml_ctx->xml_banks=NULL;
545
pci->xml_ctx->xml_registers=NULL;
539
549
xmlCleanupParser();