4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/inttypes.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
33 #include <sys/bootconf.h>
34 #include <sys/sysconf.h>
35 #include <sys/sunddi.h>
36 #include <sys/esunddi.h>
37 #include <sys/ddi_impldefs.h>
40 #include <sys/fs/ufs_fsdir.h>
41 #include <sys/hwconf.h>
42 #include <sys/modctl.h>
43 #include <sys/cmn_err.h>
45 #include <sys/kobj_lex.h>
46 #include <sys/errno.h>
47 #include <sys/debug.h>
48 #include <sys/autoconf.h>
49 #include <sys/callb.h>
50 #include <sys/sysmacros.h>
52 #include <vm/seg_kmem.h>
54 struct hwc_class
*hcl_head
; /* head of list of classes */
55 static kmutex_t hcl_lock
; /* for accessing list of classes */
57 #define DAFILE "/etc/driver_aliases"
58 #define CLASSFILE "/etc/driver_classes"
59 #define DACFFILE "/etc/dacf.conf"
61 static char class_file
[] = CLASSFILE
;
62 static char dafile
[] = DAFILE
;
63 static char dacffile
[] = DACFFILE
;
65 char *systemfile
= "/etc/system"; /* name of ascii system file */
67 static struct sysparam
*sysparam_hd
; /* head of parameters list */
68 static struct sysparam
*sysparam_tl
; /* tail of parameters list */
69 static vmem_t
*mod_sysfile_arena
; /* parser memory */
71 char obp_bootpath
[BO_MAXOBJNAME
]; /* bootpath from obp */
72 char svm_bootpath
[BO_MAXOBJNAME
]; /* bootpath redirected via rootdev */
74 #if defined(_PSM_MODULES)
77 struct psm_mach
*m_next
;
81 static struct psm_mach
*pmach_head
; /* head of list of classes */
83 #define MACHFILE "/etc/mach"
84 static char mach_file
[] = MACHFILE
;
86 #endif /* _PSM_MODULES */
88 #if defined(_RTC_CONFIG)
89 static char rtc_config_file
[] = "/etc/rtc_config";
92 static void sys_set_var(int, struct sysparam
*, void *);
94 static void setparams(void);
97 * driver.conf parse thread control structure
101 char *name
; /* name of .conf files */
102 struct par_list
**pl
; /* parsed parent list */
103 ddi_prop_t
**props
; /* parsed properties */
104 int rv
; /* return value */
107 static int hwc_parse_now(char *, struct par_list
**, ddi_prop_t
**);
108 static void hwc_parse_thread(struct hwc_parse_mt
*);
109 static struct hwc_parse_mt
*hwc_parse_mtalloc(char *, struct par_list
**,
111 static void hwc_parse_mtfree(struct hwc_parse_mt
*);
112 static void add_spec(struct hwc_spec
*, struct par_list
**);
113 static void add_props(struct hwc_spec
*, ddi_prop_t
**);
115 static void check_system_file(void);
116 static int sysparam_compare_entry(struct sysparam
*, struct sysparam
*);
117 static char *sysparam_type_to_str(int);
118 static void sysparam_count_entry(struct sysparam
*, int *, u_longlong_t
*);
119 static void sysparam_print_warning(struct sysparam
*, u_longlong_t
);
122 static int parse_debug_on
= 0;
126 parse_debug(struct _buf
*file
, char *fmt
, ...)
130 if (parse_debug_on
) {
134 printf(" on line %d of %s\n", kobj_linenum(file
),
135 kobj_filename(file
));
141 #define FE_BUFLEN 256
145 kobj_file_err(int type
, struct _buf
*file
, char *fmt
, ...)
149 * If we're in trouble, we might be short on stack... be paranoid
151 char *buf
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
152 char *trailer
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
153 char *fmt_str
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
157 if (strchr("^!?", fmt
[0]) != NULL
) {
161 (void) vsnprintf(buf
, FE_BUFLEN
, fmt
, ap
);
163 (void) snprintf(trailer
, FE_BUFLEN
, " on line %d of %s",
164 kobj_linenum(file
), kobj_filename(file
));
167 * If prefixed with !^?, prepend that character
169 if (prefix
!= '\0') {
170 (void) snprintf(fmt_str
, FE_BUFLEN
, "%c%%s%%s", prefix
);
172 (void) strncpy(fmt_str
, "%s%s", FE_BUFLEN
);
175 cmn_err(type
, fmt_str
, buf
, trailer
);
176 kmem_free(buf
, FE_BUFLEN
);
177 kmem_free(trailer
, FE_BUFLEN
);
178 kmem_free(fmt_str
, FE_BUFLEN
);
182 char *tokennames
[] = {
204 kobj_lex(struct _buf
*file
, char *val
, size_t size
)
207 int ch
, oval
, badquote
;
209 token_t token
= UNEXPECTED
;
212 return (token
); /* this token is UNEXPECTED */
215 while ((ch
= kobj_getc(file
)) == ' ' || ch
== '\t')
251 while ((ch
= kobj_getc(file
)) == ' ' ||
252 ch
== '\t' || ch
== '\f') {
259 (void) kobj_ungetc(file
);
270 while (!badquote
&& (ch
= kobj_getc(file
)) != '"') {
274 kobj_file_err(CE_WARN
, file
, "Missing \"");
279 /* since we consumed the newline/EOF */
280 (void) kobj_ungetc(file
);
288 ch
= (char)kobj_getc(file
);
290 /* escape the character */
295 while (ch
>= '0' && ch
<= '7') {
297 oval
= (oval
<< 3) + ch
;
298 ch
= (char)kobj_getc(file
);
300 (void) kobj_ungetc(file
);
301 /* check for character overflow? */
305 "overflow detected.");
327 * detect a lone '-' (including at the end of a line), and
328 * identify it as a 'name'
335 *cp
++ = (char)(ch
= kobj_getc(file
));
336 if (iswhite(ch
) || (ch
== '\n')) {
337 (void) kobj_ungetc(file
);
343 } else if (isunary(ch
)) {
348 *cp
++ = (char)(ch
= kobj_getc(file
));
354 if ((ch
= kobj_getc(file
)) == 'x') {
360 ch
= kobj_getc(file
);
361 while (isxdigit(ch
)) {
367 ch
= kobj_getc(file
);
369 (void) kobj_ungetc(file
);
375 ch
= kobj_getc(file
);
377 while (isdigit(ch
)) {
383 ch
= kobj_getc(file
);
385 (void) kobj_ungetc(file
);
388 } else if (isalpha(ch
) || ch
== '\\' || ch
== '_') {
390 ch
= kobj_getc(file
);
393 * if the character was a backslash,
394 * back up so we can overwrite it with
395 * the next (i.e. escaped) character.
400 while (isnamechar(ch
) || ch
== '\\') {
402 ch
= kobj_getc(file
);
408 ch
= kobj_getc(file
);
410 (void) kobj_ungetc(file
);
422 * The UNEXPECTED token is the first element of the tokennames array,
423 * but its token value is -1. Adjust the value by adding one to it
424 * to change it to an index of the array.
426 parse_debug(NULL
, "kobj_lex: token %s value '%s'\n",
427 tokennames
[token
+1], val
);
433 * Leave NEWLINE as the next character.
437 kobj_find_eol(struct _buf
*file
)
441 while ((ch
= kobj_getc(file
)) != -1) {
443 (void) kobj_ungetc(file
);
450 * The ascii system file is read and processed.
452 * The syntax of commands is as follows:
454 * '*' in column 1 is a comment line.
455 * <command> : <value>
457 * command is EXCLUDE, INCLUDE, FORCELOAD, ROOTDEV, ROOTFS,
458 * SWAPDEV, SWAPFS, MODDIR, SET
460 * value is an ascii string meaningful for the command.
466 static struct modcmd modcmd
[] = {
467 { "EXCLUDE", MOD_EXCLUDE
},
468 { "exclude", MOD_EXCLUDE
},
469 { "INCLUDE", MOD_INCLUDE
},
470 { "include", MOD_INCLUDE
},
471 { "FORCELOAD", MOD_FORCELOAD
},
472 { "forceload", MOD_FORCELOAD
},
473 { "ROOTDEV", MOD_ROOTDEV
},
474 { "rootdev", MOD_ROOTDEV
},
475 { "ROOTFS", MOD_ROOTFS
},
476 { "rootfs", MOD_ROOTFS
},
477 { "SWAPDEV", MOD_SWAPDEV
},
478 { "swapdev", MOD_SWAPDEV
},
479 { "SWAPFS", MOD_SWAPFS
},
480 { "swapfs", MOD_SWAPFS
},
481 { "MODDIR", MOD_MODDIR
},
482 { "moddir", MOD_MODDIR
},
485 { "SET32", MOD_SET32
},
486 { "set32", MOD_SET32
},
487 { "SET64", MOD_SET64
},
488 { "set64", MOD_SET64
},
489 { NULL
, MOD_UNKNOWN
}
493 static char bad_op
[] = "illegal operator '%s' used on a string";
494 static char colon_err
[] = "A colon (:) must follow the '%s' command";
495 static char tok_err
[] = "Unexpected token '%s'";
496 static char extra_err
[] = "extraneous input ignored starting at '%s'";
497 static char oversize_err
[] = "value too long";
499 static struct sysparam
*
500 do_sysfile_cmd(struct _buf
*file
, const char *cmd
)
502 struct sysparam
*sysp
;
507 char tok1
[MOD_MAXPATH
+ 1]; /* used to read the path set by 'moddir' */
510 for (mcp
= modcmd
; mcp
->mc_cmdname
!= NULL
; mcp
++) {
511 if (strcmp(mcp
->mc_cmdname
, cmd
) == 0)
514 sysp
= vmem_alloc(mod_sysfile_arena
, sizeof (struct sysparam
),
516 bzero(sysp
, sizeof (struct sysparam
));
517 sysp
->sys_op
= SETOP_NONE
; /* set op to noop initially */
519 switch (sysp
->sys_type
= mcp
->mc_type
) {
524 * Are followed by colon.
528 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) == COLON
) {
529 token
= kobj_lex(file
, tok1
, sizeof (tok1
));
531 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
534 kobj_file_err(CE_WARN
, file
, "value expected");
538 cp
= tok1
+ strlen(tok1
);
539 while ((ch
= kobj_getc(file
)) != -1 && !iswhite(ch
) &&
541 if (cp
- tok1
>= sizeof (tok1
) - 1) {
542 kobj_file_err(CE_WARN
, file
, oversize_err
);
550 (void) kobj_ungetc(file
);
551 if (sysp
->sys_type
== MOD_INCLUDE
)
553 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
555 (void) strcpy(sysp
->sys_ptr
, tok1
);
564 if (kobj_lex(file
, tok1
, sizeof (tok1
)) != NAME
) {
565 kobj_file_err(CE_WARN
, file
, "value expected");
570 * If the next token is a colon (:),
571 * we have the <modname>:<variable> construct.
573 if ((token
= kobj_lex(file
, tok2
, sizeof (tok2
))) == COLON
) {
574 if ((token
= kobj_lex(file
, tok2
,
575 sizeof (tok2
))) == NAME
) {
578 * Save the module name.
580 sysp
->sys_modnam
= vmem_alloc(mod_sysfile_arena
,
581 strlen(tok1
) + 1, VM_SLEEP
);
582 (void) strcpy(sysp
->sys_modnam
, tok1
);
583 op
= kobj_lex(file
, tok1
, sizeof (tok1
));
585 kobj_file_err(CE_WARN
, file
, "value expected");
589 /* otherwise, it was the op */
594 * kernel param - place variable name in sys_ptr.
596 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(var
) + 1,
598 (void) strcpy(sysp
->sys_ptr
, var
);
602 /* simple assignment */
603 sysp
->sys_op
= SETOP_ASSIGN
;
607 sysp
->sys_op
= SETOP_AND
;
611 sysp
->sys_op
= SETOP_OR
;
614 /* unsupported operation */
615 kobj_file_err(CE_WARN
, file
,
616 "unsupported operator %s", tok2
);
620 switch ((tok3
= kobj_lex(file
, tok1
, sizeof (tok1
)))) {
622 /* string variable */
623 if (sysp
->sys_op
!= SETOP_ASSIGN
) {
624 kobj_file_err(CE_WARN
, file
, bad_op
, tok1
);
627 if (kobj_get_string(&sysp
->sys_info
, tok1
) == 0) {
628 kobj_file_err(CE_WARN
, file
, "string garbled");
632 * Set SYSPARAM_STR_TOKEN in sys_flags to notify
633 * sysparam_print_warning() that this is a string
636 sysp
->sys_flags
|= SYSPARAM_STR_TOKEN
;
640 if (kobj_getvalue(tok1
, &sysp
->sys_info
) == -1) {
641 kobj_file_err(CE_WARN
, file
,
642 "invalid number '%s'", tok1
);
647 * Set the appropriate flag (hexadecimal or decimal)
648 * in sys_flags for sysparam_print_warning() to be
649 * able to print the number with the correct format.
651 if (tok3
== HEXVAL
) {
652 sysp
->sys_flags
|= SYSPARAM_HEX_TOKEN
;
654 sysp
->sys_flags
|= SYSPARAM_DEC_TOKEN
;
658 kobj_file_err(CE_WARN
, file
, "bad rvalue '%s'", tok1
);
663 * Now that we've parsed it to check the syntax, consider
664 * discarding it (because it -doesn't- apply to this flavor
668 if (sysp
->sys_type
== MOD_SET32
)
671 if (sysp
->sys_type
== MOD_SET64
)
674 sysp
->sys_type
= MOD_SET
;
678 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) != COLON
) {
679 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
684 while ((token
= kobj_lex(file
, cp
,
685 sizeof (tok1
) - (cp
- tok1
))) != NEWLINE
&& token
!= EOF
) {
687 kobj_file_err(CE_WARN
, file
, oversize_err
);
691 while ((ch
= kobj_getc(file
)) != -1 && !iswhite(ch
) &&
692 !isnewline(ch
) && ch
!= ':') {
693 if (cp
- tok1
>= sizeof (tok1
) - 1) {
694 kobj_file_err(CE_WARN
, file
,
703 (void) kobj_ungetc(file
);
706 (void) kobj_ungetc(file
);
708 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
710 (void) strcpy(sysp
->sys_ptr
, tok1
);
715 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) != COLON
) {
716 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
719 while ((ch
= kobj_getc(file
)) == ' ' || ch
== '\t')
722 while (!iswhite(ch
) && !isnewline(ch
) && ch
!= -1) {
723 if (cp
- tok1
>= sizeof (tok1
) - 1) {
724 kobj_file_err(CE_WARN
, file
, oversize_err
);
729 ch
= kobj_getc(file
);
732 (void) kobj_ungetc(file
);
735 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
737 (void) strcpy(sysp
->sys_ptr
, tok1
);
742 kobj_file_err(CE_WARN
, file
, "unknown command '%s'", cmd
);
754 mod_read_system_file(int ask
)
756 register struct sysparam
*sp
;
757 register struct _buf
*file
;
758 register token_t token
, last_tok
;
759 char tokval
[MAXLINESIZE
];
761 mod_sysfile_arena
= vmem_create("mod_sysfile", NULL
, 0, 8,
762 segkmem_alloc
, segkmem_free
, heap_arena
, 0, VM_SLEEP
);
767 if (systemfile
!= NULL
) {
769 if ((file
= kobj_open_file(systemfile
)) ==
771 cmn_err(CE_WARN
, "cannot open system file: %s",
774 sysparam_tl
= (struct sysparam
*)&sysparam_hd
;
777 while ((token
= kobj_lex(file
, tokval
,
778 sizeof (tokval
))) != EOF
) {
792 if (last_tok
!= NEWLINE
) {
793 kobj_file_err(CE_WARN
, file
,
796 } else if ((sp
= do_sysfile_cmd(file
,
799 sysparam_tl
->sys_next
= sp
;
805 kobj_file_err(CE_WARN
,
806 file
, tok_err
, tokval
);
811 kobj_close_file(file
);
816 * Sanity check of /etc/system.
821 (void) mod_sysctl(SYS_SET_KVAR
, NULL
);
829 * Search for a specific module variable assignment in /etc/system. If
830 * successful, 1 is returned and the value is stored in '*value'.
831 * Otherwise 0 is returned and '*value' isn't modified. If 'module' is
832 * NULL we look for global definitions.
834 * This is useful if the value of an assignment is needed before a
835 * module is loaded (e.g. to obtain a default privileged rctl limit).
838 mod_sysvar(const char *module
, const char *name
, u_longlong_t
*value
)
840 struct sysparam
*sysp
;
841 int cnt
= 0; /* dummy */
843 ASSERT(name
!= NULL
);
844 ASSERT(value
!= NULL
);
845 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
847 if ((sysp
->sys_type
== MOD_SET
) &&
848 (((module
== NULL
) && (sysp
->sys_modnam
== NULL
)) ||
849 ((module
!= NULL
) && (sysp
->sys_modnam
!= NULL
) &&
850 (strcmp(module
, sysp
->sys_modnam
) == 0)))) {
852 ASSERT(sysp
->sys_ptr
!= NULL
);
854 if (strcmp(name
, sysp
->sys_ptr
) == 0) {
855 sysparam_count_entry(sysp
, &cnt
, value
);
856 if ((sysp
->sys_flags
& SYSPARAM_TERM
) != 0)
867 * This function scans sysparam records, which are created from the
868 * contents of /etc/system, for entries which are logical duplicates,
869 * and prints warning messages as appropriate. When multiple "set"
870 * commands are encountered, the pileup of values with "&", "|"
871 * and "=" operators results in the final value.
874 check_system_file(void)
876 struct sysparam
*sysp
;
878 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
879 struct sysparam
*entry
, *final
;
880 u_longlong_t value
= 0;
883 * If the entry is already checked, skip it.
885 if ((sysp
->sys_flags
& SYSPARAM_DUP
) != 0)
888 * Check if there is a duplicate entry by doing a linear
892 for (entry
= sysp
->sys_next
; entry
!= NULL
;
893 entry
= entry
->sys_next
) {
895 * Check the entry. if it's different, skip this.
897 if (sysparam_compare_entry(sysp
, entry
) != 0)
900 * Count the entry and put the mark.
902 sysparam_count_entry(entry
, &cnt
, &value
);
903 entry
->sys_flags
|= SYSPARAM_DUP
;
906 final
->sys_flags
|= SYSPARAM_TERM
;
908 * Print the warning if it's duplicated.
911 sysparam_print_warning(final
, value
);
916 * Compare the sysparam records.
917 * Return 0 if they are the same, return 1 if not.
920 sysparam_compare_entry(struct sysparam
*sysp
, struct sysparam
*entry
)
922 ASSERT(sysp
->sys_ptr
!= NULL
&& entry
->sys_ptr
!= NULL
);
925 * If the command is rootdev, rootfs, swapdev, swapfs or moddir,
926 * the record with the same type is treated as a duplicate record.
927 * In other cases, the record is treated as a duplicate record when
928 * its type, its module name (if it exists), and its variable name
931 switch (sysp
->sys_type
) {
937 return (sysp
->sys_type
== entry
->sys_type
? 0 : 1);
938 default: /* In other cases, just go through it. */
942 if (sysp
->sys_type
!= entry
->sys_type
)
945 if (sysp
->sys_modnam
!= NULL
&& entry
->sys_modnam
== NULL
)
948 if (sysp
->sys_modnam
== NULL
&& entry
->sys_modnam
!= NULL
)
951 if (sysp
->sys_modnam
!= NULL
&& entry
->sys_modnam
!= NULL
&&
952 strcmp(sysp
->sys_modnam
, entry
->sys_modnam
) != 0)
955 return (strcmp(sysp
->sys_ptr
, entry
->sys_ptr
));
959 * Translate a sysparam type value to a string.
962 sysparam_type_to_str(int type
)
966 for (mcp
= modcmd
; mcp
->mc_cmdname
!= NULL
; mcp
++) {
967 if (mcp
->mc_type
== type
)
970 ASSERT(mcp
->mc_type
== type
);
972 if (type
!= MOD_UNKNOWN
)
973 return ((++mcp
)->mc_cmdname
); /* lower case */
975 return (""); /* MOD_UNKNOWN */
979 * Check the entry and accumulate the number of entries.
982 sysparam_count_entry(struct sysparam
*sysp
, int *cnt
, u_longlong_t
*value
)
984 u_longlong_t ul
= sysp
->sys_info
;
986 switch (sysp
->sys_op
) {
997 default: /* Not MOD_SET */
1004 * Print out the warning if multiple entries are found in the system file.
1007 sysparam_print_warning(struct sysparam
*sysp
, u_longlong_t value
)
1009 char *modnam
= sysp
->sys_modnam
;
1010 char *varnam
= sysp
->sys_ptr
;
1011 int type
= sysp
->sys_type
;
1012 char *typenam
= sysparam_type_to_str(type
);
1013 boolean_t str_token
= ((sysp
->sys_flags
& SYSPARAM_STR_TOKEN
) != 0);
1014 boolean_t hex_number
= ((sysp
->sys_flags
& SYSPARAM_HEX_TOKEN
) != 0);
1015 #define warn_format1 " is set more than once in /%s. "
1016 #define warn_format2 " applied as the current setting.\n"
1018 ASSERT(varnam
!= NULL
);
1020 if (type
== MOD_SET
) {
1022 * If a string token is set, print out the string
1023 * instead of its pointer value. In other cases,
1024 * print out the value with the appropriate format
1025 * for a hexadecimal number or a decimal number.
1027 if (modnam
== NULL
) {
1028 if (str_token
== B_TRUE
) {
1029 cmn_err(CE_WARN
, "%s" warn_format1
1030 "\"%s %s = %s\"" warn_format2
,
1031 varnam
, systemfile
, typenam
,
1032 varnam
, (char *)(uintptr_t)value
);
1033 } else if (hex_number
== B_TRUE
) {
1034 cmn_err(CE_WARN
, "%s" warn_format1
1035 "\"%s %s = 0x%llx\"" warn_format2
,
1036 varnam
, systemfile
, typenam
,
1039 cmn_err(CE_WARN
, "%s" warn_format1
1040 "\"%s %s = %lld\"" warn_format2
,
1041 varnam
, systemfile
, typenam
,
1045 if (str_token
== B_TRUE
) {
1046 cmn_err(CE_WARN
, "%s:%s" warn_format1
1047 "\"%s %s:%s = %s\"" warn_format2
,
1048 modnam
, varnam
, systemfile
,
1049 typenam
, modnam
, varnam
,
1050 (char *)(uintptr_t)value
);
1051 } else if (hex_number
== B_TRUE
) {
1052 cmn_err(CE_WARN
, "%s:%s" warn_format1
1053 "\"%s %s:%s = 0x%llx\"" warn_format2
,
1054 modnam
, varnam
, systemfile
,
1055 typenam
, modnam
, varnam
, value
);
1057 cmn_err(CE_WARN
, "%s:%s" warn_format1
1058 "\"%s %s:%s = %lld\"" warn_format2
,
1059 modnam
, varnam
, systemfile
,
1060 typenam
, modnam
, varnam
, value
);
1065 * If the type is MOD_ROOTDEV, MOD_ROOTFS, MOD_SWAPDEV,
1066 * MOD_SWAPFS or MOD_MODDIR, the entry is treated as
1067 * a duplicate one if it has the same type regardless
1068 * of its variable name.
1076 cmn_err(CE_WARN
, "\"%s\" appears more than once "
1077 "in /%s.", typenam
, systemfile
);
1080 cmn_err(CE_NOTE
, "\"%s: %s\" appears more than once "
1081 "in /%s.", typenam
, varnam
, systemfile
);
1088 * Process the system file commands.
1091 mod_sysctl(int fcn
, void *p
)
1093 static char wmesg
[] = "forceload of %s failed";
1094 struct sysparam
*sysp
;
1096 struct modctl
*modp
;
1098 if (sysparam_hd
== NULL
)
1101 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
1106 if (sysp
->sys_type
== MOD_FORCELOAD
) {
1107 name
= sysp
->sys_ptr
;
1108 if (modload(NULL
, name
) == -1)
1109 cmn_err(CE_WARN
, wmesg
, name
);
1111 * The following works because it
1112 * runs before autounloading is started!!
1114 modp
= mod_find_by_filename(NULL
, name
);
1116 modp
->mod_loadflags
|= MOD_NOAUTOUNLOAD
;
1118 * For drivers, attempt to install it.
1120 if (strncmp(sysp
->sys_ptr
, "drv", 3) == 0) {
1121 (void) ddi_install_driver(name
+ 4);
1128 if (sysp
->sys_type
== MOD_SET
)
1129 sys_set_var(fcn
, sysp
, p
);
1132 case SYS_CHECK_EXCLUDE
:
1133 if (sysp
->sys_type
== MOD_EXCLUDE
) {
1134 if (p
== NULL
|| sysp
->sys_ptr
== NULL
)
1136 if (strcmp((char *)p
, sysp
->sys_ptr
) == 0)
1146 * Process the system file commands, by type.
1149 mod_sysctl_type(int type
, int (*func
)(struct sysparam
*, void *), void *p
)
1151 struct sysparam
*sysp
;
1154 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
)
1155 if (sysp
->sys_type
== type
)
1156 if (err
= (*(func
))(sysp
, p
))
1162 static char seterr
[] = "Symbol %s has size of 0 in symbol table. %s";
1163 static char assumption
[] = "Assuming it is an 'int'";
1164 static char defmsg
[] = "Trying to set a variable that is of size %d";
1166 static void set_int8_var(uintptr_t, struct sysparam
*);
1167 static void set_int16_var(uintptr_t, struct sysparam
*);
1168 static void set_int32_var(uintptr_t, struct sysparam
*);
1169 static void set_int64_var(uintptr_t, struct sysparam
*);
1172 sys_set_var(int fcn
, struct sysparam
*sysp
, void *p
)
1177 if (fcn
== SYS_SET_KVAR
&& sysp
->sys_modnam
== NULL
) {
1178 symaddr
= kobj_getelfsym(sysp
->sys_ptr
, NULL
, &size
);
1179 } else if (fcn
== SYS_SET_MVAR
) {
1180 if (sysp
->sys_modnam
== (char *)NULL
||
1181 strcmp(((struct modctl
*)p
)->mod_modname
,
1182 sysp
->sys_modnam
) != 0)
1184 symaddr
= kobj_getelfsym(sysp
->sys_ptr
,
1185 ((struct modctl
*)p
)->mod_mp
, &size
);
1189 if (symaddr
!= NULL
) {
1192 set_int8_var(symaddr
, sysp
);
1195 set_int16_var(symaddr
, sysp
);
1198 cmn_err(CE_WARN
, seterr
, sysp
->sys_ptr
, assumption
);
1201 set_int32_var(symaddr
, sysp
);
1204 set_int64_var(symaddr
, sysp
);
1207 cmn_err(CE_WARN
, defmsg
, size
);
1211 printf("sorry, variable '%s' is not defined in the '%s' ",
1213 sysp
->sys_modnam
? sysp
->sys_modnam
: "kernel");
1214 if (sysp
->sys_modnam
)
1221 set_int8_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1223 uint8_t uc
= (uint8_t)sysp
->sys_info
;
1225 if (moddebug
& MODDEBUG_LOADMSG
)
1226 printf("OP: %x: param '%s' was '0x%" PRIx8
1227 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1228 *(uint8_t *)symaddr
, sysp
->sys_modnam
);
1230 switch (sysp
->sys_op
) {
1232 *(uint8_t *)symaddr
= uc
;
1235 *(uint8_t *)symaddr
&= uc
;
1238 *(uint8_t *)symaddr
|= uc
;
1242 if (moddebug
& MODDEBUG_LOADMSG
)
1243 printf("now it is set to '0x%" PRIx8
"'.\n",
1244 *(uint8_t *)symaddr
);
1248 set_int16_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1250 uint16_t us
= (uint16_t)sysp
->sys_info
;
1252 if (moddebug
& MODDEBUG_LOADMSG
)
1253 printf("OP: %x: param '%s' was '0x%" PRIx16
1254 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1255 *(uint16_t *)symaddr
, sysp
->sys_modnam
);
1257 switch (sysp
->sys_op
) {
1259 *(uint16_t *)symaddr
= us
;
1262 *(uint16_t *)symaddr
&= us
;
1265 *(uint16_t *)symaddr
|= us
;
1269 if (moddebug
& MODDEBUG_LOADMSG
)
1270 printf("now it is set to '0x%" PRIx16
"'.\n",
1271 *(uint16_t *)symaddr
);
1275 set_int32_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1277 uint32_t ui
= (uint32_t)sysp
->sys_info
;
1279 if (moddebug
& MODDEBUG_LOADMSG
)
1280 printf("OP: %x: param '%s' was '0x%" PRIx32
1281 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1282 *(uint32_t *)symaddr
, sysp
->sys_modnam
);
1284 switch (sysp
->sys_op
) {
1286 *(uint32_t *)symaddr
= ui
;
1289 *(uint32_t *)symaddr
&= ui
;
1292 *(uint32_t *)symaddr
|= ui
;
1296 if (moddebug
& MODDEBUG_LOADMSG
)
1297 printf("now it is set to '0x%" PRIx32
"'.\n",
1298 *(uint32_t *)symaddr
);
1302 set_int64_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1304 uint64_t ul
= sysp
->sys_info
;
1306 if (moddebug
& MODDEBUG_LOADMSG
)
1307 printf("OP: %x: param '%s' was '0x%" PRIx64
1308 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1309 *(uint64_t *)symaddr
, sysp
->sys_modnam
);
1311 switch (sysp
->sys_op
) {
1313 *(uint64_t *)symaddr
= ul
;
1316 *(uint64_t *)symaddr
&= ul
;
1319 *(uint64_t *)symaddr
|= ul
;
1323 if (moddebug
& MODDEBUG_LOADMSG
)
1324 printf("now it is set to '0x%" PRIx64
"'.\n",
1325 *(uint64_t *)symaddr
);
1329 * The next item on the line is a string value. Allocate memory for
1330 * it and copy the string. Return 1, and set arg ptr to newly allocated
1331 * and initialized buffer, or NULL if an error occurs.
1334 kobj_get_string(u_longlong_t
*llptr
, char *tchar
)
1337 char *start
= (char *)0;
1340 len
= strlen(tchar
);
1343 cp
= vmem_alloc(mod_sysfile_arena
, len
+ 1, VM_SLEEP
);
1345 *llptr
= (u_longlong_t
)(uintptr_t)cp
;
1346 for (; len
> 0; len
--) {
1347 /* convert some common escape sequences */
1348 if (*start
== '\\') {
1349 switch (*(start
+ 1)) {
1369 /* simply copy it */
1382 * this function frees the memory allocated by kobj_get_string
1385 kobj_free_string(void *ptr
, int len
)
1387 vmem_free(mod_sysfile_arena
, ptr
, len
);
1392 * get a decimal octal or hex number. Handle '~' for one's complement.
1395 kobj_getvalue(const char *token
, u_longlong_t
*valuep
)
1398 u_longlong_t retval
= 0;
1403 if (*token
== '~') {
1404 onescompl
++; /* perform one's complement on result */
1406 } else if (*token
== '-') {
1410 if (*token
== '0') {
1415 *valuep
= 0; /* value is 0 */
1419 if (c
== 'x' || c
== 'X') {
1427 while ((c
= *token
++)) {
1430 if (c
>= '0' && c
<= '7')
1433 return (-1); /* invalid number */
1434 retval
= (retval
<< 3) + c
;
1437 if (c
>= '0' && c
<= '9')
1440 return (-1); /* invalid number */
1441 retval
= (retval
* 10) + c
;
1444 if (c
>= 'a' && c
<= 'f')
1446 else if (c
>= 'A' && c
<= 'F')
1448 else if (c
>= '0' && c
<= '9')
1451 return (-1); /* invalid number */
1452 retval
= (retval
<< 4) + c
;
1465 * Path to the root device and root filesystem type from
1466 * property information derived from the boot subsystem
1469 setbootpath(char *path
)
1471 rootfs
.bo_flags
|= BO_VALID
;
1472 (void) copystr(path
, rootfs
.bo_name
, BO_MAXOBJNAME
, NULL
);
1473 BMDPRINTF(("rootfs bootpath: %s\n", rootfs
.bo_name
));
1477 setbootfstype(char *fstype
)
1479 (void) copystr(fstype
, rootfs
.bo_fstype
, BO_MAXFSNAME
, NULL
);
1480 BMDPRINTF(("rootfs fstype: %s\n", rootfs
.bo_fstype
));
1484 * set parameters that can be set early during initialization.
1489 struct sysparam
*sysp
;
1490 struct bootobj
*bootobjp
;
1492 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
1494 if (sysp
->sys_type
== MOD_MODDIR
) {
1495 default_path
= sysp
->sys_ptr
;
1499 if (sysp
->sys_type
== MOD_SWAPDEV
||
1500 sysp
->sys_type
== MOD_SWAPFS
)
1501 bootobjp
= &swapfile
;
1502 else if (sysp
->sys_type
== MOD_ROOTFS
)
1505 switch (sysp
->sys_type
) {
1508 (void) copystr(sysp
->sys_ptr
, svm_bootpath
,
1509 BO_MAXOBJNAME
, NULL
);
1512 bootobjp
->bo_flags
|= BO_VALID
;
1513 (void) copystr(sysp
->sys_ptr
, bootobjp
->bo_name
,
1514 BO_MAXOBJNAME
, NULL
);
1518 bootobjp
->bo_flags
|= BO_VALID
;
1519 (void) copystr(sysp
->sys_ptr
, bootobjp
->bo_fstype
,
1520 BO_MAXOBJNAME
, NULL
);
1529 * clean up after an error.
1532 hwc_free(struct hwc_spec
*hwcp
)
1536 if ((name
= hwcp
->hwc_parent_name
) != NULL
)
1537 kmem_free(name
, strlen(name
) + 1);
1538 if ((name
= hwcp
->hwc_class_name
) != NULL
)
1539 kmem_free(name
, strlen(name
) + 1);
1540 if ((name
= hwcp
->hwc_devi_name
) != NULL
)
1541 kmem_free(name
, strlen(name
) + 1);
1542 i_ddi_prop_list_delete(hwcp
->hwc_devi_sys_prop_ptr
);
1543 kmem_free(hwcp
, sizeof (struct hwc_spec
));
1547 * Free a list of specs
1550 hwc_free_spec_list(struct hwc_spec
*list
)
1553 struct hwc_spec
*tmp
= list
;
1554 list
= tmp
->hwc_next
;
1560 struct val_list
*val_next
;
1572 static struct val_list
*
1573 add_val(struct val_list
**val_listp
, struct val_list
*tail
,
1574 int val_type
, caddr_t val
)
1576 struct val_list
*new_val
;
1578 struct val_list
*listp
= *val_listp
;
1581 new_val
= kmem_alloc(sizeof (struct val_list
), KM_SLEEP
);
1582 new_val
->val_next
= NULL
;
1583 if ((new_val
->val_type
= val_type
) == VAL_STRING
) {
1584 new_val
->val_size
= strlen((char *)val
) + 1;
1585 new_val
->val
.string
= kmem_alloc(new_val
->val_size
, KM_SLEEP
);
1586 (void) strcpy(new_val
->val
.string
, (char *)val
);
1588 new_val
->val_size
= sizeof (int);
1589 new_val
->val
.integer
= (int)(uintptr_t)val
;
1592 ASSERT((listp
== NULL
&& tail
== NULL
) ||
1593 (listp
!= NULL
&& tail
!= NULL
));
1596 ASSERT(tail
->val_next
== NULL
);
1597 tail
->val_next
= new_val
;
1599 *val_listp
= new_val
;
1606 free_val_list(struct val_list
*head
)
1608 struct val_list
*tval_list
;
1610 for (/* CSTYLED */; head
!= NULL
; /* CSTYLED */) {
1612 head
= head
->val_next
;
1613 if (tval_list
->val_type
== VAL_STRING
)
1614 kmem_free(tval_list
->val
.string
, tval_list
->val_size
);
1615 kmem_free(tval_list
, sizeof (struct val_list
));
1620 * make sure there are no reserved IEEE 1275 characters (except
1621 * for uppercase characters).
1624 valid_prop_name(char *name
)
1627 int len
= strlen(name
);
1629 for (i
= 0; i
< len
; i
++) {
1630 if (name
[i
] < 0x21 ||
1643 make_prop(struct _buf
*file
, dev_info_t
*devi
, char *name
, struct val_list
*val
)
1645 int propcnt
= 0, val_type
;
1646 struct val_list
*vl
, *tvl
;
1647 caddr_t valbuf
= NULL
;
1655 parse_debug(NULL
, "%s", name
);
1657 if (!valid_prop_name(name
)) {
1658 cmn_err(CE_WARN
, "invalid property name '%s'", name
);
1662 for (vl
= val
, val_type
= vl
->val_type
; vl
; vl
= vl
->val_next
) {
1663 if (val_type
!= vl
->val_type
) {
1664 cmn_err(CE_WARN
, "Mixed types in value list");
1672 if (val_type
== VAL_INTEGER
) {
1673 valip
= (int *)kmem_alloc(
1674 (propcnt
* sizeof (int)), KM_SLEEP
);
1675 valbuf
= (caddr_t
)valip
;
1680 parse_debug(NULL
, " %x", tvl
->val
.integer
);
1682 *valip
= tvl
->val
.integer
;
1686 valip
= (int *)valbuf
;
1688 /* create the property */
1689 if (e_ddi_prop_update_int_array(DDI_DEV_T_NONE
, devi
,
1690 name
, valip
, propcnt
) != DDI_PROP_SUCCESS
) {
1691 kobj_file_err(CE_WARN
, file
,
1692 "cannot create property %s", name
);
1695 kmem_free(valip
, (propcnt
* sizeof (int)));
1696 } else if (val_type
== VAL_STRING
) {
1697 valsp
= (char **)kmem_alloc(
1698 ((propcnt
+ 1) * sizeof (char *)), KM_SLEEP
);
1699 valbuf
= (caddr_t
)valsp
;
1704 parse_debug(NULL
, " %s", tvl
->val
.string
);
1706 *valsp
= tvl
->val
.string
;
1709 /* terminate array with NULL */
1713 valsp
= (char **)valbuf
;
1715 /* create the property */
1716 if (e_ddi_prop_update_string_array(DDI_DEV_T_NONE
,
1717 devi
, name
, valsp
, propcnt
)
1718 != DDI_PROP_SUCCESS
) {
1719 kobj_file_err(CE_WARN
, file
,
1720 "cannot create property %s", name
);
1723 kmem_free(valsp
, ((propcnt
+ 1) * sizeof (char *)));
1725 cmn_err(CE_WARN
, "Invalid property type");
1730 * No value was passed in with property so we will assume
1731 * it is a "boolean" property and create an integer
1732 * property with 0 value.
1735 parse_debug(NULL
, "\n");
1737 if (e_ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, name
, 0)
1738 != DDI_PROP_SUCCESS
) {
1739 kobj_file_err(CE_WARN
, file
,
1740 "cannot create property %s", name
);
1745 static char omit_err
[] = "(the ';' may have been omitted on previous spec!)";
1746 static char prnt_err
[] = "'parent' property already specified";
1747 static char nm_err
[] = "'name' property already specified";
1748 static char class_err
[] = "'class' property already specified";
1751 hwc_begin
, parent
, drvname
, drvclass
, prop
,
1752 parent_equals
, name_equals
, drvclass_equals
,
1753 parent_equals_string
, name_equals_string
,
1754 drvclass_equals_string
,
1755 prop_equals
, prop_equals_string
, prop_equals_integer
,
1756 prop_equals_string_comma
, prop_equals_integer_comma
1759 static struct hwc_spec
*
1760 get_hwc_spec(struct _buf
*file
, char *tokbuf
, size_t linesize
)
1764 struct hwc_spec
*hwcp
;
1765 struct dev_info
*devi
;
1766 struct val_list
*val_list
, *tail
;
1770 hwcp
= kmem_zalloc(sizeof (*hwcp
), KM_SLEEP
);
1771 devi
= kmem_zalloc(sizeof (*devi
), KM_SLEEP
);
1780 parse_debug(NULL
, "state 0x%x\n", state
);
1786 case prop_equals_string
:
1787 case prop_equals_integer
:
1788 make_prop(file
, (dev_info_t
*)devi
,
1789 prop_name
, val_list
);
1791 kmem_free(prop_name
,
1792 strlen(prop_name
) + 1);
1796 free_val_list(val_list
);
1802 if (strcmp(tokbuf
, "PARENT") == 0 ||
1803 strcmp(tokbuf
, "parent") == 0) {
1805 } else if (strcmp(tokbuf
, "NAME") == 0 ||
1806 strcmp(tokbuf
, "name") == 0) {
1808 } else if (strcmp(tokbuf
, "CLASS") == 0 ||
1809 strcmp(tokbuf
, "class") == 0) {
1811 prop_name
= kmem_alloc(strlen(tokbuf
) +
1813 (void) strcpy(prop_name
, tokbuf
);
1816 prop_name
= kmem_alloc(strlen(tokbuf
) +
1818 (void) strcpy(prop_name
, tokbuf
);
1822 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1828 state
= name_equals
;
1831 state
= parent_equals
;
1834 state
= drvclass_equals
;
1837 state
= prop_equals
;
1840 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1846 if (ddi_get_name((dev_info_t
*)devi
)) {
1847 kobj_file_err(CE_WARN
, file
, "%s %s",
1851 devi
->devi_name
= kmem_alloc(strlen(tokbuf
) + 1,
1853 (void) strcpy(devi
->devi_name
, tokbuf
);
1857 if (hwcp
->hwc_parent_name
) {
1858 kobj_file_err(CE_WARN
, file
, "%s %s",
1859 prnt_err
, omit_err
);
1862 hwcp
->hwc_parent_name
= kmem_alloc(strlen
1863 (tokbuf
) + 1, KM_SLEEP
);
1864 (void) strcpy(hwcp
->hwc_parent_name
, tokbuf
);
1867 case drvclass_equals
:
1868 if (hwcp
->hwc_class_name
) {
1869 kobj_file_err(CE_WARN
, file
, class_err
);
1872 hwcp
->hwc_class_name
= kmem_alloc(
1873 strlen(tokbuf
) + 1, KM_SLEEP
);
1874 (void) strcpy(hwcp
->hwc_class_name
, tokbuf
);
1877 case prop_equals_string_comma
:
1878 tail
= add_val(&val_list
, tail
, VAL_STRING
,
1880 state
= prop_equals_string
;
1883 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1890 case prop_equals_integer_comma
:
1891 (void) kobj_getvalue(tokbuf
, &ival
);
1892 tail
= add_val(&val_list
, tail
,
1893 VAL_INTEGER
, (caddr_t
)(uintptr_t)ival
);
1894 state
= prop_equals_integer
;
1897 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1902 case prop_equals_string
:
1903 state
= prop_equals_string_comma
;
1905 case prop_equals_integer
:
1906 state
= prop_equals_integer_comma
;
1909 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1919 kobj_find_eol(file
);
1922 kobj_file_err(CE_WARN
, file
, "Unexpected EOF");
1925 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1928 } while ((token
= kobj_lex(file
, tokbuf
, linesize
)) != SEMICOLON
);
1932 case prop_equals_string
:
1933 case prop_equals_integer
:
1934 make_prop(file
, (dev_info_t
*)devi
,
1935 prop_name
, val_list
);
1941 kobj_file_err(CE_WARN
, file
, "Unexpected end of line");
1945 /* copy 2 relevant members of devi to hwcp */
1946 hwcp
->hwc_devi_sys_prop_ptr
= devi
->devi_sys_prop_ptr
;
1947 hwcp
->hwc_devi_name
= devi
->devi_name
;
1950 kmem_free(prop_name
, strlen(prop_name
) + 1);
1952 free_val_list(val_list
);
1954 kmem_free(devi
, sizeof (struct dev_info
));
1960 kmem_free(prop_name
, strlen(prop_name
) + 1);
1962 free_val_list(val_list
);
1966 if (devi
->devi_name
)
1967 kmem_free(devi
->devi_name
, strlen(devi
->devi_name
) + 1);
1969 kmem_free(devi
, sizeof (struct dev_info
));
1975 * This is the primary kernel interface to parse driver.conf files.
1977 * Yet another bigstk thread handoff due to deep kernel stacks when booting
1978 * cache-only-clients.
1981 hwc_parse(char *fname
, struct par_list
**pl
, ddi_prop_t
**props
)
1984 struct hwc_parse_mt
*pltp
= hwc_parse_mtalloc(fname
, pl
, props
);
1986 if (curthread
!= &t0
) {
1987 (void) thread_create(NULL
, DEFAULTSTKSZ
* 2,
1988 hwc_parse_thread
, pltp
, 0, &p0
, TS_RUN
, maxclsyspri
);
1989 sema_p(&pltp
->sema
);
1991 pltp
->rv
= hwc_parse_now(fname
, pl
, props
);
1994 hwc_parse_mtfree(pltp
);
1999 * Calls to hwc_parse() are handled off to this routine in a separate
2003 hwc_parse_thread(struct hwc_parse_mt
*pltp
)
2008 mutex_init(&cpr_lk
, NULL
, MUTEX_DEFAULT
, NULL
);
2009 CALLB_CPR_INIT(&cpr_i
, &cpr_lk
, callb_generic_cpr
, "hwc_parse");
2012 * load and parse the .conf file
2013 * return the hwc_spec list (if any) to the creator of this thread
2015 pltp
->rv
= hwc_parse_now(pltp
->name
, pltp
->pl
, pltp
->props
);
2016 sema_v(&pltp
->sema
);
2017 mutex_enter(&cpr_lk
);
2018 CALLB_CPR_EXIT(&cpr_i
);
2019 mutex_destroy(&cpr_lk
);
2024 * allocate and initialize a hwc_parse thread control structure
2026 static struct hwc_parse_mt
*
2027 hwc_parse_mtalloc(char *name
, struct par_list
**pl
, ddi_prop_t
**props
)
2029 struct hwc_parse_mt
*pltp
= kmem_zalloc(sizeof (*pltp
), KM_SLEEP
);
2031 ASSERT(name
!= NULL
);
2033 pltp
->name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
2034 bcopy(name
, pltp
->name
, strlen(name
) + 1);
2036 pltp
->props
= props
;
2038 sema_init(&pltp
->sema
, 0, NULL
, SEMA_DEFAULT
, NULL
);
2043 * free a hwc_parse thread control structure
2046 hwc_parse_mtfree(struct hwc_parse_mt
*pltp
)
2048 sema_destroy(&pltp
->sema
);
2050 kmem_free(pltp
->name
, strlen(pltp
->name
) + 1);
2051 kmem_free(pltp
, sizeof (*pltp
));
2055 * hwc_parse -- parse an hwconf file. Ignore error lines and parse
2056 * as much as possible.
2059 hwc_parse_now(char *fname
, struct par_list
**pl
, ddi_prop_t
**props
)
2062 struct hwc_spec
*hwcp
;
2067 * Don't use kobj_open_path's use_moddir_suffix option, we only
2068 * expect to find conf files in the base module directory, not
2069 * an ISA-specific subdirectory.
2071 if ((file
= kobj_open_path(fname
, 1, 0)) == (struct _buf
*)-1) {
2072 if (moddebug
& MODDEBUG_ERRMSG
)
2073 cmn_err(CE_WARN
, "Cannot open %s", fname
);
2078 * Initialize variables
2080 tokval
= kmem_alloc(MAX_HWC_LINESIZE
, KM_SLEEP
);
2082 while ((token
= kobj_lex(file
, tokval
, MAX_HWC_LINESIZE
)) != EOF
) {
2088 kobj_find_eol(file
);
2091 hwcp
= get_hwc_spec(file
, tokval
, MAX_HWC_LINESIZE
);
2095 * No devi_name indicates global property.
2096 * Make sure parent and class not NULL.
2098 if (hwcp
->hwc_devi_name
== NULL
) {
2099 if (hwcp
->hwc_parent_name
||
2100 hwcp
->hwc_class_name
) {
2101 kobj_file_err(CE_WARN
, file
,
2102 "missing name attribute");
2106 /* Add to global property list */
2107 add_props(hwcp
, props
);
2112 * This is a node spec, either parent or class
2113 * must be specified.
2115 if ((hwcp
->hwc_parent_name
== NULL
) &&
2116 (hwcp
->hwc_class_name
== NULL
)) {
2117 kobj_file_err(CE_WARN
, file
,
2118 "missing parent or class attribute");
2123 /* add to node spec list */
2130 kobj_file_err(CE_WARN
, file
, tok_err
, tokval
);
2135 * XXX - Check for clean termination.
2137 kmem_free(tokval
, MAX_HWC_LINESIZE
);
2138 kobj_close_file(file
);
2139 return (0); /* always return success */
2143 make_aliases(struct bind
**bhash
)
2146 AL_NEW
, AL_DRVNAME
, AL_DRVNAME_COMMA
, AL_ALIAS
, AL_ALIAS_COMMA
2150 char tokbuf
[MAXPATHLEN
];
2151 char drvbuf
[MAXPATHLEN
];
2155 static char dupwarn
[] = "!Driver alias \"%s\" conflicts with "
2156 "an existing driver name or alias.";
2158 if ((file
= kobj_open_file(dafile
)) == (struct _buf
*)-1)
2162 major
= DDI_MAJOR_T_NONE
;
2164 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2170 kobj_find_eol(file
);
2176 (void) strcpy(drvbuf
, tokbuf
);
2179 case AL_DRVNAME_COMMA
:
2180 (void) strcat(drvbuf
, tokbuf
);
2183 case AL_ALIAS_COMMA
:
2184 (void) strcat(drvbuf
, tokbuf
);
2188 major
= mod_name_to_major(drvbuf
);
2189 if (major
== DDI_MAJOR_T_NONE
) {
2190 kobj_find_eol(file
);
2193 (void) strcpy(drvbuf
, tokbuf
);
2198 if (make_mbind(drvbuf
, major
, NULL
, bhash
)
2200 cmn_err(CE_WARN
, dupwarn
, drvbuf
);
2203 * copy this token just in case that there
2204 * are multiple names on the same line.
2206 (void) strcpy(drvbuf
, tokbuf
);
2211 (void) strcat(drvbuf
, tokbuf
);
2214 state
= AL_DRVNAME_COMMA
;
2217 state
= AL_ALIAS_COMMA
;
2220 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2227 if (state
== AL_ALIAS
) {
2228 if (make_mbind(drvbuf
, major
, NULL
, bhash
)
2230 cmn_err(CE_WARN
, dupwarn
, drvbuf
);
2232 } else if (state
!= AL_NEW
) {
2233 kobj_file_err(CE_WARN
, file
,
2234 "Missing alias for %s", drvbuf
);
2239 major
= DDI_MAJOR_T_NONE
;
2242 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2246 kobj_close_file(file
);
2251 * It is called for parsing these files:
2252 * - /etc/path_to_inst
2253 * - /etc/name_to_major
2254 * - /etc/name_to_sysnum
2255 * A callback "int (*line_parser)(char *, int, char *, struct bind **)"
2256 * is invoked for each line of the file.
2257 * The callback can inhash the entry into a hashtable by supplying
2258 * a pre-allocated hashtable in "struct bind **hashtab".
2261 read_binding_file(char *bindfile
, struct bind
**hashtab
,
2262 int (*line_parser
)(char *, int, char *, struct bind
**))
2265 B_NEW
, B_NAME
, B_VAL
, B_BIND_NAME
2268 char tokbuf
[MAXNAMELEN
];
2271 char *bind_name
= NULL
, *name
= NULL
, *bn
= NULL
;
2275 static char num_err
[] = "Missing number on preceding line?";
2276 static char dupwarn
[] = "!The binding file entry \"%s %u\" conflicts "
2277 "with a previous entry";
2279 if (hashtab
!= NULL
) {
2280 clear_binding_hash(hashtab
);
2283 if ((file
= kobj_open_file(bindfile
)) == (struct _buf
*)-1)
2284 panic("read_binding_file: %s file not found", bindfile
);
2289 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2296 kobj_find_eol(file
);
2303 * This case is for the first name and
2304 * possibly only name in an entry.
2306 ASSERT(name
== NULL
);
2307 name
= kmem_alloc(strlen(tokbuf
) + 1, KM_SLEEP
);
2308 (void) strcpy(name
, tokbuf
);
2313 * This case is for a second name, which
2314 * would be the binding name if the first
2315 * name was actually a generic name.
2317 ASSERT(bind_name
== NULL
);
2318 bind_name
= kmem_alloc(strlen(tokbuf
) + 1,
2320 (void) strcpy(bind_name
, tokbuf
);
2321 state
= B_BIND_NAME
;
2324 kobj_file_err(CE_WARN
, file
, num_err
);
2329 if (state
!= B_NAME
) {
2330 kobj_file_err(CE_WARN
, file
, "Missing name?");
2334 (void) kobj_getvalue(tokbuf
, &val
);
2335 if (val
> (u_longlong_t
)INT_MAX
) {
2336 kobj_file_err(CE_WARN
, file
,
2337 "value %llu too large", val
);
2347 if ((state
== B_BIND_NAME
) || (state
== B_VAL
)) {
2348 if (state
== B_BIND_NAME
)
2353 if (line_parser
!= NULL
) {
2354 if ((*line_parser
)(name
, (int)val
, bn
,
2356 maxnum
= MAX((int)val
, maxnum
);
2358 kobj_file_err(CE_WARN
, file
,
2359 dupwarn
, name
, (uint_t
)val
);
2361 } else if (state
!= B_NEW
)
2362 kobj_file_err(CE_WARN
, file
, "Syntax error?");
2365 kmem_free(name
, strlen(name
) + 1);
2369 kmem_free(bind_name
, strlen(bind_name
) + 1);
2376 kobj_file_err(CE_WARN
, file
, "Missing name/number?");
2381 ASSERT(name
== NULL
); /* any leaks? */
2382 ASSERT(bind_name
== NULL
);
2384 kobj_close_file(file
);
2389 * read_dacf_binding_file()
2390 * Read the /etc/dacf.conf file and build the dacf_rule_t database from it.
2392 * The syntax of a line in the dacf.conf file is:
2393 * dev-spec [module:]op-set operation options [config-args];
2396 * 1. dev-spec is of the format: name="data"
2397 * 2. operation is the operation that this rule matches. (i.e. pre-detach)
2398 * 3. options is a comma delimited list of options (i.e. debug,foobar)
2399 * 4. config-data is a whitespace delimited list of the format: name="data"
2402 read_dacf_binding_file(char *filename
)
2406 /* minor_nodetype="ddi_mouse:serial" */
2407 DACF_NT_SPEC
, DACF_NT_EQUALS
, DACF_NT_DATA
,
2408 /* consconfig:mouseconfig */
2409 DACF_MN_MODNAME
, DACF_MN_COLON
, DACF_MN_OPSET
,
2412 /* [ option1, option2, option3... | - ] */
2413 DACF_OPT_OPTION
, DACF_OPT_COMMA
, DACF_OPT_END
,
2414 /* argname1="argval1" argname2="argval2" ... */
2415 DACF_OPARG_SPEC
, DACF_OPARG_EQUALS
, DACF_OPARG_DATA
,
2416 DACF_ERR
, DACF_ERR_NEWLINE
, DACF_COMMENT
2417 } state
= DACF_BEGIN
;
2423 char tokbuf
[MAXNAMELEN
];
2424 char mn_modname_buf
[MAXNAMELEN
], *mn_modnamep
= NULL
;
2425 char mn_opset_buf
[MAXNAMELEN
], *mn_opsetp
= NULL
;
2426 char nt_data_buf
[MAXNAMELEN
], *nt_datap
= NULL
;
2427 char arg_spec_buf
[MAXNAMELEN
];
2430 dacf_devspec_t nt_spec_type
= DACF_DS_ERROR
;
2432 dacf_arg_t
*arg_list
= NULL
;
2433 dacf_opid_t opid
= DACF_OPID_ERROR
;
2436 static char w_syntax
[] = "'%s' unexpected";
2437 static char w_equals
[] = "'=' is illegal in the current context";
2438 static char w_baddevspec
[] = "device specification '%s' unrecognized";
2439 static char w_badop
[] = "operation '%s' unrecognized";
2440 static char w_badopt
[] = "option '%s' unrecognized, ignoring";
2441 static char w_newline
[] = "rule is incomplete";
2442 static char w_insert
[] = "failed to register rule";
2443 static char w_comment
[] = "'#' not allowed except at start of line";
2444 static char w_dupargs
[] =
2445 "argument '%s' duplicates a previous argument, skipping";
2446 static char w_nt_empty
[] = "empty device specification not allowed";
2448 if (filename
== NULL
) {
2449 fname
= dacffile
; /* default binding file */
2451 fname
= filename
; /* user specified */
2454 if ((file
= kobj_open_file(fname
)) == (struct _buf
*)-1) {
2458 if (dacfdebug
& DACF_DBG_MSGS
) {
2459 printf("dacf debug: clearing rules database\n");
2462 mutex_enter(&dacf_lock
);
2465 if (dacfdebug
& DACF_DBG_MSGS
) {
2466 printf("dacf debug: parsing %s\n", fname
);
2470 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2473 case POUND
: /* comment line */
2474 if (state
!= DACF_BEGIN
) {
2475 kobj_file_err(CE_WARN
, file
, w_comment
);
2479 state
= DACF_COMMENT
;
2480 kobj_find_eol(file
);
2486 state
= DACF_NT_EQUALS
;
2488 case DACF_OPARG_SPEC
:
2489 state
= DACF_OPARG_EQUALS
;
2492 kobj_file_err(CE_WARN
, file
, w_equals
);
2500 nt_spec_type
= dacf_get_devspec(tokbuf
);
2501 if (nt_spec_type
== DACF_DS_ERROR
) {
2502 kobj_file_err(CE_WARN
, file
,
2503 w_baddevspec
, tokbuf
);
2507 state
= DACF_NT_SPEC
;
2510 (void) strncpy(mn_modname_buf
, tokbuf
,
2511 sizeof (mn_modname_buf
));
2512 mn_modnamep
= mn_modname_buf
;
2513 state
= DACF_MN_MODNAME
;
2515 case DACF_MN_MODNAME
:
2517 * This handles the 'optional' modname.
2518 * What we thought was the modname is really
2519 * the op-set. So it is copied over.
2521 ASSERT(mn_modnamep
);
2522 (void) strncpy(mn_opset_buf
, mn_modnamep
,
2523 sizeof (mn_opset_buf
));
2524 mn_opsetp
= mn_opset_buf
;
2527 * Now, the token we just read is the opset,
2528 * so look that up and fill in opid
2530 if ((opid
= dacf_get_op(tokbuf
)) ==
2532 kobj_file_err(CE_WARN
, file
, w_badop
,
2537 state
= DACF_OP_NAME
;
2540 (void) strncpy(mn_opset_buf
, tokbuf
,
2541 sizeof (mn_opset_buf
));
2542 mn_opsetp
= mn_opset_buf
;
2543 state
= DACF_MN_OPSET
;
2546 if ((opid
= dacf_get_op(tokbuf
)) ==
2548 kobj_file_err(CE_WARN
, file
, w_badop
,
2553 state
= DACF_OP_NAME
;
2557 * This case is just like DACF_OPT_COMMA below,
2558 * but we check for the sole '-' argument
2560 if (strcmp(tokbuf
, "-") == 0) {
2561 state
= DACF_OPT_END
;
2565 case DACF_OPT_COMMA
:
2567 * figure out what option was given, but don't
2568 * make a federal case if invalid, just skip it
2570 if (dacf_getopt(tokbuf
, &opts
) != 0) {
2571 kobj_file_err(CE_WARN
, file
, w_badopt
,
2574 state
= DACF_OPT_OPTION
;
2577 case DACF_OPT_OPTION
:
2578 case DACF_OPARG_DATA
:
2579 (void) strncpy(arg_spec_buf
, tokbuf
,
2580 sizeof (arg_spec_buf
));
2581 state
= DACF_OPARG_SPEC
;
2583 case DACF_OPARG_EQUALS
:
2585 * Add the arg. Warn if it's a duplicate
2587 if (dacf_arg_insert(&arg_list
, arg_spec_buf
,
2589 kobj_file_err(CE_WARN
, file
, w_dupargs
,
2592 state
= DACF_OPARG_DATA
;
2595 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2603 * We need to check to see if the string has a \n in it.
2604 * If so, we had an unmatched " mark error, and lex has
2605 * already emitted an error for us, so we need to enter
2606 * the error state. Stupid lex.
2608 if (strchr(tokbuf
, '\n')) {
2613 case DACF_NT_EQUALS
:
2614 if (strlen(tokbuf
) == 0) {
2615 kobj_file_err(CE_WARN
, file
,
2620 state
= DACF_NT_DATA
;
2621 nt_datap
= nt_data_buf
;
2622 (void) strncpy(nt_datap
, tokbuf
,
2623 sizeof (nt_data_buf
));
2625 case DACF_OPARG_EQUALS
:
2627 * Add the arg. Warn if it's a duplicate
2629 if (dacf_arg_insert(&arg_list
, arg_spec_buf
,
2631 kobj_file_err(CE_WARN
, file
, w_dupargs
,
2634 state
= DACF_OPARG_DATA
;
2637 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2645 case DACF_OPT_OPTION
:
2646 state
= DACF_OPT_COMMA
;
2649 kobj_file_err(CE_WARN
, file
, w_syntax
, ",");
2656 if (state
== DACF_MN_MODNAME
)
2657 state
= DACF_MN_COLON
;
2659 kobj_file_err(CE_WARN
, file
, w_syntax
, ":");
2668 if (state
== DACF_COMMENT
|| state
== DACF_BEGIN
) {
2673 if ((state
!= DACF_OPT_OPTION
) &&
2674 (state
!= DACF_OPARG_DATA
) &&
2675 (state
!= DACF_OPT_END
)) {
2676 kobj_file_err(CE_WARN
, file
, w_newline
);
2678 * We can't just do DACF_ERR here, since we'll
2679 * wind up eating the _next_ newline if so.
2681 state
= DACF_ERR_NEWLINE
;
2689 if (dacf_rule_insert(nt_spec_type
, nt_datap
,
2690 mn_modnamep
, mn_opsetp
, opid
, opts
, arg_list
) < 0) {
2692 * We can't just do DACF_ERR here, since we'll
2693 * wind up eating the _next_ newline if so.
2695 kobj_file_err(CE_WARN
, file
, w_insert
);
2696 state
= DACF_ERR_NEWLINE
;
2706 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2711 * Clean up after ourselves, either after a line has terminated
2712 * successfully or because of a syntax error; or when we reach
2713 * EOF (remember, we may reach EOF without being 'done' with
2714 * handling a particular line).
2716 if (state
== DACF_ERR
) {
2717 kobj_find_eol(file
);
2719 if ((state
== DACF_BEGIN
) || (state
== DACF_ERR
) ||
2720 (state
== DACF_ERR_NEWLINE
) || done
) {
2722 mn_modnamep
= mn_opsetp
= NULL
;
2724 opid
= DACF_OPID_ERROR
;
2725 nt_spec_type
= DACF_DS_ERROR
;
2726 dacf_arglist_delete(&arg_list
);
2731 if (dacfdebug
& DACF_DBG_MSGS
) {
2732 printf("\ndacf debug: done!\n");
2735 mutex_exit(&dacf_lock
);
2737 kobj_close_file(file
);
2742 lock_hw_class_list()
2744 mutex_enter(&hcl_lock
);
2748 unlock_hw_class_list()
2750 mutex_exit(&hcl_lock
);
2754 add_class(char *exporter
, char *class)
2756 struct hwc_class
*hcl
;
2759 * If exporter's major is not registered in /etc/name_to_major,
2760 * don't update hwc_class, but just return here.
2762 if (ddi_name_to_major(exporter
) >= devcnt
) {
2763 cmn_err(CE_WARN
, "No major number for driver %s"
2764 " in class %s", exporter
, class);
2767 hcl
= kmem_zalloc(sizeof (struct hwc_class
), KM_SLEEP
);
2768 hcl
->class_exporter
= kmem_alloc(strlen(exporter
) + 1, KM_SLEEP
);
2769 hcl
->class_name
= kmem_alloc(strlen(class) + 1, KM_SLEEP
);
2770 (void) strcpy(hcl
->class_exporter
, exporter
);
2771 (void) strcpy(hcl
->class_name
, class);
2772 lock_hw_class_list();
2773 hcl
->class_next
= hcl_head
;
2775 unlock_hw_class_list();
2779 * Return the number of classes exported. If buf is not NULL, fill in
2780 * the array of the class names as well.
2782 * Caller must hold hcl_lock to ensure the class list unmodified while
2783 * it is accessed. A typical caller will get a count first and then
2784 * allocate buf. The lock should be held by the caller.
2787 get_class(const char *exporter
, char **buf
)
2790 struct hwc_class
*hcl
;
2792 ASSERT(mutex_owned(&hcl_lock
));
2793 for (hcl
= hcl_head
; hcl
!= NULL
; hcl
= hcl
->class_next
) {
2794 if (strcmp(exporter
, hcl
->class_exporter
) == 0) {
2796 buf
[n
] = hcl
->class_name
;
2805 read_class_file(void)
2808 struct hwc_class
*hcl
, *hcl1
;
2809 char tokbuf
[MAXNAMELEN
];
2811 C_BEGIN
, C_EXPORTER
, C_END
2815 char *exporter
= NULL
, *class = NULL
, *name
= NULL
;
2817 if (hcl_head
!= NULL
) {
2819 while (hcl
!= NULL
) {
2820 kmem_free(hcl
->class_exporter
,
2821 strlen(hcl
->class_exporter
) + 1);
2823 hcl
= hcl
->class_next
;
2824 kmem_free(hcl1
, sizeof (struct hwc_class
));
2829 if ((file
= kobj_open_file(class_file
)) == (struct _buf
*)-1)
2834 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2841 kobj_find_eol(file
);
2845 name
= kmem_alloc(strlen(tokbuf
) + 1, KM_SLEEP
);
2846 (void) strcpy(name
, tokbuf
);
2854 add_class(exporter
, class);
2858 kobj_file_err(CE_WARN
, file
,
2859 "Extra noise after entry");
2860 kmem_free(name
, strlen(name
) + 1);
2861 kobj_find_eol(file
);
2870 if (state
== C_EXPORTER
)
2871 kobj_file_err(CE_WARN
, file
,
2872 "Partial entry ignored");
2875 kmem_free(exporter
, strlen(exporter
) + 1);
2877 kmem_free(class, strlen(class) + 1);
2882 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2886 kobj_close_file(file
);
2890 * Given par_list, get a list of parent major number
2893 impl_parlist_to_major(struct par_list
*pl
, char parents
[])
2895 struct hwc_spec
*hwcp
;
2896 struct hwc_class
*hcl
;
2901 for (; pl
!= NULL
; pl
= pl
->par_next
) {
2902 if ((pl
->par_major
< devcnt
) && (parents
[pl
->par_major
] == 0)) {
2903 parents
[pl
->par_major
] = 1;
2908 /* parent specs cannot be mapped to a driver */
2909 if (pl
->par_major
!= DDI_MAJOR_T_NONE
)
2913 hwcp
= pl
->par_specs
;
2914 ASSERT(hwcp
->hwc_class_name
);
2915 ASSERT(hwcp
->hwc_parent_name
== NULL
);
2917 for (hcl
= hcl_head
; hcl
!= NULL
; hcl
= hcl
->class_next
) {
2918 if (strcmp(hwcp
->hwc_class_name
, hcl
->class_name
) != 0)
2920 major
= ddi_name_to_major(hcl
->class_exporter
);
2921 ASSERT(major
!= DDI_MAJOR_T_NONE
);
2922 if (parents
[major
] == 0) {
2932 * delete a parent list and all its hwc specs
2935 impl_delete_par_list(struct par_list
*pl
)
2937 struct par_list
*saved_pl
;
2938 struct hwc_spec
*hp
, *hp1
;
2949 kmem_free(saved_pl
, sizeof (*saved_pl
));
2953 #if defined(_PSM_MODULES)
2955 open_mach_list(void)
2958 char tokbuf
[MAXNAMELEN
];
2960 struct psm_mach
*machp
;
2962 if ((file
= kobj_open_file(mach_file
)) == (struct _buf
*)-1)
2965 while ((token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
))) != EOF
) {
2971 kobj_find_eol(file
);
2975 machp
= kmem_alloc((sizeof (struct psm_mach
) +
2976 strlen(tokbuf
) + 1), KM_SLEEP
);
2977 machp
->m_next
= pmach_head
;
2978 machp
->m_machname
= (char *)(machp
+ 1);
2979 (void) strcpy(machp
->m_machname
, tokbuf
);
2986 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2990 kobj_close_file(file
);
2994 get_next_mach(void *handle
, char *buf
)
2996 struct psm_mach
*machp
;
2998 machp
= (struct psm_mach
*)handle
;
3000 machp
= machp
->m_next
;
3004 (void) strcpy(buf
, machp
->m_machname
);
3009 close_mach_list(void)
3011 struct psm_mach
*machp
;
3013 while (pmach_head
) {
3015 pmach_head
= machp
->m_next
;
3016 kmem_free(machp
, sizeof (struct psm_mach
) +
3017 strlen(machp
->m_machname
) + 1);
3020 #endif /* _PSM_MODULES */
3022 #if defined(_RTC_CONFIG)
3024 * Read in the 'zone_lag' value from the rtc configuration file,
3025 * and return the value to the caller. Note that there is other information
3026 * in this file (zone_info), so we ignore unknown values. We do spit out
3027 * warnings if the line doesn't begin with an identifier, or if we don't find
3028 * exactly "zone_lag=value". No one should be editing this file by hand
3029 * (use the rtc command instead), but it's better to be careful.
3032 process_rtc_config_file(void)
3035 R_NEW
, R_NAME
, R_EQUALS
, R_VALUE
3038 char tokbuf
[MAXNAMELEN
];
3044 if ((file
= kobj_open_file(rtc_config_file
)) == (struct _buf
*)-1)
3050 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
3057 kobj_find_eol(file
);
3061 if (state
== R_NEW
) {
3062 if (strcmp(tokbuf
, "zone_lag") == 0)
3065 kobj_find_eol(file
); /* Ignore */
3067 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3070 if (state
== R_NAME
)
3073 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3076 if (state
== R_EQUALS
) {
3077 if (kobj_getvalue(tokbuf
, &tmp
) != 0)
3078 kobj_file_err(CE_WARN
, file
,
3079 "Bad value %s for zone_lag",
3082 zone_lag
= (long)tmp
;
3085 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3091 if (state
!= R_NEW
&& state
!= R_VALUE
)
3092 kobj_file_err(CE_WARN
, file
,
3093 "Partial zone_lag entry ignored");
3098 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3102 kobj_close_file(file
);
3105 #endif /* _RTC_CONFIG */
3109 * Append node spec to the end of par_list
3112 append(struct hwc_spec
*spec
, struct par_list
*par
)
3114 struct hwc_spec
*hwc
, *last
;
3116 ASSERT(par
->par_specs
);
3117 for (hwc
= par
->par_specs
; hwc
; hwc
= hwc
->hwc_next
)
3119 last
->hwc_next
= spec
;
3123 * Given a parent=/full-pathname, see if the platform
3124 * can resolve the pathname to driver, otherwise, try
3125 * the leaf node name.
3128 get_major(char *parent
)
3130 major_t major
= DDI_MAJOR_T_NONE
;
3131 char *tmp
, *driver
= NULL
;
3134 major
= path_to_major(parent
);
3136 if (major
!= DDI_MAJOR_T_NONE
)
3139 /* extract the name between '/' and '@' */
3141 driver
= strrchr(parent
, '/') + 1;
3144 if ((tmp
= strchr(driver
, '@')) != NULL
)
3146 major
= ddi_name_to_major(driver
);
3153 * Chain together specs whose parent's module name is the same.
3156 add_spec(struct hwc_spec
*spec
, struct par_list
**par
)
3159 struct par_list
*pl
, *par_last
= NULL
;
3160 char *parent
= spec
->hwc_parent_name
;
3161 char *class = spec
->hwc_class_name
;
3163 ASSERT(parent
|| class);
3166 * If given a parent=/full-pathname, see if the platform
3167 * can resolve the pathname to driver, otherwise, try
3168 * the leaf node name.
3170 * If parent=/full-pathname doesn't resolve to a driver,
3171 * this could be cause by DR removal of the device.
3172 * We put it on the major=-2 list in case the device
3173 * is brought back into the system by DR.
3176 maj
= get_major(parent
);
3177 if (maj
== DDI_MAJOR_T_NONE
) {
3178 if ((*parent
== '/') &&
3179 (strncmp(parent
, "/pseudo", 7) != 0)) {
3183 "add_spec: No major number for %s",
3190 maj
= DDI_MAJOR_T_NONE
;
3193 * Scan the list looking for a matching parent. When parent is
3194 * not NULL, we match the parent by major. If parent is NULL but
3195 * class is not NULL, we mache the pl by class name.
3197 for (pl
= *par
; pl
; pl
= pl
->par_next
) {
3198 if ((parent
&& (maj
== pl
->par_major
)) || ((parent
== NULL
) &&
3199 class && pl
->par_specs
->hwc_class_name
&& (strncmp(class,
3200 pl
->par_specs
->hwc_class_name
, strlen(class)) == 0))) {
3208 * Didn't find a match on the list. Make a new parent list.
3210 pl
= kmem_zalloc(sizeof (*pl
), KM_SLEEP
);
3211 pl
->par_major
= maj
;
3212 pl
->par_specs
= spec
;
3213 if (*par
== NULL
) { /* null par list */
3217 /* put "class=" entries last (lower pri if dups) */
3218 if (maj
== DDI_MAJOR_T_NONE
) {
3219 par_last
->par_next
= pl
;
3223 /* ensure unresolved "parent=/full-path" goes first */
3224 if ((maj
!= (major_t
)-2) && ((*par
)->par_major
== (major_t
)-2))
3225 par
= &(*par
)->par_next
;
3226 pl
->par_next
= *par
;
3231 * Add property spec to property list in original order
3234 add_props(struct hwc_spec
*spec
, ddi_prop_t
**props
)
3236 ASSERT(spec
->hwc_devi_name
== NULL
);
3238 if (spec
->hwc_devi_sys_prop_ptr
) {
3240 props
= &(*props
)->prop_next
;
3241 *props
= spec
->hwc_devi_sys_prop_ptr
;
3243 /* remove these properties from the spec */
3244 spec
->hwc_devi_sys_prop_ptr
= NULL
;