driver-gen/xml-lib: Search for version header files in the correct dir
[driver-gen.git] / utilities.c
blob223677d5123a5c4995150fbbd8112ddd23f38380
1 /**
2 * @file utilities.c
4 * @brief Handy DriverGen functions are located here.
6 * @author Copyright (C) 2004 - 2010 CERN. Georgievskiy Yury <ygeorgie@cern.ch>
8 * @date Created on 27/02/2004
10 * @section license_sec License
11 * Released under the GPL
13 #include <ctype.h>
14 #include <sys/mman.h> /* for mmap cruft */
15 #include "driverGen.h"
16 #include "dit.h"
18 /**
19 * @brief Constructs a string representation of an integer.
21 * @param val -- value to convert
22 * @param base -- base of the value [2 - 16]
24 * Different based are possible (at least was tested for 2, 10, 16).
26 * @return pointer to the string with converted value - if succeed.
27 * @return NULL - if fails.
29 char *itoa(int val, int base)
31 static char buf[34] = { 0 };
32 char *out = &buf[33];
33 int sign = (val < 0) ? sign = -val : val;
35 /* check if the base is valid */
36 if (base < 2 || base > 16)
37 return (NULL);
39 /* base 16 and base 2 cases */
40 if (base == 16 || base == 2) {
41 unsigned int hval = val;
42 unsigned int hbase = base;
43 do {
44 *out = "0123456789abcdef"[hval % hbase];
45 --out;
46 hval /= hbase;
47 } while (hval);
49 if (base == 16) /* apply 0x prefix */
50 *out-- = 'x', *out = '0';
51 else
52 ++out;
54 return (out);
57 /* for all remaining bases */
58 do {
59 *out = "0123456789abcdef"[sign % base];
60 --out;
61 sign /= base;
62 } while (sign);
64 if (val < 0 && base == 10) /* apply negative sign only for base 10 */
65 *out = '-';
66 else
67 ++out;
69 return (out);
72 /**
73 * @brief Convert a string to lower case.
75 * @param string -- string to convert.
77 * @return void
79 void StrToLower(char *string)
81 int i = -1;
83 while (string[++i] != '\0')
84 string[i] = (char)tolower(string[i]);
87 /**
88 * @brief Convert a string to upper case.
90 * @param string -- string to convert
92 * @return void
94 void StrToUpper(char *string)
96 int i = -1;
98 while (string[++i] != '\0')
99 string[i] = (char)toupper(string[i]);
103 * @brief Service function for debug purposes.
105 * @param reginfo -- register description
106 * @param regNum -- register amount
108 * @return void
110 void PrintoutRegInfo(RegisterDef_t * reginfo, int regNum)
112 int cntr;
114 for (cntr = 0; cntr < regNum; cntr++) {
115 printf("----- [%03d] %s -----\n\tblock %d\n\toffset %#x\n"
116 "\tdepth %d (%#x)\n--------------------\n",
117 cntr, reginfo[cntr].name, reginfo[cntr].blockP->blockID,
118 reginfo[cntr].offset, reginfo[cntr].depth,
119 reginfo[cntr].depth);
125 * @brief How many registers does block has
127 * @param reg -- first register in the block
129 * @return register amount
131 static int calc_block_reg_amount(RegisterDef_t *reg)
133 int cntr = 0;
134 int bid = reg->blockP->blockID;
136 while (bid == reg->blockP->blockID) {
137 ++cntr;
138 if (reg->last)
139 break;
140 else
141 ++reg;
144 return cntr;
148 * @brief Get block size in bytes.
150 * @param reg -- first register in the block
151 * @param type -- driver (DRIVER_FT) or simulator (SIM_FT)
153 * Calculate block size, depending on the type (driver/simulator).
154 * If driver -- gaps are taken into account.
155 * If simulator -- there will be no gaps.
157 * @return block size in bytes
159 int calc_block_size(RegisterDef_t *reg, int type)
161 long bsz = 0;
162 int i;
163 int ram = calc_block_reg_amount(reg);
165 /* for simulator -- count size without gaps */
166 if (type == SIM_FT) {
167 for (i = 0; i < ram; i++) {
168 bsz += ((reg[i].depth) ? reg[i].depth : 1) *
169 reg[i].regSize;
171 } else { /* count gaps only for real driver */
172 reg = &reg[ram-1]; /* last block register */
173 bsz = reg->offset + ((reg->depth) ? reg->depth : 1)
174 * reg->regSize;
177 return bsz;
182 * @brief Find out how many gaps does block has.
184 * @param reg -- first register in the block
186 * @return gap amount
188 int calc_block_gap_amount(RegisterDef_t *reg)
190 int gap = 0;
191 int i, addr;
192 RegisterDef_t *preg;
193 int ram = calc_block_reg_amount(reg);
195 if (reg->offset)
196 ++gap;
198 for (i = 1, preg = &reg[i-1], reg = &reg[1]; i < ram;
199 i++, reg++, preg++) {
200 addr = preg->offset + ((preg->depth) ? preg->depth : 1)
201 * preg->regSize;
202 if (reg->offset - addr)
203 ++gap;
206 return gap;
210 * @brief Set block size and block register amount information.
212 * @param regs -- register descr
214 * This function is called after we get and check all info from the DB
215 * in order to set missing information blocks, namely:
216 * 1. block size for the real driver (gap sizes are taken into account)
217 * 2. block size for driver simulator (gaps are not considered)
218 * 3. number of registers in the block.
220 void set_extra_block_data(RegisterDef_t *regs)
222 int ram = 0;
223 RegisterDef_t *ptr;
225 do {
226 ram = calc_block_reg_amount(regs);
227 ptr = &regs[ram-1]; /* 'last register' detection */
228 regs->blockP->blksz_drvr = calc_block_size(regs, DRIVER_FT);
229 regs->blockP->blksz_sim = calc_block_size(regs, SIM_FT);
230 regs->blockP->reg_am = ram;
231 regs += ram; /* move to the first register of next block */
232 } while (!ptr->last);
235 /*! @name BE <-> LE convertion
237 //@{
238 #define _ENDIAN(x) \
239 ({ \
240 typeof(x) __x; \
241 typeof(x) __val = (x); \
242 __endian(&(__val), &(__x), sizeof(__x)); \
243 __x; \
245 //@}
248 * @brief Converts Device Info Table from BE to LE
250 * @param src -- source. Device info table to convert
251 * @param dst -- destanation. If not NULL - converted table goes here.
252 * If NULL - @ref src will be used as destanation.
254 * Info file stores all data in the BE format. It should be converted it LE
255 * in order to be able to use it.
257 * @e NOTE
258 * If dsc is NULL - current info table (in @ref src parameter) will be
259 * overwritten!
261 * @return pointer to LE-converted info table
263 DevInfo_t* convert_dit(DevInfo_t *src, DevInfo_t *dsc)
265 int i;
266 DevInfo_t *res = (dsc)?dsc:src; /* where results will go */
268 /* addr1 member */
269 res->addr1.baseAddr = _ENDIAN(src->addr1.baseAddr);
270 res->addr1.range = _ENDIAN(src->addr1.range);
271 res->addr1.increment = _ENDIAN(src->addr1.increment);
272 res->addr1.dpSize = _ENDIAN(src->addr1.dpSize);
273 res->addr1.addrModif = _ENDIAN(src->addr1.addrModif);
275 /* addr2 member */
276 res->addr2.baseAddr = _ENDIAN(src->addr2.baseAddr);
277 res->addr2.range = _ENDIAN(src->addr2.range);
278 res->addr2.increment = _ENDIAN(src->addr2.increment);
279 res->addr2.dpSize = _ENDIAN(src->addr2.dpSize);
280 res->addr2.addrModif = _ENDIAN(src->addr2.addrModif);
282 res->mtn = _ENDIAN(src->mtn);
283 res->mlun = _ENDIAN(src->mlun);
284 res->debugFlag = _ENDIAN(src->debugFlag);
285 /* 'opaque' is char */
286 res->iLevel = _ENDIAN(src->iLevel);
287 res->iVector = _ENDIAN(src->iVector);
288 res->iVectorInc = _ENDIAN(src->iVectorInc);
289 res->chan = _ENDIAN(src->chan);
290 res->chrindex = _ENDIAN(src->chrindex);
291 res->gen_date = _ENDIAN(src->gen_date);
292 /* 'dg_vers' is char */
293 res->regAmount = _ENDIAN(src->regAmount);
295 for (i = 0; i < res->regAmount; i++) {
296 res->regDesc[i].regId = _ENDIAN(src->regDesc[i].regId);
297 /* 'regName' is char */
298 /* 'busType' is char */
299 res->regDesc[i].regType = _ENDIAN(src->regDesc[i].regType);
300 res->regDesc[i].regSize = _ENDIAN(src->regDesc[i].regSize);
301 /* 'b_a' is char */
302 res->regDesc[i].bid = _ENDIAN(src->regDesc[i].bid);
303 res->regDesc[i].regOffset = _ENDIAN(src->regDesc[i].regOffset);
304 res->regDesc[i].regDepth = _ENDIAN(src->regDesc[i].regDepth);
305 res->regDesc[i].regtl = _ENDIAN(src->regDesc[i].regtl);
306 res->regDesc[i].regar = _ENDIAN(src->regDesc[i].regar);
307 res->regDesc[i].rwIoctlOpNum = _ENDIAN(src->regDesc[i].rwIoctlOpNum);
310 res->maxRegSz = _ENDIAN(src->maxRegSz);
311 res->blkAmount = _ENDIAN(src->blkAmount);
313 for (i = 0; i < res->blkAmount; i++) {
314 res->blkDesc[i].block = _ENDIAN(src->blkDesc[i].block);
315 res->blkDesc[i].blkBaseAddr = _ENDIAN(src->blkDesc[i].blkBaseAddr);
316 res->blkDesc[i].offset = _ENDIAN(src->blkDesc[i].offset);
317 res->blkDesc[i].blksz_drvr = _ENDIAN(src->blkDesc[i].blksz_drvr);
318 res->blkDesc[i].blksz_sim = _ENDIAN(src->blkDesc[i].blksz_sim);
319 res->blkDesc[i].reg_am = _ENDIAN(src->blkDesc[i].reg_am);
322 /* 'checksum' is char */
324 return res;
328 * @brief Open info file with DataBase module description.
330 * Returned pointer should be freed by the caller afterwards!
332 * @param fNm -- info file name to open
333 * Note, that info file is a Big Endian encoded.
335 * @return pointer -- if everything is OK.
336 * NOTE. Should be freed by the caller afterwards.
337 * @return NULL -- failed
339 DevInfo_t* read_info_file(char *fNm)
341 int fd, fSz;
342 struct stat fSt;
343 DevInfo_t *devD, *dit; /* device data from the info file */
345 if ((fd = open(fNm, O_RDONLY)) < 0) {
346 perror("open()");
347 return NULL;
350 fstat(fd, &fSt);
351 fSz = fSt.st_size;
353 devD = mmap(0, fSz, PROT_READ, MAP_SHARED, fd, 0);
354 if (devD == MAP_FAILED) {
355 perror("mmap()");
356 close(fd);
357 return NULL;
360 close(fd); /* we don't need it anymore */
362 dit = calloc(1, sizeof(*dit));
363 /* copy it locally */
364 memmove(dit, devD, sizeof(*devD));
365 munmap(devD, fSz);
367 #ifdef __linux__
368 convert_dit(dit, NULL); /* convert to BE */
369 #endif
370 return dit;
374 * @brief Exploit driver .info file
376 * @param info table to printout.
378 * Useful for debug purposes. User can check if info file contains
379 * correct data.
381 * @return void
384 void exploit_info_file(DevInfo_t * info)
386 int cntr;
387 AddrInfo_t *aiptr = &(info->addr1);
388 REGDESC *rdp = info->regDesc;
389 BLKDESC *bdp = info->blkDesc;
391 printf("\n%s.info file data:\n\n", TranslationGetSysLower());
392 /* general info */
393 printf("+---- general info -----------\n");
394 printf("| 'mtn' => %d\n", info->mtn);
395 printf("| 'mlun' => 0x%x\n", info->mlun);
396 printf("| 'debugFlag' => 0x%X\n", info->debugFlag);
397 printf("| 'opaque' => '%s'\n", info->opaque);
398 printf("| 'iLevel' => %d\n", info->iLevel);
399 printf("| 'iVector' => %d\n", info->iVector);
400 printf("| 'iVectorInc' => %d\n", info->iVectorInc);
401 printf("| 'chan' => %d\n", info->chan);
402 printf("| 'chrindex' => %d\n", info->chrindex);
403 printf("| 'gen_date' => %ld\n", info->gen_date);
404 printf("| 'dg_vers' => '%s'\n", info->dg_vers);
405 printf("| 'regAmount' => %d\n", info->regAmount);
406 printf("| 'maxRegSz' => %d\n", info->maxRegSz);
407 printf("| 'blkAmount' => %d\n", info->blkAmount);
408 printf("| 'checksum' => %d\n", info->checksum);
409 printf("+-----------------------------\n\n");
411 /* 2 address space info */
412 for (cntr = 0; cntr < 2; cntr++) {
413 printf("+-----------------------------\n");
414 printf("| Addr[%d].baseAddr => 0x%lx\n", cntr,
415 aiptr->baseAddr);
416 printf("| Addr[%d].range => 0x%x\n", cntr, aiptr->range);
417 printf("| Addr[%d].increment => 0x%x\n", cntr,
418 aiptr->increment);
419 printf("| Addr[%d].dpSize => %d\n", cntr, aiptr->dpSize);
420 printf("| Addr[%d].addrModif => 0x%x\n", cntr,
421 aiptr->addrModif);
422 printf("+-----------------------------\n\n");
423 aiptr++;
426 /* all block info */
427 for (cntr = 0; cntr < info->blkAmount; cntr++) {
428 printf("+---------------------------------------------\n");
429 printf("| Blk[%d].block => %d\n", cntr, bdp[cntr].block);
430 printf("| Blk[%d].blkBaseAddr => %d\n", cntr,
431 bdp[cntr].blkBaseAddr);
432 printf("| Blk[%d].offset => 0x%lX\n", cntr,
433 bdp[cntr].offset);
434 printf("| Blk[%d].blksz_drvr => %d bytes\n", cntr,
435 bdp[cntr].blksz_drvr);
436 printf("| Blk[%d].blksz_sim => %d bytes\n", cntr,
437 bdp[cntr].blksz_sim);
438 printf("| Blk[%d].reg_am => %d\n", cntr,
439 bdp[cntr].reg_am);
441 printf("+---------------------------------------------\n\n");
444 /* all registers info */
445 for (cntr = 0; cntr < info->regAmount; cntr++) {
446 printf("+---------------------------------------------\n");
447 printf("| Reg[%d].regId => %d\n", cntr, rdp[cntr].regId);
448 printf("| Reg[%d].regName => %s\n", cntr,
449 rdp[cntr].regName);
450 printf("| Reg[%d].busType => %s\n", cntr,
451 rdp[cntr].busType);
452 printf("| Reg[%d].regType => %s (%d)\n", cntr,
453 (rdp[cntr].regType ==
454 RT_REAL) ? "RT_REAL" : (rdp[cntr].regType ==
455 RT_EXTR) ? "RT_EXTR" :
456 "RT_SRVS", rdp[cntr].regType);
457 printf("| Reg[%d].regSize => %d\n", cntr,
458 rdp[cntr].regSize);
459 printf("| Reg[%d].b_a => %s\n", cntr, rdp[cntr].b_a);
460 printf("| Reg[%d].bid => %d\n", cntr, rdp[cntr].bid);
461 printf("| Reg[%d].regOffset => 0x%X\n", cntr,
462 rdp[cntr].regOffset);
463 printf("| Reg[%d].regDepth => %d\n", cntr,
464 rdp[cntr].regDepth);
465 printf("| Reg[%d].regtl => %d\n", cntr, rdp[cntr].regtl);
466 printf("| Reg[%d].regar => %d\n", cntr, rdp[cntr].regar);
467 printf("| Reg[%d].rwIoctlOpNum => 0x%x\n", cntr,
468 rdp[cntr].rwIoctlOpNum);
469 printf("+---------------------------------------------\n\n");
474 char* get_info_fn(void)
476 static char ifn[MAX_STR] = { 0 };
478 if (ifn[0]) /* already initialized */
479 return ifn;
481 snprintf(ifn, sizeof(ifn), "%s/object_%s/%s.info", get_msd(NULL),
482 TranslationGetSysLower(), TranslationGetSysLower());
484 return ifn;
487 char* get_xml_fn(void)
489 static char xfn[MAX_STR] = { 0 };
491 if (xfn[0]) /* already initialized */
492 return xfn;
494 snprintf(xfn, sizeof(xfn), "%s/object_%s/%s.xml", get_msd(NULL),
495 TranslationGetSysLower(), TranslationGetModName());
497 return xfn;