xref: /onnv-gate/usr/src/cmd/devfsadm/usb_link.c (revision 10975:9dd13a7cd2e3)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  *
219430SRaymond.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
220Sstevel@tonic-gate  * Use is subject to license terms.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <devfsadm.h>
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <limits.h>
290Sstevel@tonic-gate #include <string.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/stat.h>
330Sstevel@tonic-gate #include <strings.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate extern char *devfsadm_get_devices_dir();
360Sstevel@tonic-gate static int usb_process(di_minor_t minor, di_node_t node);
370Sstevel@tonic-gate 
380Sstevel@tonic-gate static void ugen_create_link(char *p_path, char *node_name,
390Sstevel@tonic-gate     di_node_t node, di_minor_t minor);
400Sstevel@tonic-gate 
410Sstevel@tonic-gate 
420Sstevel@tonic-gate /* Rules for creating links */
430Sstevel@tonic-gate static devfsadm_create_t usb_cbt[] = {
440Sstevel@tonic-gate 	{ "usb", NULL, "usb_ac",	DRV_EXACT,
450Sstevel@tonic-gate 						ILEVEL_0, usb_process },
460Sstevel@tonic-gate 	{ "usb", NULL, "usb_as",	DRV_EXACT,
470Sstevel@tonic-gate 						ILEVEL_0, usb_process },
480Sstevel@tonic-gate 	{ "usb", NULL, "ddivs_usbc",	DRV_EXACT,
490Sstevel@tonic-gate 						ILEVEL_0, usb_process },
503329Syz147069 	{ "usb", NULL, "usbvc",		DRV_EXACT,
513329Syz147069 						ILEVEL_0, usb_process },
520Sstevel@tonic-gate 	{ "usb", NULL, "hid",		DRV_EXACT,
530Sstevel@tonic-gate 						ILEVEL_0, usb_process },
549430SRaymond.Chen@Sun.COM 	{ "usb", NULL, "hwarc",	DRV_EXACT,
559430SRaymond.Chen@Sun.COM 						ILEVEL_0, usb_process },
569430SRaymond.Chen@Sun.COM 	{ "usb", NULL, "wusb_ca",	DRV_EXACT,
579430SRaymond.Chen@Sun.COM 						ILEVEL_0, usb_process },
580Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "hubd",	DRV_EXACT|TYPE_EXACT,
590Sstevel@tonic-gate 						ILEVEL_0, usb_process },
600Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ohci",	DRV_EXACT|TYPE_EXACT,
610Sstevel@tonic-gate 						ILEVEL_0, usb_process },
620Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ehci",	DRV_EXACT|TYPE_EXACT,
630Sstevel@tonic-gate 						ILEVEL_0, usb_process },
640Sstevel@tonic-gate 	{ "usb", DDI_NT_SCSI_NEXUS, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
650Sstevel@tonic-gate 						ILEVEL_0, usb_process },
660Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
670Sstevel@tonic-gate 						ILEVEL_0, usb_process },
680Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "uhci",	DRV_EXACT|TYPE_EXACT,
690Sstevel@tonic-gate 						ILEVEL_0, usb_process },
700Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "ugen",	DRV_EXACT|TYPE_EXACT,
710Sstevel@tonic-gate 						ILEVEL_0, usb_process },
720Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "usb_mid", DRV_EXACT|TYPE_EXACT,
730Sstevel@tonic-gate 						ILEVEL_0, usb_process },
740Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usb_mid", DRV_EXACT|TYPE_EXACT,
750Sstevel@tonic-gate 						ILEVEL_0, usb_process },
760Sstevel@tonic-gate 	{ "usb", DDI_NT_PRINTER, "usbprn", DRV_EXACT|TYPE_EXACT,
770Sstevel@tonic-gate 						ILEVEL_0, usb_process },
780Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usbprn", DRV_EXACT|TYPE_EXACT,
790Sstevel@tonic-gate 						ILEVEL_0, usb_process },
809430SRaymond.Chen@Sun.COM 	{ "usb", DDI_NT_NEXUS, "hwahc", DRV_EXACT|TYPE_EXACT,
819430SRaymond.Chen@Sun.COM 						ILEVEL_0, usb_process },
820Sstevel@tonic-gate };
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /* For debug printing (-V filter) */
850Sstevel@tonic-gate static char *debug_mid = "usb_mid";
860Sstevel@tonic-gate 
870Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(usb_cbt);
880Sstevel@tonic-gate 
890Sstevel@tonic-gate /* USB device links */
900Sstevel@tonic-gate #define	USB_LINK_RE_AUDIO	"^usb/audio[0-9]+$"
910Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOMUX	"^usb/audio-mux[0-9]+$"
920Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOCTL	"^usb/audio-control[0-9]+$"
930Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOSTREAM	"^usb/audio-stream[0-9]+$"
940Sstevel@tonic-gate #define	USB_LINK_RE_DDIVS_USBC	"^usb/ddivs_usbc[0-9]+$"
953329Syz147069 #define	USB_LINK_RE_VIDEO	"^usb/video[0-9]+$"
963329Syz147069 #define	USB_LINK_RE_VIDEO2	"^video[0-9]+$"
970Sstevel@tonic-gate #define	USB_LINK_RE_DEVICE	"^usb/device[0-9]+$"
980Sstevel@tonic-gate #define	USB_LINK_RE_HID		"^usb/hid[0-9]+$"
990Sstevel@tonic-gate #define	USB_LINK_RE_HUB		"^usb/hub[0-9]+$"
1000Sstevel@tonic-gate #define	USB_LINK_RE_MASS_STORE	"^usb/mass-storage[0-9]+$"
1010Sstevel@tonic-gate #define	USB_LINK_RE_UGEN	"^usb/[0-9,a-f]+\\.[0-9,a-f]+/[0-9]+/.+$"
1020Sstevel@tonic-gate #define	USB_LINK_RE_USBPRN	"^usb/printer[0-9]+$"
1039430SRaymond.Chen@Sun.COM #define	USB_LINK_RE_WHOST	"^usb/whost[0-9]+$"
1049430SRaymond.Chen@Sun.COM #define	USB_LINK_RE_HWARC	"^usb/hwarc[0-9]+$"
1059430SRaymond.Chen@Sun.COM #define	USB_LINK_RE_WUSB_CA	"^usb/wusb_ca[0-9]+$"
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /* Rules for removing links */
1080Sstevel@tonic-gate static devfsadm_remove_t usb_remove_cbt[] = {
1090Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIO, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1100Sstevel@tonic-gate 			devfsadm_rm_all },
1110Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOMUX, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1120Sstevel@tonic-gate 			devfsadm_rm_all },
1130Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOCTL, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1140Sstevel@tonic-gate 			devfsadm_rm_all },
1150Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOSTREAM, RM_POST | RM_HOT | RM_ALWAYS,
1160Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
1170Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DDIVS_USBC, RM_POST | RM_HOT | RM_ALWAYS,
1180Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
119*10975SRaymond.Chen@Sun.COM 	{ "usb", USB_LINK_RE_VIDEO2, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1203329Syz147069 			devfsadm_rm_all },
121*10975SRaymond.Chen@Sun.COM 	{ "usb", USB_LINK_RE_VIDEO, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1223329Syz147069 			devfsadm_rm_all },
1230Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DEVICE, RM_POST | RM_HOT, ILEVEL_0,
1240Sstevel@tonic-gate 			devfsadm_rm_all },
1250Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HID, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1260Sstevel@tonic-gate 			devfsadm_rm_all },
1270Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HUB, RM_POST | RM_HOT, ILEVEL_0, devfsadm_rm_all },
1280Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_MASS_STORE, RM_POST | RM_HOT | RM_ALWAYS,
1290Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
1300Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_UGEN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1310Sstevel@tonic-gate 			devfsadm_rm_all },
1320Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_USBPRN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1330Sstevel@tonic-gate 			devfsadm_rm_link },
1349430SRaymond.Chen@Sun.COM 	{ "usb", USB_LINK_RE_WHOST, RM_POST | RM_HOT, ILEVEL_0,
1359430SRaymond.Chen@Sun.COM 			devfsadm_rm_all },
1369430SRaymond.Chen@Sun.COM 	{ "usb", USB_LINK_RE_HWARC, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1379430SRaymond.Chen@Sun.COM 			devfsadm_rm_all },
1389430SRaymond.Chen@Sun.COM 	{ "usb", USB_LINK_RE_WUSB_CA, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1399430SRaymond.Chen@Sun.COM 			devfsadm_rm_all }
1400Sstevel@tonic-gate };
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate /*
1430Sstevel@tonic-gate  * Rules for different USB devices except ugen which is dynamically
1440Sstevel@tonic-gate  * created
1450Sstevel@tonic-gate  */
1460Sstevel@tonic-gate static devfsadm_enumerate_t audio_rules[1] =
1470Sstevel@tonic-gate 	{"^usb$/^audio([0-9]+)$", 1, MATCH_ALL};
1480Sstevel@tonic-gate static devfsadm_enumerate_t audio_mux_rules[1] =
1490Sstevel@tonic-gate 	{"^usb$/^audio-mux([0-9]+)$", 1, MATCH_ALL};
1500Sstevel@tonic-gate static devfsadm_enumerate_t audio_control_rules[1] =
1510Sstevel@tonic-gate 	{"^usb$/^audio-control([0-9]+)$", 1, MATCH_ALL};
1520Sstevel@tonic-gate static devfsadm_enumerate_t audio_stream_rules[1] =
1530Sstevel@tonic-gate 	{"^usb$/^audio-stream([0-9]+)$", 1, MATCH_ALL};
1540Sstevel@tonic-gate static devfsadm_enumerate_t ddivs_usbc_rules[1] =
1550Sstevel@tonic-gate 	{"^usb$/^ddivs_usbc([0-9]+)$", 1, MATCH_ALL};
1563329Syz147069 static devfsadm_enumerate_t video_rules[1] =
1573329Syz147069 	{"^usb$/^video([0-9]+)$", 1, MATCH_ALL};
1580Sstevel@tonic-gate static devfsadm_enumerate_t device_rules[1] =
1590Sstevel@tonic-gate 	{"^usb$/^device([0-9]+)$", 1, MATCH_ALL};
1600Sstevel@tonic-gate static devfsadm_enumerate_t hid_rules[1] =
1610Sstevel@tonic-gate 	{"^usb$/^hid([0-9]+)$", 1, MATCH_ALL};
1620Sstevel@tonic-gate static devfsadm_enumerate_t hub_rules[1] =
1630Sstevel@tonic-gate 	{"^usb$/^hub([0-9]+)$", 1, MATCH_ALL};
1640Sstevel@tonic-gate static devfsadm_enumerate_t mass_storage_rules[1] =
1650Sstevel@tonic-gate 	{"^usb$/^mass-storage([0-9]+)$", 1, MATCH_ALL};
1660Sstevel@tonic-gate static devfsadm_enumerate_t usbprn_rules[1] =
1670Sstevel@tonic-gate 	{"^usb$/^printer([0-9]+)$", 1, MATCH_ALL};
1689430SRaymond.Chen@Sun.COM static devfsadm_enumerate_t whost_rules[1] =
1699430SRaymond.Chen@Sun.COM 	{"^usb$/^whost([0-9]+)$", 1, MATCH_ALL};
1709430SRaymond.Chen@Sun.COM static devfsadm_enumerate_t hwarc_rules[1] =
1719430SRaymond.Chen@Sun.COM 	{"^usb$/^hwarc([0-9]+)$", 1, MATCH_ALL};
1729430SRaymond.Chen@Sun.COM static devfsadm_enumerate_t wusb_ca_rules[1] =
1739430SRaymond.Chen@Sun.COM 	{"^usb$/^wusb_ca([0-9]+)$", 1, MATCH_ALL};
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(usb_remove_cbt);
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate int
minor_init(void)1780Sstevel@tonic-gate minor_init(void)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_init\n");
1810Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate int
minor_fini(void)1850Sstevel@tonic-gate minor_fini(void)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_fini\n");
1880Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate typedef enum {
1920Sstevel@tonic-gate 	DRIVER_HUBD	= 0,
1930Sstevel@tonic-gate 	DRIVER_OHCI	= 1,
1940Sstevel@tonic-gate 	DRIVER_EHCI	= 2,
1950Sstevel@tonic-gate 	DRIVER_UHCI	= 3,
1960Sstevel@tonic-gate 	DRIVER_USB_AC	= 4,
1970Sstevel@tonic-gate 	DRIVER_USB_AS	= 5,
1980Sstevel@tonic-gate 	DRIVER_HID	= 6,
1990Sstevel@tonic-gate 	DRIVER_USB_MID	= 7,
2000Sstevel@tonic-gate 	DRIVER_DDIVS_USBC = 8,
2010Sstevel@tonic-gate 	DRIVER_SCSA2USB = 9,
2020Sstevel@tonic-gate 	DRIVER_USBPRN	= 10,
2030Sstevel@tonic-gate 	DRIVER_UGEN	= 11,
2043329Syz147069 	DRIVER_VIDEO	= 12,
2059430SRaymond.Chen@Sun.COM 	DRIVER_HWAHC	= 13,
2069430SRaymond.Chen@Sun.COM 	DRIVER_HWARC	= 14,
2079430SRaymond.Chen@Sun.COM 	DRIVER_WUSB_CA	= 15,
2089430SRaymond.Chen@Sun.COM 	DRIVER_UNKNOWN	= 16
2090Sstevel@tonic-gate } driver_defs_t;
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate typedef struct {
2120Sstevel@tonic-gate 	char	*driver_name;
2130Sstevel@tonic-gate 	int	index;
2140Sstevel@tonic-gate } driver_name_table_entry_t;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate driver_name_table_entry_t driver_name_table[] = {
2170Sstevel@tonic-gate 	{ "hubd",	DRIVER_HUBD },
2180Sstevel@tonic-gate 	{ "ohci",	DRIVER_OHCI },
2190Sstevel@tonic-gate 	{ "ehci",	DRIVER_EHCI },
2200Sstevel@tonic-gate 	{ "uhci",	DRIVER_UHCI },
2210Sstevel@tonic-gate 	{ "usb_ac",	DRIVER_USB_AC },
2220Sstevel@tonic-gate 	{ "usb_as",	DRIVER_USB_AS },
2230Sstevel@tonic-gate 	{ "hid",	DRIVER_HID },
2240Sstevel@tonic-gate 	{ "usb_mid",	DRIVER_USB_MID },
2250Sstevel@tonic-gate 	{ "ddivs_usbc",	DRIVER_DDIVS_USBC },
2260Sstevel@tonic-gate 	{ "scsa2usb",	DRIVER_SCSA2USB },
2270Sstevel@tonic-gate 	{ "usbprn",	DRIVER_USBPRN },
2280Sstevel@tonic-gate 	{ "ugen",	DRIVER_UGEN },
2293329Syz147069 	{ "usbvc",	DRIVER_VIDEO },
2309430SRaymond.Chen@Sun.COM 	{ "hwahc",	DRIVER_HWAHC },
2319430SRaymond.Chen@Sun.COM 	{ "hwarc",	DRIVER_HWARC },
2329430SRaymond.Chen@Sun.COM 	{ "wusb_ca",	DRIVER_WUSB_CA },
2330Sstevel@tonic-gate 	{ NULL,		DRIVER_UNKNOWN }
2340Sstevel@tonic-gate };
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate /*
2370Sstevel@tonic-gate  * This function is called for every usb minor node.
2380Sstevel@tonic-gate  * Calls enumerate to assign a logical usb id, and then
2390Sstevel@tonic-gate  * devfsadm_mklink to make the link.
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate static int
usb_process(di_minor_t minor,di_node_t node)2420Sstevel@tonic-gate usb_process(di_minor_t minor, di_node_t node)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1];
2450Sstevel@tonic-gate 	char *l_path, *p_path, *buf, *devfspath;
2460Sstevel@tonic-gate 	char *minor_nm, *drvr_nm, *name = (char *)NULL;
2470Sstevel@tonic-gate 	int i, index;
2481676Sjpk 	int flags = 0;
2490Sstevel@tonic-gate 	int create_secondary_link = 0;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	minor_nm = di_minor_name(minor);
2520Sstevel@tonic-gate 	drvr_nm = di_driver_name(node);
2530Sstevel@tonic-gate 	if ((minor_nm == NULL) || (drvr_nm == NULL)) {
2540Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: minor=%s node=%s type=%s\n",
2589430SRaymond.Chen@Sun.COM 	    minor_nm, di_node_name(node), di_minor_nodetype(minor));
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
2610Sstevel@tonic-gate 	if (devfspath == NULL) {
2620Sstevel@tonic-gate 		devfsadm_print(debug_mid,
2630Sstevel@tonic-gate 		    "USB_process: devfspath is	NULL\n");
2640Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	l_path = (char *)malloc(PATH_MAX);
2680Sstevel@tonic-gate 	if (l_path == NULL) {
2690Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2700Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
2710Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2720Sstevel@tonic-gate 	}
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	p_path = (char *)malloc(PATH_MAX);
2750Sstevel@tonic-gate 	if (p_path == NULL) {
2760Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
2770Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2780Sstevel@tonic-gate 		free(l_path);
2790Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2800Sstevel@tonic-gate 	}
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
2830Sstevel@tonic-gate 	(void) strcat(p_path, ":");
2840Sstevel@tonic-gate 	(void) strcat(p_path, minor_nm);
2850Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: path %s\n", p_path);
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	for (i = 0; ; i++) {
2900Sstevel@tonic-gate 		if ((driver_name_table[i].driver_name == NULL) ||
2910Sstevel@tonic-gate 		    (strcmp(drvr_nm, driver_name_table[i].driver_name) == 0)) {
2920Sstevel@tonic-gate 			index = driver_name_table[i].index;
2930Sstevel@tonic-gate 			break;
2940Sstevel@tonic-gate 		}
2950Sstevel@tonic-gate 	}
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	if (strcmp(di_minor_nodetype(minor), DDI_NT_UGEN) == 0) {
2980Sstevel@tonic-gate 		ugen_create_link(p_path, minor_nm, node, minor);
2990Sstevel@tonic-gate 		free(l_path);
3000Sstevel@tonic-gate 		free(p_path);
3010Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/* Figure out which rules to apply */
3050Sstevel@tonic-gate 	switch (index) {
3060Sstevel@tonic-gate 	case DRIVER_HUBD:
3070Sstevel@tonic-gate 	case DRIVER_OHCI:
3080Sstevel@tonic-gate 	case DRIVER_EHCI:
3090Sstevel@tonic-gate 	case DRIVER_UHCI:
3100Sstevel@tonic-gate 		rules[0] = hub_rules[0];	/* For HUBs */
3110Sstevel@tonic-gate 		name = "hub";
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		break;
3140Sstevel@tonic-gate 	case DRIVER_USB_AC:
3150Sstevel@tonic-gate 		if (strcmp(minor_nm, "sound,audio") == 0) {
3160Sstevel@tonic-gate 			rules[0] = audio_rules[0];
3170Sstevel@tonic-gate 			name = "audio";		/* For audio */
3180Sstevel@tonic-gate 			create_secondary_link = 1;
3190Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "sound,audioctl") == 0) {
3200Sstevel@tonic-gate 			rules[0] = audio_control_rules[0];
3210Sstevel@tonic-gate 			name = "audio-control";		/* For audio */
3220Sstevel@tonic-gate 			create_secondary_link = 1;
3230Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "mux") == 0) {
3240Sstevel@tonic-gate 			rules[0] = audio_mux_rules[0];
3250Sstevel@tonic-gate 			name = "audio-mux";		/* For audio */
3260Sstevel@tonic-gate 		} else {
3270Sstevel@tonic-gate 			free(l_path);
3280Sstevel@tonic-gate 			free(p_path);
3290Sstevel@tonic-gate 			return (DEVFSADM_CONTINUE);
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 		break;
3320Sstevel@tonic-gate 	case DRIVER_USB_AS:
3330Sstevel@tonic-gate 		rules[0] = audio_stream_rules[0];
3340Sstevel@tonic-gate 		name = "audio-stream";		/* For audio */
3350Sstevel@tonic-gate 		break;
3363329Syz147069 	case DRIVER_VIDEO:
3373329Syz147069 		rules[0] = video_rules[0];
3383329Syz147069 		name = "video";			/* For video */
3393329Syz147069 		create_secondary_link = 1;
3403329Syz147069 		break;
3410Sstevel@tonic-gate 	case DRIVER_HID:
3420Sstevel@tonic-gate 		rules[0] = hid_rules[0];
3430Sstevel@tonic-gate 		name = "hid";			/* For HIDs */
3440Sstevel@tonic-gate 		break;
3450Sstevel@tonic-gate 	case DRIVER_USB_MID:
3460Sstevel@tonic-gate 		rules[0] = device_rules[0];
3470Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
3480Sstevel@tonic-gate 		break;
3490Sstevel@tonic-gate 	case DRIVER_DDIVS_USBC:
3500Sstevel@tonic-gate 		rules[0] = ddivs_usbc_rules[0];
3510Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
3520Sstevel@tonic-gate 		break;
3530Sstevel@tonic-gate 	case DRIVER_SCSA2USB:
3540Sstevel@tonic-gate 		rules[0] = mass_storage_rules[0];
3550Sstevel@tonic-gate 		name = "mass-storage";		/* For mass-storage devices */
3560Sstevel@tonic-gate 		break;
3570Sstevel@tonic-gate 	case DRIVER_USBPRN:
3580Sstevel@tonic-gate 		rules[0] = usbprn_rules[0];
3590Sstevel@tonic-gate 		name = "printer";
3600Sstevel@tonic-gate 		break;
3619430SRaymond.Chen@Sun.COM 	case DRIVER_HWAHC:
3629430SRaymond.Chen@Sun.COM 		if (strcmp(minor_nm, "hwahc") == 0) {
3639430SRaymond.Chen@Sun.COM 			rules[0] = whost_rules[0];
3649430SRaymond.Chen@Sun.COM 			name = "whost";		/* For HWA HC */
3659430SRaymond.Chen@Sun.COM 		} else if (strcmp(minor_nm, "hubd") == 0) {
3669430SRaymond.Chen@Sun.COM 			rules[0] = hub_rules[0];
3679430SRaymond.Chen@Sun.COM 			name = "hub";		/* For HWA HC */
3689430SRaymond.Chen@Sun.COM 		} else {
3699430SRaymond.Chen@Sun.COM 			free(l_path);
3709430SRaymond.Chen@Sun.COM 			free(p_path);
3719430SRaymond.Chen@Sun.COM 			return (DEVFSADM_CONTINUE);
3729430SRaymond.Chen@Sun.COM 		}
3739430SRaymond.Chen@Sun.COM 		break;
3749430SRaymond.Chen@Sun.COM 	case DRIVER_HWARC:
3759430SRaymond.Chen@Sun.COM 		rules[0] = hwarc_rules[0];
3769430SRaymond.Chen@Sun.COM 		name = "hwarc";		/* For UWB HWA Radio Controllers */
3779430SRaymond.Chen@Sun.COM 		break;
3789430SRaymond.Chen@Sun.COM 	case DRIVER_WUSB_CA:
3799430SRaymond.Chen@Sun.COM 		rules[0] = wusb_ca_rules[0];
3809430SRaymond.Chen@Sun.COM 		name = "wusb_ca";	/* for wusb cable association */
3819430SRaymond.Chen@Sun.COM 		break;
3820Sstevel@tonic-gate 	default:
3830Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: unknown driver=%s\n",
3840Sstevel@tonic-gate 		    drvr_nm);
3850Sstevel@tonic-gate 		free(l_path);
3860Sstevel@tonic-gate 		free(p_path);
3870Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/*
3910Sstevel@tonic-gate 	 *  build the physical path from the components.
3920Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
3950Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: exit/continue\n");
3960Sstevel@tonic-gate 		free(l_path);
3970Sstevel@tonic-gate 		free(p_path);
3980Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	(void) snprintf(l_path, PATH_MAX, "usb/%s%s", name, buf);
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: p_path=%s buf=%s\n",
4040Sstevel@tonic-gate 	    p_path, buf);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	free(buf);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
4090Sstevel@tonic-gate 
4101676Sjpk 	(void) devfsadm_mklink(l_path, node, minor, flags);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	if (create_secondary_link) {
4130Sstevel@tonic-gate 		/*
4140Sstevel@tonic-gate 		 * Create secondary links to make newly hotplugged
4150Sstevel@tonic-gate 		 * usb audio device the primary device.
4160Sstevel@tonic-gate 		 */
4170Sstevel@tonic-gate 		if (strcmp(name, "audio") == 0) {
4180Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audio", l_path, 0);
4190Sstevel@tonic-gate 		} else if (strcmp(name, "audio-control") == 0) {
4200Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audioctl", l_path, 0);
4213329Syz147069 		} else if (strcmp(name, "video") == 0) {
4223329Syz147069 			(void) devfsadm_secondary_link(l_path + 4, l_path, 0);
4230Sstevel@tonic-gate 		}
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	free(p_path);
4270Sstevel@tonic-gate 	free(l_path);
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate static void
ugen_create_link(char * p_path,char * node_name,di_node_t node,di_minor_t minor)4330Sstevel@tonic-gate ugen_create_link(char *p_path, char *node_name,
4340Sstevel@tonic-gate     di_node_t node, di_minor_t minor)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	char *buf, s[MAXPATHLEN];
4370Sstevel@tonic-gate 	char *lasts = s;
4380Sstevel@tonic-gate 	char *vid, *pid;
4390Sstevel@tonic-gate 	char *minor_name;
4400Sstevel@tonic-gate 	char ugen_RE[128];
4410Sstevel@tonic-gate 	devfsadm_enumerate_t ugen_rules[1];
4420Sstevel@tonic-gate 	char l_path[PATH_MAX];
4431676Sjpk 	int flags = 0;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	devfsadm_print(debug_mid, "ugen_create_link: p_path=%s name=%s\n",
4460Sstevel@tonic-gate 	    p_path, node_name);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	(void) strlcpy(s, node_name, sizeof (s));
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/* get vid, pid and minor name strings */
4510Sstevel@tonic-gate 	vid = strtok_r(lasts, ".", &lasts);
4520Sstevel@tonic-gate 	pid = strtok_r(NULL, ".", &lasts);
4530Sstevel@tonic-gate 	minor_name = lasts;
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	if ((vid == NULL) || (pid == NULL) || (minor_name == NULL)) {
4560Sstevel@tonic-gate 		return;
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	/* create regular expression contain vid and pid */
4600Sstevel@tonic-gate 	(void) snprintf(ugen_RE, sizeof (ugen_RE),
4610Sstevel@tonic-gate 	    "^usb$/^%s\\.%s$/^([0-9]+)$", vid, pid);
4620Sstevel@tonic-gate 	devfsadm_print(debug_mid,
4630Sstevel@tonic-gate 	    "ugen_create_link: ugen_RE=%s minor_name=%s\n",
4640Sstevel@tonic-gate 	    ugen_RE, minor_name);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	bzero(ugen_rules, sizeof (ugen_rules));
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	ugen_rules[0].re = ugen_RE;
4690Sstevel@tonic-gate 	ugen_rules[0].subexp = 1;
4700Sstevel@tonic-gate 	ugen_rules[0].flags = MATCH_ADDR;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	/*
4730Sstevel@tonic-gate 	 *  build the physical path from the components.
4740Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
4750Sstevel@tonic-gate 	 */
4760Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, ugen_rules, 1)) {
4770Sstevel@tonic-gate 		devfsadm_print(debug_mid, "ugen_create_link: exit/continue\n");
4780Sstevel@tonic-gate 		return;
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	(void) snprintf(l_path, sizeof (l_path), "usb/%s.%s/%s/%s",
4820Sstevel@tonic-gate 	    vid, pid, buf, minor_name);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
4850Sstevel@tonic-gate 
4861676Sjpk 	(void) devfsadm_mklink(l_path, node, minor, flags);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	free(buf);
4890Sstevel@tonic-gate }
490