v2.4.8 -> v2.4.8.1
[opensuse:kernel.git] / drivers / scsi / aic7xxx / aicasm / aicasm_symbol.c
1 /*
2  * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
3  *
4  * Copyright (c) 1997 Justin T. Gibbs.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions, and the following disclaimer,
12  *    without modification.
13  * 2. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * Alternatively, this software may be distributed under the terms of the
17  * GNU Public License ("GPL").
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $Id: //depot/src/aic7xxx/aicasm/aicasm_symbol.c#7 $
32  *
33  * $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11 2000/09/22 22:19:54 gibbs Exp $
34  */
35
36 #include <sys/types.h>
37
38 #ifdef __linux__
39 #include "aicdb.h"
40 #else
41 #include <db.h>
42 #endif
43 #include <fcntl.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sysexits.h>
48
49 #include "aicasm_symbol.h"
50 #include "aicasm.h"
51
52 static DB *symtable;
53
54 symbol_t *
55 symbol_create(char *name)
56 {
57         symbol_t *new_symbol;
58
59         new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
60         if (new_symbol == NULL) {
61                 perror("Unable to create new symbol");
62                 exit(EX_SOFTWARE);
63         }
64         memset(new_symbol, 0, sizeof(*new_symbol));
65         new_symbol->name = strdup(name);
66         new_symbol->type = UNINITIALIZED;
67         return (new_symbol);
68 }
69
70 void
71 symbol_delete(symbol_t *symbol)
72 {
73         if (symtable != NULL) {
74                 DBT      key;
75
76                 key.data = symbol->name;
77                 key.size = strlen(symbol->name);
78                 symtable->del(symtable, &key, /*flags*/0);
79         }
80         switch(symbol->type) {
81         case SCBLOC:
82         case SRAMLOC:
83         case REGISTER:
84                 if (symbol->info.rinfo != NULL)
85                         free(symbol->info.rinfo);
86                 break;
87         case ALIAS:
88                 if (symbol->info.ainfo != NULL)
89                         free(symbol->info.ainfo);
90                 break;
91         case MASK:
92         case BIT:
93                 if (symbol->info.minfo != NULL) {
94                         symlist_free(&symbol->info.minfo->symrefs);
95                         free(symbol->info.minfo);
96                 }
97                 break;
98         case DOWNLOAD_CONST:
99         case CONST:
100                 if (symbol->info.cinfo != NULL)
101                         free(symbol->info.cinfo);
102                 break;
103         case LABEL:
104                 if (symbol->info.linfo != NULL)
105                         free(symbol->info.linfo);
106                 break;
107         case UNINITIALIZED:
108         default:
109                 break;
110         }
111         free(symbol->name);
112         free(symbol);
113 }
114
115 void
116 symtable_open()
117 {
118         symtable = dbopen(/*filename*/NULL,
119                           O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
120                           /*openinfo*/NULL);
121
122         if (symtable == NULL) {
123                 perror("Symbol table creation failed");
124                 exit(EX_SOFTWARE);
125                 /* NOTREACHED */
126         }
127 }
128
129 void
130 symtable_close()
131 {
132         if (symtable != NULL) {
133                 DBT      key;
134                 DBT      data;
135
136                 while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
137                         symbol_t *stored_ptr;
138
139                         memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
140                         symbol_delete(stored_ptr);
141                 }
142                 symtable->close(symtable);
143         }
144 }
145
146 /*
147  * The semantics of get is to return an uninitialized symbol entry
148  * if a lookup fails.
149  */
150 symbol_t *
151 symtable_get(char *name)
152 {
153         symbol_t *stored_ptr;
154         DBT       key;
155         DBT       data;
156         int       retval;
157
158         key.data = (void *)name;
159         key.size = strlen(name);
160
161         if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
162                 if (retval == -1) {
163                         perror("Symbol table get operation failed");
164                         exit(EX_SOFTWARE);
165                         /* NOTREACHED */
166                 } else if (retval == 1) {
167                         /* Symbol wasn't found, so create a new one */
168                         symbol_t *new_symbol;
169
170                         new_symbol = symbol_create(name);
171                         data.data = &new_symbol;
172                         data.size = sizeof(new_symbol);
173                         if (symtable->put(symtable, &key, &data,
174                                           /*flags*/0) !=0) {
175                                 perror("Symtable put failed");
176                                 exit(EX_SOFTWARE);
177                         }
178                         return (new_symbol);
179                 } else {
180                         perror("Unexpected return value from db get routine");
181                         exit(EX_SOFTWARE);
182                         /* NOTREACHED */
183                 }
184         }
185         memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
186         return (stored_ptr);
187 }
188
189 symbol_node_t *
190 symlist_search(symlist_t *symlist, char *symname)
191 {
192         symbol_node_t *curnode;
193
194         curnode = SLIST_FIRST(symlist);
195         while(curnode != NULL) {
196                 if (strcmp(symname, curnode->symbol->name) == 0)
197                         break;
198                 curnode = SLIST_NEXT(curnode, links);
199         }
200         return (curnode);
201 }
202
203 void
204 symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
205 {
206         symbol_node_t *newnode;
207
208         newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
209         if (newnode == NULL) {
210                 stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
211                 /* NOTREACHED */
212         }
213         newnode->symbol = symbol;
214         if (how == SYMLIST_SORT) {
215                 symbol_node_t *curnode;
216                 int mask;
217
218                 mask = FALSE;
219                 switch(symbol->type) {
220                 case REGISTER:
221                 case SCBLOC:
222                 case SRAMLOC:
223                         break;
224                 case BIT:
225                 case MASK:
226                         mask = TRUE;
227                         break;
228                 default:
229                         stop("symlist_add: Invalid symbol type for sorting",
230                              EX_SOFTWARE);
231                         /* NOTREACHED */
232                 }
233
234                 curnode = SLIST_FIRST(symlist);
235                 if (curnode == NULL
236                  || (mask && (curnode->symbol->info.minfo->mask >
237                               newnode->symbol->info.minfo->mask))
238                  || (!mask && (curnode->symbol->info.rinfo->address >
239                                newnode->symbol->info.rinfo->address))) {
240                         SLIST_INSERT_HEAD(symlist, newnode, links);
241                         return;
242                 }
243
244                 while (1) {
245                         if (SLIST_NEXT(curnode, links) == NULL) {
246                                 SLIST_INSERT_AFTER(curnode, newnode,
247                                                    links);
248                                 break;
249                         } else {
250                                 symbol_t *cursymbol;
251
252                                 cursymbol = SLIST_NEXT(curnode, links)->symbol;
253                                 if ((mask && (cursymbol->info.minfo->mask >
254                                               symbol->info.minfo->mask))
255                                  || (!mask &&(cursymbol->info.rinfo->address >
256                                               symbol->info.rinfo->address))){
257                                         SLIST_INSERT_AFTER(curnode, newnode,
258                                                            links);
259                                         break;
260                                 }
261                         }
262                         curnode = SLIST_NEXT(curnode, links);
263                 }
264         } else {
265                 SLIST_INSERT_HEAD(symlist, newnode, links);
266         }
267 }
268
269 void
270 symlist_free(symlist_t *symlist)
271 {
272         symbol_node_t *node1, *node2;
273
274         node1 = SLIST_FIRST(symlist);
275         while (node1 != NULL) {
276                 node2 = SLIST_NEXT(node1, links);
277                 free(node1);
278                 node1 = node2;
279         }
280         SLIST_INIT(symlist);
281 }
282
283 void
284 symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
285               symlist_t *symlist_src2)
286 {
287         symbol_node_t *node;
288
289         *symlist_dest = *symlist_src1;
290         while((node = SLIST_FIRST(symlist_src2)) != NULL) {
291                 SLIST_REMOVE_HEAD(symlist_src2, links);
292                 SLIST_INSERT_HEAD(symlist_dest, node, links);
293         }
294
295         /* These are now empty */
296         SLIST_INIT(symlist_src1);
297         SLIST_INIT(symlist_src2);
298 }
299
300 void
301 symtable_dump(FILE *ofile)
302 {
303         /*
304          * Sort the registers by address with a simple insertion sort.
305          * Put bitmasks next to the first register that defines them.
306          * Put constants at the end.
307          */
308         symlist_t registers;
309         symlist_t masks;
310         symlist_t constants;
311         symlist_t download_constants;
312         symlist_t aliases;
313
314         SLIST_INIT(&registers);
315         SLIST_INIT(&masks);
316         SLIST_INIT(&constants);
317         SLIST_INIT(&download_constants);
318         SLIST_INIT(&aliases);
319
320         if (symtable != NULL) {
321                 DBT      key;
322                 DBT      data;
323                 int      flag = R_FIRST;
324
325                 while (symtable->seq(symtable, &key, &data, flag) == 0) {
326                         symbol_t *cursym;
327
328                         memcpy(&cursym, data.data, sizeof(cursym));
329                         switch(cursym->type) {
330                         case REGISTER:
331                         case SCBLOC:
332                         case SRAMLOC:
333                                 symlist_add(&registers, cursym, SYMLIST_SORT);
334                                 break;
335                         case MASK:
336                         case BIT:
337                                 symlist_add(&masks, cursym, SYMLIST_SORT);
338                                 break;
339                         case CONST:
340                                 if (cursym->info.cinfo->define == FALSE) {
341                                         symlist_add(&constants, cursym,
342                                                     SYMLIST_INSERT_HEAD);
343                                 }
344                                 break;
345                         case DOWNLOAD_CONST:
346                                 symlist_add(&download_constants, cursym,
347                                             SYMLIST_INSERT_HEAD);
348                                 break;
349                         case ALIAS:
350                                 symlist_add(&aliases, cursym,
351                                             SYMLIST_INSERT_HEAD);
352                                 break;
353                         default:
354                                 break;
355                         }
356                         flag = R_NEXT;
357                 }
358
359                 /* Put in the masks and bits */
360                 while (SLIST_FIRST(&masks) != NULL) {
361                         symbol_node_t *curnode;
362                         symbol_node_t *regnode;
363                         char *regname;
364
365                         curnode = SLIST_FIRST(&masks);
366                         SLIST_REMOVE_HEAD(&masks, links);
367
368                         regnode =
369                             SLIST_FIRST(&curnode->symbol->info.minfo->symrefs);
370                         regname = regnode->symbol->name;
371                         regnode = symlist_search(&registers, regname);
372                         SLIST_INSERT_AFTER(regnode, curnode, links);
373                 }
374
375                 /* Add the aliases */
376                 while (SLIST_FIRST(&aliases) != NULL) {
377                         symbol_node_t *curnode;
378                         symbol_node_t *regnode;
379                         char *regname;
380
381                         curnode = SLIST_FIRST(&aliases);
382                         SLIST_REMOVE_HEAD(&aliases, links);
383
384                         regname = curnode->symbol->info.ainfo->parent->name;
385                         regnode = symlist_search(&registers, regname);
386                         SLIST_INSERT_AFTER(regnode, curnode, links);
387                 }
388
389                 /* Output what we have */
390                 fprintf(ofile,
391 "/*
392  * DO NOT EDIT - This file is automatically generated
393  *               from the following source files:
394  *
395 %s */\n", versions);
396                 while (SLIST_FIRST(&registers) != NULL) {
397                         symbol_node_t *curnode;
398                         u_int8_t value;
399                         char *tab_str;
400                         char *tab_str2;
401
402                         curnode = SLIST_FIRST(&registers);
403                         SLIST_REMOVE_HEAD(&registers, links);
404                         switch(curnode->symbol->type) {
405                         case REGISTER:
406                         case SCBLOC:
407                         case SRAMLOC:
408                                 fprintf(ofile, "\n");
409                                 value = curnode->symbol->info.rinfo->address;
410                                 tab_str = "\t";
411                                 tab_str2 = "\t\t";
412                                 break;
413                         case ALIAS:
414                         {
415                                 symbol_t *parent;
416
417                                 parent = curnode->symbol->info.ainfo->parent;
418                                 value = parent->info.rinfo->address;
419                                 tab_str = "\t";
420                                 tab_str2 = "\t\t";
421                                 break;
422                         }
423                         case MASK:
424                         case BIT:
425                                 value = curnode->symbol->info.minfo->mask;
426                                 tab_str = "\t\t";
427                                 tab_str2 = "\t";
428                                 break;
429                         default:
430                                 value = 0; /* Quiet compiler */
431                                 tab_str = NULL;
432                                 tab_str2 = NULL;
433                                 stop("symtable_dump: Invalid symbol type "
434                                      "encountered", EX_SOFTWARE);
435                                 break;
436                         }
437                         fprintf(ofile, "#define%s%-16s%s0x%02x\n",
438                                 tab_str, curnode->symbol->name, tab_str2,
439                                 value);
440                         free(curnode);
441                 }
442                 fprintf(ofile, "\n\n");
443
444                 while (SLIST_FIRST(&constants) != NULL) {
445                         symbol_node_t *curnode;
446
447                         curnode = SLIST_FIRST(&constants);
448                         SLIST_REMOVE_HEAD(&constants, links);
449                         fprintf(ofile, "#define\t%-8s\t0x%02x\n",
450                                 curnode->symbol->name,
451                                 curnode->symbol->info.cinfo->value);
452                         free(curnode);
453                 }
454
455                 
456                 fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
457
458                 while (SLIST_FIRST(&download_constants) != NULL) {
459                         symbol_node_t *curnode;
460
461                         curnode = SLIST_FIRST(&download_constants);
462                         SLIST_REMOVE_HEAD(&download_constants, links);
463                         fprintf(ofile, "#define\t%-8s\t0x%02x\n",
464                                 curnode->symbol->name,
465                                 curnode->symbol->info.cinfo->value);
466                         free(curnode);
467                 }
468         }
469 }
470