|
|
1.1 root 1: /*
2: *-IMPORT:
3: * <sys/compat.h>
4: * CONST
5: * LOCAL
6: * USE_PROTO
7: * ARGS ()
8: * <stdlib.h>
9: * NULL
10: * free ()
11: * malloc ()
12: * <string.h>
13: * strchr ()
14: * "ehand.h"
15: * ehand_t
16: * CHAIN_ERROR ()
17: * POP_HANDLER ()
18: * PUSH_HANDLER ()
19: * throw_error ()
20: * "symbol.h"
21: * LEX_WILD
22: * RANGE
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: #include <string.h>
34:
35: #include "ehand.h"
36: #include "symbol.h"
37: #include "read.h"
38: #include "lex.h"
39: #include "input.h"
40:
41: #include "mdev.h"
42:
43:
44: LOCAL mdev_t * _mdevices;
45:
46:
47: /*
48: * Find a device by symbol.
49: */
50:
51: #if USE_PROTO
52: mdev_t * (find_mdev) (symbol_t * sym)
53: #else
54: mdev_t *
55: find_mdev ARGS ((sym))
56: symbol_t * sym;
57: #endif
58: {
59: mdev_t * scan;
60:
61: for (scan = _mdevices ; scan != NULL ; scan = scan->md_next) {
62:
63: if (scan->md_devname == sym)
64: return scan;
65: }
66:
67: return NULL;
68: }
69:
70:
71: /*
72: * Write a single number or a range of device major numbers.
73: */
74:
75: #if USE_PROTO
76: LOCAL int write_range (input_t * input, maj_t major [2])
77: #else
78: LOCAL int
79: write_range (input, major)
80: input_t * input;
81: maj_t major [2];
82: #endif
83: {
84: if (major [0] == major [1])
85: return (* input->in_filter) (input, "%d\t", major [0]);
86:
87: return (* input->in_filter) (input, "%d-%d\t", major [0], major [1]);
88: }
89:
90:
91: /*
92: * Regenerate an 'mdevice' line from the stored record.
93: */
94:
95: #define HYPHEN(x) ((x) == NULL ? (unsigned char *) "-" : (x))
96:
97: #if USE_PROTO
98: void (write_mdevice) (mdev_t * mdevp, input_t * input)
99: #else
100: void
101: write_mdevice ARGS ((mdevp, input))
102: mdev_t * mdevp;
103: input_t * input;
104: #endif
105: {
106: if ((* input->in_filter) (input, "%s<1>%s<2>%s<3>%s<4>",
107: mdevp->md_devname->s_data,
108: HYPHEN (mdevp->md_functions->s_data),
109: HYPHEN (mdevp->md_flags->s_data),
110: mdevp->md_prefix->s_data) < 0 ||
111: write_range (input, mdevp->md_blk_maj) < 0 ||
112: write_range (input, mdevp->md_chr_maj) < 0 ||
113: (* input->in_filter) (input, "%d<7>%d<8>%d<9>%d\n",
114: mdevp->md_minor_min, mdevp->md_minor_max,
115: mdevp->md_dma_chan, mdevp->md_cpu_id) < 0) {
116:
117: throw_error ("Output error");
118: }
119: }
120:
121:
122: /*
123: * Read lines from an "mdevice" file.
124: *
125: * This code is really messy. My apologies.
126: */
127:
128: #if USE_PROTO
129: LOCAL mdev_t * (read_mdevice) (input_t * input, lex_t * lexp, int * end_char)
130: #else
131: LOCAL mdev_t *
132: read_mdevice ARGS ((input, lexp, end_char))
133: input_t * input;
134: lex_t * lexp;
135: int * end_char;
136: #endif
137: {
138: VOLATILE int ch = '\n';
139: mdev_t * VOLATILE mdevp;
140: ehand_t err;
141: lex_t functions = { NULL, NULL, "-", MDEV_FUNCS, LEX_WILD };
142: lex_t flags = { NULL, NULL, "-", MDEV_FLAGS, LEX_WILD };
143:
144: functions.l_prev = lexp;
145: flags.l_prev = lexp;
146:
147: if ((mdevp = (mdev_t *) malloc (sizeof (* mdevp))) == NULL)
148: throw_error ("out of memory in read_mdevice ()");
149:
150: if (PUSH_HANDLER (err) == 0) {
151: /*
152: * If the first thing on the line works out to be an EOF,
153: * then bail out without an error.
154: */
155:
156: ch = read_symbol (input, lexp, & mdevp->md_devname);
157:
158: if (mdevp->md_devname == NULL) {
159: /*
160: * We allow an EOF at the beginning of a line and we
161: * also allow a blank line.
162: */
163:
164: free (mdevp);
165: mdevp = NULL;
166: goto at_eof;
167: }
168: check_not_eol (ch);
169:
170: if (mdevp->md_devname->s_size > MAX_DEVNAME)
171: throw_error ("device name must be <= %d characters",
172: MAX_DEVNAME);
173:
174: /*
175: * We read the functions and characteristics field as symbols,
176: * even though they are really strings, since it makes no
177: * difference to the result.
178: */
179:
180: ch = read_symbol (input, & functions, & mdevp->md_functions);
181: if (mdevp->md_functions == NULL && ch != '-')
182: throw_error ("Unable to read functions");
183: check_not_eol (ch);
184:
185: ch = read_symbol (input, & flags, & mdevp->md_flags);
186: if (mdevp->md_flags == NULL && ch != '-')
187: throw_error ("Unable to read flags");
188: check_not_eol (ch);
189:
190: if ((mdev_flag (mdevp, MDEV_BLOCK) ||
191: mdev_flag (mdevp, MDEV_CHAR) ||
192: mdev_flag (mdevp, MDEV_STREAM)) &&
193: ! mdev_flag (mdevp, MDEV_DDI_DDK)) {
194:
195: throw_error ("devices must be DDI/DDK compliant");
196: }
197:
198:
199: /*
200: * We don't check for a unique device prefix, since there may
201: * be a legitimate reason to configure the same prefix twice.
202: *
203: * If the user installs multiple devices with the same prefix,
204: * the linker should catch it. Of course, a registration
205: * system might help. We only enforce the size limit for
206: * drivers... other kernel facilities can user longer names.
207: */
208:
209: ch = read_symbol (input, lexp, & mdevp->md_prefix);
210: check_not_eol (ch);
211:
212: if ((mdev_flag (mdevp, MDEV_BLOCK) ||
213: mdev_flag (mdevp, MDEV_CHAR) ||
214: mdev_flag (mdevp, MDEV_STREAM)) &&
215: mdevp->md_prefix->s_size > MAX_PREFIX)
216: throw_error ("device prefix must be <= %d characters",
217: MAX_PREFIX);
218:
219:
220: ch = read_uints (input, lexp, mdevp->md_blk_maj, RANGE);
221: check_not_eol (ch);
222:
223: if (mdev_flag (mdevp, MDEV_BLOCK)) {
224:
225: if (mdevp->md_blk_maj [0] > mdevp->md_blk_maj [1])
226: throw_error ("lower range bound higher than upper bound");
227:
228: if (mdevp->md_blk_maj [0] < MAJOR_RESERVED)
229: throw_error ("major devices up to %d reserved",
230: MAJOR_RESERVED - 1);
231:
232: } else if (mdev_flag (mdevp, MDEV_COHERENT)) {
233:
234: if (mdevp->md_blk_maj [0] != mdevp->md_blk_maj [1])
235: throw_error ("Coherent devices occupy a single major number");
236:
237: if (mdevp->md_blk_maj [0] >= MAJOR_RESERVED)
238: throw_error ("Coherent devices only in range 0-%d",
239: MAJOR_RESERVED - 1);
240: } else
241: mdevp->md_blk_maj [0] = mdevp->md_blk_maj [1] = 0;
242:
243:
244: ch = read_uints (input, lexp, mdevp->md_chr_maj, RANGE);
245: check_not_eol (ch);
246:
247: if (mdev_flag (mdevp, MDEV_CHAR)) {
248:
249: if (mdevp->md_chr_maj [0] > mdevp->md_chr_maj [1])
250: throw_error ("lower range bound higher that upper bound");
251:
252: if (mdevp->md_chr_maj [0] < MAJOR_RESERVED)
253: throw_error ("major devices 0-%d reserved",
254: MAJOR_RESERVED - 1);
255: } else if (mdev_flag (mdevp, MDEV_COHERENT)) {
256:
257: if (mdevp->md_chr_maj [0] != mdevp->md_blk_maj [0] ||
258: mdevp->md_blk_maj [0] != mdevp->md_chr_maj [0])
259: throw_error ("Coherent drivers must have same "
260: "block and character numbers");
261: } else
262: mdevp->md_chr_maj [0] = mdevp->md_chr_maj [1] = 0;
263:
264: ch = read_uints (input, lexp, & mdevp->md_minor_min,
265: NO_RANGE);
266: check_not_eol (ch);
267:
268: ch = read_uints (input, lexp, & mdevp->md_minor_max,
269: NO_RANGE);
270: check_not_eol (ch);
271:
272: if (mdevp->md_minor_min > mdevp->md_minor_max)
273: throw_error ("minor minimum higher than maximum");
274:
275: ch = read_ints (input, lexp, & mdevp->md_dma_chan, NO_RANGE);
276:
277: if (ch != '\n' && ch != SYM_EOF) {
278: /*
279: * The "cpu_id" field is optional.
280: */
281:
282: ch = read_ints (input, lexp, & mdevp->md_cpu_id,
283: NO_RANGE);
284: } else
285: mdevp->md_cpu_id = -1;
286:
287: ch = expect_eol (input, lexp, ch);
288:
289:
290: /*
291: * Having passed all the reasonableness checks, we link the
292: * new entry into the chain.
293: */
294:
295: mdevp->md_sdevices = NULL;
296: mdevp->md_interrupt = 0;
297:
298: mdevp->md_configure = MD_INSTALLABLE;
299: } else {
300:
301: free (mdevp);
302: CHAIN_ERROR (err);
303: }
304:
305: at_eof:
306: POP_HANDLER (err);
307:
308: * end_char = ch;
309: return mdevp;
310: }
311:
312:
313: /*
314: * This function is passed as a parameter to read_dev_string () to read an
315: * 'mtune' entry (usually a program argument) and hook it into a global list.
316: */
317:
318: #if USE_PROTO
319: LOCAL int _read_mdev_string (input_t * input, lex_t * lexp,
320: mdev_t ** mdlistp)
321: #else
322: LOCAL int
323: _read_mdev_string (input, lexp, mdlistp)
324: input_t * input;
325: lex_t * lexp;
326: mdev_t ** mdlistp;
327: #endif
328: {
329: mdev_t * mdevp;
330: int ch;
331:
332: if ((mdevp = read_mdevice (input, lexp, & ch)) != NULL) {
333: mdevp->md_next = * mdlistp;
334: * mdlistp = mdevp;
335: }
336:
337: return ch;
338: }
339:
340:
341: /*
342: * Common code from _read_mdevice_file () to link an entry into the global
343: * 'mdevice' chain.
344: */
345:
346: #if USE_PROTO
347: LOCAL void (link_mdevice) (mdev_t * mdevp, input_t * input)
348: #else
349: LOCAL void
350: link_mdevice ARGS ((mdevp, input))
351: mdev_t * mdevp;
352: input_t * input;
353: #endif
354: {
355: if (find_mdev (mdevp->md_devname) != NULL)
356: throw_error ("device name must be unique");
357:
358: mdevp->md_next = _mdevices;
359: _mdevices = mdevp;
360:
361: write_mdevice (mdevp, input);
362: }
363:
364:
365: /*
366: * This function is passed as a pointer to read_dev_file () to read an
367: * 'mdevice' entry from the input and link it in to the global device list.
368: *
369: * The extra argument is the head of a list of 'mdevice' entries which are to
370: * replace/be added to the existing 'mdevice' entries.
371: */
372:
373: #if USE_PROTO
374: LOCAL int _read_mdevice_file (input_t * input, lex_t * lexp,
375: mdev_t ** changes)
376: #else
377: LOCAL int
378: _read_mdevice_file (input, lexp, changes)
379: input_t * input;
380: lex_t * lexp;
381: mdev_t ** changes;
382: #endif
383: {
384: mdev_t * mdevp;
385: int ch;
386:
387: if ((mdevp = read_mdevice (input, lexp, & ch)) == NULL) {
388: if (ch == READ_EOF) {
389: /*
390: * Blow the remaining changes out as new entries.
391: */
392:
393: while ((mdevp = * changes) != NULL) {
394: * changes = mdevp->md_next;
395: link_mdevice (mdevp, input);
396: }
397: }
398: return ch;
399: }
400:
401: /*
402: * Link the newly-allocated mdevice entry into the global
403: * mdevice chain.
404: */
405:
406: if (changes) {
407: mdev_t ** scan;
408:
409: for (scan = changes ; * scan != NULL ;
410: scan = & (* scan)->md_next) {
411:
412: if ((* scan)->md_devname == mdevp->md_devname) {
413: /*
414: * Our current entry is being replaced by a
415: * new one; unlink the new entry from the
416: * change list and discard the old entry.
417: */
418:
419: free (mdevp);
420:
421: if (report_mode ())
422: return ch;
423:
424: mdevp = * scan;
425: * scan = mdevp->md_next;
426: break;
427: }
428: }
429: }
430:
431: link_mdevice (mdevp, input);
432: return ch;
433: }
434:
435:
436: /*
437: * Test a device for a function code; returns 1 if code is present, or 0 if
438: * code is not specified for device.
439: */
440:
441: #if USE_PROTO
442: int (mdev_func) (mdev_t * mdevp, char func)
443: #else
444: int
445: mdev_func ARGS ((mdevp, func))
446: mdev_t * mdevp;
447: char func;
448: #endif
449: {
450: if (mdevp->md_functions == NULL)
451: return 0;
452: return strchr (mdevp->md_functions->s_data, func) != NULL;
453: }
454:
455:
456: /*
457: * Test device characteristics; returns 1 if characteristic is specified for
458: * device, 0 if it is not.
459: */
460:
461: #if USE_PROTO
462: int (mdev_flag) (mdev_t * mdevp, char flag)
463: #else
464: int
465: mdev_flag ARGS ((mdevp, flag))
466: mdev_t * mdevp;
467: char flag;
468: #endif
469: {
470: if (mdevp->md_flags == NULL)
471: return 0;
472: return strchr (mdevp->md_flags->s_data, flag) != NULL;
473: }
474:
475:
476: /*
477: * Read in an "mtune" entry from a string and add it to a list.
478: */
479:
480: #if USE_PROTO
481: void read_mdev_string (CONST char * string, VOID * extra)
482: #else
483: void
484: read_mdev_string (string, extra)
485: CONST char * string;
486: VOID * extra;
487: #endif
488: {
489: read_dev_string (string, (dev_func_p) _read_mdev_string, extra);
490: }
491:
492:
493: /*
494: * Suck in a complete 'mdevice' file.
495: */
496:
497: #if USE_PROTO
498: void (read_mdev_file) (CONST char * inname, CONST char * outname, VOID * extra)
499: #else
500: void
501: read_mdev_file ARGS ((inname, outname, extra))
502: CONST char * inname;
503: CONST char * outname;
504: VOID * extra;
505: #endif
506: {
507: read_dev_file (inname, outname, (dev_func_p) _read_mdevice_file,
508: extra);
509: }
510:
511:
512: /*
513: * Iterate over all the mdevices in the system.
514: */
515:
516: #if USE_PROTO
517: void (for_all_mdevices) (miter_t iter, VOID * extra)
518: #else
519: void
520: for_all_mdevices ARGS ((iter, extra))
521: miter_t iter;
522: VOID * extra;
523: #endif
524: {
525: mdev_t * temp;
526:
527: for (temp = _mdevices ; temp != NULL ; temp = temp->md_next)
528: (* iter) (extra, temp);
529: }
530:
531:
532: /*
533: * Generic insertion sort algorithm for "mdevice" entries based on a
534: * selection predicate and a comparison predicate.
535: *
536: * So that this can be a reasonably generic function, we pass it the internal
537: * offset of the "mdev_t *" member of the "mdevice" structure which will be
538: * used to link together the sorted entries.
539: *
540: * The return value is the length of the sorted list.
541: */
542:
543: #define LINK(mdevp,off) (* (mdev_t **) ((char *) (mdevp) + off))
544:
545: #if USE_PROTO
546: int (mdev_sort) (mdev_t ** mdlistp, mdev_t ** mdendp, msel_t selpred,
547: mcmp_t cmppred, size_t ptroff)
548: #else
549: int
550: mdev_sort ARGS ((mdlistp, mdendp, selpred, cmppred, ptroff))
551: mdev_t ** mdlistp;
552: mdev_t ** mdendp;
553: msel_t selpred;
554: mcmp_t cmppred;
555: size_t ptroff;
556: #endif
557: {
558: mdev_t * scan;
559: mdev_t * next;
560: int count;
561:
562: if (mdlistp == NULL || ptroff > sizeof (mdev_t))
563: throw_error ("bogus parameters to mdev_sort ()");
564:
565:
566: /*
567: * We'll just insert each selected member of the total list of
568: * mdevices into the output list in order by running down the output
569: * list until we compare true.
570: *
571: * We fetch "scan" before initializing the output list in case we are
572: * sorting the master device list.
573: */
574:
575: * mdlistp = NULL;
576: if (mdendp != NULL)
577: * mdendp = NULL;
578:
579: for (count = 0, scan = _mdevices ; scan != NULL ; scan = next) {
580: mdev_t * findpos;
581: mdev_t * prev;
582:
583: /*
584: * We get the "next" entry now in case we are sorting the
585: * master list. We allow a "selpred" of NULL to select all
586: * the entries.
587: */
588:
589: next = scan->md_next;
590:
591: if (selpred != NULL && (* selpred) (scan) == 0)
592: continue;
593:
594:
595: /*
596: * Now attempt to find the right place for the new entry and
597: * insert it there.
598: */
599:
600: prev = NULL;
601:
602: for (findpos = * mdlistp ; findpos != NULL ;
603: findpos = LINK ((prev = findpos), ptroff)) {
604: /*
605: * A "cmppred" that is NULL means that the order of
606: * output entries is irrelevant.
607: */
608:
609: if (cmppred == NULL ||
610: (* cmppred) (findpos, scan) == 0)
611: break;
612: }
613:
614: if (prev == NULL)
615: * mdlistp = scan;
616: else
617: LINK (prev, ptroff) = scan;
618:
619: if ((LINK (scan, ptroff) = findpos) == NULL && mdendp != NULL)
620: * mdendp = scan;
621:
622: count ++;
623: }
624:
625: return count;
626: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.