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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright 2016 Nexenta Systems, Inc.
28 #include <sys/types.h>
29 #include <sys/inttypes.h>
30 #include <sys/param.h>
31 #include <sys/systm.h>
35 #include <sys/bootconf.h>
36 #include <sys/sysconf.h>
37 #include <sys/sunddi.h>
38 #include <sys/esunddi.h>
39 #include <sys/ddi_impldefs.h>
42 #include <sys/fs/ufs_fsdir.h>
43 #include <sys/hwconf.h>
44 #include <sys/modctl.h>
45 #include <sys/cmn_err.h>
47 #include <sys/kobj_lex.h>
48 #include <sys/errno.h>
49 #include <sys/debug.h>
50 #include <sys/autoconf.h>
51 #include <sys/callb.h>
52 #include <sys/sysmacros.h>
54 #include <vm/seg_kmem.h>
56 struct hwc_class
*hcl_head
; /* head of list of classes */
57 static kmutex_t hcl_lock
; /* for accessing list of classes */
59 #define DAFILE "/etc/driver_aliases"
60 #define CLASSFILE "/etc/driver_classes"
61 #define DACFFILE "/etc/dacf.conf"
63 static char class_file
[] = CLASSFILE
;
64 static char dafile
[] = DAFILE
;
65 static char dacffile
[] = DACFFILE
;
67 char *systemfile
= "/etc/system"; /* name of ascii system file */
69 static struct sysparam
*sysparam_hd
; /* head of parameters list */
70 static struct sysparam
*sysparam_tl
; /* tail of parameters list */
71 static vmem_t
*mod_sysfile_arena
; /* parser memory */
73 char obp_bootpath
[BO_MAXOBJNAME
]; /* bootpath from obp */
75 #if defined(_PSM_MODULES)
78 struct psm_mach
*m_next
;
82 static struct psm_mach
*pmach_head
; /* head of list of classes */
84 #define MACHFILE "/etc/mach"
85 static char mach_file
[] = MACHFILE
;
87 #endif /* _PSM_MODULES */
89 #if defined(_RTC_CONFIG)
90 static char rtc_config_file
[] = "/etc/rtc_config";
93 static void sys_set_var(int, struct sysparam
*, void *);
95 static void setparams(void);
98 * driver.conf parse thread control structure
100 struct hwc_parse_mt
{
102 char *name
; /* name of .conf files */
103 struct par_list
**pl
; /* parsed parent list */
104 ddi_prop_t
**props
; /* parsed properties */
105 int rv
; /* return value */
108 static int hwc_parse_now(char *, struct par_list
**, ddi_prop_t
**);
109 static void hwc_parse_thread(struct hwc_parse_mt
*);
110 static struct hwc_parse_mt
*hwc_parse_mtalloc(char *, struct par_list
**,
112 static void hwc_parse_mtfree(struct hwc_parse_mt
*);
113 static void add_spec(struct hwc_spec
*, struct par_list
**);
114 static void add_props(struct hwc_spec
*, ddi_prop_t
**);
116 static void check_system_file(void);
117 static int sysparam_compare_entry(struct sysparam
*, struct sysparam
*);
118 static char *sysparam_type_to_str(int);
119 static void sysparam_count_entry(struct sysparam
*, int *, u_longlong_t
*);
120 static void sysparam_print_warning(struct sysparam
*, u_longlong_t
);
123 static int parse_debug_on
= 0;
127 parse_debug(struct _buf
*file
, char *fmt
, ...)
131 if (parse_debug_on
) {
135 printf(" on line %d of %s\n", kobj_linenum(file
),
136 kobj_filename(file
));
142 #define FE_BUFLEN 256
146 kobj_file_err(int type
, struct _buf
*file
, char *fmt
, ...)
150 * If we're in trouble, we might be short on stack... be paranoid
152 char *buf
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
153 char *trailer
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
154 char *fmt_str
= kmem_alloc(FE_BUFLEN
, KM_SLEEP
);
158 if (strchr("^!?", fmt
[0]) != NULL
) {
162 (void) vsnprintf(buf
, FE_BUFLEN
, fmt
, ap
);
164 (void) snprintf(trailer
, FE_BUFLEN
, " on line %d of %s",
165 kobj_linenum(file
), kobj_filename(file
));
168 * If prefixed with !^?, prepend that character
170 if (prefix
!= '\0') {
171 (void) snprintf(fmt_str
, FE_BUFLEN
, "%c%%s%%s", prefix
);
173 (void) strncpy(fmt_str
, "%s%s", FE_BUFLEN
);
176 cmn_err(type
, fmt_str
, buf
, trailer
);
177 kmem_free(buf
, FE_BUFLEN
);
178 kmem_free(trailer
, FE_BUFLEN
);
179 kmem_free(fmt_str
, FE_BUFLEN
);
183 char *tokennames
[] = {
205 kobj_lex(struct _buf
*file
, char *val
, size_t size
)
208 int ch
, oval
, badquote
;
210 token_t token
= UNEXPECTED
;
213 return (token
); /* this token is UNEXPECTED */
216 while ((ch
= kobj_getc(file
)) == ' ' || ch
== '\t')
252 while ((ch
= kobj_getc(file
)) == ' ' ||
253 ch
== '\t' || ch
== '\f') {
260 (void) kobj_ungetc(file
);
271 while (!badquote
&& (ch
= kobj_getc(file
)) != '"') {
275 kobj_file_err(CE_WARN
, file
, "Missing \"");
280 /* since we consumed the newline/EOF */
281 (void) kobj_ungetc(file
);
289 ch
= (char)kobj_getc(file
);
291 /* escape the character */
296 while (ch
>= '0' && ch
<= '7') {
298 oval
= (oval
<< 3) + ch
;
299 ch
= (char)kobj_getc(file
);
301 (void) kobj_ungetc(file
);
302 /* check for character overflow? */
306 "overflow detected.");
328 * detect a lone '-' (including at the end of a line), and
329 * identify it as a 'name'
336 *cp
++ = (char)(ch
= kobj_getc(file
));
337 if (iswhite(ch
) || (ch
== '\n')) {
338 (void) kobj_ungetc(file
);
344 } else if (isunary(ch
)) {
349 *cp
++ = (char)(ch
= kobj_getc(file
));
355 if ((ch
= kobj_getc(file
)) == 'x') {
361 ch
= kobj_getc(file
);
362 while (isxdigit(ch
)) {
368 ch
= kobj_getc(file
);
370 (void) kobj_ungetc(file
);
376 ch
= kobj_getc(file
);
378 while (isdigit(ch
)) {
384 ch
= kobj_getc(file
);
386 (void) kobj_ungetc(file
);
389 } else if (isalpha(ch
) || ch
== '\\' || ch
== '_') {
391 ch
= kobj_getc(file
);
394 * if the character was a backslash,
395 * back up so we can overwrite it with
396 * the next (i.e. escaped) character.
401 while (isnamechar(ch
) || ch
== '\\') {
403 ch
= kobj_getc(file
);
409 ch
= kobj_getc(file
);
411 (void) kobj_ungetc(file
);
423 * The UNEXPECTED token is the first element of the tokennames array,
424 * but its token value is -1. Adjust the value by adding one to it
425 * to change it to an index of the array.
427 parse_debug(NULL
, "kobj_lex: token %s value '%s'\n",
428 tokennames
[token
+1], val
);
434 * Leave NEWLINE as the next character.
438 kobj_find_eol(struct _buf
*file
)
442 while ((ch
= kobj_getc(file
)) != -1) {
444 (void) kobj_ungetc(file
);
451 * The ascii system file is read and processed.
453 * The syntax of commands is as follows:
455 * '*' in column 1 is a comment line.
456 * <command> : <value>
458 * command is EXCLUDE, INCLUDE, FORCELOAD, ROOTDEV, ROOTFS,
459 * SWAPDEV, SWAPFS, MODDIR, SET
461 * value is an ascii string meaningful for the command.
467 static struct modcmd modcmd
[] = {
468 { "EXCLUDE", MOD_EXCLUDE
},
469 { "exclude", MOD_EXCLUDE
},
470 { "INCLUDE", MOD_INCLUDE
},
471 { "include", MOD_INCLUDE
},
472 { "FORCELOAD", MOD_FORCELOAD
},
473 { "forceload", MOD_FORCELOAD
},
474 { "ROOTDEV", MOD_ROOTDEV
},
475 { "rootdev", MOD_ROOTDEV
},
476 { "ROOTFS", MOD_ROOTFS
},
477 { "rootfs", MOD_ROOTFS
},
478 { "SWAPDEV", MOD_SWAPDEV
},
479 { "swapdev", MOD_SWAPDEV
},
480 { "SWAPFS", MOD_SWAPFS
},
481 { "swapfs", MOD_SWAPFS
},
482 { "MODDIR", MOD_MODDIR
},
483 { "moddir", MOD_MODDIR
},
486 { "SET32", MOD_SET32
},
487 { "set32", MOD_SET32
},
488 { "SET64", MOD_SET64
},
489 { "set64", MOD_SET64
},
490 { NULL
, MOD_UNKNOWN
}
494 static char bad_op
[] = "illegal operator '%s' used on a string";
495 static char colon_err
[] = "A colon (:) must follow the '%s' command";
496 static char tok_err
[] = "Unexpected token '%s'";
497 static char extra_err
[] = "extraneous input ignored starting at '%s'";
498 static char oversize_err
[] = "value too long";
500 static struct sysparam
*
501 do_sysfile_cmd(struct _buf
*file
, const char *cmd
)
503 struct sysparam
*sysp
;
508 char tok1
[MOD_MAXPATH
+ 1]; /* used to read the path set by 'moddir' */
511 for (mcp
= modcmd
; mcp
->mc_cmdname
!= NULL
; mcp
++) {
512 if (strcmp(mcp
->mc_cmdname
, cmd
) == 0)
515 sysp
= vmem_alloc(mod_sysfile_arena
, sizeof (struct sysparam
),
517 bzero(sysp
, sizeof (struct sysparam
));
518 sysp
->sys_op
= SETOP_NONE
; /* set op to noop initially */
520 switch (sysp
->sys_type
= mcp
->mc_type
) {
525 * Are followed by colon.
529 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) == COLON
) {
530 token
= kobj_lex(file
, tok1
, sizeof (tok1
));
532 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
535 kobj_file_err(CE_WARN
, file
, "value expected");
539 cp
= tok1
+ strlen(tok1
);
540 while ((ch
= kobj_getc(file
)) != -1 && !iswhite(ch
) &&
542 if (cp
- tok1
>= sizeof (tok1
) - 1) {
543 kobj_file_err(CE_WARN
, file
, oversize_err
);
551 (void) kobj_ungetc(file
);
552 if (sysp
->sys_type
== MOD_INCLUDE
)
554 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
556 (void) strcpy(sysp
->sys_ptr
, tok1
);
565 if (kobj_lex(file
, tok1
, sizeof (tok1
)) != NAME
) {
566 kobj_file_err(CE_WARN
, file
, "value expected");
571 * If the next token is a colon (:),
572 * we have the <modname>:<variable> construct.
574 if ((token
= kobj_lex(file
, tok2
, sizeof (tok2
))) == COLON
) {
575 if ((token
= kobj_lex(file
, tok2
,
576 sizeof (tok2
))) == NAME
) {
579 * Save the module name.
581 sysp
->sys_modnam
= vmem_alloc(mod_sysfile_arena
,
582 strlen(tok1
) + 1, VM_SLEEP
);
583 (void) strcpy(sysp
->sys_modnam
, tok1
);
584 op
= kobj_lex(file
, tok1
, sizeof (tok1
));
586 kobj_file_err(CE_WARN
, file
, "value expected");
590 /* otherwise, it was the op */
595 * kernel param - place variable name in sys_ptr.
597 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(var
) + 1,
599 (void) strcpy(sysp
->sys_ptr
, var
);
603 /* simple assignment */
604 sysp
->sys_op
= SETOP_ASSIGN
;
608 sysp
->sys_op
= SETOP_AND
;
612 sysp
->sys_op
= SETOP_OR
;
615 /* unsupported operation */
616 kobj_file_err(CE_WARN
, file
,
617 "unsupported operator %s", tok2
);
621 switch ((tok3
= kobj_lex(file
, tok1
, sizeof (tok1
)))) {
623 /* string variable */
624 if (sysp
->sys_op
!= SETOP_ASSIGN
) {
625 kobj_file_err(CE_WARN
, file
, bad_op
, tok1
);
628 if (kobj_get_string(&sysp
->sys_info
, tok1
) == 0) {
629 kobj_file_err(CE_WARN
, file
, "string garbled");
633 * Set SYSPARAM_STR_TOKEN in sys_flags to notify
634 * sysparam_print_warning() that this is a string
637 sysp
->sys_flags
|= SYSPARAM_STR_TOKEN
;
641 if (kobj_getvalue(tok1
, &sysp
->sys_info
) == -1) {
642 kobj_file_err(CE_WARN
, file
,
643 "invalid number '%s'", tok1
);
648 * Set the appropriate flag (hexadecimal or decimal)
649 * in sys_flags for sysparam_print_warning() to be
650 * able to print the number with the correct format.
652 if (tok3
== HEXVAL
) {
653 sysp
->sys_flags
|= SYSPARAM_HEX_TOKEN
;
655 sysp
->sys_flags
|= SYSPARAM_DEC_TOKEN
;
659 kobj_file_err(CE_WARN
, file
, "bad rvalue '%s'", tok1
);
664 * Now that we've parsed it to check the syntax, consider
665 * discarding it (because it -doesn't- apply to this flavor
669 if (sysp
->sys_type
== MOD_SET32
)
672 if (sysp
->sys_type
== MOD_SET64
)
675 sysp
->sys_type
= MOD_SET
;
679 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) != COLON
) {
680 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
685 while ((token
= kobj_lex(file
, cp
,
686 sizeof (tok1
) - (cp
- tok1
))) != NEWLINE
&& token
!= EOF
) {
688 kobj_file_err(CE_WARN
, file
, oversize_err
);
692 while ((ch
= kobj_getc(file
)) != -1 && !iswhite(ch
) &&
693 !isnewline(ch
) && ch
!= ':') {
694 if (cp
- tok1
>= sizeof (tok1
) - 1) {
695 kobj_file_err(CE_WARN
, file
,
704 (void) kobj_ungetc(file
);
707 (void) kobj_ungetc(file
);
709 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
711 (void) strcpy(sysp
->sys_ptr
, tok1
);
716 if ((token
= kobj_lex(file
, tok1
, sizeof (tok1
))) != COLON
) {
717 kobj_file_err(CE_WARN
, file
, colon_err
, cmd
);
720 while ((ch
= kobj_getc(file
)) == ' ' || ch
== '\t')
723 while (!iswhite(ch
) && !isnewline(ch
) && ch
!= -1) {
724 if (cp
- tok1
>= sizeof (tok1
) - 1) {
725 kobj_file_err(CE_WARN
, file
, oversize_err
);
730 ch
= kobj_getc(file
);
733 (void) kobj_ungetc(file
);
736 sysp
->sys_ptr
= vmem_alloc(mod_sysfile_arena
, strlen(tok1
) + 1,
738 (void) strcpy(sysp
->sys_ptr
, tok1
);
743 kobj_file_err(CE_WARN
, file
, "unknown command '%s'", cmd
);
755 mod_read_system_file(int ask
)
757 register struct sysparam
*sp
;
758 register struct _buf
*file
;
759 register token_t token
, last_tok
;
760 char tokval
[MAXLINESIZE
];
762 mod_sysfile_arena
= vmem_create("mod_sysfile", NULL
, 0, 8,
763 segkmem_alloc
, segkmem_free
, heap_arena
, 0, VM_SLEEP
);
768 if (systemfile
!= NULL
) {
770 if ((file
= kobj_open_file(systemfile
)) ==
772 cmn_err(CE_WARN
, "cannot open system file: %s",
775 sysparam_tl
= (struct sysparam
*)&sysparam_hd
;
778 while ((token
= kobj_lex(file
, tokval
,
779 sizeof (tokval
))) != EOF
) {
793 if (last_tok
!= NEWLINE
) {
794 kobj_file_err(CE_WARN
, file
,
797 } else if ((sp
= do_sysfile_cmd(file
,
800 sysparam_tl
->sys_next
= sp
;
806 kobj_file_err(CE_WARN
,
807 file
, tok_err
, tokval
);
812 kobj_close_file(file
);
817 * Sanity check of /etc/system.
822 (void) mod_sysctl(SYS_SET_KVAR
, NULL
);
830 * Search for a specific module variable assignment in /etc/system. If
831 * successful, 1 is returned and the value is stored in '*value'.
832 * Otherwise 0 is returned and '*value' isn't modified. If 'module' is
833 * NULL we look for global definitions.
835 * This is useful if the value of an assignment is needed before a
836 * module is loaded (e.g. to obtain a default privileged rctl limit).
839 mod_sysvar(const char *module
, const char *name
, u_longlong_t
*value
)
841 struct sysparam
*sysp
;
842 int cnt
= 0; /* dummy */
844 ASSERT(name
!= NULL
);
845 ASSERT(value
!= NULL
);
846 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
848 if ((sysp
->sys_type
== MOD_SET
) &&
849 (((module
== NULL
) && (sysp
->sys_modnam
== NULL
)) ||
850 ((module
!= NULL
) && (sysp
->sys_modnam
!= NULL
) &&
851 (strcmp(module
, sysp
->sys_modnam
) == 0)))) {
853 ASSERT(sysp
->sys_ptr
!= NULL
);
855 if (strcmp(name
, sysp
->sys_ptr
) == 0) {
856 sysparam_count_entry(sysp
, &cnt
, value
);
857 if ((sysp
->sys_flags
& SYSPARAM_TERM
) != 0)
868 * This function scans sysparam records, which are created from the
869 * contents of /etc/system, for entries which are logical duplicates,
870 * and prints warning messages as appropriate. When multiple "set"
871 * commands are encountered, the pileup of values with "&", "|"
872 * and "=" operators results in the final value.
875 check_system_file(void)
877 struct sysparam
*sysp
;
879 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
880 struct sysparam
*entry
, *final
;
881 u_longlong_t value
= 0;
884 * If the entry is already checked, skip it.
886 if ((sysp
->sys_flags
& SYSPARAM_DUP
) != 0)
889 * Check if there is a duplicate entry by doing a linear
893 for (entry
= sysp
->sys_next
; entry
!= NULL
;
894 entry
= entry
->sys_next
) {
896 * Check the entry. if it's different, skip this.
898 if (sysparam_compare_entry(sysp
, entry
) != 0)
901 * Count the entry and put the mark.
903 sysparam_count_entry(entry
, &cnt
, &value
);
904 entry
->sys_flags
|= SYSPARAM_DUP
;
907 final
->sys_flags
|= SYSPARAM_TERM
;
909 * Print the warning if it's duplicated.
912 sysparam_print_warning(final
, value
);
917 * Compare the sysparam records.
918 * Return 0 if they are the same, return 1 if not.
921 sysparam_compare_entry(struct sysparam
*sysp
, struct sysparam
*entry
)
923 ASSERT(sysp
->sys_ptr
!= NULL
&& entry
->sys_ptr
!= NULL
);
926 * If the command is rootdev, rootfs, swapdev, swapfs or moddir,
927 * the record with the same type is treated as a duplicate record.
928 * In other cases, the record is treated as a duplicate record when
929 * its type, its module name (if it exists), and its variable name
932 switch (sysp
->sys_type
) {
938 return (sysp
->sys_type
== entry
->sys_type
? 0 : 1);
939 default: /* In other cases, just go through it. */
943 if (sysp
->sys_type
!= entry
->sys_type
)
946 if (sysp
->sys_modnam
!= NULL
&& entry
->sys_modnam
== NULL
)
949 if (sysp
->sys_modnam
== NULL
&& entry
->sys_modnam
!= NULL
)
952 if (sysp
->sys_modnam
!= NULL
&& entry
->sys_modnam
!= NULL
&&
953 strcmp(sysp
->sys_modnam
, entry
->sys_modnam
) != 0)
956 return (strcmp(sysp
->sys_ptr
, entry
->sys_ptr
));
960 * Translate a sysparam type value to a string.
963 sysparam_type_to_str(int type
)
967 for (mcp
= modcmd
; mcp
->mc_cmdname
!= NULL
; mcp
++) {
968 if (mcp
->mc_type
== type
)
971 ASSERT(mcp
->mc_type
== type
);
973 if (type
!= MOD_UNKNOWN
)
974 return ((++mcp
)->mc_cmdname
); /* lower case */
976 return (""); /* MOD_UNKNOWN */
980 * Check the entry and accumulate the number of entries.
983 sysparam_count_entry(struct sysparam
*sysp
, int *cnt
, u_longlong_t
*value
)
985 u_longlong_t ul
= sysp
->sys_info
;
987 switch (sysp
->sys_op
) {
998 default: /* Not MOD_SET */
1005 * Print out the warning if multiple entries are found in the system file.
1008 sysparam_print_warning(struct sysparam
*sysp
, u_longlong_t value
)
1010 char *modnam
= sysp
->sys_modnam
;
1011 char *varnam
= sysp
->sys_ptr
;
1012 int type
= sysp
->sys_type
;
1013 char *typenam
= sysparam_type_to_str(type
);
1014 boolean_t str_token
= ((sysp
->sys_flags
& SYSPARAM_STR_TOKEN
) != 0);
1015 boolean_t hex_number
= ((sysp
->sys_flags
& SYSPARAM_HEX_TOKEN
) != 0);
1016 #define warn_format1 " is set more than once in /%s. "
1017 #define warn_format2 " applied as the current setting.\n"
1019 ASSERT(varnam
!= NULL
);
1021 if (type
== MOD_SET
) {
1023 * If a string token is set, print out the string
1024 * instead of its pointer value. In other cases,
1025 * print out the value with the appropriate format
1026 * for a hexadecimal number or a decimal number.
1028 if (modnam
== NULL
) {
1029 if (str_token
== B_TRUE
) {
1030 cmn_err(CE_WARN
, "%s" warn_format1
1031 "\"%s %s = %s\"" warn_format2
,
1032 varnam
, systemfile
, typenam
,
1033 varnam
, (char *)(uintptr_t)value
);
1034 } else if (hex_number
== B_TRUE
) {
1035 cmn_err(CE_WARN
, "%s" warn_format1
1036 "\"%s %s = 0x%llx\"" warn_format2
,
1037 varnam
, systemfile
, typenam
,
1040 cmn_err(CE_WARN
, "%s" warn_format1
1041 "\"%s %s = %lld\"" warn_format2
,
1042 varnam
, systemfile
, typenam
,
1046 if (str_token
== B_TRUE
) {
1047 cmn_err(CE_WARN
, "%s:%s" warn_format1
1048 "\"%s %s:%s = %s\"" warn_format2
,
1049 modnam
, varnam
, systemfile
,
1050 typenam
, modnam
, varnam
,
1051 (char *)(uintptr_t)value
);
1052 } else if (hex_number
== B_TRUE
) {
1053 cmn_err(CE_WARN
, "%s:%s" warn_format1
1054 "\"%s %s:%s = 0x%llx\"" warn_format2
,
1055 modnam
, varnam
, systemfile
,
1056 typenam
, modnam
, varnam
, value
);
1058 cmn_err(CE_WARN
, "%s:%s" warn_format1
1059 "\"%s %s:%s = %lld\"" warn_format2
,
1060 modnam
, varnam
, systemfile
,
1061 typenam
, modnam
, varnam
, value
);
1066 * If the type is MOD_ROOTDEV, MOD_ROOTFS, MOD_SWAPDEV,
1067 * MOD_SWAPFS or MOD_MODDIR, the entry is treated as
1068 * a duplicate one if it has the same type regardless
1069 * of its variable name.
1077 cmn_err(CE_WARN
, "\"%s\" appears more than once "
1078 "in /%s.", typenam
, systemfile
);
1081 cmn_err(CE_NOTE
, "\"%s: %s\" appears more than once "
1082 "in /%s.", typenam
, varnam
, systemfile
);
1089 * Process the system file commands.
1092 mod_sysctl(int fcn
, void *p
)
1094 static char wmesg
[] = "forceload of %s failed";
1095 struct sysparam
*sysp
;
1097 struct modctl
*modp
;
1099 if (sysparam_hd
== NULL
)
1102 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
1107 if (sysp
->sys_type
== MOD_FORCELOAD
) {
1108 name
= sysp
->sys_ptr
;
1109 if (modload(NULL
, name
) == -1)
1110 cmn_err(CE_WARN
, wmesg
, name
);
1112 * The following works because it
1113 * runs before autounloading is started!!
1115 modp
= mod_find_by_filename(NULL
, name
);
1117 modp
->mod_loadflags
|= MOD_NOAUTOUNLOAD
;
1119 * For drivers, attempt to install it.
1121 if (strncmp(sysp
->sys_ptr
, "drv", 3) == 0) {
1122 (void) ddi_install_driver(name
+ 4);
1129 if (sysp
->sys_type
== MOD_SET
)
1130 sys_set_var(fcn
, sysp
, p
);
1133 case SYS_CHECK_EXCLUDE
:
1134 if (sysp
->sys_type
== MOD_EXCLUDE
) {
1135 if (p
== NULL
|| sysp
->sys_ptr
== NULL
)
1137 if (strcmp((char *)p
, sysp
->sys_ptr
) == 0)
1147 * Process the system file commands, by type.
1150 mod_sysctl_type(int type
, int (*func
)(struct sysparam
*, void *), void *p
)
1152 struct sysparam
*sysp
;
1155 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
)
1156 if (sysp
->sys_type
== type
)
1157 if (err
= (*(func
))(sysp
, p
))
1163 static char seterr
[] = "Symbol %s has size of 0 in symbol table. %s";
1164 static char assumption
[] = "Assuming it is an 'int'";
1165 static char defmsg
[] = "Trying to set a variable that is of size %d";
1167 static void set_int8_var(uintptr_t, struct sysparam
*);
1168 static void set_int16_var(uintptr_t, struct sysparam
*);
1169 static void set_int32_var(uintptr_t, struct sysparam
*);
1170 static void set_int64_var(uintptr_t, struct sysparam
*);
1173 sys_set_var(int fcn
, struct sysparam
*sysp
, void *p
)
1178 if (fcn
== SYS_SET_KVAR
&& sysp
->sys_modnam
== NULL
) {
1179 symaddr
= kobj_getelfsym(sysp
->sys_ptr
, NULL
, &size
);
1180 } else if (fcn
== SYS_SET_MVAR
) {
1181 if (sysp
->sys_modnam
== NULL
||
1182 strcmp(((struct modctl
*)p
)->mod_modname
,
1183 sysp
->sys_modnam
) != 0)
1185 symaddr
= kobj_getelfsym(sysp
->sys_ptr
,
1186 ((struct modctl
*)p
)->mod_mp
, &size
);
1190 if (symaddr
!= (uintptr_t)NULL
) {
1193 set_int8_var(symaddr
, sysp
);
1196 set_int16_var(symaddr
, sysp
);
1199 cmn_err(CE_WARN
, seterr
, sysp
->sys_ptr
, assumption
);
1202 set_int32_var(symaddr
, sysp
);
1205 set_int64_var(symaddr
, sysp
);
1208 cmn_err(CE_WARN
, defmsg
, size
);
1212 printf("sorry, variable '%s' is not defined in the '%s' ",
1214 sysp
->sys_modnam
? sysp
->sys_modnam
: "kernel");
1215 if (sysp
->sys_modnam
)
1222 set_int8_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1224 uint8_t uc
= (uint8_t)sysp
->sys_info
;
1226 if (moddebug
& MODDEBUG_LOADMSG
)
1227 printf("OP: %x: param '%s' was '0x%" PRIx8
1228 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1229 *(uint8_t *)symaddr
, sysp
->sys_modnam
);
1231 switch (sysp
->sys_op
) {
1233 *(uint8_t *)symaddr
= uc
;
1236 *(uint8_t *)symaddr
&= uc
;
1239 *(uint8_t *)symaddr
|= uc
;
1243 if (moddebug
& MODDEBUG_LOADMSG
)
1244 printf("now it is set to '0x%" PRIx8
"'.\n",
1245 *(uint8_t *)symaddr
);
1249 set_int16_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1251 uint16_t us
= (uint16_t)sysp
->sys_info
;
1253 if (moddebug
& MODDEBUG_LOADMSG
)
1254 printf("OP: %x: param '%s' was '0x%" PRIx16
1255 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1256 *(uint16_t *)symaddr
, sysp
->sys_modnam
);
1258 switch (sysp
->sys_op
) {
1260 *(uint16_t *)symaddr
= us
;
1263 *(uint16_t *)symaddr
&= us
;
1266 *(uint16_t *)symaddr
|= us
;
1270 if (moddebug
& MODDEBUG_LOADMSG
)
1271 printf("now it is set to '0x%" PRIx16
"'.\n",
1272 *(uint16_t *)symaddr
);
1276 set_int32_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1278 uint32_t ui
= (uint32_t)sysp
->sys_info
;
1280 if (moddebug
& MODDEBUG_LOADMSG
)
1281 printf("OP: %x: param '%s' was '0x%" PRIx32
1282 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1283 *(uint32_t *)symaddr
, sysp
->sys_modnam
);
1285 switch (sysp
->sys_op
) {
1287 *(uint32_t *)symaddr
= ui
;
1290 *(uint32_t *)symaddr
&= ui
;
1293 *(uint32_t *)symaddr
|= ui
;
1297 if (moddebug
& MODDEBUG_LOADMSG
)
1298 printf("now it is set to '0x%" PRIx32
"'.\n",
1299 *(uint32_t *)symaddr
);
1303 set_int64_var(uintptr_t symaddr
, struct sysparam
*sysp
)
1305 uint64_t ul
= sysp
->sys_info
;
1307 if (moddebug
& MODDEBUG_LOADMSG
)
1308 printf("OP: %x: param '%s' was '0x%" PRIx64
1309 "' in module: '%s'.\n", sysp
->sys_op
, sysp
->sys_ptr
,
1310 *(uint64_t *)symaddr
, sysp
->sys_modnam
);
1312 switch (sysp
->sys_op
) {
1314 *(uint64_t *)symaddr
= ul
;
1317 *(uint64_t *)symaddr
&= ul
;
1320 *(uint64_t *)symaddr
|= ul
;
1324 if (moddebug
& MODDEBUG_LOADMSG
)
1325 printf("now it is set to '0x%" PRIx64
"'.\n",
1326 *(uint64_t *)symaddr
);
1330 * The next item on the line is a string value. Allocate memory for
1331 * it and copy the string. Return 1, and set arg ptr to newly allocated
1332 * and initialized buffer, or NULL if an error occurs.
1335 kobj_get_string(u_longlong_t
*llptr
, char *tchar
)
1338 char *start
= (char *)0;
1341 len
= strlen(tchar
);
1344 cp
= vmem_alloc(mod_sysfile_arena
, len
+ 1, VM_SLEEP
);
1346 *llptr
= (u_longlong_t
)(uintptr_t)cp
;
1347 for (; len
> 0; len
--) {
1348 /* convert some common escape sequences */
1349 if (*start
== '\\') {
1350 switch (*(start
+ 1)) {
1370 /* simply copy it */
1383 * this function frees the memory allocated by kobj_get_string
1386 kobj_free_string(void *ptr
, int len
)
1388 vmem_free(mod_sysfile_arena
, ptr
, len
);
1393 * get a decimal octal or hex number. Handle '~' for one's complement.
1396 kobj_getvalue(const char *token
, u_longlong_t
*valuep
)
1399 u_longlong_t retval
= 0;
1404 if (*token
== '~') {
1405 onescompl
++; /* perform one's complement on result */
1407 } else if (*token
== '-') {
1411 if (*token
== '0') {
1416 *valuep
= 0; /* value is 0 */
1420 if (c
== 'x' || c
== 'X') {
1428 while ((c
= *token
++)) {
1431 if (c
>= '0' && c
<= '7')
1434 return (-1); /* invalid number */
1435 retval
= (retval
<< 3) + c
;
1438 if (c
>= '0' && c
<= '9')
1441 return (-1); /* invalid number */
1442 retval
= (retval
* 10) + c
;
1445 if (c
>= 'a' && c
<= 'f')
1447 else if (c
>= 'A' && c
<= 'F')
1449 else if (c
>= '0' && c
<= '9')
1452 return (-1); /* invalid number */
1453 retval
= (retval
<< 4) + c
;
1466 * Path to the root device and root filesystem type from
1467 * property information derived from the boot subsystem
1470 setbootpath(char *path
)
1472 rootfs
.bo_flags
|= BO_VALID
;
1473 (void) copystr(path
, rootfs
.bo_name
, BO_MAXOBJNAME
, NULL
);
1474 BMDPRINTF(("rootfs bootpath: %s\n", rootfs
.bo_name
));
1478 setbootfstype(char *fstype
)
1480 (void) copystr(fstype
, rootfs
.bo_fstype
, BO_MAXFSNAME
, NULL
);
1481 BMDPRINTF(("rootfs fstype: %s\n", rootfs
.bo_fstype
));
1485 * set parameters that can be set early during initialization.
1490 struct sysparam
*sysp
;
1491 struct bootobj
*bootobjp
;
1493 for (sysp
= sysparam_hd
; sysp
!= NULL
; sysp
= sysp
->sys_next
) {
1495 if (sysp
->sys_type
== MOD_MODDIR
) {
1496 default_path
= sysp
->sys_ptr
;
1500 if (sysp
->sys_type
== MOD_SWAPDEV
||
1501 sysp
->sys_type
== MOD_SWAPFS
)
1502 bootobjp
= &swapfile
;
1503 else if (sysp
->sys_type
== MOD_ROOTFS
)
1506 switch (sysp
->sys_type
) {
1508 bootobjp
->bo_flags
|= BO_VALID
;
1509 (void) copystr(sysp
->sys_ptr
, bootobjp
->bo_name
,
1510 BO_MAXOBJNAME
, NULL
);
1514 bootobjp
->bo_flags
|= BO_VALID
;
1515 (void) copystr(sysp
->sys_ptr
, bootobjp
->bo_fstype
,
1516 BO_MAXOBJNAME
, NULL
);
1526 * clean up after an error.
1529 hwc_free(struct hwc_spec
*hwcp
)
1533 if ((name
= hwcp
->hwc_parent_name
) != NULL
)
1534 kmem_free(name
, strlen(name
) + 1);
1535 if ((name
= hwcp
->hwc_class_name
) != NULL
)
1536 kmem_free(name
, strlen(name
) + 1);
1537 if ((name
= hwcp
->hwc_devi_name
) != NULL
)
1538 kmem_free(name
, strlen(name
) + 1);
1539 i_ddi_prop_list_delete(hwcp
->hwc_devi_sys_prop_ptr
);
1540 kmem_free(hwcp
, sizeof (struct hwc_spec
));
1544 * Free a list of specs
1547 hwc_free_spec_list(struct hwc_spec
*list
)
1550 struct hwc_spec
*tmp
= list
;
1551 list
= tmp
->hwc_next
;
1557 struct val_list
*val_next
;
1569 static struct val_list
*
1570 add_val(struct val_list
**val_listp
, struct val_list
*tail
,
1571 int val_type
, caddr_t val
)
1573 struct val_list
*new_val
;
1575 struct val_list
*listp
= *val_listp
;
1578 new_val
= kmem_alloc(sizeof (struct val_list
), KM_SLEEP
);
1579 new_val
->val_next
= NULL
;
1580 if ((new_val
->val_type
= val_type
) == VAL_STRING
) {
1581 new_val
->val_size
= strlen((char *)val
) + 1;
1582 new_val
->val
.string
= kmem_alloc(new_val
->val_size
, KM_SLEEP
);
1583 (void) strcpy(new_val
->val
.string
, (char *)val
);
1585 new_val
->val_size
= sizeof (int);
1586 new_val
->val
.integer
= (int)(uintptr_t)val
;
1589 ASSERT((listp
== NULL
&& tail
== NULL
) ||
1590 (listp
!= NULL
&& tail
!= NULL
));
1593 ASSERT(tail
->val_next
== NULL
);
1594 tail
->val_next
= new_val
;
1596 *val_listp
= new_val
;
1603 free_val_list(struct val_list
*head
)
1605 struct val_list
*tval_list
;
1607 for (/* CSTYLED */; head
!= NULL
; /* CSTYLED */) {
1609 head
= head
->val_next
;
1610 if (tval_list
->val_type
== VAL_STRING
)
1611 kmem_free(tval_list
->val
.string
, tval_list
->val_size
);
1612 kmem_free(tval_list
, sizeof (struct val_list
));
1617 * make sure there are no reserved IEEE 1275 characters (except
1618 * for uppercase characters).
1621 valid_prop_name(char *name
)
1624 int len
= strlen(name
);
1626 for (i
= 0; i
< len
; i
++) {
1627 if (name
[i
] < 0x21 ||
1640 make_prop(struct _buf
*file
, dev_info_t
*devi
, char *name
, struct val_list
*val
)
1642 int propcnt
= 0, val_type
;
1643 struct val_list
*vl
, *tvl
;
1644 caddr_t valbuf
= NULL
;
1652 parse_debug(NULL
, "%s", name
);
1654 if (!valid_prop_name(name
)) {
1655 cmn_err(CE_WARN
, "invalid property name '%s'", name
);
1659 for (vl
= val
, val_type
= vl
->val_type
; vl
; vl
= vl
->val_next
) {
1660 if (val_type
!= vl
->val_type
) {
1661 cmn_err(CE_WARN
, "Mixed types in value list");
1669 if (val_type
== VAL_INTEGER
) {
1670 valip
= (int *)kmem_alloc(
1671 (propcnt
* sizeof (int)), KM_SLEEP
);
1672 valbuf
= (caddr_t
)valip
;
1677 parse_debug(NULL
, " %x", tvl
->val
.integer
);
1679 *valip
= tvl
->val
.integer
;
1683 valip
= (int *)valbuf
;
1685 /* create the property */
1686 if (e_ddi_prop_update_int_array(DDI_DEV_T_NONE
, devi
,
1687 name
, valip
, propcnt
) != DDI_PROP_SUCCESS
) {
1688 kobj_file_err(CE_WARN
, file
,
1689 "cannot create property %s", name
);
1692 kmem_free(valip
, (propcnt
* sizeof (int)));
1693 } else if (val_type
== VAL_STRING
) {
1694 valsp
= (char **)kmem_alloc(
1695 ((propcnt
+ 1) * sizeof (char *)), KM_SLEEP
);
1696 valbuf
= (caddr_t
)valsp
;
1701 parse_debug(NULL
, " %s", tvl
->val
.string
);
1703 *valsp
= tvl
->val
.string
;
1706 /* terminate array with NULL */
1710 valsp
= (char **)valbuf
;
1712 /* create the property */
1713 if (e_ddi_prop_update_string_array(DDI_DEV_T_NONE
,
1714 devi
, name
, valsp
, propcnt
)
1715 != DDI_PROP_SUCCESS
) {
1716 kobj_file_err(CE_WARN
, file
,
1717 "cannot create property %s", name
);
1720 kmem_free(valsp
, ((propcnt
+ 1) * sizeof (char *)));
1722 cmn_err(CE_WARN
, "Invalid property type");
1727 * No value was passed in with property so we will assume
1728 * it is a "boolean" property and create an integer
1729 * property with 0 value.
1732 parse_debug(NULL
, "\n");
1734 if (e_ddi_prop_update_int(DDI_DEV_T_NONE
, devi
, name
, 0)
1735 != DDI_PROP_SUCCESS
) {
1736 kobj_file_err(CE_WARN
, file
,
1737 "cannot create property %s", name
);
1742 static char omit_err
[] = "(the ';' may have been omitted on previous spec!)";
1743 static char prnt_err
[] = "'parent' property already specified";
1744 static char nm_err
[] = "'name' property already specified";
1745 static char class_err
[] = "'class' property already specified";
1748 hwc_begin
, parent
, drvname
, drvclass
, prop
,
1749 parent_equals
, name_equals
, drvclass_equals
,
1750 parent_equals_string
, name_equals_string
,
1751 drvclass_equals_string
,
1752 prop_equals
, prop_equals_string
, prop_equals_integer
,
1753 prop_equals_string_comma
, prop_equals_integer_comma
1756 static struct hwc_spec
*
1757 get_hwc_spec(struct _buf
*file
, char *tokbuf
, size_t linesize
)
1761 struct hwc_spec
*hwcp
;
1762 struct dev_info
*devi
;
1763 struct val_list
*val_list
, *tail
;
1767 hwcp
= kmem_zalloc(sizeof (*hwcp
), KM_SLEEP
);
1768 devi
= kmem_zalloc(sizeof (*devi
), KM_SLEEP
);
1777 parse_debug(NULL
, "state 0x%x\n", state
);
1783 case prop_equals_string
:
1784 case prop_equals_integer
:
1785 make_prop(file
, (dev_info_t
*)devi
,
1786 prop_name
, val_list
);
1788 kmem_free(prop_name
,
1789 strlen(prop_name
) + 1);
1793 free_val_list(val_list
);
1799 if (strcmp(tokbuf
, "PARENT") == 0 ||
1800 strcmp(tokbuf
, "parent") == 0) {
1802 } else if (strcmp(tokbuf
, "NAME") == 0 ||
1803 strcmp(tokbuf
, "name") == 0) {
1805 } else if (strcmp(tokbuf
, "CLASS") == 0 ||
1806 strcmp(tokbuf
, "class") == 0) {
1808 prop_name
= kmem_alloc(strlen(tokbuf
) +
1810 (void) strcpy(prop_name
, tokbuf
);
1813 prop_name
= kmem_alloc(strlen(tokbuf
) +
1815 (void) strcpy(prop_name
, tokbuf
);
1819 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1825 state
= name_equals
;
1828 state
= parent_equals
;
1831 state
= drvclass_equals
;
1834 state
= prop_equals
;
1837 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1843 if (ddi_get_name((dev_info_t
*)devi
)) {
1844 kobj_file_err(CE_WARN
, file
, "%s %s",
1848 devi
->devi_name
= kmem_alloc(strlen(tokbuf
) + 1,
1850 (void) strcpy(devi
->devi_name
, tokbuf
);
1854 if (hwcp
->hwc_parent_name
) {
1855 kobj_file_err(CE_WARN
, file
, "%s %s",
1856 prnt_err
, omit_err
);
1859 hwcp
->hwc_parent_name
= kmem_alloc(strlen
1860 (tokbuf
) + 1, KM_SLEEP
);
1861 (void) strcpy(hwcp
->hwc_parent_name
, tokbuf
);
1864 case drvclass_equals
:
1865 if (hwcp
->hwc_class_name
) {
1866 kobj_file_err(CE_WARN
, file
, class_err
);
1869 hwcp
->hwc_class_name
= kmem_alloc(
1870 strlen(tokbuf
) + 1, KM_SLEEP
);
1871 (void) strcpy(hwcp
->hwc_class_name
, tokbuf
);
1874 case prop_equals_string_comma
:
1875 tail
= add_val(&val_list
, tail
, VAL_STRING
,
1877 state
= prop_equals_string
;
1880 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1887 case prop_equals_integer_comma
:
1888 (void) kobj_getvalue(tokbuf
, &ival
);
1889 tail
= add_val(&val_list
, tail
,
1890 VAL_INTEGER
, (caddr_t
)(uintptr_t)ival
);
1891 state
= prop_equals_integer
;
1894 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1899 case prop_equals_string
:
1900 state
= prop_equals_string_comma
;
1902 case prop_equals_integer
:
1903 state
= prop_equals_integer_comma
;
1906 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1916 kobj_find_eol(file
);
1919 kobj_file_err(CE_WARN
, file
, "Unexpected EOF");
1922 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
1925 } while ((token
= kobj_lex(file
, tokbuf
, linesize
)) != SEMICOLON
);
1929 case prop_equals_string
:
1930 case prop_equals_integer
:
1931 make_prop(file
, (dev_info_t
*)devi
,
1932 prop_name
, val_list
);
1938 kobj_file_err(CE_WARN
, file
, "Unexpected end of line");
1942 /* copy 2 relevant members of devi to hwcp */
1943 hwcp
->hwc_devi_sys_prop_ptr
= devi
->devi_sys_prop_ptr
;
1944 hwcp
->hwc_devi_name
= devi
->devi_name
;
1947 kmem_free(prop_name
, strlen(prop_name
) + 1);
1949 free_val_list(val_list
);
1951 kmem_free(devi
, sizeof (struct dev_info
));
1957 kmem_free(prop_name
, strlen(prop_name
) + 1);
1959 free_val_list(val_list
);
1963 if (devi
->devi_name
)
1964 kmem_free(devi
->devi_name
, strlen(devi
->devi_name
) + 1);
1966 kmem_free(devi
, sizeof (struct dev_info
));
1972 * This is the primary kernel interface to parse driver.conf files.
1974 * Yet another bigstk thread handoff due to deep kernel stacks when booting
1975 * cache-only-clients.
1978 hwc_parse(char *fname
, struct par_list
**pl
, ddi_prop_t
**props
)
1981 struct hwc_parse_mt
*pltp
= hwc_parse_mtalloc(fname
, pl
, props
);
1983 if (curthread
!= &t0
) {
1984 (void) thread_create(NULL
, DEFAULTSTKSZ
* 2,
1985 hwc_parse_thread
, pltp
, 0, &p0
, TS_RUN
, maxclsyspri
);
1986 sema_p(&pltp
->sema
);
1988 pltp
->rv
= hwc_parse_now(fname
, pl
, props
);
1991 hwc_parse_mtfree(pltp
);
1996 * Calls to hwc_parse() are handled off to this routine in a separate
2000 hwc_parse_thread(struct hwc_parse_mt
*pltp
)
2005 mutex_init(&cpr_lk
, NULL
, MUTEX_DEFAULT
, NULL
);
2006 CALLB_CPR_INIT(&cpr_i
, &cpr_lk
, callb_generic_cpr
, "hwc_parse");
2009 * load and parse the .conf file
2010 * return the hwc_spec list (if any) to the creator of this thread
2012 pltp
->rv
= hwc_parse_now(pltp
->name
, pltp
->pl
, pltp
->props
);
2013 sema_v(&pltp
->sema
);
2014 mutex_enter(&cpr_lk
);
2015 CALLB_CPR_EXIT(&cpr_i
);
2016 mutex_destroy(&cpr_lk
);
2021 * allocate and initialize a hwc_parse thread control structure
2023 static struct hwc_parse_mt
*
2024 hwc_parse_mtalloc(char *name
, struct par_list
**pl
, ddi_prop_t
**props
)
2026 struct hwc_parse_mt
*pltp
= kmem_zalloc(sizeof (*pltp
), KM_SLEEP
);
2028 ASSERT(name
!= NULL
);
2030 pltp
->name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
2031 bcopy(name
, pltp
->name
, strlen(name
) + 1);
2033 pltp
->props
= props
;
2035 sema_init(&pltp
->sema
, 0, NULL
, SEMA_DEFAULT
, NULL
);
2040 * free a hwc_parse thread control structure
2043 hwc_parse_mtfree(struct hwc_parse_mt
*pltp
)
2045 sema_destroy(&pltp
->sema
);
2047 kmem_free(pltp
->name
, strlen(pltp
->name
) + 1);
2048 kmem_free(pltp
, sizeof (*pltp
));
2052 * hwc_parse -- parse an hwconf file. Ignore error lines and parse
2053 * as much as possible.
2056 hwc_parse_now(char *fname
, struct par_list
**pl
, ddi_prop_t
**props
)
2059 struct hwc_spec
*hwcp
;
2064 * Don't use kobj_open_path's use_moddir_suffix option, we only
2065 * expect to find conf files in the base module directory, not
2066 * an ISA-specific subdirectory.
2068 if ((file
= kobj_open_path(fname
, 1, 0)) == (struct _buf
*)-1) {
2069 if (moddebug
& MODDEBUG_ERRMSG
)
2070 cmn_err(CE_WARN
, "Cannot open %s", fname
);
2075 * Initialize variables
2077 tokval
= kmem_alloc(MAX_HWC_LINESIZE
, KM_SLEEP
);
2079 while ((token
= kobj_lex(file
, tokval
, MAX_HWC_LINESIZE
)) != EOF
) {
2085 kobj_find_eol(file
);
2088 hwcp
= get_hwc_spec(file
, tokval
, MAX_HWC_LINESIZE
);
2092 * No devi_name indicates global property.
2093 * Make sure parent and class not NULL.
2095 if (hwcp
->hwc_devi_name
== NULL
) {
2096 if (hwcp
->hwc_parent_name
||
2097 hwcp
->hwc_class_name
) {
2098 kobj_file_err(CE_WARN
, file
,
2099 "missing name attribute");
2103 /* Add to global property list */
2104 add_props(hwcp
, props
);
2109 * This is a node spec, either parent or class
2110 * must be specified.
2112 if ((hwcp
->hwc_parent_name
== NULL
) &&
2113 (hwcp
->hwc_class_name
== NULL
)) {
2114 kobj_file_err(CE_WARN
, file
,
2115 "missing parent or class attribute");
2120 /* add to node spec list */
2127 kobj_file_err(CE_WARN
, file
, tok_err
, tokval
);
2132 * XXX - Check for clean termination.
2134 kmem_free(tokval
, MAX_HWC_LINESIZE
);
2135 kobj_close_file(file
);
2136 return (0); /* always return success */
2140 make_aliases(struct bind
**bhash
)
2143 AL_NEW
, AL_DRVNAME
, AL_DRVNAME_COMMA
, AL_ALIAS
, AL_ALIAS_COMMA
2147 char tokbuf
[MAXPATHLEN
];
2148 char drvbuf
[MAXPATHLEN
];
2152 static char dupwarn
[] = "!Driver alias \"%s\" conflicts with "
2153 "an existing driver name or alias.";
2155 if ((file
= kobj_open_file(dafile
)) == (struct _buf
*)-1)
2159 major
= DDI_MAJOR_T_NONE
;
2161 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2167 kobj_find_eol(file
);
2173 (void) strcpy(drvbuf
, tokbuf
);
2176 case AL_DRVNAME_COMMA
:
2177 (void) strcat(drvbuf
, tokbuf
);
2180 case AL_ALIAS_COMMA
:
2181 (void) strcat(drvbuf
, tokbuf
);
2185 major
= mod_name_to_major(drvbuf
);
2186 if (major
== DDI_MAJOR_T_NONE
) {
2187 kobj_find_eol(file
);
2190 (void) strcpy(drvbuf
, tokbuf
);
2195 if (make_mbind(drvbuf
, major
, NULL
, bhash
)
2197 cmn_err(CE_WARN
, dupwarn
, drvbuf
);
2200 * copy this token just in case that there
2201 * are multiple names on the same line.
2203 (void) strcpy(drvbuf
, tokbuf
);
2208 (void) strcat(drvbuf
, tokbuf
);
2211 state
= AL_DRVNAME_COMMA
;
2214 state
= AL_ALIAS_COMMA
;
2217 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2224 if (state
== AL_ALIAS
) {
2225 if (make_mbind(drvbuf
, major
, NULL
, bhash
)
2227 cmn_err(CE_WARN
, dupwarn
, drvbuf
);
2229 } else if (state
!= AL_NEW
) {
2230 kobj_file_err(CE_WARN
, file
,
2231 "Missing alias for %s", drvbuf
);
2236 major
= DDI_MAJOR_T_NONE
;
2239 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2243 kobj_close_file(file
);
2248 * It is called for parsing these files:
2249 * - /etc/path_to_inst
2250 * - /etc/name_to_major
2251 * - /etc/name_to_sysnum
2252 * A callback "int (*line_parser)(char *, int, char *, struct bind **)"
2253 * is invoked for each line of the file.
2254 * The callback can inhash the entry into a hashtable by supplying
2255 * a pre-allocated hashtable in "struct bind **hashtab".
2258 read_binding_file(char *bindfile
, struct bind
**hashtab
,
2259 int (*line_parser
)(char *, int, char *, struct bind
**))
2262 B_NEW
, B_NAME
, B_VAL
, B_BIND_NAME
2265 char tokbuf
[MAXNAMELEN
];
2268 char *bind_name
= NULL
, *name
= NULL
, *bn
= NULL
;
2272 static char num_err
[] = "Missing number on preceding line?";
2273 static char dupwarn
[] = "!The binding file entry \"%s %u\" conflicts "
2274 "with a previous entry";
2276 if (hashtab
!= NULL
) {
2277 clear_binding_hash(hashtab
);
2280 if ((file
= kobj_open_file(bindfile
)) == (struct _buf
*)-1)
2281 panic("read_binding_file: %s file not found", bindfile
);
2286 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2293 kobj_find_eol(file
);
2300 * This case is for the first name and
2301 * possibly only name in an entry.
2303 ASSERT(name
== NULL
);
2304 name
= kmem_alloc(strlen(tokbuf
) + 1, KM_SLEEP
);
2305 (void) strcpy(name
, tokbuf
);
2310 * This case is for a second name, which
2311 * would be the binding name if the first
2312 * name was actually a generic name.
2314 ASSERT(bind_name
== NULL
);
2315 bind_name
= kmem_alloc(strlen(tokbuf
) + 1,
2317 (void) strcpy(bind_name
, tokbuf
);
2318 state
= B_BIND_NAME
;
2321 kobj_file_err(CE_WARN
, file
, num_err
);
2326 if (state
!= B_NAME
) {
2327 kobj_file_err(CE_WARN
, file
, "Missing name?");
2331 (void) kobj_getvalue(tokbuf
, &val
);
2332 if (val
> (u_longlong_t
)INT_MAX
) {
2333 kobj_file_err(CE_WARN
, file
,
2334 "value %llu too large", val
);
2344 if ((state
== B_BIND_NAME
) || (state
== B_VAL
)) {
2345 if (state
== B_BIND_NAME
)
2350 if (line_parser
!= NULL
) {
2351 if ((*line_parser
)(name
, (int)val
, bn
,
2353 maxnum
= MAX((int)val
, maxnum
);
2355 kobj_file_err(CE_WARN
, file
,
2356 dupwarn
, name
, (uint_t
)val
);
2358 } else if (state
!= B_NEW
)
2359 kobj_file_err(CE_WARN
, file
, "Syntax error?");
2362 kmem_free(name
, strlen(name
) + 1);
2366 kmem_free(bind_name
, strlen(bind_name
) + 1);
2373 kobj_file_err(CE_WARN
, file
, "Missing name/number?");
2378 ASSERT(name
== NULL
); /* any leaks? */
2379 ASSERT(bind_name
== NULL
);
2381 kobj_close_file(file
);
2386 * read_dacf_binding_file()
2387 * Read the /etc/dacf.conf file and build the dacf_rule_t database from it.
2389 * The syntax of a line in the dacf.conf file is:
2390 * dev-spec [module:]op-set operation options [config-args];
2393 * 1. dev-spec is of the format: name="data"
2394 * 2. operation is the operation that this rule matches. (i.e. pre-detach)
2395 * 3. options is a comma delimited list of options (i.e. debug,foobar)
2396 * 4. config-data is a whitespace delimited list of the format: name="data"
2399 read_dacf_binding_file(char *filename
)
2403 /* minor_nodetype="ddi_mouse:serial" */
2404 DACF_NT_SPEC
, DACF_NT_EQUALS
, DACF_NT_DATA
,
2405 /* consconfig:mouseconfig */
2406 DACF_MN_MODNAME
, DACF_MN_COLON
, DACF_MN_OPSET
,
2409 /* [ option1, option2, option3... | - ] */
2410 DACF_OPT_OPTION
, DACF_OPT_COMMA
, DACF_OPT_END
,
2411 /* argname1="argval1" argname2="argval2" ... */
2412 DACF_OPARG_SPEC
, DACF_OPARG_EQUALS
, DACF_OPARG_DATA
,
2413 DACF_ERR
, DACF_ERR_NEWLINE
, DACF_COMMENT
2414 } state
= DACF_BEGIN
;
2420 char tokbuf
[MAXNAMELEN
];
2421 char mn_modname_buf
[MAXNAMELEN
], *mn_modnamep
= NULL
;
2422 char mn_opset_buf
[MAXNAMELEN
], *mn_opsetp
= NULL
;
2423 char nt_data_buf
[MAXNAMELEN
], *nt_datap
= NULL
;
2424 char arg_spec_buf
[MAXNAMELEN
];
2427 dacf_devspec_t nt_spec_type
= DACF_DS_ERROR
;
2429 dacf_arg_t
*arg_list
= NULL
;
2430 dacf_opid_t opid
= DACF_OPID_ERROR
;
2433 static char w_syntax
[] = "'%s' unexpected";
2434 static char w_equals
[] = "'=' is illegal in the current context";
2435 static char w_baddevspec
[] = "device specification '%s' unrecognized";
2436 static char w_badop
[] = "operation '%s' unrecognized";
2437 static char w_badopt
[] = "option '%s' unrecognized, ignoring";
2438 static char w_newline
[] = "rule is incomplete";
2439 static char w_insert
[] = "failed to register rule";
2440 static char w_comment
[] = "'#' not allowed except at start of line";
2441 static char w_dupargs
[] =
2442 "argument '%s' duplicates a previous argument, skipping";
2443 static char w_nt_empty
[] = "empty device specification not allowed";
2445 if (filename
== NULL
) {
2446 fname
= dacffile
; /* default binding file */
2448 fname
= filename
; /* user specified */
2451 if ((file
= kobj_open_file(fname
)) == (struct _buf
*)-1) {
2455 if (dacfdebug
& DACF_DBG_MSGS
) {
2456 printf("dacf debug: clearing rules database\n");
2459 mutex_enter(&dacf_lock
);
2462 if (dacfdebug
& DACF_DBG_MSGS
) {
2463 printf("dacf debug: parsing %s\n", fname
);
2467 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2470 case POUND
: /* comment line */
2471 if (state
!= DACF_BEGIN
) {
2472 kobj_file_err(CE_WARN
, file
, w_comment
);
2476 state
= DACF_COMMENT
;
2477 kobj_find_eol(file
);
2483 state
= DACF_NT_EQUALS
;
2485 case DACF_OPARG_SPEC
:
2486 state
= DACF_OPARG_EQUALS
;
2489 kobj_file_err(CE_WARN
, file
, w_equals
);
2497 nt_spec_type
= dacf_get_devspec(tokbuf
);
2498 if (nt_spec_type
== DACF_DS_ERROR
) {
2499 kobj_file_err(CE_WARN
, file
,
2500 w_baddevspec
, tokbuf
);
2504 state
= DACF_NT_SPEC
;
2507 (void) strncpy(mn_modname_buf
, tokbuf
,
2508 sizeof (mn_modname_buf
));
2509 mn_modnamep
= mn_modname_buf
;
2510 state
= DACF_MN_MODNAME
;
2512 case DACF_MN_MODNAME
:
2514 * This handles the 'optional' modname.
2515 * What we thought was the modname is really
2516 * the op-set. So it is copied over.
2518 ASSERT(mn_modnamep
);
2519 (void) strncpy(mn_opset_buf
, mn_modnamep
,
2520 sizeof (mn_opset_buf
));
2521 mn_opsetp
= mn_opset_buf
;
2524 * Now, the token we just read is the opset,
2525 * so look that up and fill in opid
2527 if ((opid
= dacf_get_op(tokbuf
)) ==
2529 kobj_file_err(CE_WARN
, file
, w_badop
,
2534 state
= DACF_OP_NAME
;
2537 (void) strncpy(mn_opset_buf
, tokbuf
,
2538 sizeof (mn_opset_buf
));
2539 mn_opsetp
= mn_opset_buf
;
2540 state
= DACF_MN_OPSET
;
2543 if ((opid
= dacf_get_op(tokbuf
)) ==
2545 kobj_file_err(CE_WARN
, file
, w_badop
,
2550 state
= DACF_OP_NAME
;
2554 * This case is just like DACF_OPT_COMMA below,
2555 * but we check for the sole '-' argument
2557 if (strcmp(tokbuf
, "-") == 0) {
2558 state
= DACF_OPT_END
;
2562 case DACF_OPT_COMMA
:
2564 * figure out what option was given, but don't
2565 * make a federal case if invalid, just skip it
2567 if (dacf_getopt(tokbuf
, &opts
) != 0) {
2568 kobj_file_err(CE_WARN
, file
, w_badopt
,
2571 state
= DACF_OPT_OPTION
;
2574 case DACF_OPT_OPTION
:
2575 case DACF_OPARG_DATA
:
2576 (void) strncpy(arg_spec_buf
, tokbuf
,
2577 sizeof (arg_spec_buf
));
2578 state
= DACF_OPARG_SPEC
;
2580 case DACF_OPARG_EQUALS
:
2582 * Add the arg. Warn if it's a duplicate
2584 if (dacf_arg_insert(&arg_list
, arg_spec_buf
,
2586 kobj_file_err(CE_WARN
, file
, w_dupargs
,
2589 state
= DACF_OPARG_DATA
;
2592 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2600 * We need to check to see if the string has a \n in it.
2601 * If so, we had an unmatched " mark error, and lex has
2602 * already emitted an error for us, so we need to enter
2603 * the error state. Stupid lex.
2605 if (strchr(tokbuf
, '\n')) {
2610 case DACF_NT_EQUALS
:
2611 if (strlen(tokbuf
) == 0) {
2612 kobj_file_err(CE_WARN
, file
,
2617 state
= DACF_NT_DATA
;
2618 nt_datap
= nt_data_buf
;
2619 (void) strncpy(nt_datap
, tokbuf
,
2620 sizeof (nt_data_buf
));
2622 case DACF_OPARG_EQUALS
:
2624 * Add the arg. Warn if it's a duplicate
2626 if (dacf_arg_insert(&arg_list
, arg_spec_buf
,
2628 kobj_file_err(CE_WARN
, file
, w_dupargs
,
2631 state
= DACF_OPARG_DATA
;
2634 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2642 case DACF_OPT_OPTION
:
2643 state
= DACF_OPT_COMMA
;
2646 kobj_file_err(CE_WARN
, file
, w_syntax
, ",");
2653 if (state
== DACF_MN_MODNAME
)
2654 state
= DACF_MN_COLON
;
2656 kobj_file_err(CE_WARN
, file
, w_syntax
, ":");
2665 if (state
== DACF_COMMENT
|| state
== DACF_BEGIN
) {
2670 if ((state
!= DACF_OPT_OPTION
) &&
2671 (state
!= DACF_OPARG_DATA
) &&
2672 (state
!= DACF_OPT_END
)) {
2673 kobj_file_err(CE_WARN
, file
, w_newline
);
2675 * We can't just do DACF_ERR here, since we'll
2676 * wind up eating the _next_ newline if so.
2678 state
= DACF_ERR_NEWLINE
;
2686 if (dacf_rule_insert(nt_spec_type
, nt_datap
,
2687 mn_modnamep
, mn_opsetp
, opid
, opts
, arg_list
) < 0) {
2689 * We can't just do DACF_ERR here, since we'll
2690 * wind up eating the _next_ newline if so.
2692 kobj_file_err(CE_WARN
, file
, w_insert
);
2693 state
= DACF_ERR_NEWLINE
;
2703 kobj_file_err(CE_WARN
, file
, w_syntax
, tokbuf
);
2708 * Clean up after ourselves, either after a line has terminated
2709 * successfully or because of a syntax error; or when we reach
2710 * EOF (remember, we may reach EOF without being 'done' with
2711 * handling a particular line).
2713 if (state
== DACF_ERR
) {
2714 kobj_find_eol(file
);
2716 if ((state
== DACF_BEGIN
) || (state
== DACF_ERR
) ||
2717 (state
== DACF_ERR_NEWLINE
) || done
) {
2719 mn_modnamep
= mn_opsetp
= NULL
;
2721 opid
= DACF_OPID_ERROR
;
2722 nt_spec_type
= DACF_DS_ERROR
;
2723 dacf_arglist_delete(&arg_list
);
2728 if (dacfdebug
& DACF_DBG_MSGS
) {
2729 printf("\ndacf debug: done!\n");
2732 mutex_exit(&dacf_lock
);
2734 kobj_close_file(file
);
2739 lock_hw_class_list()
2741 mutex_enter(&hcl_lock
);
2745 unlock_hw_class_list()
2747 mutex_exit(&hcl_lock
);
2751 add_class(char *exporter
, char *class)
2753 struct hwc_class
*hcl
;
2756 * If exporter's major is not registered in /etc/name_to_major,
2757 * don't update hwc_class, but just return here.
2759 if (ddi_name_to_major(exporter
) >= devcnt
) {
2760 cmn_err(CE_WARN
, "No major number for driver %s"
2761 " in class %s", exporter
, class);
2764 hcl
= kmem_zalloc(sizeof (struct hwc_class
), KM_SLEEP
);
2765 hcl
->class_exporter
= kmem_alloc(strlen(exporter
) + 1, KM_SLEEP
);
2766 hcl
->class_name
= kmem_alloc(strlen(class) + 1, KM_SLEEP
);
2767 (void) strcpy(hcl
->class_exporter
, exporter
);
2768 (void) strcpy(hcl
->class_name
, class);
2769 lock_hw_class_list();
2770 hcl
->class_next
= hcl_head
;
2772 unlock_hw_class_list();
2776 * Return the number of classes exported. If buf is not NULL, fill in
2777 * the array of the class names as well.
2779 * Caller must hold hcl_lock to ensure the class list unmodified while
2780 * it is accessed. A typical caller will get a count first and then
2781 * allocate buf. The lock should be held by the caller.
2784 get_class(const char *exporter
, char **buf
)
2787 struct hwc_class
*hcl
;
2789 ASSERT(mutex_owned(&hcl_lock
));
2790 for (hcl
= hcl_head
; hcl
!= NULL
; hcl
= hcl
->class_next
) {
2791 if (strcmp(exporter
, hcl
->class_exporter
) == 0) {
2793 buf
[n
] = hcl
->class_name
;
2802 read_class_file(void)
2805 struct hwc_class
*hcl
, *hcl1
;
2806 char tokbuf
[MAXNAMELEN
];
2808 C_BEGIN
, C_EXPORTER
, C_END
2812 char *exporter
= NULL
, *class = NULL
, *name
= NULL
;
2814 if (hcl_head
!= NULL
) {
2816 while (hcl
!= NULL
) {
2817 kmem_free(hcl
->class_exporter
,
2818 strlen(hcl
->class_exporter
) + 1);
2820 hcl
= hcl
->class_next
;
2821 kmem_free(hcl1
, sizeof (struct hwc_class
));
2826 if ((file
= kobj_open_file(class_file
)) == (struct _buf
*)-1)
2831 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
2838 kobj_find_eol(file
);
2842 name
= kmem_alloc(strlen(tokbuf
) + 1, KM_SLEEP
);
2843 (void) strcpy(name
, tokbuf
);
2851 add_class(exporter
, class);
2855 kobj_file_err(CE_WARN
, file
,
2856 "Extra noise after entry");
2857 kmem_free(name
, strlen(name
) + 1);
2858 kobj_find_eol(file
);
2867 if (state
== C_EXPORTER
)
2868 kobj_file_err(CE_WARN
, file
,
2869 "Partial entry ignored");
2872 kmem_free(exporter
, strlen(exporter
) + 1);
2874 kmem_free(class, strlen(class) + 1);
2879 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2883 kobj_close_file(file
);
2887 * Given par_list, get a list of parent major number
2890 impl_parlist_to_major(struct par_list
*pl
, char parents
[])
2892 struct hwc_spec
*hwcp
;
2893 struct hwc_class
*hcl
;
2898 for (; pl
!= NULL
; pl
= pl
->par_next
) {
2899 if ((pl
->par_major
< devcnt
) && (parents
[pl
->par_major
] == 0)) {
2900 parents
[pl
->par_major
] = 1;
2905 /* parent specs cannot be mapped to a driver */
2906 if (pl
->par_major
!= DDI_MAJOR_T_NONE
)
2910 hwcp
= pl
->par_specs
;
2911 ASSERT(hwcp
->hwc_class_name
);
2912 ASSERT(hwcp
->hwc_parent_name
== NULL
);
2914 for (hcl
= hcl_head
; hcl
!= NULL
; hcl
= hcl
->class_next
) {
2915 if (strcmp(hwcp
->hwc_class_name
, hcl
->class_name
) != 0)
2917 major
= ddi_name_to_major(hcl
->class_exporter
);
2918 ASSERT(major
!= DDI_MAJOR_T_NONE
);
2919 if (parents
[major
] == 0) {
2929 * delete a parent list and all its hwc specs
2932 impl_delete_par_list(struct par_list
*pl
)
2934 struct par_list
*saved_pl
;
2935 struct hwc_spec
*hp
, *hp1
;
2946 kmem_free(saved_pl
, sizeof (*saved_pl
));
2950 #if defined(_PSM_MODULES)
2952 open_mach_list(void)
2955 char tokbuf
[MAXNAMELEN
];
2957 struct psm_mach
*machp
;
2959 if ((file
= kobj_open_file(mach_file
)) == (struct _buf
*)-1)
2962 while ((token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
))) != EOF
) {
2968 kobj_find_eol(file
);
2972 machp
= kmem_alloc((sizeof (struct psm_mach
) +
2973 strlen(tokbuf
) + 1), KM_SLEEP
);
2974 machp
->m_next
= pmach_head
;
2975 machp
->m_machname
= (char *)(machp
+ 1);
2976 (void) strcpy(machp
->m_machname
, tokbuf
);
2983 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
2987 kobj_close_file(file
);
2991 get_next_mach(void *handle
, char *buf
)
2993 struct psm_mach
*machp
;
2995 machp
= (struct psm_mach
*)handle
;
2997 machp
= machp
->m_next
;
3001 (void) strcpy(buf
, machp
->m_machname
);
3006 close_mach_list(void)
3008 struct psm_mach
*machp
;
3010 while (pmach_head
) {
3012 pmach_head
= machp
->m_next
;
3013 kmem_free(machp
, sizeof (struct psm_mach
) +
3014 strlen(machp
->m_machname
) + 1);
3017 #endif /* _PSM_MODULES */
3019 #if defined(_RTC_CONFIG)
3021 * Read in the 'zone_lag' value from the rtc configuration file,
3022 * and return the value to the caller. Note that there is other information
3023 * in this file (zone_info), so we ignore unknown values. We do spit out
3024 * warnings if the line doesn't begin with an identifier, or if we don't find
3025 * exactly "zone_lag=value". No one should be editing this file by hand
3026 * (use the rtc command instead), but it's better to be careful.
3029 process_rtc_config_file(void)
3032 R_NEW
, R_NAME
, R_EQUALS
, R_VALUE
3035 char tokbuf
[MAXNAMELEN
];
3041 if ((file
= kobj_open_file(rtc_config_file
)) == (struct _buf
*)-1)
3047 token
= kobj_lex(file
, tokbuf
, sizeof (tokbuf
));
3054 kobj_find_eol(file
);
3058 if (state
== R_NEW
) {
3059 if (strcmp(tokbuf
, "zone_lag") == 0)
3062 kobj_find_eol(file
); /* Ignore */
3064 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3067 if (state
== R_NAME
)
3070 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3073 if (state
== R_EQUALS
) {
3074 if (kobj_getvalue(tokbuf
, &tmp
) != 0)
3075 kobj_file_err(CE_WARN
, file
,
3076 "Bad value %s for zone_lag",
3079 zone_lag
= (long)tmp
;
3082 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3088 if (state
!= R_NEW
&& state
!= R_VALUE
)
3089 kobj_file_err(CE_WARN
, file
,
3090 "Partial zone_lag entry ignored");
3095 kobj_file_err(CE_WARN
, file
, tok_err
, tokbuf
);
3099 kobj_close_file(file
);
3102 #endif /* _RTC_CONFIG */
3106 * Append node spec to the end of par_list
3109 append(struct hwc_spec
*spec
, struct par_list
*par
)
3111 struct hwc_spec
*hwc
, *last
;
3113 ASSERT(par
->par_specs
);
3114 for (hwc
= par
->par_specs
; hwc
; hwc
= hwc
->hwc_next
)
3116 last
->hwc_next
= spec
;
3120 * Given a parent=/full-pathname, see if the platform
3121 * can resolve the pathname to driver, otherwise, try
3122 * the leaf node name.
3125 get_major(char *parent
)
3127 major_t major
= DDI_MAJOR_T_NONE
;
3128 char *tmp
, *driver
= NULL
;
3131 major
= path_to_major(parent
);
3133 if (major
!= DDI_MAJOR_T_NONE
)
3136 /* extract the name between '/' and '@' */
3138 driver
= strrchr(parent
, '/') + 1;
3141 if ((tmp
= strchr(driver
, '@')) != NULL
)
3143 major
= ddi_name_to_major(driver
);
3150 * Chain together specs whose parent's module name is the same.
3153 add_spec(struct hwc_spec
*spec
, struct par_list
**par
)
3156 struct par_list
*pl
, *par_last
= NULL
;
3157 char *parent
= spec
->hwc_parent_name
;
3158 char *class = spec
->hwc_class_name
;
3160 ASSERT(parent
|| class);
3163 * If given a parent=/full-pathname, see if the platform
3164 * can resolve the pathname to driver, otherwise, try
3165 * the leaf node name.
3167 * If parent=/full-pathname doesn't resolve to a driver,
3168 * this could be cause by DR removal of the device.
3169 * We put it on the major=-2 list in case the device
3170 * is brought back into the system by DR.
3173 maj
= get_major(parent
);
3174 if (maj
== DDI_MAJOR_T_NONE
) {
3175 if ((*parent
== '/') &&
3176 (strncmp(parent
, "/pseudo", 7) != 0)) {
3180 "add_spec: No major number for %s",
3187 maj
= DDI_MAJOR_T_NONE
;
3190 * Scan the list looking for a matching parent. When parent is
3191 * not NULL, we match the parent by major. If parent is NULL but
3192 * class is not NULL, we mache the pl by class name.
3194 for (pl
= *par
; pl
; pl
= pl
->par_next
) {
3195 if ((parent
&& (maj
== pl
->par_major
)) || ((parent
== NULL
) &&
3196 class && pl
->par_specs
->hwc_class_name
&& (strncmp(class,
3197 pl
->par_specs
->hwc_class_name
, strlen(class)) == 0))) {
3205 * Didn't find a match on the list. Make a new parent list.
3207 pl
= kmem_zalloc(sizeof (*pl
), KM_SLEEP
);
3208 pl
->par_major
= maj
;
3209 pl
->par_specs
= spec
;
3210 if (*par
== NULL
) { /* null par list */
3214 /* put "class=" entries last (lower pri if dups) */
3215 if (maj
== DDI_MAJOR_T_NONE
) {
3216 par_last
->par_next
= pl
;
3220 /* ensure unresolved "parent=/full-path" goes first */
3221 if ((maj
!= (major_t
)-2) && ((*par
)->par_major
== (major_t
)-2))
3222 par
= &(*par
)->par_next
;
3223 pl
->par_next
= *par
;
3228 * Add property spec to property list in original order
3231 add_props(struct hwc_spec
*spec
, ddi_prop_t
**props
)
3233 ASSERT(spec
->hwc_devi_name
== NULL
);
3235 if (spec
->hwc_devi_sys_prop_ptr
) {
3237 props
= &(*props
)->prop_next
;
3238 *props
= spec
->hwc_devi_sys_prop_ptr
;
3240 /* remove these properties from the spec */
3241 spec
->hwc_devi_sys_prop_ptr
= NULL
;