17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5112116d8Sfb  * Common Development and Distribution License (the "License").
6112116d8Sfb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22112116d8Sfb  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*0d2006e4SRobert Mustacchi  * Copyright 2019, Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #define	USBA_FRAMEWORK
297c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
30d29f5a71Szhigang lu - Sun Microsystems - Beijing China #include <sys/strsun.h>
317c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_impl.h>
327c478bd9Sstevel@tonic-gate #include <sys/usb/usba/usba_devdb_impl.h>
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate static usb_log_handle_t	usba_devdb_log_handle;
354610e4a0Sfrits uint_t	usba_devdb_errlevel = USB_LOG_L4;
364610e4a0Sfrits uint_t	usba_devdb_errmask = (uint_t)-1;
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate boolean_t	usba_build_devdb = B_FALSE;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate avl_tree_t	usba_devdb;		/* tree of records */
417c478bd9Sstevel@tonic-gate static krwlock_t usba_devdb_lock;	/* lock protecting the tree */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate _NOTE(RWLOCK_PROTECTS_DATA(usba_devdb_lock, usba_devdb))
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Reader Writer locks have problem with warlock. warlock is unable to
477c478bd9Sstevel@tonic-gate  * decode that the structure is local and doesn't need locking
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unshared", usba_devdb_info))
507c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unshared", usba_configrec))
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /* function prototypes */
537c478bd9Sstevel@tonic-gate static int usb_devdb_compare_pathnames(char *, char *);
547c478bd9Sstevel@tonic-gate static int usba_devdb_compare(const void *, const void *);
557c478bd9Sstevel@tonic-gate static int usba_devdb_build_device_database();
567c478bd9Sstevel@tonic-gate static void usba_devdb_destroy_device_database();
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * usba_devdb_initialization
607c478bd9Sstevel@tonic-gate  *	Initialize this module that builds the usb device database
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate void
usba_devdb_initialization()637c478bd9Sstevel@tonic-gate usba_devdb_initialization()
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	usba_devdb_log_handle = usb_alloc_log_hdl(NULL, "devdb",
667c478bd9Sstevel@tonic-gate 	    &usba_devdb_errlevel, &usba_devdb_errmask, NULL, 0);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
697c478bd9Sstevel@tonic-gate 	    "usba_devdb_initialization");
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	rw_init(&usba_devdb_lock, NULL, RW_DRIVER, NULL);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	rw_enter(&usba_devdb_lock, RW_WRITER);
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	usba_build_devdb = B_TRUE;
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	/* now create the avl tree */
787c478bd9Sstevel@tonic-gate 	avl_create(&usba_devdb, usba_devdb_compare,
797c478bd9Sstevel@tonic-gate 	    sizeof (usba_devdb_info_t),
807c478bd9Sstevel@tonic-gate 	    offsetof(struct usba_devdb_info, avl_link));
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	(void) usba_devdb_build_device_database();
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	usba_build_devdb = B_FALSE;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	rw_exit(&usba_devdb_lock);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * usba_devdb_destroy
927c478bd9Sstevel@tonic-gate  *	Free up all the resources being used by this module
937c478bd9Sstevel@tonic-gate  */
947c478bd9Sstevel@tonic-gate void
usba_devdb_destroy()957c478bd9Sstevel@tonic-gate usba_devdb_destroy()
967c478bd9Sstevel@tonic-gate {
977c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
987c478bd9Sstevel@tonic-gate 	    "usba_devdb_destroy");
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	rw_enter(&usba_devdb_lock, RW_WRITER);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	usba_devdb_destroy_device_database();
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	rw_exit(&usba_devdb_lock);
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	rw_destroy(&usba_devdb_lock);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	usb_free_log_hdl(usba_devdb_log_handle);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * usba_devdb_get_var_type:
1147c478bd9Sstevel@tonic-gate  *	returns the field from the token
1157c478bd9Sstevel@tonic-gate  */
1167c478bd9Sstevel@tonic-gate static config_field_t
usba_devdb_get_var_type(char * str)1177c478bd9Sstevel@tonic-gate usba_devdb_get_var_type(char *str)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	usba_cfg_var_t	*cfgvar;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	cfgvar = &usba_cfg_varlist[0];
1227c478bd9Sstevel@tonic-gate 	while (cfgvar->field != USB_NONE) {
123cdcfeaaeSToomas Soome 		if (strcasecmp(cfgvar->name, str) == 0) {
1247c478bd9Sstevel@tonic-gate 			break;
1257c478bd9Sstevel@tonic-gate 		} else {
1267c478bd9Sstevel@tonic-gate 			cfgvar++;
1277c478bd9Sstevel@tonic-gate 		}
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return (cfgvar->field);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * usba_devdb_get_conf_rec:
1367c478bd9Sstevel@tonic-gate  *	Fetch one record from the file
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate static token_t
usba_devdb_get_conf_rec(struct _buf * file,usba_configrec_t ** rec)1397c478bd9Sstevel@tonic-gate usba_devdb_get_conf_rec(struct _buf *file, usba_configrec_t **rec)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	token_t		token;
1427c478bd9Sstevel@tonic-gate 	char		tokval[MAXPATHLEN];
1437c478bd9Sstevel@tonic-gate 	usba_configrec_t	*cfgrec;
144*0d2006e4SRobert Mustacchi 	config_field_t	cfgvar = USB_NONE;
1457c478bd9Sstevel@tonic-gate 	u_longlong_t	llptr;
1467c478bd9Sstevel@tonic-gate 	u_longlong_t	value;
1477c478bd9Sstevel@tonic-gate 	enum {
1487c478bd9Sstevel@tonic-gate 		USB_NEWVAR, USB_CONFIG_VAR, USB_VAR_EQUAL, USB_VAR_VALUE,
149112116d8Sfb 		    USB_ERROR
150*0d2006e4SRobert Mustacchi 	} parse_state = USB_NEWVAR;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	cfgrec = (usba_configrec_t *)kmem_zalloc(
1537c478bd9Sstevel@tonic-gate 	    sizeof (usba_configrec_t), KM_SLEEP);
1547c478bd9Sstevel@tonic-gate 	cfgrec->idVendor = cfgrec->idProduct = cfgrec->cfg_index = -1;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	token = kobj_lex(file, tokval, sizeof (tokval));
1577c478bd9Sstevel@tonic-gate 	while ((token != EOF) && (token != SEMICOLON)) {
1587c478bd9Sstevel@tonic-gate 		switch (token) {
1597c478bd9Sstevel@tonic-gate 		case STAR:
1607c478bd9Sstevel@tonic-gate 		case POUND:
1617c478bd9Sstevel@tonic-gate 			/* skip comments */
1627c478bd9Sstevel@tonic-gate 			kobj_find_eol(file);
1637c478bd9Sstevel@tonic-gate 			break;
1647c478bd9Sstevel@tonic-gate 		case NEWLINE:
1657c478bd9Sstevel@tonic-gate 			kobj_newline(file);
1667c478bd9Sstevel@tonic-gate 			break;
1677c478bd9Sstevel@tonic-gate 		case NAME:
1687c478bd9Sstevel@tonic-gate 		case STRING:
1697c478bd9Sstevel@tonic-gate 			switch (parse_state) {
1707c478bd9Sstevel@tonic-gate 			case USB_NEWVAR:
1717c478bd9Sstevel@tonic-gate 				cfgvar = usba_devdb_get_var_type(tokval);
1727c478bd9Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
1737c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
1747c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
1757c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid field %s",
1767c478bd9Sstevel@tonic-gate 					    tokval);
1777c478bd9Sstevel@tonic-gate 				} else {
1787c478bd9Sstevel@tonic-gate 					parse_state = USB_CONFIG_VAR;
1797c478bd9Sstevel@tonic-gate 				}
1807c478bd9Sstevel@tonic-gate 				break;
1817c478bd9Sstevel@tonic-gate 			case USB_VAR_VALUE:
1827c478bd9Sstevel@tonic-gate 				if ((cfgvar == USB_VENDOR) ||
1837c478bd9Sstevel@tonic-gate 				    (cfgvar == USB_PRODUCT) ||
1847c478bd9Sstevel@tonic-gate 				    (cfgvar == USB_CFGNDX)) {
1857c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
1867c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
1877c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s"
1887c478bd9Sstevel@tonic-gate 					    " for field: %s\n", tokval,
1897c478bd9Sstevel@tonic-gate 					    usba_cfg_varlist[cfgvar].name);
1907c478bd9Sstevel@tonic-gate 				} else if (kobj_get_string(&llptr, tokval)) {
1917c478bd9Sstevel@tonic-gate 					switch (cfgvar) {
1927c478bd9Sstevel@tonic-gate 					case USB_SELECTION:
1937c478bd9Sstevel@tonic-gate 						cfgrec->selection =
1947c478bd9Sstevel@tonic-gate 						    (char *)(uintptr_t)llptr;
1957c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
1967c478bd9Sstevel@tonic-gate 						break;
1977c478bd9Sstevel@tonic-gate 					case USB_SRNO:
1987c478bd9Sstevel@tonic-gate 						cfgrec->serialno =
1997c478bd9Sstevel@tonic-gate 						    (char *)(uintptr_t)llptr;
2007c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
2017c478bd9Sstevel@tonic-gate 						break;
2027c478bd9Sstevel@tonic-gate 					case USB_PATH:
2037c478bd9Sstevel@tonic-gate 						cfgrec->pathname =
2047c478bd9Sstevel@tonic-gate 						    (char *)(uintptr_t)llptr;
2057c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
2067c478bd9Sstevel@tonic-gate 						break;
2077c478bd9Sstevel@tonic-gate 					case USB_DRIVER:
2087c478bd9Sstevel@tonic-gate 						cfgrec->driver =
2097c478bd9Sstevel@tonic-gate 						    (char *)(uintptr_t)llptr;
2107c478bd9Sstevel@tonic-gate 						parse_state = USB_NEWVAR;
2117c478bd9Sstevel@tonic-gate 						break;
2127c478bd9Sstevel@tonic-gate 					default:
2137c478bd9Sstevel@tonic-gate 						parse_state = USB_ERROR;
2147c478bd9Sstevel@tonic-gate 					}
2157c478bd9Sstevel@tonic-gate 				} else {
2167c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
2177c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2187c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value %s"
2197c478bd9Sstevel@tonic-gate 					    " for field: %s\n", tokval,
2207c478bd9Sstevel@tonic-gate 					    usba_cfg_varlist[cfgvar].name);
2217c478bd9Sstevel@tonic-gate 				}
2227c478bd9Sstevel@tonic-gate 				break;
2237c478bd9Sstevel@tonic-gate 			case USB_ERROR:
2247c478bd9Sstevel@tonic-gate 				/* just skip */
2257c478bd9Sstevel@tonic-gate 				break;
2267c478bd9Sstevel@tonic-gate 			default:
2277c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
2287c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2297c478bd9Sstevel@tonic-gate 				    "Syntax Error: at %s", tokval);
2307c478bd9Sstevel@tonic-gate 				break;
2317c478bd9Sstevel@tonic-gate 			}
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 		case EQUALS:
2347c478bd9Sstevel@tonic-gate 			if (parse_state == USB_CONFIG_VAR) {
2357c478bd9Sstevel@tonic-gate 				if (cfgvar == USB_NONE) {
2367c478bd9Sstevel@tonic-gate 					parse_state = USB_ERROR;
2377c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2387c478bd9Sstevel@tonic-gate 					    "Syntax Error: unexpected '='");
2397c478bd9Sstevel@tonic-gate 				} else {
2407c478bd9Sstevel@tonic-gate 					parse_state = USB_VAR_VALUE;
2417c478bd9Sstevel@tonic-gate 				}
2427c478bd9Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
2437c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file,
2447c478bd9Sstevel@tonic-gate 				    "Syntax Error: unexpected '='");
2457c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			break;
2487c478bd9Sstevel@tonic-gate 		case HEXVAL:
2497c478bd9Sstevel@tonic-gate 		case DECVAL:
2507c478bd9Sstevel@tonic-gate 			if ((parse_state == USB_VAR_VALUE) && (cfgvar !=
2517c478bd9Sstevel@tonic-gate 			    USB_NONE)) {
2527c478bd9Sstevel@tonic-gate 				(void) kobj_getvalue(tokval, &value);
2537c478bd9Sstevel@tonic-gate 				switch (cfgvar) {
2547c478bd9Sstevel@tonic-gate 				case USB_VENDOR:
2557c478bd9Sstevel@tonic-gate 					cfgrec->idVendor = (int)value;
2567c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
2577c478bd9Sstevel@tonic-gate 					break;
2587c478bd9Sstevel@tonic-gate 				case USB_PRODUCT:
2597c478bd9Sstevel@tonic-gate 					cfgrec->idProduct = (int)value;
2607c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
2617c478bd9Sstevel@tonic-gate 					break;
2627c478bd9Sstevel@tonic-gate 				case USB_CFGNDX:
2637c478bd9Sstevel@tonic-gate 					cfgrec->cfg_index = (int)value;
2647c478bd9Sstevel@tonic-gate 					parse_state = USB_NEWVAR;
2657c478bd9Sstevel@tonic-gate 					break;
2667c478bd9Sstevel@tonic-gate 				default:
2677c478bd9Sstevel@tonic-gate 					kobj_file_err(CE_WARN, file,
2687c478bd9Sstevel@tonic-gate 					    "Syntax Error: Invalid value for "
2697c478bd9Sstevel@tonic-gate 					    "%s",
2707c478bd9Sstevel@tonic-gate 					    usba_cfg_varlist[cfgvar].name);
2717c478bd9Sstevel@tonic-gate 				}
2727c478bd9Sstevel@tonic-gate 			} else if (parse_state != USB_ERROR) {
2737c478bd9Sstevel@tonic-gate 				parse_state = USB_ERROR;
2747c478bd9Sstevel@tonic-gate 				kobj_file_err(CE_WARN, file, "Syntax Error:"
2757c478bd9Sstevel@tonic-gate 				    "unexpected hex/decimal: %s", tokval);
2767c478bd9Sstevel@tonic-gate 			}
2777c478bd9Sstevel@tonic-gate 			break;
2787c478bd9Sstevel@tonic-gate 		default:
2797c478bd9Sstevel@tonic-gate 			kobj_file_err(CE_WARN, file, "Syntax Error: at: %s",
2807c478bd9Sstevel@tonic-gate 			    tokval);
2817c478bd9Sstevel@tonic-gate 			parse_state = USB_ERROR;
2827c478bd9Sstevel@tonic-gate 			break;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 		token = kobj_lex(file, tokval, sizeof (tokval));
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	*rec = cfgrec;
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	return (token);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate  * usba_devdb_free_rec:
2947c478bd9Sstevel@tonic-gate  *	Free the record allocated in usba_devdb_get_conf_rec.
2957c478bd9Sstevel@tonic-gate  *	We use kobj_free_string as kobj_get_string allocates memory
2967c478bd9Sstevel@tonic-gate  *	in mod_sysfile_arena.
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate static void
usba_devdb_free_rec(usba_configrec_t * rec)2997c478bd9Sstevel@tonic-gate usba_devdb_free_rec(usba_configrec_t *rec)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	if (rec->selection) {
3027c478bd9Sstevel@tonic-gate 		kobj_free_string(rec->selection, strlen(rec->selection) + 1);
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 	if (rec->serialno) {
3057c478bd9Sstevel@tonic-gate 		kobj_free_string(rec->serialno, strlen(rec->serialno) + 1);
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 	if (rec->pathname) {
3087c478bd9Sstevel@tonic-gate 		kobj_free_string(rec->pathname, strlen(rec->pathname) + 1);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	if (rec->driver) {
3117c478bd9Sstevel@tonic-gate 		kobj_free_string(rec->driver, strlen(rec->driver) + 1);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 	kmem_free(rec, sizeof (usba_configrec_t));
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate /*
3197c478bd9Sstevel@tonic-gate  * usb_devdb_compare_pathnames:
3207c478bd9Sstevel@tonic-gate  *	Compare the two pathnames. If we are building the tree, we do a
3217c478bd9Sstevel@tonic-gate  *	straight string compare to enable correct tree generation. If we
3227c478bd9Sstevel@tonic-gate  *	are searching for a matching node, we compare only the selected
3237c478bd9Sstevel@tonic-gate  *	portion of the pathname to give a correct match.
3247c478bd9Sstevel@tonic-gate  */
3257c478bd9Sstevel@tonic-gate static int
usb_devdb_compare_pathnames(char * p1,char * p2)3267c478bd9Sstevel@tonic-gate usb_devdb_compare_pathnames(char *p1, char *p2)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate 	int	rval;
3297c478bd9Sstevel@tonic-gate 	char	*ustr, *hstr;
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
332112116d8Sfb 	    "usb_devdb_compare_pathnames: p1=0x%p p2=0x%p",
333112116d8Sfb 	    (void *)p1, (void *)p2);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	if (p1 && p2) {
3367c478bd9Sstevel@tonic-gate 		if (usba_build_devdb == B_TRUE) {
3377c478bd9Sstevel@tonic-gate 			/* this is a straight string compare */
3387c478bd9Sstevel@tonic-gate 			rval = strcmp(p1, p2);
3397c478bd9Sstevel@tonic-gate 			if (rval < 0) {
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 				return (-1);
3427c478bd9Sstevel@tonic-gate 			} else if (rval > 0) {
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 				return (+1);
3457c478bd9Sstevel@tonic-gate 			} else {
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 				return (0);
3487c478bd9Sstevel@tonic-gate 			}
3497c478bd9Sstevel@tonic-gate 		} else {
3507c478bd9Sstevel@tonic-gate 			/*
3517c478bd9Sstevel@tonic-gate 			 * Comparing on this is tricky.
3527c478bd9Sstevel@tonic-gate 			 * p1 is the string hubd is looking for &
3537c478bd9Sstevel@tonic-gate 			 * p2 is the string in the device db.
3547c478bd9Sstevel@tonic-gate 			 * At this point hubd knows: ../hubd@P/device@P
3557c478bd9Sstevel@tonic-gate 			 * while user will specify  ..../hubd@P/keyboard@P
3567c478bd9Sstevel@tonic-gate 			 * First compare till .../hubd@P
3577c478bd9Sstevel@tonic-gate 			 * Second compare is just P in "device@P"
3587c478bd9Sstevel@tonic-gate 			 */
3597c478bd9Sstevel@tonic-gate 			ustr = strrchr(p2, '/');
3607c478bd9Sstevel@tonic-gate 			hstr = strrchr(p1, '/');
361d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			rval = strncmp(p1, p2,
362d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    MAX(_PTRDIFF(ustr, p2),
363d29f5a71Szhigang lu - Sun Microsystems - Beijing China 			    _PTRDIFF(hstr, p1)));
3647c478bd9Sstevel@tonic-gate 			if (rval < 0) {
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 				return (-1);
3677c478bd9Sstevel@tonic-gate 			} else if (rval > 0) {
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 				return (+1);
3707c478bd9Sstevel@tonic-gate 			} else {
3717c478bd9Sstevel@tonic-gate 				/* now compare the ports */
3727c478bd9Sstevel@tonic-gate 				hstr = p1 + strlen(p1) -1;
3737c478bd9Sstevel@tonic-gate 				ustr = p2 + strlen(p2) -1;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 				if (*hstr < *ustr) {
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 					return (-1);
3787c478bd9Sstevel@tonic-gate 				} else if (*hstr > *ustr) {
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 					return (+1);
3817c478bd9Sstevel@tonic-gate 				} else {
3827c478bd9Sstevel@tonic-gate 					/* finally got a match */
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 					return (0);
3857c478bd9Sstevel@tonic-gate 				}
3867c478bd9Sstevel@tonic-gate 			}
3877c478bd9Sstevel@tonic-gate 		}
3887c478bd9Sstevel@tonic-gate 	} else if ((p1 == NULL) && (p2 == NULL)) {
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 		return (0);
3917c478bd9Sstevel@tonic-gate 	} else {
3927c478bd9Sstevel@tonic-gate 		if (p1 == NULL) {
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 			return (-1);
3957c478bd9Sstevel@tonic-gate 		} else {
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 			return (+1);
3987c478bd9Sstevel@tonic-gate 		}
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate /*
4047c478bd9Sstevel@tonic-gate  * usba_devdb_compare
4057c478bd9Sstevel@tonic-gate  *	Compares the two nodes. Returns -1 when p1 < p2, 0 when p1 == p2
4067c478bd9Sstevel@tonic-gate  *	and +1 when p1 > p2. This function is invoked by avl_find
4077c478bd9Sstevel@tonic-gate  *	Here p1 is always the node that we are trying to insert or match in
4087c478bd9Sstevel@tonic-gate  *	the device database.
4097c478bd9Sstevel@tonic-gate  */
4107c478bd9Sstevel@tonic-gate static int
usba_devdb_compare(const void * p1,const void * p2)4117c478bd9Sstevel@tonic-gate usba_devdb_compare(const void *p1, const void *p2)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	usba_configrec_t	*u1, *u2;
4147c478bd9Sstevel@tonic-gate 	int	rval;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	u1 = ((usba_devdb_info_t *)p1)->usb_dev;
4177c478bd9Sstevel@tonic-gate 	u2 = ((usba_devdb_info_t *)p2)->usb_dev;
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
4207c478bd9Sstevel@tonic-gate 	    "usba_devdb_compare: p1=0x%p u1=0x%p p2=0x%p u2=0x%p",
4218793b36bSNick Todd 	    p1, (void *)u1, p2, (void *)u2);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	/* first match vendor id */
4247c478bd9Sstevel@tonic-gate 	if (u1->idVendor < u2->idVendor) {
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 		return (-1);
4277c478bd9Sstevel@tonic-gate 	} else if (u1->idVendor > u2->idVendor) {
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 		return (+1);
4307c478bd9Sstevel@tonic-gate 	} else {
4317c478bd9Sstevel@tonic-gate 		/* idvendor match, now check idproduct */
4327c478bd9Sstevel@tonic-gate 		if (u1->idProduct < u2->idProduct) {
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 			return (-1);
4357c478bd9Sstevel@tonic-gate 		} else if (u1->idProduct > u2->idProduct) {
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 			return (+1);
4387c478bd9Sstevel@tonic-gate 		} else {
4397c478bd9Sstevel@tonic-gate 			/* idproduct match, now check serial no. */
4407c478bd9Sstevel@tonic-gate 			if (u1->serialno && u2->serialno) {
4417c478bd9Sstevel@tonic-gate 				rval = strcmp(u1->serialno, u2->serialno);
4427c478bd9Sstevel@tonic-gate 				if (rval > 0) {
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 					return (+1);
4457c478bd9Sstevel@tonic-gate 				} else if (rval < 0) {
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 					return (-1);
4487c478bd9Sstevel@tonic-gate 				} else {
4497c478bd9Sstevel@tonic-gate 					/* srno. matches */
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 					return (usb_devdb_compare_pathnames(
4527c478bd9Sstevel@tonic-gate 					    u1->pathname, u2->pathname));
4537c478bd9Sstevel@tonic-gate 				}
4547c478bd9Sstevel@tonic-gate 			} else if ((u1->serialno == NULL) &&
4557c478bd9Sstevel@tonic-gate 			    (u2->serialno == NULL)) {
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 				return (usb_devdb_compare_pathnames(
4587c478bd9Sstevel@tonic-gate 				    u1->pathname, u2->pathname));
4597c478bd9Sstevel@tonic-gate 			} else {
4607c478bd9Sstevel@tonic-gate 				if (u1->serialno == NULL) {
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 					return (-1);
4637c478bd9Sstevel@tonic-gate 				} else {
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 					return (+1);
4667c478bd9Sstevel@tonic-gate 				}
4677c478bd9Sstevel@tonic-gate 			}
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /*
4747c478bd9Sstevel@tonic-gate  * usba_devdb_build_device_database
4757c478bd9Sstevel@tonic-gate  *	Builds a height balanced tree of all the records present in the file.
4767c478bd9Sstevel@tonic-gate  *	Records that are "not enabled" and are duplicate are discarded.
4777c478bd9Sstevel@tonic-gate  */
4787c478bd9Sstevel@tonic-gate static int
usba_devdb_build_device_database()4797c478bd9Sstevel@tonic-gate usba_devdb_build_device_database()
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	struct _buf	*file;
4827c478bd9Sstevel@tonic-gate 	usba_configrec_t	*user_rec;
4837c478bd9Sstevel@tonic-gate 	avl_index_t	where;
4847c478bd9Sstevel@tonic-gate 	usba_devdb_info_t	*dbnode;
4857c478bd9Sstevel@tonic-gate 	token_t		token;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
4887c478bd9Sstevel@tonic-gate 	    "usba_devdb_build_device_database: Start");
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	file = kobj_open_file(usbconf_file);
4917c478bd9Sstevel@tonic-gate 	if (file != (struct _buf *)-1) {
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 		do {
4947c478bd9Sstevel@tonic-gate 			user_rec = NULL;
4957c478bd9Sstevel@tonic-gate 			token = usba_devdb_get_conf_rec(file, &user_rec);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 			if (user_rec != NULL) {
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 				if ((user_rec->selection == NULL) ||
5007c478bd9Sstevel@tonic-gate 				    (strcasecmp(user_rec->selection,
5017c478bd9Sstevel@tonic-gate 				    "enable") != 0)) {
5027c478bd9Sstevel@tonic-gate 					/* we don't store disabled entries */
5037c478bd9Sstevel@tonic-gate 					usba_devdb_free_rec(user_rec);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 					continue;
5067c478bd9Sstevel@tonic-gate 				}
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 				dbnode = (usba_devdb_info_t *)kmem_zalloc(
5097c478bd9Sstevel@tonic-gate 				    sizeof (usba_devdb_info_t), KM_SLEEP);
5107c478bd9Sstevel@tonic-gate 				dbnode->usb_dev = user_rec;
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 				if (avl_find(&usba_devdb, dbnode, &where) ==
5137c478bd9Sstevel@tonic-gate 				    NULL) {
5147c478bd9Sstevel@tonic-gate 					/* insert new node */
5157c478bd9Sstevel@tonic-gate 					avl_insert(&usba_devdb, dbnode, where);
5167c478bd9Sstevel@tonic-gate 				} else {
5177c478bd9Sstevel@tonic-gate 					/*
5187c478bd9Sstevel@tonic-gate 					 * we don't maintain duplicate entries
5197c478bd9Sstevel@tonic-gate 					 */
5207c478bd9Sstevel@tonic-gate 					usba_devdb_free_rec(user_rec);
5217c478bd9Sstevel@tonic-gate 					kmem_free(dbnode,
5227c478bd9Sstevel@tonic-gate 					    sizeof (usba_devdb_info_t));
5237c478bd9Sstevel@tonic-gate 				}
5247c478bd9Sstevel@tonic-gate 			}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 		} while (token != EOF);
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		kobj_close_file(file);
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
5327c478bd9Sstevel@tonic-gate 	    "usba_devdb_build_device_database: End");
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/* XXX: return the no. of errors encountered */
5357c478bd9Sstevel@tonic-gate 	return (0);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate /*
5407c478bd9Sstevel@tonic-gate  * usba_devdb_destroy_device_database
5417c478bd9Sstevel@tonic-gate  *	Destory all records in the tree
5427c478bd9Sstevel@tonic-gate  */
5437c478bd9Sstevel@tonic-gate static void
usba_devdb_destroy_device_database()5447c478bd9Sstevel@tonic-gate usba_devdb_destroy_device_database()
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	usba_devdb_info_t	*dbnode;
5477c478bd9Sstevel@tonic-gate 	void			*cookie = NULL;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
5507c478bd9Sstevel@tonic-gate 	    "usba_devdb_destroy_device_database");
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	/* while there are nodes in the tree, keep destroying them */
5537c478bd9Sstevel@tonic-gate 	while ((dbnode = (usba_devdb_info_t *)
5547c478bd9Sstevel@tonic-gate 	    avl_destroy_nodes(&usba_devdb, &cookie)) != NULL) {
5557c478bd9Sstevel@tonic-gate 		/*
5567c478bd9Sstevel@tonic-gate 		 * destroy record
5577c478bd9Sstevel@tonic-gate 		 * destroy tree node
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate 		usba_devdb_free_rec(dbnode->usb_dev);
5607c478bd9Sstevel@tonic-gate 		kmem_free(dbnode, sizeof (usba_devdb_info_t));
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	avl_destroy(&usba_devdb);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate  * usba_devdb_get_user_preferences
5687c478bd9Sstevel@tonic-gate  *	Returns configrec structure to the caller that contains user
5697c478bd9Sstevel@tonic-gate  *	preferences for the device pointed by the parameters.
5707c478bd9Sstevel@tonic-gate  *	The first search is for a record that has serial number and/or
5717c478bd9Sstevel@tonic-gate  *	a pathname. If search fails, we search for a rule that is generic
5727c478bd9Sstevel@tonic-gate  *	i.e. without serial no. and pathname.
5737c478bd9Sstevel@tonic-gate  */
5747c478bd9Sstevel@tonic-gate usba_configrec_t *
usba_devdb_get_user_preferences(int idVendor,int idProduct,char * serialno,char * pathname)5757c478bd9Sstevel@tonic-gate usba_devdb_get_user_preferences(int idVendor, int idProduct, char *serialno,
5767c478bd9Sstevel@tonic-gate     char *pathname)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	usba_configrec_t		*req_rec;
5797c478bd9Sstevel@tonic-gate 	usba_devdb_info_t	*req_node, *dbnode;
5807c478bd9Sstevel@tonic-gate 	avl_index_t		where;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	USB_DPRINTF_L4(DPRINT_MASK_DEVDB, usba_devdb_log_handle,
5837c478bd9Sstevel@tonic-gate 	    "usba_devdb_get_user_preferences");
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	req_rec = kmem_zalloc(sizeof (usba_configrec_t), KM_SLEEP);
5867c478bd9Sstevel@tonic-gate 	req_node = kmem_zalloc(sizeof (usba_devdb_info_t), KM_SLEEP);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	/* fill in the requested parameters */
5897c478bd9Sstevel@tonic-gate 	req_rec->idVendor = idVendor;
5907c478bd9Sstevel@tonic-gate 	req_rec->idProduct = idProduct;
5917c478bd9Sstevel@tonic-gate 	req_rec->serialno = serialno;
5927c478bd9Sstevel@tonic-gate 	req_rec->pathname = pathname;
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	req_node->usb_dev = req_rec;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	rw_enter(&usba_devdb_lock, RW_READER);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	/* try to find a perfect match in the device database */
5997c478bd9Sstevel@tonic-gate 	dbnode = (usba_devdb_info_t *)avl_find(&usba_devdb, req_node, &where);
6007c478bd9Sstevel@tonic-gate #ifdef __lock_lint
6017c478bd9Sstevel@tonic-gate 	(void) usba_devdb_compare(req_node, dbnode);
6027c478bd9Sstevel@tonic-gate #endif
6037c478bd9Sstevel@tonic-gate 	if (dbnode == NULL) {
6047c478bd9Sstevel@tonic-gate 		/* look for a generic rule */
6057c478bd9Sstevel@tonic-gate 		req_rec->serialno = req_rec->pathname = NULL;
6067c478bd9Sstevel@tonic-gate 		dbnode = (usba_devdb_info_t *)avl_find(&usba_devdb, req_node,
6077c478bd9Sstevel@tonic-gate 		    &where);
6087c478bd9Sstevel@tonic-gate #ifdef __lock_lint
6097c478bd9Sstevel@tonic-gate 		(void) usba_devdb_compare(req_node, dbnode);
6107c478bd9Sstevel@tonic-gate #endif
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 	rw_exit(&usba_devdb_lock);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	kmem_free(req_rec, sizeof (usba_configrec_t));
6157c478bd9Sstevel@tonic-gate 	kmem_free(req_node, sizeof (usba_devdb_info_t));
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	if (dbnode) {
6187c478bd9Sstevel@tonic-gate 		return (dbnode->usb_dev);
6197c478bd9Sstevel@tonic-gate 	} else {
6207c478bd9Sstevel@tonic-gate 		return (NULL);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate }
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate  * usba_devdb_refresh
6277c478bd9Sstevel@tonic-gate  *	Reinitializes the device database. It destroys the old one and creates
6287c478bd9Sstevel@tonic-gate  *	a new one by re-reading the file.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate int
usba_devdb_refresh()6317c478bd9Sstevel@tonic-gate usba_devdb_refresh()
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	rw_enter(&usba_devdb_lock, RW_WRITER);
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	usba_build_devdb = B_TRUE;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/* destroy all nodes in the existing database */
6387c478bd9Sstevel@tonic-gate 	usba_devdb_destroy_device_database();
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/* now build a new one */
6417c478bd9Sstevel@tonic-gate 	(void) usba_devdb_build_device_database();
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	usba_build_devdb = B_FALSE;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	rw_exit(&usba_devdb_lock);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	return (0);
6487c478bd9Sstevel@tonic-gate }
649