|
|
1.1 root 1: /*
2: *-IMPORTS:
3: * <sys/compat.h>
4: * LOCAL
5: * USE_PROTO
6: * ARGS ()
7: * <stdlib.h>
8: * NULL
9: * free ()
10: * malloc ()
11: * "ehand.h"
12: * ehand_t
13: * CHAIN_ERROR ();
14: * POP_HANDLER ();
15: * PUSH_HANDLER ();
16: * throw_error ();
17: * "mdev.h"
18: * mdev_t
19: * check_errs ()
20: * find_mdev ()
21: * "symbol.h"
22: * LEX_WILD
23: * SIGNED
24: * SYM_EOF
25: * UNSIGNED
26: * read_dev_file ()
27: * read_number ()
28: * read_symbol ()
29: */
30:
31: #include <sys/compat.h>
32: #include <stdlib.h>
33:
34: #include "ehand.h"
35: #include "mdev.h"
36: #include "symbol.h"
37: #include "read.h"
38: #include "lex.h"
39: #include "input.h"
40:
41: #include "sdev.h"
42:
43: #include <string.h>
44:
45:
46: LOCAL sdev_t * _sdevices;
47:
48:
49: /*
50: * Macro to test whether some number ranges intersect; the arguments could be
51: * either a pointer to a pair of longs or a pair of ints.
52: */
53:
54: #define INTERSECT(left,right) \
55: (((left) [0] >= (right) [0] && (left) [0] <= (right) [1]) || \
56: ((left) [1] >= (right) [0] && (left) [1] <= (right) [1]))
57:
58:
59: /*
60: * This function checks all existing 'sdevice' entries to see if there is an
61: * IOA conflict.
62: *
63: * The value returned is the same value that would be returned by the matching
64: * check performed by the idcheck(1M) utility, namely:
65: * 0 if no conflict.
66: * 1 if there is a conflict.
67: * 3 if there is a conflict, but the 'mdevice' entry has the O flag set.
68: *
69: * As usual, the specification does not take into account the possibility that
70: * an IOA range may conflict with several devices with a different setting of
71: * the 'O' flag. This routine returns 3 if and only if all devices which have
72: * IOA conflicts have the 'O' flag set.
73: *
74: * If "who" is non-NULL, it will be written with the address of the sdevice
75: * entry which caused the conflict which caused the non-zero return.
76: */
77:
78: #ifdef __USE_PROTO__
79: LOCAL int (sdev_check_ioa) (sdev_t * check)
80: #else
81: LOCAL int
82: sdev_check_ioa ARGS ((check))
83: sdev_t * check;
84: #endif
85: {
86: sdev_t * sdevp;
87: int share_conflict = 0;
88:
89: if (check == NULL)
90: throw_error ("check argument is NULL in sdev_check_ioa ()");
91:
92: if (check->sd_ioa [1] == 0)
93: return 0;
94:
95: for (sdevp = _sdevices ; sdevp != NULL ; sdevp = sdevp->sd_next) {
96:
97: if (sdevp->sd_ioa [1] == 0 ||
98: ! INTERSECT (sdevp->sd_ioa, check->sd_ioa))
99: continue;
100:
101: if (mdev_flag (sdevp->sd_mdevp, MDEV_ALLOW_IOA_OVERLAP) &&
102: mdev_flag (check->sd_mdevp, MDEV_ALLOW_IOA_OVERLAP)) {
103: if (share_conflict == 0)
104: share_conflict = 3;
105: } else {
106: report_conflict (check->sd_devname->s_data,
107: sdevp->sd_devname->s_data,
108: "IOA overlap");
109: share_conflict = 1;
110: }
111: }
112: return share_conflict;
113: }
114:
115:
116: /*
117: * This function checks all existing 'sdevice' entries for a CMA conflict.
118: *
119: * The value returned will be 1 if there is a conflict and 0 if no conflict
120: * occurs. If the "who" parameter is non-NULL, it will be written with the
121: * address of the 'sdevice' entry that caused the conflict (if any).
122: */
123:
124: #ifdef __USE_PROTO__
125: LOCAL int (sdev_check_cma) (sdev_t * check)
126: #else
127: LOCAL int
128: sdev_check_cma ARGS ((check))
129: sdev_t * check;
130: #endif
131: {
132: sdev_t * sdevp;
133: int conflict = 0;
134:
135: if (check == NULL)
136: throw_error ("check argument is NULL in sdev_check_cma ()");
137:
138: if (check->sd_cma [1] == 0)
139: return 0;
140:
141: for (sdevp = _sdevices ; sdevp != NULL ; sdevp = sdevp->sd_next) {
142:
143: if (sdevp->sd_cma [1] > 0 &&
144: INTERSECT (sdevp->sd_cma, check->sd_cma)) {
145:
146: report_conflict (check->sd_devname->s_data,
147: sdevp->sd_devname->s_data,
148: "CMA overlap");
149: conflict = 1;
150: }
151: }
152:
153: return conflict;
154: }
155:
156:
157: /*
158: * This function checks all existing 'sdevice' entries to see if the interrupt
159: * vector 'vec' is in use by any of them.
160: */
161:
162: #ifdef __USE_PROTO__
163: LOCAL int (sdev_check_vector) (sdev_t * check)
164: #else
165: LOCAL int
166: sdev_check_vector ARGS ((check))
167: sdev_t * check;
168: #endif
169: {
170: sdev_t * sdevp;
171: int conflict = 0;
172:
173: if (check->sd_vector == 0)
174: return 0;
175:
176: for (sdevp = _sdevices ; sdevp != NULL ; sdevp = sdevp->sd_next) {
177:
178: if (sdevp->sd_vector != check->sd_vector)
179: continue;
180:
181: switch (sdevp->sd_itype) {
182:
183: case INT_SHAREABLE:
184: if (check->sd_itype == INT_SHAREABLE)
185: break;
186:
187: /* FALL THROUGH */
188:
189: case INT_PER_DEVICE:
190: if (sdevp->sd_devname == check->sd_devname &&
191: check->sd_itype >= INT_PER_DEVICE)
192: break;
193:
194: /* FALL THROUGH */
195:
196: case INT_PER_CHANNEL:
197: report_conflict (check->sd_devname->s_data,
198: sdevp->sd_devname->s_data,
199: "Interrupt vector conflict");
200:
201: conflict = 1;
202: break;
203:
204: case INT_NONE:
205: break;
206: }
207: }
208:
209: return conflict;
210: }
211:
212:
213: /*
214: * Regenerate an 'sdevice' entry from the stored record.
215: */
216:
217: #if USE_PROTO
218: void (write_sdevice) (sdev_t * sdevp, input_t * input)
219: #else
220: void
221: write_sdevice ARGS ((sdevp, input))
222: sdev_t * sdevp;
223: input_t * input;
224: #endif
225: {
226: if ((* input->in_filter) (input, "%s<1>%c<2>%d<3>%d<4>%d<5>%d<6>"
227: "0x%x<7>0x%x<8>0x%x<9>0x%x\n",
228: sdevp->sd_devname->s_data,
229: sdevp->sd_config ? 'Y' : 'N',
230: sdevp->sd_unit, sdevp->sd_ipl,
231: sdevp->sd_itype, sdevp->sd_vector,
232: sdevp->sd_ioa [0], sdevp->sd_ioa [1],
233: sdevp->sd_cma [0], sdevp->sd_cma [1]) < 0) {
234:
235: throw_error ("Output error");
236: }
237: }
238:
239:
240: /*
241: * Read a line from an "sdevice" file.
242: *
243: * This code is really messy. My apologies.
244: */
245:
246: #if USE_PROTO
247: LOCAL sdev_t * (read_sdevice) (input_t * input, lex_t * lexp, int * end_char)
248: #else
249: LOCAL sdev_t *
250: read_sdevice ARGS ((input, lexp, end_char))
251: input_t * input;
252: lex_t * lexp;
253: int * end_char;
254: #endif
255: {
256: VOLATILE int ch = '\n';
257: sdev_t * VOLATILE sdevp;
258: sdev_t * scan;
259: ehand_t err;
260: lex_t yesno = { NULL, NULL, "-", "ynYN", LEX_WILD };
261: symbol_t * config_flag;
262:
263: yesno.l_prev = lexp;
264:
265: if ((sdevp = (sdev_t *) malloc (sizeof (* sdevp))) == NULL)
266: throw_error ("out of memory in read_sdevice ()");
267:
268: if (PUSH_HANDLER (err) == 0) {
269: /*
270: * If the first thing on the line is EOF, that's not an error,
271: * just bail out.
272: */
273:
274: ch = read_symbol (input, lexp, & sdevp->sd_devname);
275:
276: if (sdevp->sd_devname == NULL) {
277:
278: free (sdevp);
279: sdevp = NULL;
280: goto at_eof;
281: }
282:
283: check_not_eol (ch);
284:
285: if (sdevp->sd_devname->s_size > MAX_DEVNAME)
286: throw_error ("device name must be <= %d characters",
287: MAX_DEVNAME);
288:
289: /*
290: * We read the yes/no field as a symbol, since most of the
291: * entries will be identical.
292: */
293:
294: ch = read_symbol (input, & yesno, & config_flag);
295: check_not_eol (ch);
296:
297: if (config_flag->s_size > 1)
298: throw_error ("a single Y or N is required");
299:
300: sdevp->sd_config = (config_flag->s_data [0] == 'y' ||
301: config_flag->s_data [0] == 'Y');
302:
303: /*
304: * Read the unit number; since we match both the unit number
305: * and the device name when changing an entry, we only allow
306: * one sdevice entry per unit/device combination.
307: */
308:
309: ch = read_uints (input, lexp, & sdevp->sd_unit, NO_RANGE);
310: check_not_eol (ch);
311:
312: for (scan = _sdevices ; scan != NULL ; scan = scan->sd_next)
313: if (scan->sd_devname == sdevp->sd_devname &&
314: scan->sd_unit == sdevp->sd_unit) {
315: throw_error ("Only one sdevice entry per device unit allowed");
316: }
317:
318:
319: ch = read_uints (input, lexp, & sdevp->sd_ipl, NO_RANGE);
320: check_not_eol (ch);
321:
322: if (sdevp->sd_ipl > MAX_IPL)
323: throw_error ("IPL must be in the range 0 through %d",
324: MAX_IPL);
325:
326: ch = read_uints (input, lexp, & sdevp->sd_itype, NO_RANGE);
327: check_not_eol (ch);
328:
329: if (sdevp->sd_itype > MAX_ITYPE)
330: throw_error ("interrupt type must be in the range 0 to %d",
331: MAX_ITYPE);
332:
333: ch = read_uints (input, lexp, & sdevp->sd_vector, NO_RANGE);
334: check_not_eol (ch);
335:
336:
337: /*
338: * The clock device is special-cased as the only thing that
339: * can use vector 0.
340: */
341:
342: if (strcmp (sdevp->sd_devname->s_data, "clock") != 0 &&
343: ((sdevp->sd_ipl > 0 && sdevp->sd_vector == 0) ||
344: (sdevp->sd_ipl == 0 && sdevp->sd_vector > 0))) {
345: throw_error ("IPL and vector must both be either zero or non-zero");
346: }
347:
348: if (sdevp->sd_vector > MAX_VECTOR)
349: throw_error ("vector numbers run from 0 (no vector) through %d",
350: MAX_VECTOR);
351:
352: ch = read_ulongs (input, lexp, & sdevp->sd_ioa [0], NO_RANGE);
353: check_not_eol (ch);
354:
355: ch = read_ulongs (input, lexp, & sdevp->sd_ioa [1], NO_RANGE);
356: check_not_eol (ch);
357:
358: if (sdevp->sd_ioa [0] > sdevp->sd_ioa [1])
359: throw_error ("lower bound of address range higher than upper bound");
360:
361: ch = read_ulongs (input, lexp, & sdevp->sd_cma [0], NO_RANGE);
362: check_not_eol (ch);
363:
364: ch = read_ulongs (input, lexp, & sdevp->sd_cma [1], NO_RANGE);
365:
366: if (sdevp->sd_cma [0] > sdevp->sd_cma [1])
367: throw_error ("lower bound of address range higher than upper bound");
368:
369: ch = expect_eol (input, lexp, ch);
370: } else {
371:
372: free (sdevp);
373: CHAIN_ERROR (err);
374: }
375:
376: at_eof:
377: POP_HANDLER (err);
378:
379: * end_char = ch;
380: return sdevp;
381: }
382:
383:
384: /*
385: * This function is passed as a pointer to for_all_mdevices () to aid in
386: * checking to see that enabled devices have unique major numbers.
387: */
388:
389: #if USE_PROTO
390: LOCAL void check_major (mdev_t * mdevp, mdev_t * enabled)
391: #else
392: LOCAL void
393: check_major (mdevp, enabled)
394: mdev_t * mdevp;
395: mdev_t * enabled;
396: #endif
397: {
398: CONST char * msg;
399:
400: if (mdevp == enabled || enabled->md_configure != MD_ENABLED)
401: return;
402:
403: if (mdev_flag (enabled, MDEV_BLOCK) && mdev_flag (mdevp, MDEV_BLOCK))
404: if (INTERSECT (mdevp->md_blk_maj, enabled->md_blk_maj)) {
405: msg = "Block major number overlap";
406: conflict:
407: report_conflict (mdevp->md_devname->s_data,
408: enabled->md_devname->s_data,
409: msg);
410: mdevp->md_configure = MD_DISABLED;
411: return;
412: }
413:
414: if (mdev_flag (enabled, MDEV_CHAR) && mdev_flag (mdevp, MDEV_CHAR))
415: if (INTERSECT (mdevp->md_chr_maj, enabled->md_chr_maj)) {
416: msg = "Character major number overlap";
417: goto conflict;
418: }
419:
420: if (mdev_flag (enabled, MDEV_COHERENT) &&
421: mdev_flag (mdevp, MDEV_COHERENT))
422: if (INTERSECT (mdevp->md_chr_maj, enabled->md_chr_maj)) {
423: msg = "Major number overlap";
424: goto conflict;
425: }
426: }
427:
428:
429: /*
430: * This function is passed as a parameter to read_dev_string () to read an
431: * 'mtune' entry (usually a program argument) and hook it into a global list.
432: */
433:
434: #if USE_PROTO
435: LOCAL int _read_sdev_string (input_t * input, lex_t * lexp,
436: sdev_t ** sdlistp)
437: #else
438: LOCAL int
439: _read_sdev_string (input, lexp, sdlistp)
440: input_t * input;
441: lex_t * lexp;
442: sdev_t ** sdlistp;
443: #endif
444: {
445: sdev_t * sdevp;
446: int ch;
447:
448: if ((sdevp = read_sdevice (input, lexp, & ch)) != NULL) {
449: sdevp->sd_next = * sdlistp;
450: * sdlistp = sdevp;
451: }
452:
453: return ch;
454: }
455:
456:
457: /*
458: * This function is used by _read_sdevice_file () to handle the details of
459: * linking an 'sdevice' entry into the global data structures and checking the
460: * data consistency.
461: */
462:
463: #if USE_PROTO
464: LOCAL void (link_sdevice) (sdev_t * sdevp, input_t * input)
465: #else
466: LOCAL void
467: link_sdevice ARGS ((sdevp, input))
468: sdev_t * sdevp;
469: input_t * input;
470: #endif
471: {
472: CONST char * errmsg;
473:
474: if ((sdevp->sd_mdevp = find_mdev (sdevp->sd_devname)) == NULL) {
475: errmsg = "device name does not match any master device entry";
476: have_error:
477: report_error (errmsg);
478: free (sdevp);
479: return;
480: }
481:
482: if (mdev_flag (sdevp->sd_mdevp, MDEV_ONE_SDEVICE) &&
483: sdevp->sd_mdevp->md_sdevices != NULL) {
484: errmsg = "only one sdevice entry permitted for this device";
485: goto have_error;
486: }
487:
488: if (sdevp->sd_unit < sdevp->sd_mdevp->md_minor_min ||
489: sdevp->sd_unit > sdevp->sd_mdevp->md_minor_max) {
490: errmsg = "unit number out of range for device";
491: goto have_error;
492: }
493:
494: if (sdevp->sd_ioa [1] > 0 &&
495: ! mdev_flag (sdevp->sd_mdevp, MDEV_HARDWARE)) {
496: errmsg = "software-only device cannot access I/O ports";
497: goto have_error;
498: }
499:
500: switch (sdev_check_ioa (sdevp)) {
501: case 3:
502: case 0:
503: /*
504: * Every device we might conflict with has the 'O' flag set
505: * and so do we, or there is no conflict.
506: */
507: break;
508:
509: default:
510: free (sdevp);
511: return;
512: }
513:
514: if (sdevp->sd_cma [1] > 0 &&
515: ! mdev_flag (sdevp->sd_mdevp, MDEV_HARDWARE)) {
516: errmsg = "software-only device cannot have controller memory";
517: goto have_error;
518: }
519:
520: if (sdev_check_cma (sdevp) != 0) {
521: free (sdevp);
522: return;
523: }
524:
525: if (sdevp->sd_itype > 0) {
526:
527: if (! mdev_flag (sdevp->sd_mdevp, MDEV_HARDWARE)) {
528: errmsg = "software-only device cannot have a vector";
529: goto have_error;
530: }
531:
532: sdevp->sd_mdevp->md_interrupt = 1;
533: }
534:
535:
536: if (sdev_check_vector (sdevp)) {
537: free (sdevp);
538: return;
539: }
540:
541:
542: /*
543: * After we have passed all the checks above, we commit to linking the
544: * entry in... no more gotos after this point!
545: */
546:
547: sdevp->sd_next = _sdevices;
548: _sdevices = sdevp;
549:
550: sdevp->sd_mnext = sdevp->sd_mdevp->md_sdevices;
551: sdevp->sd_mdevp->md_sdevices = sdevp;
552:
553: if (sdevp->sd_config) {
554: /*
555: * Check enabled devices for major number clashes.
556: */
557:
558: for_all_mdevices ((miter_t) check_major,
559: sdevp->sd_mdevp);
560: sdevp->sd_mdevp->md_configure = MD_ENABLED;
561: }
562:
563: write_sdevice (sdevp, input);
564: }
565:
566:
567: /*
568: * This function is passed as a pointer to read_dev_file () in order to read
569: * an 'sdevice' entry and link it into a global chain.
570: */
571:
572: #if USE_PROTO
573: LOCAL int _read_sdevice_file (input_t * input, lex_t * lexp,
574: sdev_t ** changes)
575: #else
576: LOCAL int
577: _read_sdevice_file ARGS ((input, lexp, changes))
578: input_t * input;
579: lex_t * lexp;
580: sdev_t ** changes;
581: #endif
582: {
583: sdev_t * sdevp;
584: int ch;
585:
586: if ((sdevp = read_sdevice (input, lexp, & ch)) == NULL) {
587: if (ch == READ_EOF) {
588: /*
589: * Blow remaining changes out as new entries.
590: */
591:
592: while ((sdevp = * changes) != NULL) {
593: * changes = sdevp->sd_next;
594: link_sdevice (sdevp, input);
595: }
596: }
597: return ch;
598: }
599:
600:
601: /*
602: * Link the newly-read entry into the global lists.
603: */
604:
605: if (changes) {
606: sdev_t ** scan;
607:
608: for (scan = changes ; * scan != NULL ;
609: scan = & (* scan)->sd_next) {
610:
611: if ((* scan)->sd_devname == sdevp->sd_devname &&
612: (* scan)->sd_unit == sdevp->sd_unit) {
613: /*
614: * Our current entry is being replaced by a
615: * new one.
616: */
617:
618: free (sdevp);
619:
620: if (report_mode ())
621: return ch;
622:
623: sdevp = * scan;
624: * scan = sdevp->sd_next;
625: break;
626: }
627: }
628: }
629:
630: link_sdevice (sdevp, input);
631: return ch;
632: }
633:
634:
635: /*
636: * Read in an "mtune" entry from a string and add it to a list.
637: */
638:
639: #if USE_PROTO
640: void read_sdev_string (CONST char * string, VOID * extra)
641: #else
642: void
643: read_sdev_string (string, extra)
644: CONST char * string;
645: VOID * extra;
646: #endif
647: {
648: read_dev_string (string, (dev_func_p) _read_sdev_string, extra);
649: }
650:
651:
652: /*
653: * Suck in a complete 'sdevice' file.
654: */
655:
656: #if USE_PROTO
657: void (read_sdev_file) (CONST char * inname, CONST char * outname, VOID * extra)
658: #else
659: void
660: read_sdev_file ARGS ((inname, outname, extra))
661: CONST char * inname;
662: CONST char * outname;
663: VOID * extra;
664: #endif
665: {
666: read_dev_file (inname, outname, (dev_func_p) _read_sdevice_file,
667: extra);
668: }
669:
670:
671: /*
672: * Generic insertion sort algorithm for "sdevice" entries based on a
673: * selection predicate and a comparison predicate.
674: *
675: * So that this can be a reasonably generic function, we pass it the internal
676: * offset of the "sdev_t *" member of the "sdevice" structure which will be
677: * used to link together the sorted entries.
678: *
679: * The return value is the number of items in the target list.
680: */
681:
682: #define LINK(sdevp,off) (* (sdev_t **) ((char *) (sdevp) + off))
683:
684: #if USE_PROTO
685: int (sdev_sort) (sdev_t ** sdlistp, sdev_t ** sdendp, ssel_t selpred,
686: scmp_t cmppred, size_t ptroff)
687: #else
688: int
689: sdev_sort ARGS ((sdlistp, sdendp, selpred, cmppred, ptroff))
690: sdev_t **sdlistp;
691: sdev_t **sdendp;
692: ssel_t selpred;
693: scmp_t cmppred;
694: size_t ptroff;
695: #endif
696: {
697: sdev_t * scan;
698: sdev_t * next;
699: int count;
700:
701: if (sdlistp == NULL || ptroff > sizeof (sdev_t))
702: throw_error ("bogus parameters to sdev_sort ()");
703:
704:
705: /*
706: * We'll just insert each selected member of the total list of
707: * mdevices into the output list in order by running down the output
708: * list until we compare true.
709: *
710: * We fetch "scan" before initializing the output list in case we are
711: * sorting the master device list.
712: */
713:
714: * sdlistp = NULL;
715: if (sdendp != NULL)
716: * sdendp = NULL;
717:
718: for (count = 0, scan = _sdevices ; scan != NULL ; scan = next) {
719: sdev_t * findpos;
720: sdev_t * prev;
721:
722: /*
723: * We get the "next" entry now in case we are sorting the
724: * master list. We allow a "selpred" of NULL to select all
725: * the entries.
726: */
727:
728: next = scan->sd_next;
729:
730: if (selpred != NULL && (* selpred) (scan) == 0)
731: continue;
732:
733: /*
734: * Now attempt to find the right place for the new entry and
735: * insert it there.
736: */
737:
738: prev = NULL;
739:
740: for (findpos = * sdlistp ; findpos != NULL ;
741: findpos = LINK ((prev = findpos), ptroff)) {
742: /*
743: * A "cmppred" that is NULL means that the order of
744: * output entries is irrelevant.
745: */
746:
747: if (cmppred == NULL ||
748: (* cmppred) (findpos, scan) == 0)
749: break;
750: }
751:
752: if (prev == NULL)
753: * sdlistp = scan;
754: else
755: LINK (prev, ptroff) = scan;
756:
757: if ((LINK (scan, ptroff) = findpos) == NULL && sdendp != NULL)
758: * sdendp = scan;
759:
760: count ++;
761: }
762:
763: return count;
764: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.