driver-gen/xml-lib: Search for version header files in the correct dir
[driver-gen.git] / commonGeneration.c
blob23645ca8261e15172ffc8aed2c1381e02f9427a9
1 /**
2 * @file commonGeneration.c
4 * @brief Generates driver files that are common for both, VME and PCI modules.
6 * @author Copyright (C) 2002 CERN. Stuart Baird
7 * @author Copyright (C) 2003 CERN. Alain Gagnaire
8 * @author Copyright (C) 2003 - 2010 CERN. Georgievskiy Yury <ygeorgie@cern.ch>
10 * @date Created on 27/02/2004
12 * @section license_sec License
13 * Released under the GPL
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include "driverGen.h"
18 #include "utilities.h"
20 static void BuildVersionFiles(FILETYPE);
21 static char *GetGeneralSrcDir();
22 static char *GetLocalDrvrDir();
23 static char *GetLocalFcltyDir();
24 static char *GetLocalInclDir();
25 static char *GetLocalLibDir();
26 static char *GetLocalInstDir();
27 static void BuildTestProgHFile(RegisterDef_t *, int);
28 static void BuildTestProgConsts(RegisterDef_t *, int, FILE *);
29 static void BuildTestProgSubMenus(RegisterDef_t *, BlockDef_t *, int, FILE *);
30 static void BuildGeneralHeaderFiles();
31 static void BuildGeneralLibraries();
32 static void BuildGeneralInstallProgram();
33 static void BuildGeneralMakefiles();
34 static void BuildGeneralScripts();
35 static int HasExtraneous(RegisterDef_t *, int);
36 static int HasWriteOnly(RegisterDef_t *, int);
38 /**
39 * @brief TODO. REMOVE! (Still used by drmGeneration.c module)
41 * @param numDevs --
43 * @return void
45 void BuildDescsOLD(int numDevs)
47 FILE *devDescFile;
48 FILE *simDescFile;
49 FILE *opDescFile;
50 int i;
52 devDescFile = OpenFile(DRIVER_FT, LOC_MODSRC, "INST_BI/Dev.desc");
53 simDescFile = OpenFile(SIM_FT, LOC_MODSRC, "INST_BI/Dev.desc");
54 opDescFile = OpenFile(DRIVER_FT, LOC_MODSRC, "INST_BI/.desc");
56 Translate(devDescFile, "common", "descs/devHead.desc");
57 Translate(simDescFile, "common", "descs/simHead.desc");
58 Translate(opDescFile, "common", "descs/opHead.desc");
60 for (i = 0; i < numDevs; i++) {
61 TranslationSetFancyNum(i);
62 TranslationSetPlainNum(i);
63 Translate(devDescFile, "common", "descs/devDef.desc");
64 Translate(simDescFile, "common", "descs/devDef.desc");
65 Translate(opDescFile, "common", "descs/devDef.desc");
68 fclose(devDescFile);
69 fclose(simDescFile);
70 fclose(opDescFile);
73 /**
74 * @brief Create and open for editing file with the specified name <b>name</b>
76 * @param type -- @b DRIVER_FT, @b SIM_FT, @b COMMON_FT or @b EXACT_FT
77 * @param loc -- file path
78 * @param name -- filename
79 * @param ... -- extra parameters in case if filename @e name contains
80 * conversion specification(s)
82 * - 0x0. Parameter 'name' can consist of conversion
83 * specification (e.g. '%s'), that begins with the character '%'.
84 * In this case one should provide additional parameters for each
85 * specification
86 * - 0x1. This function takes into account currently processed
87 * module type (driver or simulator). If it's a driver, than
88 * suffix 'Drvr' will be added to the generated file name. If it's
89 * simulator, than suffix 'Sim' will be added. It also can be
90 * so-called 'EXACT_FT' type In this case file is created with
91 * exact given name, without adding any specific driver or
92 * simulator prefixes or suffixes. If type is COMMON_FT than
93 * only 'driver name' preffix is added (e.g. SharedCibc), but not
94 * driver or simulator suffixes.
95 * - 0x2. Nested directories, where file should be located are
96 * created also. To denote the fact that nested dir(s) are
97 * needed - one should provide their names in the 'name' parameter
98 * (e.g. 'subdir0/subdir1.../subdirN/filename.c'). Directories
99 * subdir0, subdir1, ... subdirN will be created.
100 * - 0x3. Parameter 'loc' points out initial directory, where
101 * file should be located. See definition of type 'localtion' for
102 * more information.
104 * @e Example:\n\n
105 * Consider that driver is <b>SHARED_CIBC</b>. This means that
106 * <sys_lower> is "SharedCibc". Also consider that file name that
107 * you want to generate is 'My.c' (@e name parameter):\n
108 * type == DRIVER_FT. <filename> will be 'SharedCibcMyDrvr.c'\n
109 * type == SIM_FT. <filename> will be 'SharedCibcMySim.c'\n
110 * type == COMMON_FT. <filename> will be 'SharedCibcMy.c\n
111 * type == EXACT_FT. <filename> will be 'My.c'\n\n
112 * Depending on 'loc' (location) param, file will be build in
113 * different directories:\n
114 * <I>LOC_MASTER ~/\$(MASTER_DIR)/<filename></I>\n
115 * <I>LOC_GENERAL ~/\$(MASTER_DIR)/\$(GENERAL_DIR)/<filename></I>\n
116 * <I>LOC_MODSRC ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/<filename></I>\n
117 * <I>LOC_DRVR ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/driver/<filename></I>\n
118 * <I>LOC_FCLTY ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/test/<filename></I>\n
119 * <I>LOC_INCL ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/include/<filename></I>\n
120 * <I>LOC_LIB ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/lib/<filename></I>\n
121 * <I>LOC_INST ~/\$(MASTER_DIR)/\$(DRIVER_DIRECTORY)/install/<filename></I>\n
122 * <I>LOC_EXPLICIT ~/\$(name) - NOT IMPLEMENTED YET!!! TODO
124 * @note In case of <b>LOC_EXPLICIT</b> you should provide complete directory
125 * path in the <b>name</b> parameter. Afterwards, based on the
126 * <b>type</b> parameter filename will be build.
128 * @return FILE pointer - if succeed.
129 * @return NULL - if error occurs.
131 FILE *OpenFile(FILETYPE type, location loc, char *name, ...)
133 va_list ap;
134 char inputName[MAXPATHLEN];
135 char *suffix = NULL, *prefix = NULL, *ptr;
136 int sz;
137 char *curDir;
138 char dirPath[4096];
139 char *dpPtr = dirPath;
140 char *nestDir;
141 FILE *retFd;
143 /* build-up the name first */
144 va_start(ap, name);
145 vsnprintf(inputName, sizeof(inputName), name, ap);
146 va_end(ap);
148 memset(dirPath, 0, sizeof(dirPath));
150 if (type == EXACT_FT) {
151 prefix = strdup(inputName);
152 } else {
153 if (!(suffix = rindex(inputName, '.')))
154 return (NULL); /* wrong name */
156 sz = strlen(inputName) - strlen(suffix);
157 prefix = (char *)calloc((sz + 1), sizeof(char));
158 strncpy(prefix, inputName, sz);
161 switch (loc) {
162 case LOC_MASTER:
163 ptr = get_mid(NULL);
164 break;
165 case LOC_GENERAL:
166 ptr = GetGeneralSrcDir();
167 break;
168 case LOC_MODSRC:
169 ptr = get_msd(NULL);
170 break;
171 case LOC_DRVR:
172 ptr = GetLocalDrvrDir();
173 break;
174 case LOC_FCLTY:
175 ptr = GetLocalFcltyDir();
176 break;
177 case LOC_INCL:
178 ptr = GetLocalInclDir();
179 break;
180 case LOC_LIB:
181 ptr = GetLocalLibDir();
182 break;
183 case LOC_INST:
184 ptr = GetLocalInstDir();
185 break;
186 case LOC_EXPLICIT: /* TODO */
187 break;
188 default:
189 return NULL; /* error */
190 break;
192 strncpy(dirPath, ptr, strlen(ptr));
194 /* Check if nested directories are required */
195 if ((ptr = strrchr(prefix, '/'))) {
196 char tmpBuf[2048];
197 *ptr = 0;
198 nestDir = strdup(prefix); /* copy, to prevent corruption */
199 ptr++;
200 strcpy(tmpBuf, ptr);
201 prefix = realloc(prefix, strlen(ptr) + 1);
202 strcpy(prefix, tmpBuf);
204 dpPtr += strlen(dirPath);
205 *dpPtr = '/';
206 dpPtr++;
208 curDir = strtok(nestDir, "/");
209 while (curDir) { /* create new directories */
210 strcpy(dpPtr, curDir);
211 /* TODO. no buffer overflow check! */
212 dpPtr += strlen(curDir);
213 *dpPtr = '/';
214 dpPtr++;
215 if (MakeSafeDir(dirPath) == -DRIVER_GEN_BAD)
216 return NULL;
217 curDir = strtok(NULL, "/");
219 free(nestDir);
223 struct stat status;
224 char *final_fn = GenerateFilename(type, dirPath, prefix,
225 suffix, NULL);
227 if (!stat(final_fn, &status))
228 /* filename is already exist. We should check
229 access permission rights and change them if
230 needed (as we'll need 'w' access right) */
231 chmod(final_fn, (status.st_mode | S_IWUSR | S_IWGRP));
233 retFd = fopen(final_fn, "w");
234 free(prefix);
237 return retFd;
241 * @brief Generate driver IOCTL numbers
243 * @param registers -- register description
244 * @param numRegisters -- register amount
245 * @param headerFile -- open header file descriptor
247 * @return void
249 void BuildIoctlConsts(RegisterDef_t * registers, int numRegisters,
250 FILE * headerFile)
252 int cntr;
253 int constCounter = 0; /* driver ioctl index */
255 TranslationReset();
257 /* Set first allowed ioctl number for the driver ioctl numbers
258 Keep the name in accordance with
259 templates/common/header/srvFoot.h! */
260 TranslationSetFancyString("_FIRST__IOCTL_");
262 for (cntr = 0; cntr < numRegisters; cntr++) {
263 switch (registers[cntr].rar) {
264 case AMRD: /* 'r' */
265 TranslationSetPlainNum(constCounter++);
266 TranslationSetIoctlConst("GET",
267 registers[cntr].upperName);
268 Translate(headerFile, "common", "header/ioctlConst.h");
269 break;
270 case AMWR: /* 'w' */
271 TranslationSetPlainNum(constCounter++);
272 TranslationSetIoctlConst("GET_HISTORY",
273 registers[cntr].upperName);
274 Translate(headerFile, "common", "header/ioctlConst.h");
276 TranslationSetPlainNum(constCounter++);
277 TranslationSetIoctlConst("SET",
278 registers[cntr].upperName);
279 Translate(headerFile, "common", "header/ioctlConst.h");
280 break;
281 case (AMWR | AMRD): /* 'rw' */
282 case AMEX: /* 'e' */
283 TranslationSetPlainNum(constCounter++);
284 TranslationSetIoctlConst("GET",
285 registers[cntr].upperName);
286 Translate(headerFile, "common", "header/ioctlConst.h");
288 TranslationSetPlainNum(constCounter++);
289 TranslationSetIoctlConst("SET",
290 registers[cntr].upperName);
291 Translate(headerFile, "common", "header/ioctlConst.h");
292 break;
293 default:
294 FATAL_ERR();
295 break;
297 } /* end of 'for' */
299 /* set first allowed user-defined ioctl number */
300 Translate(headerFile, "common", "dummyTemplates/1NewLine");
301 TranslationSetComment("First allowed number for user-defined ioctl");
302 Translate(headerFile, "common", "dummyTemplates/comment");
304 TranslationSetPlainNum(constCounter);
305 TranslationSetIoctlConst("FIRST_USR", "IOCTL");
306 Translate(headerFile, "common", "header/ioctlConst.h");
310 * @brief Generate module topology.
312 * @param type -- driver (DRIVER_FT) or simulator (SIM_FT)
313 * @param registers -- register description
314 * @param numRegisters -- register amount
315 * @param headerFile -- open header file descriptor
317 * Generate a history structure to store values that were written to writeonly
318 * registers, an extraneous structure for extra driver variables, defined by
319 * the user and a structure for each block that has been defined in the design.
321 * @return void
323 void BuildCommonBlocks(int type, RegisterDef_t * registers, int numRegisters,
324 FILE * headerFile)
326 int i;
327 int theGap; /* memory gap size betveen the registers */
328 int endOfBlock;
329 int prevFreeAddr; /* for memory gap computing */
331 TranslationReset();
333 /*--------------------------------------------------------------
334 00. Generate the driver's writeonly structure.
335 --------------------------------------------------------------*/
336 TranslationSetFreeFormat
337 ("keeps last written value of the 'write only' registers");
338 TranslationSetDummyString("");
339 Translate(headerFile, "common", "header/structHead.h");
340 for (i = 0; i < numRegisters; i++) {
341 if (registers[i].rar == AMWR) { /* Is the register writeonly? */
342 TranslationSetRegDepth(registers[i].depth);
343 TranslationSetRegType(registers[i].size);
344 TranslationSetRegName(registers[i].name);
345 if (registers[i].depth <= 1) { /* one register */
346 TranslationSetHexNum(registers[i].offset);
347 TranslationSetFreeFormat("last written value");
348 Translate(headerFile, "common",
349 "header/recordDefScalar.h");
350 } else { /* massive */
351 TranslationSetFreeFormat("last written values");
352 Translate(headerFile, "common",
353 "header/recordDefArray.h");
357 Translate(headerFile, "common", "header/endWriteonly.h");
359 /*-----------------------------------------------------------------
360 01. Generate the driver's extraneous variables structure.
361 -----------------------------------------------------------------*/
362 TranslationSetFreeFormat("user-defined extraneous registers");
363 TranslationSetDummyString("");
364 Translate(headerFile, "common", "header/structHead.h");
365 for (i = 0; i < numRegisters; i++) {
366 if (registers[i].rar == AMEX) { /* is it is extraneous? */
367 TranslationSetRegDepth(registers[i].depth);
368 TranslationSetRegType(registers[i].size);
369 TranslationSetRegName(registers[i].name);
370 if (registers[i].depth <= 1) { /* one register */
371 TranslationSetFreeFormat("user-def reg");
372 Translate(headerFile, "common",
373 "header/recordDefScalar.h");
374 } else { /* massive */
375 TranslationSetFreeFormat("user-def regs");
376 Translate(headerFile, "common",
377 "header/recordDefArray.h");
381 Translate(headerFile, "common", "header/endExtraneous.h");
383 /*------------------------------------------------------
384 02. Generate device memory map topology structures.
385 ------------------------------------------------------*/
386 endOfBlock = TRUE;
387 for (i = 0; i < numRegisters; i++) {
388 if (registers[i].rar != AMEX) {
389 /* exclude extraneous registers */
390 if (endOfBlock) {
391 /* If we just ended a block then we must be
392 starting a new one */
393 TranslationSetFreeFormat
394 ("Blk[#%d]@addr[#%d] Offs 0x%x."
395 " Sz %d bytes. %d reg(s). %d gap(s)",
396 registers[i].blockP->blockID,
397 registers[i].blockP->blkBaseAddr,
398 registers[i].blockP->offset,
399 (type == SIM_FT) ?
400 registers[i].blockP->blksz_sim :
401 registers[i].blockP->blksz_drvr,
402 registers[i].blockP->reg_am,
403 calc_block_gap_amount(&registers[i]));
404 TranslationSetDummyString("volatile");
405 Translate(headerFile, "common",
406 "header/structHead.h");
410 If this is the first register in a block, check that
411 it's offset is 0. If not then insert some dummy
412 records into the structure to take up the spare
413 space.
416 if (type == DRIVER_FT) {
417 /* we need to set gaps only for real driver */
418 if (endOfBlock) {
419 /* If we just ended a block then we
420 must be starting a new one */
421 prevFreeAddr = 0;
422 theGap = registers[i].offset;
423 } else {
424 prevFreeAddr =
425 registers[i - 1].offset +
426 ((registers[i - 1].depth) ?
427 registers[i - 1].depth :
428 1) * registers[i - 1].regSize;
429 theGap =
430 registers[i].offset - prevFreeAddr;
433 if (theGap > 0) {
434 TranslationSetFancyNum(i);
435 TranslationSetRegDepth(theGap);
436 TranslationSetFreeFormat("0x%x - 0x%x",
437 prevFreeAddr,
438 registers[i].
439 offset);
440 Translate(headerFile, "common",
441 "header/dummyRecord.h");
445 /* Produce a record in the structure for our register */
446 TranslationSetRegType(registers[i].size);
447 TranslationSetRegName(registers[i].name);
448 TranslationSetRegDepth(registers[i].depth);
449 if (registers[i].depth <= 1) { /* one register */
450 TranslationSetFreeFormat("0x%x",
451 registers[i].offset);
452 Translate(headerFile, "common",
453 "header/recordDefScalar.h");
454 } else { /* massive */
455 /* register offset (i.e. Base Address) */
456 unsigned int regBA = registers[i].offset;
458 /* last valid massive address (i.e. address
459 of the last register in massive) */
460 unsigned int regLA = regBA +
461 (registers[i].depth - 1) *
462 registers[i].regSize;
463 TranslationSetFreeFormat("0x%x - 0x%x", regBA,
464 regLA);
465 Translate(headerFile, "common",
466 "header/recordDefArray.h");
469 /* Determine whether we should terminate this
470 structure */
471 if (i == numRegisters - 1)
472 endOfBlock = TRUE;
473 else if (registers[i].blockP->blockID !=
474 registers[i + 1].blockP->blockID)
475 endOfBlock = TRUE;
476 else
477 endOfBlock = FALSE;
479 if (endOfBlock) {
480 TranslationSetFancyNum(registers[i].blockP->
481 blockID);
482 if (type == DRIVER_FT)
483 Translate(headerFile, "common",
484 "header/endDrvrBlock.h");
485 else
486 Translate(headerFile, "common",
487 "header/endSimBlock.h");
489 } /* end of 'rar != AMEX' */
490 } /* end of for */
494 * @brief Generate @b DEPRECATED @e IoctlAccess library.
496 * @param registers -- register description
497 * @param numRegisters -- register amount
498 * @param blocks -- block description
499 * @param numBlocks -- block amount
501 * This library enables user to use old-style ioctl calls to access the driver.
503 * @return void
505 void BuildIoctlLibrary(RegisterDef_t * registers, int numRegisters,
506 BlockDef_t * blocks, int numBlocks)
508 int cntr;
509 char accessType[8];
510 FILE *libraryFile;
511 FILE *headerFile;
512 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
514 TranslationReset();
515 libraryFile = OpenFile(COMMON_FT, LOC_LIB, "IoctlAccess.c");
516 headerFile = OpenFile(COMMON_FT, LOC_INCL, "IoctlAccess.h");
518 Translate(libraryFile, bus, "lib/IoctlAccess/head.c");
519 Translate(libraryFile, "common", "lib/ioctlAccess/enableAccess.c");
521 TranslationSetFreeFormat("%s", DG_INC_DIR);
522 Translate(headerFile, bus, "lib/IoctlAccess/headerHead.h");
523 Translate(headerFile, "common", "lib/ioctlAccess/enableAccess.h");
525 /* Generate the get and set functions for each register and write to
526 the library source file, and generate function prototypes for each
527 get and set function and write to the library's header file. */
528 for (cntr = 0; cntr < numRegisters; cntr++) {
529 TranslationSetRegName(registers[cntr].name);
530 TranslationSetRegType(registers[cntr].size);
531 TranslationSetRegDepth(registers[cntr].depth);
533 if (registers[cntr].depth <= 1)
534 strcpy(accessType, "Scalar");
535 else
536 strcpy(accessType, "Array");
538 switch (registers[cntr].rar) {
539 case AMRD: /* 'r' */
540 TranslationSetIoctlConst("GET",
541 registers[cntr].upperName);
542 Translate(libraryFile, "common",
543 "lib/ioctlAccess/get%s.c", accessType);
544 Translate(headerFile, "common",
545 "lib/ioctlAccess/get%s.h", accessType);
546 break;
547 case AMWR: /* 'w' */
548 TranslationSetIoctlConst("GET_HISTORY",
549 registers[cntr].upperName);
550 Translate(libraryFile, "common",
551 "lib/ioctlAccess/getLastHisWo%s.c",
552 accessType);
553 Translate(headerFile, "common",
554 "lib/ioctlAccess/getLastHisWo%s.h",
555 accessType);
557 TranslationSetIoctlConst("SET",
558 registers[cntr].upperName);
559 Translate(libraryFile, "common",
560 "lib/ioctlAccess/set%s.c", accessType);
561 Translate(headerFile, "common",
562 "lib/ioctlAccess/set%s.h", accessType);
563 break;
564 case (AMWR | AMRD): /* 'rw' */
565 case AMEX: /* 'e' */
566 TranslationSetIoctlConst("GET",
567 registers[cntr].upperName);
568 Translate(libraryFile, "common",
569 "lib/ioctlAccess/get%s.c", accessType);
570 Translate(headerFile, "common",
571 "lib/ioctlAccess/get%s.h", accessType);
573 TranslationSetIoctlConst("SET",
574 registers[cntr].upperName);
575 Translate(libraryFile, "common",
576 "lib/ioctlAccess/set%s.c", accessType);
577 Translate(headerFile, "common",
578 "lib/ioctlAccess/set%s.h", accessType);
579 break;
580 default:
581 FATAL_ERR();
582 break;
585 Translate(headerFile, "common", "lib/ioctlAccess/headerFoot.h");
587 fclose(libraryFile);
588 fclose(headerFile);
592 * @brief Builds test program that user will use to test driver/simulator.
594 * @param registers -- register description
595 * @param numRegisters -- register amount
596 * @param blocks -- block description
597 * @param numBlocks -- block amount
599 * @return void
601 void BuildTestProgram(RegisterDef_t * registers, int numRegisters,
602 BlockDef_t * blocks, int numBlocks)
604 FILE *tstFileC = OpenFile(COMMON_FT, LOC_FCLTY, "Test.c");
605 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
606 unsigned int freeEntry = TST_PROG_FIRST_FREE_ENTRY; /* */
607 int count;
608 int i;
610 TranslationReset();
611 /* Generate the needed block size consts and register
612 description strings */
613 BuildTestProgHFile(registers, numRegisters);
614 BuildTestProgConsts(registers, numRegisters, tstFileC);
616 /* Generate the remainder of the head and the start of main */
617 Translate(tstFileC, "common", "testProg/common/testMainBegin.c");
618 Translate(tstFileC, "common", "testProg/testMainMenu.c");
620 /* For each block that's been defined, generate an entry in the
621 program's main menu. */
622 for (count = freeEntry, i = 0; i < numBlocks; i++, count++) {
623 TranslationSetFancyNum(count);
624 TranslationSetPlainNum(blocks[i].blockID);
625 Translate(tstFileC, "common",
626 "testProg/common/mainMenuEntry.c");
629 /* Add the PCI config menu item (in case of DRM usage),
630 and the other common options. */
631 Translate(tstFileC, bus, "testProg/mainMenuFoot.c");
632 Translate(tstFileC, "common", "testProg/mainCaseHead.c");
634 /* Generate the case statements for each of the main menu entries. */
635 for (count = freeEntry, i = 0; i < numBlocks; i++, count++) {
636 TranslationSetFancyNum(blocks[i].blockID);
637 TranslationSetPlainNum(count);
638 Translate(tstFileC, "common", "testProg/common/case.c");
641 TranslationSetPlainNum(count);
642 Translate(tstFileC, bus, "testProg/mainCaseFoot.c");
644 BuildTestProgSubMenus(registers, blocks, numRegisters, tstFileC);
646 fclose(tstFileC);
650 * @brief Generates the makefiles that are used to build the generated
651 * suite of code.
653 * @param none
655 * @return void
657 void BuildMakefiles()
659 FILE *mkfd;
660 char dirPath[MAXPATHLEN] = { 0 };
662 TranslationReset();
664 /* Base Makefile */
665 mkfd = OpenFile(EXACT_FT, LOC_MODSRC, "Makefile.base");
666 Translate(mkfd, "common", "makefiles/Makefile.base");
667 fclose(mkfd);
669 /* Specific Makefile */
670 mkfd = OpenFile(EXACT_FT, LOC_MODSRC, "Makefile.specific");
671 Translate(mkfd, "common", "makefiles/Makefile.specific");
672 fclose(mkfd);
674 /* "Which dirs to compile" Makefile */
675 mkfd = OpenFile(EXACT_FT, LOC_MODSRC, "Makefile");
676 Translate(mkfd, "common", "makefiles/Makefile");
677 fclose(mkfd);
679 /* delivery */
680 mkfd = OpenFile(EXACT_FT, LOC_MODSRC, "deliver.mk");
681 Translate(mkfd, "common", "makefiles/deliver.mk");
682 fclose(mkfd);
684 /* Library Makefile */
685 mkfd = OpenFile(EXACT_FT, LOC_LIB, "Makefile");
686 Translate(mkfd, "common", "makefiles/libModule.mk");
687 fclose(mkfd);
689 /* Driver Makefiles */
690 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "makefiles/drvr-linux.mk");
691 Translate(mkfd, "common", "makefiles/drvr-linux.mk");
692 fclose(mkfd);
694 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "makefiles/drvr-lynx.mk");
695 Translate(mkfd, "common", "makefiles/drvr-lynx.mk");
696 fclose(mkfd);
698 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "makefiles/Kbuild");
699 Translate(mkfd, "common", "makefiles/Kbuild");
700 fclose(mkfd);
702 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "makefiles/drvr-paramount.mk");
703 Translate(mkfd, "common", "makefiles/drvr-paramount.mk");
704 fclose(mkfd);
706 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "Makefile");
707 Translate(mkfd, "common", "makefiles/Makefile.drvr");
708 fclose(mkfd);
710 mkfd = OpenFile(EXACT_FT, LOC_DRVR, "compiledrvr");
711 Translate(mkfd, "common", "makefiles/compiledrvr");
712 fchmod(fileno(mkfd),
713 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH);
714 fclose(mkfd);
716 /* we need this symlink for Kbuild to work */
717 sprintf(dirPath, "%s%s", GetLocalDrvrDir(), "/Kbuild");
718 symlink("makefiles/Kbuild", dirPath);
720 /* Facility (test program) Makefile */
721 mkfd = OpenFile(EXACT_FT, LOC_FCLTY, "Makefile");
722 TranslationSetFreeFormat("%s", DAL_DIR);
723 Translate(mkfd, "common", "makefiles/test.mk");
724 fclose(mkfd);
726 /* Include Makefile */
727 mkfd = OpenFile(EXACT_FT, LOC_INCL, "Makefile");
728 Translate(mkfd, "common", "makefiles/include.mk");
729 fclose(mkfd);
731 /* Install program entry point Makefile */
732 mkfd = OpenFile(EXACT_FT, LOC_INST, "Makefile");
733 TranslationSetFreeFormat("%s", DAL_DIR);
734 Translate(mkfd, "common", "makefiles/installso.mk");
735 fclose(mkfd);
739 * @brief Create (if it was not done yet) main installation directory, where
740 * newly created drivers are located.
742 * @param mdn -- Module Description
743 * If NULL, current master directory name will be returned.
745 * Will be created only *once*. Creates all general-purpose files that should
746 * present in the master diretory (user-part source copy utility for example).
748 * If directory is created already, than no action perfomed exept of returning
749 * the directory name.
751 * @return Main Installation Directory name
753 char *get_mid(struct mdescr *md)
755 static char *mainDir = NULL; /* container */
756 char *cwd = ""; /* current working directory */
757 rstat ret;
759 if (mainDir) /* master dir was already created */
760 return mainDir;
762 /* master dir is not yet created */
763 mainDir = (char *)calloc((strlen(cwd) + strlen(md->mdn) + 2), sizeof(char));
764 sprintf(mainDir, "%s%s", cwd, md->mdn);
766 ret = MakeSafeDir(mainDir);
767 if (ret == -DRIVER_GEN_BAD)
768 exit(EXIT_FAILURE); /* 1 */
770 /* make symlinks to the general utilities
771 (script for copy user-part src code) */
773 struct stat status;
774 char loc_link[128]; /* local utility symlink */
775 char glob_link[128]; /* global utility symlink */
776 char gen_dir[128];
778 sprintf(loc_link, "%s/%s", mainDir, UTIL_CP_USR_PT_LOC);
779 sprintf(glob_link, "%s/%s", mainDir, UTIL_CP_USR_PT_GLOB);
780 sprintf(gen_dir, "%s/%s", mainDir, GENERAL_DIR);
782 if (lstat(glob_link, &status)) /* global symlink doesn't
783 exist */
784 symlink(GenerateFilename(EXACT_FT, DG_DIR_PATH,
785 "scripts/" UTIL_CP_USR_PT_GLOB, NULL, NULL),
786 glob_link);
788 if (!stat(gen_dir, &status))
789 /* we have 'general' dir locally, so create local
790 symlink */
791 if (lstat(loc_link, &status)) /* local symlink doesn't
792 exist */
793 symlink(GenerateFilename
794 (EXACT_FT, GENERAL_DIR,
795 UTIL_CP_USR_PT_GLOB, NULL, NULL),
796 loc_link);
799 return (mainDir);
803 * @brief Get Module Source code Directory.
805 * @param md -- module description
807 * Creates directory, where Driver/Simulator source code of a currently
808 * processed module will be located. If directory is already created, than no
809 * action perfomed exept of returning the directory name.
811 * @return directory name for driver src code.
813 char *get_msd(struct mdescr *md)
815 static char *sourceDir = NULL; /* container */
816 time_t theTime;
817 struct tm *tmPtr;
818 char timeStr[MAX_STR];
819 char *tFmt;
821 if (sourceDir) /* driver source dir is already created */
822 return sourceDir;
824 /* Driver directory is not created yet */
825 time(&theTime);
826 tmPtr = localtime(&theTime);
828 /* obfuscate 'gcc' to bypass warnings about format string */
829 tFmt = "%d%b%G.%Hh%Mm%Ss";
831 strftime(timeStr, sizeof(timeStr), tFmt, tmPtr);
833 sourceDir = (char *)calloc(MAXPATHLEN, sizeof(char));
834 if (md->isgit)
835 snprintf(sourceDir, MAXPATHLEN, "%s/%s",
836 get_mid(NULL), TranslationGetModName());
837 else
838 snprintf(sourceDir, MAXPATHLEN, "%s/%s.%s",
839 get_mid(NULL), TranslationGetModName(), timeStr);
841 if (MakeSafeDir(sourceDir) == -DRIVER_GEN_BAD)
842 exit(EXIT_FAILURE); /* 1 */
844 return sourceDir;
848 * @brief Build the driver's Ioctl routine.
850 * @param registers -- register description
851 * @param numRegisters -- register amount
852 * @param driverFile -- open file descriptor
854 void BuildDrvrSimIoctl(RegisterDef_t * registers, int numRegisters,
855 FILE * driverFile)
857 int cntr;
859 TranslationReset();
860 Translate(driverFile, "common", "driver/ioctl/head.c");
862 /* first, build 'service' registers ioctl */
863 TranslationSetBaseAddr("");
864 for (cntr = 0; cntr < GetSrvRegNum(); cntr++) {
865 TranslationSetRegName(srv_ioctl[cntr].name);
866 switch (srv_ioctl[cntr].rar) {
867 case AMRD: /* 'r' */
868 TranslationSetIoctlConst("GET", srv_ioctl[cntr].name);
869 TranslationSetRegType("get");
870 Translate(driverFile, "common",
871 "driver/ioctl/getSetReg.c");
872 break;
873 case AMWR: /* 'w' */
874 TranslationSetIoctlConst("SET", srv_ioctl[cntr].name);
875 TranslationSetRegType("set");
876 Translate(driverFile, "common",
877 "driver/ioctl/getSetReg.c");
878 break;
879 case (AMWR | AMRD): /* 'rw' */
880 TranslationSetIoctlConst("GET", srv_ioctl[cntr].name);
881 TranslationSetRegType("get");
882 Translate(driverFile, "common",
883 "driver/ioctl/getSetReg.c");
885 TranslationSetIoctlConst("SET", srv_ioctl[cntr].name);
886 TranslationSetRegType("set");
887 Translate(driverFile, "common",
888 "driver/ioctl/getSetReg.c");
889 break;
890 default:
891 TranslationSetIoctlConst("", srv_ioctl[cntr].name);
892 TranslationSetRegType("srv_func");
893 Translate(driverFile, "common",
894 "driver/ioctl/getSetReg.c");
895 break;
899 /* now build-up r/w operations for the normal registers */
900 for (cntr = 0; cntr < numRegisters; cntr++) {
901 TranslationSetRegName(registers[cntr].name);
902 switch (registers[cntr].rar) {
903 case AMRD: /* 'r' read-only reg */
904 TranslationSetIoctlConst("GET",
905 registers[cntr].upperName);
906 TranslationSetBaseAddr("");
907 TranslationSetRegType("get");
908 Translate(driverFile, "common",
909 "driver/ioctl/getSetReg.c");
910 break;
911 case AMWR: /* 'w' write-only reg */
912 TranslationSetIoctlConst("GET_HISTORY",
913 registers[cntr].upperName);
914 TranslationSetBaseAddr("wo_");
915 TranslationSetRegType("get");
916 Translate(driverFile, "common",
917 "driver/ioctl/getSetReg.c");
919 TranslationSetIoctlConst("SET",
920 registers[cntr].upperName);
921 TranslationSetBaseAddr("");
922 TranslationSetRegType("set");
923 Translate(driverFile, "common",
924 "driver/ioctl/getSetReg.c");
925 break;
926 case (AMWR | AMRD): /* 'rw' read/write reg */
927 TranslationSetIoctlConst("GET",
928 registers[cntr].upperName);
929 TranslationSetBaseAddr("");
930 TranslationSetRegType("get");
931 Translate(driverFile, "common",
932 "driver/ioctl/getSetReg.c");
934 TranslationSetIoctlConst("SET",
935 registers[cntr].upperName);
936 TranslationSetBaseAddr("");
937 TranslationSetRegType("set");
938 Translate(driverFile, "common",
939 "driver/ioctl/getSetReg.c");
940 break;
941 case AMEX: /* 'e' extraneous (i.e. w/r) reg */
942 TranslationSetIoctlConst("GET",
943 registers[cntr].upperName);
944 TranslationSetBaseAddr("ex_");
945 TranslationSetRegType("get");
946 Translate(driverFile, "common",
947 "driver/ioctl/getSetReg.c");
949 TranslationSetIoctlConst("SET",
950 registers[cntr].upperName);
951 TranslationSetBaseAddr("ex_");
952 TranslationSetRegType("set");
953 Translate(driverFile, "common",
954 "driver/ioctl/getSetReg.c");
955 break;
956 default:
957 FATAL_ERR();
958 break;
961 Translate(driverFile, "common", "driver/ioctl/foot.c");
965 * @brief Generate the get and set (or r/w) functions
967 * @param registers -- register description
968 * @param numRegisters -- register amount
969 * @param vmeInfo -- @e vme description
971 * Header file with their declaration is also created. This functions are used
972 * by the driver ioctl routine to access hardware registers. @b CH in the name
973 * stands for @e c source file and @e h header file.
975 * @return void
977 void BuildGetSetRegCH(RegisterDef_t * registers, int numRegisters,
978 VmeInfo_t * vmeInfo)
980 FILE *c_fd = OpenFile(COMMON_FT, LOC_DRVR, "GetSetReg.inc.c");
981 FILE *h_fd = OpenFile(COMMON_FT, LOC_INCL, "GetSetReg.h");
982 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
983 char accessType[MIN_STR], *strDps, singularity[16], *rsz;
984 int cntr;
985 long dps; /* address space data port size */
986 char singular_comment_str[256];
987 char *cmt =
988 " These functions are used to deliver register values directly"
989 " to the user\n space.\n\n"
990 " API is the following:\n"
991 " 1 param -- statics table\n\n"
992 " 2 param -- ioctl argument in predefined format:\n"
993 " Massive of 3 elements, each is 4 bytes long.\n"
994 " [0] - user-space address\n"
995 " [1] - number of elements to r/w\n"
996 " [2] - element index, starting from zero\n\n"
997 " In case of service registers -- ioctl arguments"
998 " can vary.\n"
999 " Their amount depends on specific ioctl number.\n"
1000 " See service routines (those are with __SRV__"
1001 " subword)\n"
1002 " for more details on parameter amount.\n\n"
1003 " For example, if this is a repetitive r/w"
1004 " request\n"
1005 " (ioctl number is SRV__REP_REG_RW) then we should"
1006 " have 4 arguments,\n"
1007 " that are packed as follows:\n\n"
1008 " [0] -- ioctl number\n"
1009 " [1] -- user-space address\n"
1010 " [2] -- number of elements to r/w\n"
1011 " [3] -- element index, starting from zero\n\n"
1012 " 3 param -- check r/w bounds (1 - yes, 0 - no)\n"
1013 " valid only in case of Lynx\n"
1014 " 4 param -- repeatedly read register (1 - yes, 0 - no)\n\n\n"
1015 " Bear in mind, that r/w operation results goes diretly to"
1016 " the user space.\n"
1017 " If you want to operate on the HW registers inside the"
1018 " driver -- use\n"
1019 " low-level port operation functions from"
1020 " port_ops_[linux/lynx].h like:\n"
1021 " __inb -- read a byte from a port\n"
1022 " __inw -- read a word from a port\n"
1023 " __in -- lread a long from a port\n"
1024 " __outb -- write a byte to a port\n"
1025 " __outw -- write a word to a port\n"
1026 " __outl -- write a long to a port\n"
1027 " __rep_inb -- read multiple bytes from a port into a"
1028 " buffer\n"
1029 " __rep_inw -- read multiple words from a port into a"
1030 " buffer\n"
1031 " __rep_inl -- read multiple longs from a port into a"
1032 " buffer\n"
1033 " __rep_outb -- write multiple bytes to a port from a buffer\n"
1034 " __rep_outw -- write multiple words to a port from a buffer\n"
1035 " __rep_outl -- write multiple longs to a port from a"
1036 " buffer\n\n"
1037 " These functions are used to r/w HW registers inside the"
1038 " driver.\n"
1039 " Never access registers directly. Use this function to do"
1040 " this.";
1042 Translate(c_fd, "common", "driver/getSetReg/funcDefs.c");
1044 /* ----------> first handle service registers <------------------- */
1046 /* C file */
1047 TranslationSetIntNum(sizeof(time_t));
1048 TranslationSetRegType(srv_ioctl[3].type); /* size of DAL_CONSISTENT
1049 register */
1050 Translate(c_fd, bus, "driver/getSetReg/srvRegOps.c");
1052 /* header file starts */
1053 TranslationSetFancyString("GET_SET_REG");
1054 Translate(h_fd, "common", "header/headerStartEnd/hsModNmStr.h");
1055 TranslationSetComment(cmt);
1057 Translate(h_fd, "common", "dummyTemplates/comment-multiline");
1059 /* srv regs functions declaration */
1060 Translate(h_fd, "common", "dummyTemplates/1NewLine");
1061 TranslationSetComment("Service register operations");
1062 Translate(h_fd, "common", "dummyTemplates/comment");
1063 TranslationSetBaseAddr("");
1064 for (cntr = 0; cntr < GetSrvRegNum(); cntr++) {
1065 TranslationSetRegName(srv_ioctl[cntr].name);
1066 if (srv_ioctl[cntr].rar & AMRD) { /* get register function */
1067 TranslationSetRegType("get");
1068 Translate(h_fd, "common",
1069 "driver/getSetReg/declGetSet.h");
1071 if (srv_ioctl[cntr].rar & AMWR) { /* set register function */
1072 TranslationSetRegType("set");
1073 Translate(h_fd, "common",
1074 "driver/getSetReg/declGetSet.h");
1078 /* ---------------> now handle all module registers <------------- */
1079 for (cntr = 0; cntr < numRegisters; cntr++) {
1080 TranslationSetRegName(registers[cntr].name);
1081 TranslationSetRegType(registers[cntr].size);
1082 TranslationSetRegComm(registers[cntr].comment);
1083 TranslationSetRegLoop(registers[cntr].timeLoop);
1084 TranslationSetFreeFormat("block%02d",
1085 registers[cntr].blockP->blockID);
1087 switch (registers[cntr].regSize) {
1088 case 1:
1089 rsz = "b";
1090 TranslationSetRegSize(8);
1091 break;
1092 case 2:
1093 rsz = "w";
1094 TranslationSetRegSize(16);
1095 break;
1096 case 4:
1097 rsz = "l";
1098 TranslationSetRegSize(32);
1099 break;
1100 case 8:
1101 rsz = "ll";
1102 TranslationSetRegSize(64);
1103 break;
1104 default:
1105 FATAL_ERR();
1106 break;
1109 TranslationSetChar(*rsz); /* set read/write port
1110 operation suffix */
1112 /* manage dataport size */
1113 if (registers[cntr].blockP->blkBaseAddr == 1)
1114 dps = vmeInfo->addr1.dpSize;
1115 else
1116 dps = vmeInfo->addr2.dpSize;
1118 /* set max allowed r/w size */
1119 switch (dps) {
1120 case 8:
1121 strDps = "char";
1122 rsz = "b";
1123 break;
1124 case 16:
1125 strDps = "short";
1126 rsz = "w";
1127 break;
1128 case 32:
1129 strDps = "long";
1130 rsz = "l";
1131 break;
1132 case 64:
1133 strDps = "long long";
1134 rsz = "ll";
1135 break;
1136 default:
1137 fprintf(stderr, "%s Data Port Size is NOT provided in"
1138 " the DB.\n", ERROR_MSG);
1139 FATAL_ERR();
1140 break;
1143 /* singularity comment string format */
1144 #define COMMENT_SINGULAR \
1145 " *\n * @warning Element size of the current register is %d bytes,\n * which is @b BIGGER than Addr[%d] DataPort Size (%d bytes).\n * Will be read/written in parts!\n *"
1147 /* if register size is bigger than Data Port Size, then
1148 register is considered to be singular and will be
1149 read/written in parts. In this case we should adjust
1150 register type and r/w port suffix to the max allowed
1151 (i.e. the data port size) */
1152 if (dps / 8 /*convert to bytes */ < registers[cntr].regSize) {
1153 /* reg type (char, short, long) */
1154 TranslationSetRegType(strDps);
1155 /* read/write port operation suffix */
1156 TranslationSetChar(*rsz);
1159 /* if register size is bigger than MAX data width */
1160 if (registers[cntr].rar & AMEX) {
1161 /* ignore fake external registers */
1162 strcpy(singularity, "Extraneous");
1163 TranslationSetComment(" *");
1164 } else {
1165 if (registers[cntr].regSize * 8 > dps) {
1166 /* build-up singularitiy comment string
1167 for the user */
1168 snprintf(singular_comment_str,
1169 sizeof(singular_comment_str),
1170 COMMENT_SINGULAR,
1171 registers[cntr].regSize,
1172 registers[cntr].blockP->blkBaseAddr,
1173 (int)dps / 8);
1174 strcpy(singularity, "Singular");
1175 TranslationSetComment(singular_comment_str);
1176 } else {
1177 strcpy(singularity, "Normal");
1178 TranslationSetComment(" *");
1182 TranslationSetFancyString(singularity);
1184 /* if this register is a scalar, fifo or an array */
1185 if (registers[cntr].depth <= 1)
1186 strcpy(accessType, "scalar");
1187 else
1188 strcpy(accessType, "array");
1190 /* generate get/set methods depending on the register's
1191 description */
1192 switch (registers[cntr].rar) {
1193 case AMWR: /* 'w' write-only reg */
1194 /* c file */
1195 Translate(c_fd, "common",
1196 "driver/getSetReg/func_comment.c");
1197 Translate(c_fd, "common", "driver/getSetReg/wo_%s.c",
1198 accessType);
1200 /* header file */
1201 Translate(h_fd, "common", "dummyTemplates/1NewLine");
1202 TranslationSetComment(registers[cntr].comment);
1203 Translate(h_fd, "common", "dummyTemplates/comment");
1204 TranslationSetBaseAddr("wo_");
1205 TranslationSetRegType("get");
1206 Translate(h_fd, "common",
1207 "driver/getSetReg/declGetSet.h");
1208 TranslationSetBaseAddr("");
1209 TranslationSetRegType("set");
1210 Translate(h_fd, "common",
1211 "driver/getSetReg/declGetSet.h");
1212 break;
1213 case AMRD: /* 'r' read-only reg */
1214 /* c file */
1215 Translate(c_fd, "common",
1216 "driver/getSetReg/func_comment.c");
1217 Translate(c_fd, "common", "driver/getSetReg/ro_%s.c",
1218 accessType);
1220 /* header file */
1221 Translate(h_fd, "common", "dummyTemplates/1NewLine");
1222 TranslationSetComment(registers[cntr].comment);
1223 Translate(h_fd, "common", "dummyTemplates/comment");
1224 TranslationSetBaseAddr("");
1225 TranslationSetRegType("get");
1226 Translate(h_fd, "common",
1227 "driver/getSetReg/declGetSet.h");
1228 break;
1229 case (AMWR | AMRD): /* 'wr' read/write reg */
1230 /* c file */
1231 Translate(c_fd, "common",
1232 "driver/getSetReg/func_comment.c");
1233 Translate(c_fd, "common", "driver/getSetReg/rw_%s.c",
1234 accessType);
1236 /* header file */
1237 Translate(h_fd, "common", "dummyTemplates/1NewLine");
1238 TranslationSetComment(registers[cntr].comment);
1239 Translate(h_fd, "common", "dummyTemplates/comment");
1240 TranslationSetBaseAddr("");
1241 TranslationSetRegType("get");
1242 Translate(h_fd, "common",
1243 "driver/getSetReg/declGetSet.h");
1244 TranslationSetRegType("set");
1245 Translate(h_fd, "common",
1246 "driver/getSetReg/declGetSet.h");
1247 break;
1248 case AMEX: /* 'e' extraneous reg. They are always r/w */
1249 /* c file */
1250 Translate(c_fd, "common",
1251 "driver/getSetReg/func_comment.c");
1252 Translate(c_fd, "common", "driver/getSetReg/ex_%s.c",
1253 accessType);
1255 /* header file */
1256 Translate(h_fd, "common", "dummyTemplates/1NewLine");
1257 TranslationSetComment(registers[cntr].comment);
1258 Translate(h_fd, "common", "dummyTemplates/comment");
1259 TranslationSetBaseAddr("ex_");
1260 TranslationSetRegType("get");
1261 Translate(h_fd, "common",
1262 "driver/getSetReg/declGetSet.h");
1263 TranslationSetRegType("set");
1264 Translate(h_fd, "common",
1265 "driver/getSetReg/declGetSet.h");
1266 break;
1267 default:
1268 break;
1270 } /* end of 'for(cntr = 0; cntr < numRegisters; cntr++)' */
1272 /* header ends */
1273 TranslationSetFancyString("GET_SET_REG");
1274 Translate(h_fd, "common", "header/headerStartEnd/heModNmStr.h");
1276 fclose(c_fd);
1277 fclose(h_fd);
1281 * @brief Generates src code and header files that are common to all
1282 * Module drivers.
1284 * @param none
1286 * It includes header files, libraries and installation/deinstallation
1287 * programs.
1289 * @return void
1291 void BuildGeneralCode()
1293 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
1295 printf("Building general header files for '%s' modules.\n", bus);
1296 BuildGeneralHeaderFiles();
1298 printf("Building general libraries for '%s' modules.\n", bus);
1299 BuildGeneralLibraries();
1301 printf("Building general install program for '%s' modules.\n", bus);
1302 BuildGeneralInstallProgram();
1304 printf("Building general Makefiles for '%s' modules.\n", bus);
1305 BuildGeneralMakefiles();
1307 /* instantiate scripts */
1308 printf("Instantiate supplementary scripts.\n");
1309 BuildGeneralScripts();
1313 * @brief Generates files and directories, intended for user intervention.
1315 * @param none
1317 * These are so-called <E>user entry points</E>. This is a user part of the
1318 * driver. User is allowed to modify this code if he wants to implement his
1319 * own code. There are several entry points. They are in the driver/simulator,
1320 * in the test program, in the library and in the installation program.
1322 * @return void
1324 void BuildUserPartDrvrCode()
1326 FILE *file;
1327 char *system;
1329 system = TranslationGetModName();
1331 /* 0x0 build user entry points and header files for the driver */
1332 /* c-file for real driver */
1333 //printf("Building %s driver's user-defined entry poins.\n", system);
1334 TranslationSetDriverType("DRVR");
1335 TranslationSetFancyString("Drvr");
1336 TranslationSetChar('D');
1337 file = OpenFile(DRIVER_FT, LOC_DRVR, "%s/%s.c", LOCAL_USER_DIR,
1338 USER_SUBWORD_LEXEME);
1339 Translate(file, "common", "driver/userPart/uepHead.c");
1340 Translate(file, "common", "driver/isr.c"); /* generate empty ISR */
1341 Translate(file, "common", "driver/userPart/uepFoot.c");
1342 fclose(file);
1344 /* h-file for real driver */
1345 file = OpenFile(DRIVER_FT, LOC_INCL, "%s.h", USER_SUBWORD_LEXEME);
1346 Translate(file, "common", "driver/userPart/uep.h");
1347 fclose(file);
1349 /* c-file for driver simulator */
1350 //printf("Building %s simulator's user-defined entry poins.\n", system);
1351 TranslationSetDriverType("SIM");
1352 TranslationSetFancyString("Sim");
1353 TranslationSetChar('S');
1354 file =OpenFile(SIM_FT, LOC_DRVR, "%s/%s.c", LOCAL_USER_DIR,
1355 USER_SUBWORD_LEXEME);
1356 Translate(file, "common", "driver/userPart/uepHead.c");
1357 Translate(file, "common", "driver/isr.c"); /* generate empty ISR */
1358 Translate(file, "common", "driver/userPart/uepFoot.c");
1359 fclose(file);
1361 /* h-file for driver simulator */
1362 file = OpenFile(SIM_FT, LOC_INCL, "%s.h", USER_SUBWORD_LEXEME);
1363 Translate(file, "common", "driver/userPart/uep.h");
1364 fclose(file);
1366 /* add 'readme' file */
1367 file = OpenFile(EXACT_FT, LOC_DRVR, "%s/README.1ST", LOCAL_USER_DIR);
1368 Translate(file, "common", "driver/userPart/warnTemplate.txt");
1369 fclose(file);
1371 /* Driver/Simulator version files */
1372 BuildVersionFiles(DRIVER_FT | SIM_FT);
1374 /* 0x1 now build user entry points in the test programm */
1375 //printf("Building %s files for user-defined test program.\n", system);
1376 file = OpenFile(COMMON_FT, LOC_FCLTY, "%s/%sTest.c", LOCAL_USER_DIR,
1377 USER_SUBWORD_LEXEME);
1378 Translate(file, "common", "testProg/common/userTest.c");
1379 fclose(file);
1381 file = OpenFile(COMMON_FT, LOC_FCLTY, "%s/%sTest.h", LOCAL_USER_DIR,
1382 USER_SUBWORD_LEXEME);
1383 Translate(file, "common", "testProg/common/userTest.h");
1384 fclose(file);
1386 /* 0x2 now build user-defined library framework */
1387 //printf("Building %s files for user-defined access library.\n", system);
1388 file = OpenFile(COMMON_FT, LOC_LIB, "%s/%sAccess.c", LOCAL_USER_DIR,
1389 USER_SUBWORD_LEXEME);
1390 Translate(file, "common", "lib/usrAccess/userDefinedAccess.c");
1391 fclose(file);
1393 file = OpenFile(COMMON_FT, LOC_INCL, "%sAccess.h", USER_SUBWORD_LEXEME);
1394 Translate(file, "common", "lib/usrAccess/userDefinedAccess.h");
1395 fclose(file);
1397 /* 0x3 Install program entry point */
1398 file = OpenFile(EXACT_FT, LOC_INST, "%s/install-so.c", LOCAL_USER_DIR);
1399 Translate(file, "common", "install/usr-install-so.c");
1400 fclose(file);
1404 * @brief Generates filename based on directory name, filename itself and file
1405 * extension.
1407 * @param type -- Driver, Simulator, common or exact
1408 * @param root -- full directory path
1409 * @param name -- filename
1410 * @param ext -- file extension (i.e. '.h' '.c' etc.)
1411 * @param ret -- where to put the results (if not NULL)
1413 * It also takes in account if it is a driver or driver simulator.\n
1414 * For example if @e type is @b SIM_FT, @b root is @b $HOME/tmp, @e name is
1415 * @b Myname and @e ext is @b .h, than generated filename will be
1416 * @b "$HOME/tmp/<sys_lower>MynameSim.h".\n
1417 * If @e type is @b EXACT_FT than it just generates file with name @b name
1418 * without taking in account if this is a drvr or sim.
1420 * @return Generated filename.
1422 char *GenerateFilename(FILETYPE type, char *root, char *name, char *ext,
1423 char *ret)
1425 static char fn[MAXPATHLEN];
1427 if (type == DRIVER_FT) /* driver */
1428 snprintf(fn, MAXPATHLEN, "%s/%s%sDrvr%s", root,
1429 TranslationGetSysLower(), name, ext);
1430 else if (type == SIM_FT) /* driver simulator */
1431 snprintf(fn, MAXPATHLEN, "%s/%s%sSim%s", root,
1432 TranslationGetSysLower(), name, ext);
1433 else if (type == COMMON_FT) /* common for driver and simulator */
1434 snprintf(fn, MAXPATHLEN, "%s/%s%s%s", root,
1435 TranslationGetSysLower(), name, ext);
1436 else /* file with exact given name
1437 (i.e. type == EXACT_FT) */
1438 snprintf(fn, MAXPATHLEN, "%s/%s", root, name);
1440 #ifdef _VERBOSE_
1441 printf("%s(): Generated filename is-> %s\n", __FUNCTION__, fn);
1442 #endif
1444 if (ret) {
1445 strcpy(ret, fn);
1446 return ret;
1447 } else {
1448 return fn;
1453 * @brief Create version files for real and simulator driver.
1455 * @param ft -- what to build
1457 * @return void
1459 static void BuildVersionFiles(FILETYPE ft)
1461 FILE *file;
1463 if (ft & DRIVER_FT) {
1464 TranslationSetDriverType("DRVR");
1465 TranslationSetFancyString("Driver");
1466 file = OpenFile(DRIVER_FT, LOC_INCL, "%s.h", "Version");
1467 Translate(file, "common", "driver/userPart/uepVers.h");
1468 fclose(file);
1471 if (ft & SIM_FT) {
1472 TranslationSetDriverType("SIM");
1473 TranslationSetFancyString("Simulator");
1474 file = OpenFile(SIM_FT, LOC_INCL, "%s.h", "Version");
1475 Translate(file, "common", "driver/userPart/uepVers.h");
1476 fclose(file);
1481 * @brief Returns directory name for shared source code of VME/PCI buses.
1483 * @param none
1485 * @return Shared source code directory name (GENERAL_DIR).
1487 static char *GetGeneralSrcDir()
1489 static char *shDir = NULL;
1490 char *mid; /* master install dir */
1492 if (shDir) /* directory is already created, so return */
1493 return (shDir);
1495 mid = get_mid(NULL);
1496 shDir = (char *)calloc((strlen(mid) + strlen(GENERAL_DIR) + 2),
1497 sizeof(char));
1498 sprintf(shDir, "%s/%s", mid, GENERAL_DIR);
1500 if (MakeSafeDir(shDir) == -DRIVER_GEN_BAD)
1501 exit(EXIT_FAILURE); /* 1 */
1503 return shDir;
1507 * @brief local driver diectory name container.
1509 * @param none
1511 * @return local driver diectory name (LOCAL_DRVR_DIR).
1513 static char *GetLocalDrvrDir()
1515 static char *drvrDir = NULL;
1516 char *cmd; /* current module directory */
1518 if (drvrDir) /* directory is already created, so return */
1519 return (drvrDir);
1521 /* directory is not created yet. So DO it. */
1522 cmd = get_msd(NULL);
1523 drvrDir = (char *)calloc((strlen(cmd) + strlen(LOCAL_DRVR_DIR) + 2),
1524 sizeof(char));
1525 sprintf(drvrDir, "%s/%s", cmd, LOCAL_DRVR_DIR);
1527 if (MakeSafeDir(drvrDir) == -DRIVER_GEN_BAD)
1528 exit(EXIT_FAILURE); /* 1 */
1530 return drvrDir;
1534 * @brief local facility directory name container.
1536 * @param none
1538 * @return local facility directory name (LOCAL_FCLTY_DIR).
1540 static char *GetLocalFcltyDir()
1542 static char *fcltyDir = NULL;
1543 char *cmd; /* current module directory */
1545 if (fcltyDir) /* directory is already created, so return */
1546 return (fcltyDir);
1548 /* directory is not created yet. So DO it. */
1549 cmd = get_msd(NULL);
1550 fcltyDir = (char *)calloc((strlen(cmd) + strlen(LOCAL_FCLTY_DIR) + 2),
1551 sizeof(char));
1552 sprintf(fcltyDir, "%s/%s", cmd, LOCAL_FCLTY_DIR);
1554 if (MakeSafeDir(fcltyDir) == -DRIVER_GEN_BAD)
1555 exit(EXIT_FAILURE); /* 1 */
1557 return fcltyDir;
1561 * @brief local include directory name container.
1563 * @param none
1565 * @return local include directory name (LOCAL_INCL_DIR).
1567 static char *GetLocalInclDir()
1569 static char *inclDir = NULL;
1570 char *cmd; /* current module directory */
1572 if (inclDir) /* directory is already created, so return */
1573 return (inclDir);
1575 /* directory is not created yet. So DO it. */
1576 cmd = get_msd(NULL);
1577 inclDir = (char *)calloc((strlen(cmd) + strlen(LOCAL_INCL_DIR) + 2),
1578 sizeof(char));
1579 sprintf(inclDir, "%s/%s", cmd, LOCAL_INCL_DIR);
1581 if (MakeSafeDir(inclDir) == -DRIVER_GEN_BAD)
1582 exit(EXIT_FAILURE); /* 1 */
1584 return (inclDir);
1588 * @brief local library directory name container.
1590 * @param none
1592 * @return local library directory name (LOCAL_LIB_DIR).
1594 static char *GetLocalLibDir()
1596 static char *libDir = NULL;
1597 char *cmd; /* current module directory */
1599 if (libDir) /* directory is already created, so return */
1600 return (libDir);
1602 /* directory is not created yet. So DO it. */
1603 cmd = get_msd(NULL);
1604 libDir = (char *)calloc((strlen(cmd) + strlen(LOCAL_LIB_DIR) + 2),
1605 sizeof(char));
1606 sprintf(libDir, "%s/%s", cmd, LOCAL_LIB_DIR);
1608 if (MakeSafeDir(libDir) == -DRIVER_GEN_BAD)
1609 exit(EXIT_FAILURE); /* 1 */
1611 return libDir;
1615 * @brief installation entry point directory name container.
1617 * @param none
1619 * @return installation directory name (LOCAL_INST_DIR).
1621 static char *GetLocalInstDir()
1623 static char *instDir = NULL;
1624 char *cmd; /* current module directory */
1626 if (instDir) /* directory is already created, so return */
1627 return instDir;
1629 /* directory is not created yet. So DO it. */
1630 cmd = get_msd(NULL);
1631 instDir = (char *)calloc((strlen(cmd) + strlen(LOCAL_INST_DIR) + 2),
1632 sizeof(char));
1633 sprintf(instDir, "%s/%s", cmd, LOCAL_INST_DIR);
1635 if (MakeSafeDir(instDir) == -DRIVER_GEN_BAD)
1636 exit(EXIT_FAILURE); /* 1 */
1638 return instDir;
1642 * @brief Creates directory named @e dirName
1644 * @param dirName -- directory name
1646 * @return -DRIVER_GEN_BAD - in case of error.
1647 * @return DRIVER_GEN_OK - if directory is created.
1648 * @return DRIVER_GEN_EXIST - if directory already exist.
1650 rstat MakeSafeDir(char *dirName)
1652 struct stat status;
1653 rstat ret;
1655 if (!dirName)
1656 return DRIVER_GEN_BAD;
1658 if (stat(dirName, &status)) { /* directory doesn't exist - so create */
1659 umask(0002); /* set tmp mask for dir creation */
1660 if (mkdir(dirName, 0777)) {
1661 ERR_POS("mkdir");
1662 return DRIVER_GEN_BAD;
1664 ret = DRIVER_GEN_OK;
1665 } else /* directory already exist */
1666 ret = DRIVER_GEN_EXIST;
1668 #ifdef _VERBOSE_
1669 printf("%s() Created directory name is: %s\n", __func__, dirName);
1670 #endif
1672 return ret;
1676 * @brief
1678 * @param registers -- register description
1679 * @param numRegisters -- register amount
1681 * @return void
1683 static void BuildTestProgHFile(RegisterDef_t * registers, int numRegisters)
1685 FILE *tstFileH;
1686 int endOfBlock = FALSE;
1687 int i, count = 0, blockcntr = 0, exNum = 0, woNum = 0;
1689 TranslationReset();
1690 tstFileH = OpenFile(COMMON_FT, LOC_FCLTY, "Test.h");
1692 /* Generate the first portion of the test program */
1693 TranslationSetFreeFormat("%s", DG_INC_DIR);
1694 Translate(tstFileH, "common", "testProg/common/headerHead.h");
1696 /* Generate the '*NUM_REGISTERS' constants, there
1697 should be one for each block that has been defined. */
1698 count = 0;
1699 for (i = 0; i < numRegisters; i++) {
1700 count++;
1701 if (i == numRegisters - 1)
1702 endOfBlock = TRUE;
1703 else if (registers[i].blockP->blockID !=
1704 registers[i + 1].blockP->blockID)
1705 endOfBlock = TRUE;
1706 else
1707 endOfBlock = FALSE;
1709 if (endOfBlock) {
1710 blockcntr++; /* block counter */
1711 TranslationSetFancyNum(registers[i].blockP->blockID);
1712 TranslationSetPlainNum(count);
1713 Translate(tstFileH, "common",
1714 "testProg/common/numReg.h");
1715 count = 0;
1717 if (registers[i].rar == AMEX)
1718 exNum++;
1719 if (registers[i].rar == AMWR)
1720 woNum++;
1723 /* Generate tentative function decls. to suppess any
1724 possible warnings */
1725 TranslationSetPlainNum(exNum);
1726 TranslationSetRegDepth(GetSrvRegNum());
1727 TranslationSetPrecision(woNum);
1728 Translate(tstFileH, "common", "testProg/common/tentativeDecl.h");
1729 Translate(tstFileH, "common", "testProg/serviceMenuHead.h");
1730 Translate(tstFileH, "common", "testProg/common/extraneousMenuHead.h");
1731 Translate(tstFileH, "common", "testProg/writeOnlyMenuHead.h");
1732 for (i = 0; i < blockcntr; i++) {
1733 TranslationSetFancyNum(i);
1734 Translate(tstFileH, "common",
1735 "testProg/common/blockMenuHead.h");
1738 Translate(tstFileH, "common", "testProg/common/headerFoot.h");
1739 fclose(tstFileH);
1743 * @brief Generates the first portion of the driver's test program.
1745 * @param registers -- register description
1746 * @param numRegisters -- register amount
1747 * @param testFile -- open file descriptor
1749 * Namely the #includes, #defines and the arrays of strings containing
1750 * register comments.
1752 * @return void
1754 static void BuildTestProgConsts(RegisterDef_t * registers, int numRegisters,
1755 FILE * testFile)
1757 int endOfBlock = FALSE;
1758 int i;
1760 TranslationReset();
1761 Translate(testFile, "common", "testProg/common/testHead.c");
1763 /*------------------------------------------------------------------
1764 00. Generate the register comments string arrays. There should be
1765 an array of string for each defined block
1766 -----------------------------------------------------------------*/
1767 endOfBlock = TRUE;
1768 for (i = 0; i < numRegisters; i++)
1769 if (registers[i].rar != AMEX) {
1770 /* exclude extraneous registers */
1771 TranslationSetFancyNum(registers[i].blockP->blockID);
1772 TranslationSetRegName(registers[i].name);
1773 TranslationSetRegComm(registers[i].comment);
1775 /* If we've just ended a block then this must be
1776 the start of a new one */
1777 if (endOfBlock)
1778 Translate(testFile, "common",
1779 "testProg/common/blockDefHead.c");
1780 Translate(testFile, "common",
1781 "testProg/common/regData.c");
1783 /* Is this the end of a block? */
1784 if (i == numRegisters - 1)
1785 endOfBlock = TRUE;
1786 else if (registers[i].blockP->blockID !=
1787 registers[i + 1].blockP->blockID)
1788 endOfBlock = TRUE;
1789 else
1790 endOfBlock = FALSE;
1792 if (endOfBlock)
1793 Translate(testFile, "common",
1794 "dummyTemplates/endOfBraces");
1797 /*----------------------------------------------------------------
1798 01. Generate the comments string for the extraneous registers.
1799 ----------------------------------------------------------------*/
1800 Translate(testFile, "common", "testProg/common/extraneousDefHead.c");
1801 for (i = 0; i < numRegisters; i++)
1802 if (registers[i].rar == AMEX) { /* is it is extraneous? */
1803 TranslationSetRegName(registers[i].name);
1804 TranslationSetRegComm(registers[i].comment);
1805 Translate(testFile, "common",
1806 "testProg/common/regData.c");
1808 Translate(testFile, "common", "dummyTemplates/endOfBraces");
1810 /*----------------------------------------------------------------
1811 02. Generate the comments string for the writeOnly registers.
1812 ----------------------------------------------------------------*/
1813 Translate(testFile, "common", "testProg/writeOnlyDefHead.c");
1814 for (i = 0; i < numRegisters; i++)
1815 if (registers[i].rar == AMWR) { /* is it is writeOnly? */
1816 TranslationSetRegName(registers[i].name);
1817 TranslationSetRegComm(registers[i].comment);
1818 Translate(testFile, "common",
1819 "testProg/common/regData.c");
1821 Translate(testFile, "common", "dummyTemplates/endOfBraces");
1823 /*-------------------------------------------------------------
1824 03. Generate the comments string for Service Registers.
1825 -------------------------------------------------------------*/
1826 Translate(testFile, "common", "testProg/serviceDefHead.c");
1827 for (i = 0; i < GetSrvRegNum(); i++) {
1828 TranslationSetRegName(srv_ioctl[i].name);
1829 TranslationSetRegComm(srv_ioctl[i].comment);
1830 Translate(testFile, "common", "testProg/common/regData.c");
1832 Translate(testFile, "common", "dummyTemplates/endOfBraces");
1836 * @brief Generate the last portion of the driver's test program.
1838 * @param registers -- register description
1839 * @param blocks -- block description
1840 * @param numRegisters -- register amount
1841 * @param testFile -- open file descriptor
1843 * It produces a sub menu for each of the defined blocks and for the extraneous
1844 * variables block.
1846 * @return void
1848 static void BuildTestProgSubMenus(RegisterDef_t * registers,
1849 BlockDef_t * blocks, int numRegisters,
1850 FILE * testFile)
1852 int i, j, count, blockStart, endOfBlock;
1854 TranslationReset();
1856 /*=================00. Generate WriteOnly Registers sub menu.==============*/
1857 Translate(testFile, "common", "testProg/writeOnlyMenuHead.c");
1858 if (!HasWriteOnly(registers, numRegisters))
1859 Translate(testFile, "common", "testProg/writeOnlyNO.c");
1860 else {
1861 /* Add a menu item for each extraneous variable that's
1862 been defined */
1863 Translate(testFile, "common", "testProg/common/menuHead.c");
1864 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1866 for (i = 0; i < numRegisters; i++)
1867 if (registers[i].rar == AMWR) {
1868 /* is it is writeOnly reg? */
1869 TranslationSetRegName(registers[i].name);
1871 /* read */
1872 TranslationSetPlainNum(count++);
1873 Translate(testFile, "common",
1874 "testProg/common/menuReadEntry.c");
1877 Translate(testFile, "common", "testProg/common/menuFoot.c");
1878 Translate(testFile, "common", "testProg/writeOnlyCaseHead.c");
1879 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1881 for (i = 0; i < numRegisters; i++)
1882 if (registers[i].rar == AMWR) {
1883 /* is it is writeOnly? */
1884 TranslationSetRegId(registers[i].upperName);
1886 /* read */
1887 TranslationSetPlainNum(count++);
1888 TranslationSetFancyString("Get");
1889 Translate(testFile, "common",
1890 "testProg/common/caseGetSet.c");
1892 Translate(testFile, "common", "testProg/common/caseEnd.c");
1895 /*=================01. Generate Extraneous Variable sub menu.==============*/
1896 Translate(testFile, "common", "testProg/common/extraneousMenuHead.c");
1897 if (!HasExtraneous(registers, numRegisters))
1898 /* If there were not any extraneous variables then generate
1899 code to alert the test program's user that there aren't any
1900 extra variables. If there were extraneous variables then
1901 produce the case statments that should accompany the menu
1902 items. */
1903 Translate(testFile, "common", "testProg/common/extraneousNO.c");
1904 else {
1905 /* Add a menu item for each extraneous variable that's been
1906 defined */
1907 Translate(testFile, "common", "testProg/common/menuHead.c");
1908 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1910 for (i = 0; i < numRegisters; i++)
1911 if (registers[i].rar == AMEX) {
1912 /* is it is extraneous? */
1913 TranslationSetRegName(registers[i].name);
1915 /* read */
1916 TranslationSetPlainNum(count++);
1917 Translate(testFile, "common",
1918 "testProg/common/menuReadEntry.c");
1920 /* write */
1921 TranslationSetPlainNum(count++);
1922 Translate(testFile, "common",
1923 "testProg/common/menuWriteEntry.c");
1925 Translate(testFile, "common", "testProg/common/menuFoot.c");
1926 Translate(testFile, "common",
1927 "testProg/common/extraneousCaseHead.c");
1928 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1930 for (i = 0; i < numRegisters; i++)
1931 if (registers[i].rar == AMEX) {
1932 /* is it is extraneous? */
1933 TranslationSetRegId(registers[i].upperName);
1935 /* read */
1936 TranslationSetPlainNum(count++);
1937 TranslationSetFancyString("Get");
1938 Translate(testFile, "common",
1939 "testProg/common/caseGetSet.c");
1941 /* write */
1942 TranslationSetPlainNum(count++);
1943 TranslationSetFancyString("Set");
1944 Translate(testFile, "common",
1945 "testProg/common/caseGetSet.c");
1947 Translate(testFile, "common", "testProg/common/caseEnd.c");
1950 /*=========02. Generate Service Registers sub menu.====================*/
1951 Translate(testFile, "common", "testProg/serviceMenuHead.c");
1952 Translate(testFile, "common", "testProg/common/menuHead.c");
1953 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1955 for (i = 0; i < GetSrvRegNum(); i++) {
1956 TranslationSetRegName(srv_ioctl[i].name);
1957 switch (srv_ioctl[i].rar) {
1958 case AMRD: /* 'r' */
1959 TranslationSetPlainNum(count++);
1960 Translate(testFile, "common",
1961 "testProg/common/menuReadEntry.c");
1962 break;
1963 case AMWR: /* 'w' */
1964 TranslationSetPlainNum(count++);
1965 Translate(testFile, "common",
1966 "testProg/common/menuWriteEntry.c");
1967 break;
1968 case (AMRD | AMWR): /* 'rw' */
1969 TranslationSetPlainNum(count++);
1970 Translate(testFile, "common",
1971 "testProg/common/menuReadEntry.c");
1972 TranslationSetPlainNum(count++);
1973 Translate(testFile, "common",
1974 "testProg/common/menuWriteEntry.c");
1975 break;
1976 default:
1977 /* it's not an error, just this service register
1978 is not r/w */
1979 break;
1982 Translate(testFile, "common", "testProg/common/menuFoot.c");
1983 Translate(testFile, "common", "testProg/serviceCaseHead.c");
1984 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
1986 for (i = 0; i < GetSrvRegNum(); i++) {
1987 TranslationSetRegId(srv_ioctl[i].name);
1988 switch (srv_ioctl[i].rar) {
1989 case AMRD: /* 'r' */
1990 TranslationSetPlainNum(count++);
1991 TranslationSetFancyString("Get");
1992 Translate(testFile, "common",
1993 "testProg/common/caseGetSet.c");
1994 break;
1995 case AMWR: /* 'w' */
1996 TranslationSetPlainNum(count++);
1997 TranslationSetFancyString("Set");
1998 Translate(testFile, "common",
1999 "testProg/common/caseGetSet.c");
2000 break;
2001 case (AMRD | AMWR): /* 'rw' */
2002 TranslationSetPlainNum(count++);
2003 TranslationSetFancyString("Get");
2004 Translate(testFile, "common",
2005 "testProg/common/caseGetSet.c");
2007 TranslationSetPlainNum(count++);
2008 TranslationSetFancyString("Set");
2009 Translate(testFile, "common",
2010 "testProg/common/caseGetSet.c");
2011 break;
2012 default:
2013 /* it's not an error, just this service register
2014 is not r/w */
2015 break;
2018 Translate(testFile, "common", "testProg/common/caseEnd.c");
2020 /*=====03. Now generate sub menus for each of the defined blocks.==========*/
2021 endOfBlock = TRUE;
2023 for (i = 0; i < numRegisters; i++)
2024 if (registers[i].rar != AMEX) { /* skip extraneous registers */
2025 if (endOfBlock) {
2026 TranslationSetFancyNum(registers[i].blockP->
2027 blockID);
2028 TranslationSetPlainNum(registers[i].blockP->
2029 blockID);
2030 Translate(testFile, "common",
2031 "testProg/common/blockMenuHead.c");
2032 Translate(testFile, "common",
2033 "testProg/common/menuHead.c");
2034 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
2035 blockStart = i;
2037 TranslationSetRegName(registers[i].name);
2038 switch (registers[i].rar) {
2039 case AMRD: /* 'r' */
2040 TranslationSetPlainNum(count++);
2041 Translate(testFile, "common",
2042 "testProg/common/menuReadEntry.c");
2043 break;
2044 case AMWR: /* 'w' */
2045 TranslationSetPlainNum(count++);
2046 Translate(testFile, "common",
2047 "testProg/common/menuWriteEntry.c");
2048 break;
2049 case (AMWR | AMRD): /* 'rw' */
2050 TranslationSetPlainNum(count++);
2051 Translate(testFile, "common",
2052 "testProg/common/menuReadEntry.c");
2054 TranslationSetPlainNum(count++);
2055 Translate(testFile, "common",
2056 "testProg/common/menuWriteEntry.c");
2057 break;
2058 default:
2059 FATAL_ERR();
2060 break;
2063 if (i == numRegisters - 1)
2064 endOfBlock = TRUE;
2065 else if (registers[i].blockP->blockID !=
2066 registers[i + 1].blockP->blockID)
2067 endOfBlock = TRUE;
2068 else
2069 endOfBlock = FALSE;
2071 if (endOfBlock) { /* now 'switch' can be generated */
2072 Translate(testFile, "common",
2073 "testProg/common/menuFoot.c");
2074 Translate(testFile, "common",
2075 "testProg/common/blockCaseHead.c");
2076 count = TST_PROG_SUB_MENU_FIRST_ENTRY;
2078 for (j = blockStart; j <= i; j++) {
2079 TranslationSetRegId(registers[j].
2080 upperName);
2081 switch (registers[j].rar) {
2082 case AMRD: /* 'r' */
2083 TranslationSetPlainNum(count++);
2084 TranslationSetFancyString
2085 ("Get");
2086 Translate(testFile, "common",
2087 "testProg/common/"
2088 "caseGetSet.c");
2089 break;
2090 case AMWR: /* 'w' */
2091 TranslationSetPlainNum(count++);
2092 TranslationSetFancyString
2093 ("Set");
2094 Translate(testFile, "common",
2095 "testProg/common/"
2096 "caseGetSet.c");
2097 break;
2098 case (AMWR | AMRD): /* 'rw' */
2099 TranslationSetPlainNum(count++);
2100 TranslationSetFancyString
2101 ("Get");
2102 Translate(testFile, "common",
2103 "testProg/common/"
2104 "caseGetSet.c");
2106 TranslationSetPlainNum(count++);
2107 TranslationSetFancyString
2108 ("Set");
2109 Translate(testFile, "common",
2110 "testProg/common/"
2111 "caseGetSet.c");
2112 break;
2113 default:
2114 FATAL_ERR();
2115 break;
2117 } /* end of for */
2118 Translate(testFile, "common",
2119 "testProg/common/caseEnd.c");
2120 } /* end of if */
2121 } /* end of for */
2125 * @brief Create major header files that are common for all VME/DRM drivers.
2127 static void BuildGeneralHeaderFiles(void)
2129 int cntr;
2130 int constCounter; /* */
2131 FILE *fp;
2132 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
2134 /* set general constants */
2135 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/GeneralHeader.h", DG_INC_DIR);
2136 TranslationSetPrecision(MAX_STR);
2137 TranslationSetDDDNum(MIN_STR);
2138 TranslationSetPlainNum(NAME_LEN);
2139 TranslationSetRegDepth(MAX_REG);
2140 TranslationSetIntNum(MAX_BLK);
2141 TranslationSetExtraNum(NO_ADDRESS);
2142 TranslationSetHexNum(NO_LUN);
2143 Translate(fp, "common", "header/generalHeader.h");
2144 fclose(fp);
2146 /* header for driver and simulator. Differs for VME/PCI buses. */
2147 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/ModuleHeader.h", DG_INC_DIR);
2148 Translate(fp, bus, "header/generalHeader.h");
2149 fclose(fp);
2151 /* register description is placed here */
2152 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/RegDesc.h", DG_INC_DIR);
2153 Translate(fp, "common", "header/regDesc.h");
2154 fclose(fp);
2156 /* seed Linux Kernel List */
2157 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/lklist.h", DG_INC_DIR);
2158 Translate(fp, "common", "header/lklist.h");
2159 fclose(fp);
2161 /* VMEbus Address Modifier Codes */
2162 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/vme_am.h", DG_INC_DIR);
2163 Translate(fp, "../include", "vme_am.h");
2164 fclose(fp);
2166 /* port operations for Lynx */
2167 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/port_ops_lynx.h", DG_INC_DIR);
2168 Translate(fp, "common", "header/port_ops_lynx.h");
2169 fclose(fp);
2171 /* port operations for Linux */
2172 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/port_ops_linux.h", DG_INC_DIR);
2173 Translate(fp, "common", "header/port_ops_linux.h");
2174 fclose(fp);
2176 /* extra swap operations for Linux */
2177 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/swab-extra-linux.h",
2178 DG_INC_DIR);
2179 Translate(fp, "common", "header/swab-extra-linux.h");
2180 fclose(fp);
2182 /* service registers ioctl numbers */
2183 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/ServiceRegIoctl.h",
2184 DG_INC_DIR);
2185 Translate(fp, "common", "header/srvHead.h");
2186 TranslationSetFancyString("IOCTL_BASE"); /* setup base number for the
2187 service ioctl numbers */
2189 for (cntr = 0, constCounter = 0; cntr < GetSrvRegNum(); cntr++) {
2190 switch (srv_ioctl[cntr].rar) {
2191 case AMRD: /* 'r' */
2192 TranslationSetPlainNum(constCounter++);
2193 TranslationSetIoctlConst("GET", srv_ioctl[cntr].name);
2194 Translate(fp, "common", "header/ioctlConst.h");
2195 break;
2196 case AMWR: /* 'w' */
2197 TranslationSetPlainNum(constCounter++);
2198 TranslationSetIoctlConst("SET", srv_ioctl[cntr].name);
2199 Translate(fp, "common", "header/ioctlConst.h");
2200 break;
2201 case (AMWR | AMRD): /* 'rw' */
2202 TranslationSetPlainNum(constCounter++);
2203 TranslationSetIoctlConst("GET", srv_ioctl[cntr].name);
2204 Translate(fp, "common", "header/ioctlConst.h");
2206 TranslationSetPlainNum(constCounter++);
2207 TranslationSetIoctlConst("SET", srv_ioctl[cntr].name);
2208 Translate(fp, "common", "header/ioctlConst.h");
2209 break;
2210 default:
2211 /* special srv register that has ioctl entry,
2212 but it's not a 'r/w' register */
2213 TranslationSetPlainNum(constCounter++);
2214 TranslationSetIoctlConst("", srv_ioctl[cntr].name);
2215 Translate(fp, "common", "header/ioctlConst.h");
2216 break;
2220 TranslationSetPlainNum(constCounter);
2221 Translate(fp, "common", "header/srvFoot.h");
2222 fclose(fp);
2224 /* service registers ID enum */
2225 fp = OpenFile(EXACT_FT, LOC_GENERAL, "%s/ServiceRegId.h", DG_INC_DIR);
2226 Translate(fp, "common", "header/srvIdHead.h");
2228 for (cntr = 0, constCounter = 0; cntr < GetSrvRegNum(); cntr++) {
2229 TranslationSetRegId(srv_ioctl[cntr].name);
2230 TranslationSetRegComm(srv_ioctl[cntr].comment);
2231 TranslationSetFancyString(rar2mode(srv_ioctl[cntr].rar));
2232 TranslationSetDummyString(itoa(constCounter++, 10));
2233 Translate(fp, "common", "header/regIdEnumIndexed.h");
2236 /* set last service regID description */
2237 TranslationSetRegName(srv_ioctl[cntr].name);
2238 TranslationSetRegComm(srv_ioctl[cntr].comment);
2239 TranslationSetDummyString(itoa(constCounter, 10));
2240 Translate(fp, "common", "header/srvIdFoot.h");
2241 fclose(fp);
2245 * @brief Generate general libraries source code, wich are @b DriverAccess,
2246 * @b Ioconfig and @b extra-lynx
2248 * @param none
2250 * DriverAccess library enables user to use @e DaGetElement(),
2251 * @e DaSetElement() and many other functions for register accessing.
2253 * Ioconfig library enables user to access driver by means of @e ioconfig
2254 * calls, that uses a direct memory access mechanism for accessing.
2256 * xtra-lynx -- imports such handy functions as vsnprintf, asprintf etc...
2257 * into user-space apps.
2259 * @return void
2261 static void BuildGeneralLibraries()
2263 FILE *fd;
2264 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
2265 char *tstr = ctime(&mod_creation_time);
2267 tstr[strlen(tstr) - 1] = 0; /* get rid of '\n' */
2269 /* driverAccess library source code */
2270 /* generate '.h' file */
2271 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/dal.h", DG_INC_DIR);
2272 Translate(fd, bus, "lib/drvrAccess/DrvrAccess.h");
2273 fclose(fd);
2275 /* generate '.c' files */
2276 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/dal.c", DAL_DIR);
2278 /* set DAL generation time */
2279 TranslationSetHexNum(mod_creation_time);
2280 TranslationSetComment(tstr);
2282 /* DAL mainframe */
2283 Translate(fd, bus, "lib/drvrAccess/DrvrAccess.c");
2284 fclose(fd);
2286 /* Linux DMA support */
2287 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/dma.c", DAL_DIR);
2288 Translate(fd, bus, "lib/drvrAccess/dma.c");
2289 fclose(fd);
2291 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/swa.h", DG_INC_DIR);
2292 Translate(fd, bus, "lib/drvrAccess/swa.h");
2293 fclose(fd);
2296 /* mmap access for Lynx */
2297 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/IoconfAccess.c", DAL_DIR);
2298 Translate(fd, bus, "lib/drvrAccess/ioconf.c");
2299 fclose(fd);
2301 /* xtra-lynx library -- handy function for lynx user-space */
2302 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/lynx-extra.c", DAL_DIR);
2303 Translate(fd, bus, "lib/drvrAccess/lynx-extra.c");
2304 fclose(fd);
2308 * @brief Build Device driver installation/uninstallation program source code.
2310 * @param none
2312 * @return void
2314 static void BuildGeneralInstallProgram()
2316 FILE *fd;
2317 char *bus = TranslationGetBus(); /* 'VME' or 'DRM' */
2319 /* generate install program '.h' file */
2320 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/modinst.h", DG_INC_DIR);
2321 Translate(fd, bus, "installProg/modinst.h");
2322 fclose(fd);
2324 /* generate install program '.c' file */
2325 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/modinst.c", INST_RM_DIR);
2326 Translate(fd, bus, "installProg/modinst.c");
2327 fclose(fd);
2329 /* generate deinstall program '.h' file */
2330 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/moduninst.h", DG_INC_DIR);
2331 Translate(fd, bus, "installProg/moduninst.h");
2332 fclose(fd);
2334 /* generate deinstall program '.c' file */
2335 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/moduninst.c", INST_RM_DIR);
2336 Translate(fd, bus, "installProg/moduninst.c");
2337 fclose(fd);
2339 /* add utilities */
2340 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/utils.c", INST_RM_DIR);
2341 Translate(fd, bus, "installProg/utils.c");
2342 fclose(fd);
2344 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/utils.h", DG_INC_DIR);
2345 Translate(fd, bus, "installProg/utils.h");
2346 fclose(fd);
2348 /* Lynx-specific utils */
2349 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/utils-lynx.c", INST_RM_DIR);
2350 Translate(fd, bus, "installProg/utils-lynx.c");
2351 fclose(fd);
2353 /* Linux-specific utils */
2354 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/utils-linux.c", INST_RM_DIR);
2355 Translate(fd, bus, "installProg/utils-linux.c");
2356 fclose(fd);
2358 /* Lynx API, needed for linux */
2359 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/extra-linux.c", INST_RM_DIR);
2360 Translate(fd, bus, "installProg/extra-linux.c");
2361 fclose(fd);
2363 fd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/extra-linux.h", DG_INC_DIR);
2364 Translate(fd, bus, "installProg/extra-linux.h");
2365 fclose(fd);
2369 * @brief Build-up makefiles that are located in @e general directory.
2371 * @param none
2373 * They contains install/uninstall programs, DALib and header files that are
2374 * common to all generated drivers.
2376 * @return void
2378 static void BuildGeneralMakefiles()
2380 FILE *mkfd;
2382 /* Base Makefile */
2383 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "Makefile.base");
2384 Translate(mkfd, "common", "makefiles/Makefile.base");
2385 fclose(mkfd);
2387 /* "Which dirs to compile" Makefile */
2388 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "Makefile");
2389 TranslationSetFreeFormat("%s", DG_INC_DIR);
2390 TranslationSetString(DAL_DIR);
2391 TranslationSetComment(INST_RM_DIR);
2392 Translate(mkfd, "common", "makefiles/MakefileShared");
2393 fclose(mkfd);
2395 /* Include Makefile */
2396 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/Makefile", DG_INC_DIR);
2397 Translate(mkfd, "common", "makefiles/includeGeneral.mk");
2398 fclose(mkfd);
2400 /* Libraries Makefile */
2401 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/Makefile", DAL_DIR);
2403 Translate(mkfd, "common", "makefiles/libShared.mk");
2404 fclose(mkfd);
2406 /* Install program Makefile */
2407 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/Makefile", INST_RM_DIR);
2408 TranslationSetString(DG_INC_DIR);
2409 Translate(mkfd, "common", "makefiles/instProg.mk");
2410 fclose(mkfd);
2412 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, "%s/deliver.mk", INST_RM_DIR);
2413 Translate(mkfd, "common", "makefiles/deliver.mk");
2414 fclose(mkfd);
2418 * @brief
2420 * @param none
2422 * @return void
2424 static void BuildGeneralScripts(void)
2426 FILE *mkfd;
2428 mkfd = OpenFile(EXACT_FT, LOC_GENERAL, UTIL_CP_USR_PT_GLOB);
2429 Translate(mkfd, "common", UTIL_CP_USR_PT_GLOB);
2430 fchmod(fileno(mkfd), 0755); /* set new access rights */
2431 fclose(mkfd);
2435 * @brief Checks if register description obtained from the data base contains
2436 * any extraneous registers.
2438 * @param registers -- register description
2439 * @param numRegisters -- register amount
2441 * @return amount of extraneous registers
2443 static int HasExtraneous(RegisterDef_t * registers, int numRegisters)
2445 int amount = 0;
2446 int cntr;
2448 for (cntr = 0; cntr < numRegisters; cntr++)
2449 if (registers[cntr].rar == AMEX)
2450 amount++;
2452 return (amount);
2456 * @brief Checks if register description obtained from the data base contains
2457 * any writeOnly registers.
2459 * @param registers -- register description
2460 * @param numRegisters -- register amount
2462 * @return amount of writeonly registers.
2464 static int HasWriteOnly(RegisterDef_t * registers, int numRegisters)
2466 static int amount = -1;
2467 int i;
2469 if (amount == -1) {
2470 amount++;
2471 for (i = 0; i < numRegisters; i++)
2472 if (registers[i].rar == AMWR)
2473 amount++;
2476 return (amount);