xref: /titanic_53/usr/src/cmd/devfsadm/usb_link.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  *
22*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
23*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*7c478bd9Sstevel@tonic-gate  */
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*7c478bd9Sstevel@tonic-gate 
28*7c478bd9Sstevel@tonic-gate #include <devfsadm.h>
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <limits.h>
32*7c478bd9Sstevel@tonic-gate #include <string.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
36*7c478bd9Sstevel@tonic-gate #include <strings.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate extern char *devfsadm_get_devices_dir();
39*7c478bd9Sstevel@tonic-gate static int usb_process(di_minor_t minor, di_node_t node);
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate static void ugen_create_link(char *p_path, char *node_name,
42*7c478bd9Sstevel@tonic-gate     di_node_t node, di_minor_t minor);
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate /* Rules for creating links */
46*7c478bd9Sstevel@tonic-gate static devfsadm_create_t usb_cbt[] = {
47*7c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "usb_ac",	DRV_EXACT,
48*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
49*7c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "usb_as",	DRV_EXACT,
50*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
51*7c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "ddivs_usbc",	DRV_EXACT,
52*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
53*7c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "hid",		DRV_EXACT,
54*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
55*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "hubd",	DRV_EXACT|TYPE_EXACT,
56*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
57*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ohci",	DRV_EXACT|TYPE_EXACT,
58*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
59*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ehci",	DRV_EXACT|TYPE_EXACT,
60*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
61*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_SCSI_NEXUS, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
62*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
63*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
64*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
65*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "uhci",	DRV_EXACT|TYPE_EXACT,
66*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
67*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "ugen",	DRV_EXACT|TYPE_EXACT,
68*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
69*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "usb_mid", DRV_EXACT|TYPE_EXACT,
70*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
71*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usb_mid", DRV_EXACT|TYPE_EXACT,
72*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
73*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_PRINTER, "usbprn", DRV_EXACT|TYPE_EXACT,
74*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
75*7c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usbprn", DRV_EXACT|TYPE_EXACT,
76*7c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
77*7c478bd9Sstevel@tonic-gate };
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate /* For debug printing (-V filter) */
80*7c478bd9Sstevel@tonic-gate static char *debug_mid = "usb_mid";
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(usb_cbt);
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate /* USB device links */
85*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIO	"^usb/audio[0-9]+$"
86*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOMUX	"^usb/audio-mux[0-9]+$"
87*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOCTL	"^usb/audio-control[0-9]+$"
88*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOSTREAM	"^usb/audio-stream[0-9]+$"
89*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_DDIVS_USBC	"^usb/ddivs_usbc[0-9]+$"
90*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_DEVICE	"^usb/device[0-9]+$"
91*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_HID		"^usb/hid[0-9]+$"
92*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_HUB		"^usb/hub[0-9]+$"
93*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_MASS_STORE	"^usb/mass-storage[0-9]+$"
94*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_UGEN	"^usb/[0-9,a-f]+\\.[0-9,a-f]+/[0-9]+/.+$"
95*7c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_USBPRN	"^usb/printer[0-9]+$"
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /* Rules for removing links */
98*7c478bd9Sstevel@tonic-gate static devfsadm_remove_t usb_remove_cbt[] = {
99*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIO, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
100*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
101*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOMUX, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
102*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
103*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOCTL, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
104*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
105*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOSTREAM, RM_POST | RM_HOT | RM_ALWAYS,
106*7c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
107*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DDIVS_USBC, RM_POST | RM_HOT | RM_ALWAYS,
108*7c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
109*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DEVICE, RM_POST | RM_HOT, ILEVEL_0,
110*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
111*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HID, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
112*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
113*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HUB, RM_POST | RM_HOT, ILEVEL_0, devfsadm_rm_all },
114*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_MASS_STORE, RM_POST | RM_HOT | RM_ALWAYS,
115*7c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
116*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_UGEN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
117*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
118*7c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_USBPRN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
119*7c478bd9Sstevel@tonic-gate 			devfsadm_rm_link },
120*7c478bd9Sstevel@tonic-gate };
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * Rules for different USB devices except ugen which is dynamically
124*7c478bd9Sstevel@tonic-gate  * created
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_rules[1] =
127*7c478bd9Sstevel@tonic-gate 	{"^usb$/^audio([0-9]+)$", 1, MATCH_ALL};
128*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_mux_rules[1] =
129*7c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-mux([0-9]+)$", 1, MATCH_ALL};
130*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_control_rules[1] =
131*7c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-control([0-9]+)$", 1, MATCH_ALL};
132*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_stream_rules[1] =
133*7c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-stream([0-9]+)$", 1, MATCH_ALL};
134*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t ddivs_usbc_rules[1] =
135*7c478bd9Sstevel@tonic-gate 	{"^usb$/^ddivs_usbc([0-9]+)$", 1, MATCH_ALL};
136*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t device_rules[1] =
137*7c478bd9Sstevel@tonic-gate 	{"^usb$/^device([0-9]+)$", 1, MATCH_ALL};
138*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t hid_rules[1] =
139*7c478bd9Sstevel@tonic-gate 	{"^usb$/^hid([0-9]+)$", 1, MATCH_ALL};
140*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t hub_rules[1] =
141*7c478bd9Sstevel@tonic-gate 	{"^usb$/^hub([0-9]+)$", 1, MATCH_ALL};
142*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t mass_storage_rules[1] =
143*7c478bd9Sstevel@tonic-gate 	{"^usb$/^mass-storage([0-9]+)$", 1, MATCH_ALL};
144*7c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t usbprn_rules[1] =
145*7c478bd9Sstevel@tonic-gate 	{"^usb$/^printer([0-9]+)$", 1, MATCH_ALL};
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(usb_remove_cbt);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate int
150*7c478bd9Sstevel@tonic-gate minor_init(void)
151*7c478bd9Sstevel@tonic-gate {
152*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_init\n");
153*7c478bd9Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
154*7c478bd9Sstevel@tonic-gate }
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate int
157*7c478bd9Sstevel@tonic-gate minor_fini(void)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_fini\n");
160*7c478bd9Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
161*7c478bd9Sstevel@tonic-gate }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate typedef enum {
164*7c478bd9Sstevel@tonic-gate 	DRIVER_HUBD	= 0,
165*7c478bd9Sstevel@tonic-gate 	DRIVER_OHCI	= 1,
166*7c478bd9Sstevel@tonic-gate 	DRIVER_EHCI	= 2,
167*7c478bd9Sstevel@tonic-gate 	DRIVER_UHCI	= 3,
168*7c478bd9Sstevel@tonic-gate 	DRIVER_USB_AC	= 4,
169*7c478bd9Sstevel@tonic-gate 	DRIVER_USB_AS	= 5,
170*7c478bd9Sstevel@tonic-gate 	DRIVER_HID	= 6,
171*7c478bd9Sstevel@tonic-gate 	DRIVER_USB_MID	= 7,
172*7c478bd9Sstevel@tonic-gate 	DRIVER_DDIVS_USBC = 8,
173*7c478bd9Sstevel@tonic-gate 	DRIVER_SCSA2USB = 9,
174*7c478bd9Sstevel@tonic-gate 	DRIVER_USBPRN	= 10,
175*7c478bd9Sstevel@tonic-gate 	DRIVER_UGEN	= 11,
176*7c478bd9Sstevel@tonic-gate 	DRIVER_UNKNOWN	= 12
177*7c478bd9Sstevel@tonic-gate } driver_defs_t;
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate typedef struct {
180*7c478bd9Sstevel@tonic-gate 	char	*driver_name;
181*7c478bd9Sstevel@tonic-gate 	int	index;
182*7c478bd9Sstevel@tonic-gate } driver_name_table_entry_t;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate driver_name_table_entry_t driver_name_table[] = {
185*7c478bd9Sstevel@tonic-gate 	{ "hubd",	DRIVER_HUBD },
186*7c478bd9Sstevel@tonic-gate 	{ "ohci",	DRIVER_OHCI },
187*7c478bd9Sstevel@tonic-gate 	{ "ehci",	DRIVER_EHCI },
188*7c478bd9Sstevel@tonic-gate 	{ "uhci",	DRIVER_UHCI },
189*7c478bd9Sstevel@tonic-gate 	{ "usb_ac",	DRIVER_USB_AC },
190*7c478bd9Sstevel@tonic-gate 	{ "usb_as",	DRIVER_USB_AS },
191*7c478bd9Sstevel@tonic-gate 	{ "hid",	DRIVER_HID },
192*7c478bd9Sstevel@tonic-gate 	{ "usb_mid",	DRIVER_USB_MID },
193*7c478bd9Sstevel@tonic-gate 	{ "ddivs_usbc",	DRIVER_DDIVS_USBC },
194*7c478bd9Sstevel@tonic-gate 	{ "scsa2usb",	DRIVER_SCSA2USB },
195*7c478bd9Sstevel@tonic-gate 	{ "usbprn",	DRIVER_USBPRN },
196*7c478bd9Sstevel@tonic-gate 	{ "ugen",	DRIVER_UGEN },
197*7c478bd9Sstevel@tonic-gate 	{ NULL,		DRIVER_UNKNOWN }
198*7c478bd9Sstevel@tonic-gate };
199*7c478bd9Sstevel@tonic-gate 
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate /*
202*7c478bd9Sstevel@tonic-gate  * This function is called for every usb minor node.
203*7c478bd9Sstevel@tonic-gate  * Calls enumerate to assign a logical usb id, and then
204*7c478bd9Sstevel@tonic-gate  * devfsadm_mklink to make the link.
205*7c478bd9Sstevel@tonic-gate  */
206*7c478bd9Sstevel@tonic-gate static int
207*7c478bd9Sstevel@tonic-gate usb_process(di_minor_t minor, di_node_t node)
208*7c478bd9Sstevel@tonic-gate {
209*7c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1];
210*7c478bd9Sstevel@tonic-gate 	char *l_path, *p_path, *buf, *devfspath;
211*7c478bd9Sstevel@tonic-gate 	char *minor_nm, *drvr_nm, *name = (char *)NULL;
212*7c478bd9Sstevel@tonic-gate 	int i, index;
213*7c478bd9Sstevel@tonic-gate 	int create_secondary_link = 0;
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	minor_nm = di_minor_name(minor);
216*7c478bd9Sstevel@tonic-gate 	drvr_nm = di_driver_name(node);
217*7c478bd9Sstevel@tonic-gate 	if ((minor_nm == NULL) || (drvr_nm == NULL)) {
218*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
219*7c478bd9Sstevel@tonic-gate 	}
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: minor=%s node=%s type=%s\n",
222*7c478bd9Sstevel@tonic-gate 		minor_nm, di_node_name(node), di_minor_nodetype(minor));
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
225*7c478bd9Sstevel@tonic-gate 	if (devfspath == NULL) {
226*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid,
227*7c478bd9Sstevel@tonic-gate 		    "USB_process: devfspath is	NULL\n");
228*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	l_path = (char *)malloc(PATH_MAX);
232*7c478bd9Sstevel@tonic-gate 	if (l_path == NULL) {
233*7c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
234*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
235*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	p_path = (char *)malloc(PATH_MAX);
239*7c478bd9Sstevel@tonic-gate 	if (p_path == NULL) {
240*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
241*7c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
242*7c478bd9Sstevel@tonic-gate 		free(l_path);
243*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
244*7c478bd9Sstevel@tonic-gate 	}
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
247*7c478bd9Sstevel@tonic-gate 	(void) strcat(p_path, ":");
248*7c478bd9Sstevel@tonic-gate 	(void) strcat(p_path, minor_nm);
249*7c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: path %s\n", p_path);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
254*7c478bd9Sstevel@tonic-gate 		if ((driver_name_table[i].driver_name == NULL) ||
255*7c478bd9Sstevel@tonic-gate 		    (strcmp(drvr_nm, driver_name_table[i].driver_name) == 0)) {
256*7c478bd9Sstevel@tonic-gate 			index = driver_name_table[i].index;
257*7c478bd9Sstevel@tonic-gate 			break;
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	if (strcmp(di_minor_nodetype(minor), DDI_NT_UGEN) == 0) {
262*7c478bd9Sstevel@tonic-gate 		ugen_create_link(p_path, minor_nm, node, minor);
263*7c478bd9Sstevel@tonic-gate 		free(l_path);
264*7c478bd9Sstevel@tonic-gate 		free(p_path);
265*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	/* Figure out which rules to apply */
269*7c478bd9Sstevel@tonic-gate 	switch (index) {
270*7c478bd9Sstevel@tonic-gate 	case DRIVER_HUBD:
271*7c478bd9Sstevel@tonic-gate 	case DRIVER_OHCI:
272*7c478bd9Sstevel@tonic-gate 	case DRIVER_EHCI:
273*7c478bd9Sstevel@tonic-gate 	case DRIVER_UHCI:
274*7c478bd9Sstevel@tonic-gate 		rules[0] = hub_rules[0];	/* For HUBs */
275*7c478bd9Sstevel@tonic-gate 		name = "hub";
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 		break;
278*7c478bd9Sstevel@tonic-gate 	case DRIVER_USB_AC:
279*7c478bd9Sstevel@tonic-gate 		if (strcmp(minor_nm, "sound,audio") == 0) {
280*7c478bd9Sstevel@tonic-gate 			rules[0] = audio_rules[0];
281*7c478bd9Sstevel@tonic-gate 			name = "audio";		/* For audio */
282*7c478bd9Sstevel@tonic-gate 			create_secondary_link = 1;
283*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "sound,audioctl") == 0) {
284*7c478bd9Sstevel@tonic-gate 			rules[0] = audio_control_rules[0];
285*7c478bd9Sstevel@tonic-gate 			name = "audio-control";		/* For audio */
286*7c478bd9Sstevel@tonic-gate 			create_secondary_link = 1;
287*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "mux") == 0) {
288*7c478bd9Sstevel@tonic-gate 			rules[0] = audio_mux_rules[0];
289*7c478bd9Sstevel@tonic-gate 			name = "audio-mux";		/* For audio */
290*7c478bd9Sstevel@tonic-gate 		} else {
291*7c478bd9Sstevel@tonic-gate 			free(l_path);
292*7c478bd9Sstevel@tonic-gate 			free(p_path);
293*7c478bd9Sstevel@tonic-gate 			return (DEVFSADM_CONTINUE);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 		break;
296*7c478bd9Sstevel@tonic-gate 	case DRIVER_USB_AS:
297*7c478bd9Sstevel@tonic-gate 		rules[0] = audio_stream_rules[0];
298*7c478bd9Sstevel@tonic-gate 		name = "audio-stream";		/* For audio */
299*7c478bd9Sstevel@tonic-gate 		break;
300*7c478bd9Sstevel@tonic-gate 	case DRIVER_HID:
301*7c478bd9Sstevel@tonic-gate 		rules[0] = hid_rules[0];
302*7c478bd9Sstevel@tonic-gate 		name = "hid";			/* For HIDs */
303*7c478bd9Sstevel@tonic-gate 		break;
304*7c478bd9Sstevel@tonic-gate 	case DRIVER_USB_MID:
305*7c478bd9Sstevel@tonic-gate 		rules[0] = device_rules[0];
306*7c478bd9Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
307*7c478bd9Sstevel@tonic-gate 		break;
308*7c478bd9Sstevel@tonic-gate 	case DRIVER_DDIVS_USBC:
309*7c478bd9Sstevel@tonic-gate 		rules[0] = ddivs_usbc_rules[0];
310*7c478bd9Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
311*7c478bd9Sstevel@tonic-gate 		break;
312*7c478bd9Sstevel@tonic-gate 	case DRIVER_SCSA2USB:
313*7c478bd9Sstevel@tonic-gate 		rules[0] = mass_storage_rules[0];
314*7c478bd9Sstevel@tonic-gate 		name = "mass-storage";		/* For mass-storage devices */
315*7c478bd9Sstevel@tonic-gate 		break;
316*7c478bd9Sstevel@tonic-gate 	case DRIVER_USBPRN:
317*7c478bd9Sstevel@tonic-gate 		rules[0] = usbprn_rules[0];
318*7c478bd9Sstevel@tonic-gate 		name = "printer";
319*7c478bd9Sstevel@tonic-gate 		break;
320*7c478bd9Sstevel@tonic-gate 	default:
321*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: unknown driver=%s\n",
322*7c478bd9Sstevel@tonic-gate 		    drvr_nm);
323*7c478bd9Sstevel@tonic-gate 		free(l_path);
324*7c478bd9Sstevel@tonic-gate 		free(p_path);
325*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 	/*
329*7c478bd9Sstevel@tonic-gate 	 *  build the physical path from the components.
330*7c478bd9Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
331*7c478bd9Sstevel@tonic-gate 	 */
332*7c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
333*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: exit/continue\n");
334*7c478bd9Sstevel@tonic-gate 		free(l_path);
335*7c478bd9Sstevel@tonic-gate 		free(p_path);
336*7c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 	(void) snprintf(l_path, PATH_MAX, "usb/%s%s", name, buf);
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: p_path=%s buf=%s\n",
342*7c478bd9Sstevel@tonic-gate 	    p_path, buf);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	free(buf);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	if (create_secondary_link) {
351*7c478bd9Sstevel@tonic-gate 		/*
352*7c478bd9Sstevel@tonic-gate 		 * Create secondary links to make newly hotplugged
353*7c478bd9Sstevel@tonic-gate 		 * usb audio device the primary device.
354*7c478bd9Sstevel@tonic-gate 		 */
355*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, "audio") == 0) {
356*7c478bd9Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audio", l_path, 0);
357*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(name, "audio-control") == 0) {
358*7c478bd9Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audioctl", l_path, 0);
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	free(p_path);
363*7c478bd9Sstevel@tonic-gate 	free(l_path);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
366*7c478bd9Sstevel@tonic-gate }
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate static void
369*7c478bd9Sstevel@tonic-gate ugen_create_link(char *p_path, char *node_name,
370*7c478bd9Sstevel@tonic-gate     di_node_t node, di_minor_t minor)
371*7c478bd9Sstevel@tonic-gate {
372*7c478bd9Sstevel@tonic-gate 	char *buf, s[MAXPATHLEN];
373*7c478bd9Sstevel@tonic-gate 	char *lasts = s;
374*7c478bd9Sstevel@tonic-gate 	char *vid, *pid;
375*7c478bd9Sstevel@tonic-gate 	char *minor_name;
376*7c478bd9Sstevel@tonic-gate 	char ugen_RE[128];
377*7c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t ugen_rules[1];
378*7c478bd9Sstevel@tonic-gate 	char l_path[PATH_MAX];
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "ugen_create_link: p_path=%s name=%s\n",
381*7c478bd9Sstevel@tonic-gate 	    p_path, node_name);
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	(void) strlcpy(s, node_name, sizeof (s));
384*7c478bd9Sstevel@tonic-gate 
385*7c478bd9Sstevel@tonic-gate 	/* get vid, pid and minor name strings */
386*7c478bd9Sstevel@tonic-gate 	vid = strtok_r(lasts, ".", &lasts);
387*7c478bd9Sstevel@tonic-gate 	pid = strtok_r(NULL, ".", &lasts);
388*7c478bd9Sstevel@tonic-gate 	minor_name = lasts;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	if ((vid == NULL) || (pid == NULL) || (minor_name == NULL)) {
391*7c478bd9Sstevel@tonic-gate 		return;
392*7c478bd9Sstevel@tonic-gate 	}
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate 	/* create regular expression contain vid and pid */
395*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ugen_RE, sizeof (ugen_RE),
396*7c478bd9Sstevel@tonic-gate 	    "^usb$/^%s\\.%s$/^([0-9]+)$", vid, pid);
397*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid,
398*7c478bd9Sstevel@tonic-gate 	    "ugen_create_link: ugen_RE=%s minor_name=%s\n",
399*7c478bd9Sstevel@tonic-gate 	    ugen_RE, minor_name);
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 	bzero(ugen_rules, sizeof (ugen_rules));
402*7c478bd9Sstevel@tonic-gate 
403*7c478bd9Sstevel@tonic-gate 	ugen_rules[0].re = ugen_RE;
404*7c478bd9Sstevel@tonic-gate 	ugen_rules[0].subexp = 1;
405*7c478bd9Sstevel@tonic-gate 	ugen_rules[0].flags = MATCH_ADDR;
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/*
408*7c478bd9Sstevel@tonic-gate 	 *  build the physical path from the components.
409*7c478bd9Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
410*7c478bd9Sstevel@tonic-gate 	 */
411*7c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, ugen_rules, 1)) {
412*7c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "ugen_create_link: exit/continue\n");
413*7c478bd9Sstevel@tonic-gate 		return;
414*7c478bd9Sstevel@tonic-gate 	}
415*7c478bd9Sstevel@tonic-gate 
416*7c478bd9Sstevel@tonic-gate 	(void) snprintf(l_path, sizeof (l_path), "usb/%s.%s/%s/%s",
417*7c478bd9Sstevel@tonic-gate 	    vid, pid, buf, minor_name);
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 	(void) devfsadm_mklink(l_path, node, minor, 0);
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	free(buf);
424*7c478bd9Sstevel@tonic-gate }
425