xref: /illumos-gate/usr/src/cmd/devfsadm/usb_link.c (revision a61ed2ce)
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
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * 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  *
21ff0e937bSRaymond Chen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
227c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
237c478bd9Sstevel@tonic-gate  */
24*a61ed2ceSHans Rosenfeld /*
25*a61ed2ceSHans Rosenfeld  * Copyright 2019, Joyent, Inc.
26*a61ed2ceSHans Rosenfeld  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <devfsadm.h>
297c478bd9Sstevel@tonic-gate #include <stdio.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <limits.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate extern char *devfsadm_get_devices_dir();
397c478bd9Sstevel@tonic-gate static int usb_process(di_minor_t minor, di_node_t node);
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static void ugen_create_link(char *p_path, char *node_name,
427c478bd9Sstevel@tonic-gate     di_node_t node, di_minor_t minor);
43*a61ed2ceSHans Rosenfeld static void ccid_create_link(char *p_path, char *node_name,
44*a61ed2ceSHans Rosenfeld     di_node_t node, di_minor_t minor);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* Rules for creating links */
487c478bd9Sstevel@tonic-gate static devfsadm_create_t usb_cbt[] = {
497c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "usb_ac",	DRV_EXACT,
507c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
517c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "usb_as",	DRV_EXACT,
527c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
537c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "ddivs_usbc",	DRV_EXACT,
547c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
55c77a61a7Syz 	{ "usb", NULL, "usbvc",		DRV_EXACT,
56c77a61a7Syz 						ILEVEL_0, usb_process },
577c478bd9Sstevel@tonic-gate 	{ "usb", NULL, "hid",		DRV_EXACT,
587c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
59ff0e937bSRaymond Chen 	{ "usb", NULL, "hwarc",	DRV_EXACT,
60ff0e937bSRaymond Chen 						ILEVEL_0, usb_process },
61ff0e937bSRaymond Chen 	{ "usb", NULL, "wusb_ca",	DRV_EXACT,
62ff0e937bSRaymond Chen 						ILEVEL_0, usb_process },
637c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "hubd",	DRV_EXACT|TYPE_EXACT,
647c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
657c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ohci",	DRV_EXACT|TYPE_EXACT,
667c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
677c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "ehci",	DRV_EXACT|TYPE_EXACT,
687c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
69fcd69270SAlexander Pyhalov 	{ "usb", DDI_NT_NEXUS, "xhci",	DRV_EXACT|TYPE_EXACT,
70fcd69270SAlexander Pyhalov 						ILEVEL_0, usb_process },
717c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_SCSI_NEXUS, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
727c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
737c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "scsa2usb",	DRV_EXACT|TYPE_EXACT,
747c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
757c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "uhci",	DRV_EXACT|TYPE_EXACT,
767c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
777c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "ugen",	DRV_EXACT|TYPE_EXACT,
787c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
797c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_NEXUS, "usb_mid", DRV_EXACT|TYPE_EXACT,
807c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
817c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usb_mid", DRV_EXACT|TYPE_EXACT,
827c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
837c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_PRINTER, "usbprn", DRV_EXACT|TYPE_EXACT,
847c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
857c478bd9Sstevel@tonic-gate 	{ "usb", DDI_NT_UGEN, "usbprn", DRV_EXACT|TYPE_EXACT,
867c478bd9Sstevel@tonic-gate 						ILEVEL_0, usb_process },
87ff0e937bSRaymond Chen 	{ "usb", DDI_NT_NEXUS, "hwahc", DRV_EXACT|TYPE_EXACT,
88ff0e937bSRaymond Chen 						ILEVEL_0, usb_process },
89*a61ed2ceSHans Rosenfeld 	{ "usb", DDI_NT_CCID_ATTACHMENT_POINT, "ccid", DRV_EXACT|TYPE_EXACT,
90*a61ed2ceSHans Rosenfeld 						ILEVEL_0, usb_process },
917c478bd9Sstevel@tonic-gate };
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /* For debug printing (-V filter) */
947c478bd9Sstevel@tonic-gate static char *debug_mid = "usb_mid";
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(usb_cbt);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* USB device links */
997c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIO	"^usb/audio[0-9]+$"
1007c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOMUX	"^usb/audio-mux[0-9]+$"
1017c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOCTL	"^usb/audio-control[0-9]+$"
1027c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_AUDIOSTREAM	"^usb/audio-stream[0-9]+$"
1037c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_DDIVS_USBC	"^usb/ddivs_usbc[0-9]+$"
104c77a61a7Syz #define	USB_LINK_RE_VIDEO	"^usb/video[0-9]+$"
105c77a61a7Syz #define	USB_LINK_RE_VIDEO2	"^video[0-9]+$"
1067c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_DEVICE	"^usb/device[0-9]+$"
1077c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_HID		"^usb/hid[0-9]+$"
1087c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_HUB		"^usb/hub[0-9]+$"
1097c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_MASS_STORE	"^usb/mass-storage[0-9]+$"
1107c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_UGEN	"^usb/[0-9,a-f]+\\.[0-9,a-f]+/[0-9]+/.+$"
1117c478bd9Sstevel@tonic-gate #define	USB_LINK_RE_USBPRN	"^usb/printer[0-9]+$"
112ff0e937bSRaymond Chen #define	USB_LINK_RE_WHOST	"^usb/whost[0-9]+$"
113ff0e937bSRaymond Chen #define	USB_LINK_RE_HWARC	"^usb/hwarc[0-9]+$"
114ff0e937bSRaymond Chen #define	USB_LINK_RE_WUSB_CA	"^usb/wusb_ca[0-9]+$"
115*a61ed2ceSHans Rosenfeld #define	USB_LINK_RE_CCID	"^ccid/ccid[0-9]+/slot[0-9]+$"
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate /* Rules for removing links */
1187c478bd9Sstevel@tonic-gate static devfsadm_remove_t usb_remove_cbt[] = {
1197c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIO, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1207c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1217c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOMUX, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1227c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1237c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOCTL, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1247c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1257c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_AUDIOSTREAM, RM_POST | RM_HOT | RM_ALWAYS,
1267c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
1277c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DDIVS_USBC, RM_POST | RM_HOT | RM_ALWAYS,
1287c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
129c77a61a7Syz 	{ "usb", USB_LINK_RE_VIDEO2, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
130c77a61a7Syz 			devfsadm_rm_all },
1313fb52c73SRaymond Chen 	{ "usb", USB_LINK_RE_VIDEO, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1323fb52c73SRaymond Chen 			devfsadm_rm_all },
1337c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_DEVICE, RM_POST | RM_HOT, ILEVEL_0,
1347c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1357c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HID, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1367c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1377c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_HUB, RM_POST | RM_HOT, ILEVEL_0, devfsadm_rm_all },
1387c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_MASS_STORE, RM_POST | RM_HOT | RM_ALWAYS,
1397c478bd9Sstevel@tonic-gate 			ILEVEL_0, devfsadm_rm_all },
1407c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_UGEN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1417c478bd9Sstevel@tonic-gate 			devfsadm_rm_all },
1427c478bd9Sstevel@tonic-gate 	{ "usb", USB_LINK_RE_USBPRN, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
1437c478bd9Sstevel@tonic-gate 			devfsadm_rm_link },
144ff0e937bSRaymond Chen 	{ "usb", USB_LINK_RE_WHOST, RM_POST | RM_HOT, ILEVEL_0,
145ff0e937bSRaymond Chen 			devfsadm_rm_all },
146ff0e937bSRaymond Chen 	{ "usb", USB_LINK_RE_HWARC, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
147ff0e937bSRaymond Chen 			devfsadm_rm_all },
148ff0e937bSRaymond Chen 	{ "usb", USB_LINK_RE_WUSB_CA, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
149*a61ed2ceSHans Rosenfeld 			devfsadm_rm_all },
150*a61ed2ceSHans Rosenfeld 	{ "usb", USB_LINK_RE_CCID, RM_POST | RM_HOT | RM_ALWAYS, ILEVEL_0,
151*a61ed2ceSHans Rosenfeld 		devfsadm_rm_all }
1527c478bd9Sstevel@tonic-gate };
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate /*
1557c478bd9Sstevel@tonic-gate  * Rules for different USB devices except ugen which is dynamically
1567c478bd9Sstevel@tonic-gate  * created
1577c478bd9Sstevel@tonic-gate  */
1587c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_rules[1] =
1597c478bd9Sstevel@tonic-gate 	{"^usb$/^audio([0-9]+)$", 1, MATCH_ALL};
1607c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_mux_rules[1] =
1617c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-mux([0-9]+)$", 1, MATCH_ALL};
1627c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_control_rules[1] =
1637c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-control([0-9]+)$", 1, MATCH_ALL};
1647c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t audio_stream_rules[1] =
1657c478bd9Sstevel@tonic-gate 	{"^usb$/^audio-stream([0-9]+)$", 1, MATCH_ALL};
1667c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t ddivs_usbc_rules[1] =
1677c478bd9Sstevel@tonic-gate 	{"^usb$/^ddivs_usbc([0-9]+)$", 1, MATCH_ALL};
168c77a61a7Syz static devfsadm_enumerate_t video_rules[1] =
169c77a61a7Syz 	{"^usb$/^video([0-9]+)$", 1, MATCH_ALL};
1707c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t device_rules[1] =
1717c478bd9Sstevel@tonic-gate 	{"^usb$/^device([0-9]+)$", 1, MATCH_ALL};
1727c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t hid_rules[1] =
1737c478bd9Sstevel@tonic-gate 	{"^usb$/^hid([0-9]+)$", 1, MATCH_ALL};
1747c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t hub_rules[1] =
1757c478bd9Sstevel@tonic-gate 	{"^usb$/^hub([0-9]+)$", 1, MATCH_ALL};
1767c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t mass_storage_rules[1] =
1777c478bd9Sstevel@tonic-gate 	{"^usb$/^mass-storage([0-9]+)$", 1, MATCH_ALL};
1787c478bd9Sstevel@tonic-gate static devfsadm_enumerate_t usbprn_rules[1] =
1797c478bd9Sstevel@tonic-gate 	{"^usb$/^printer([0-9]+)$", 1, MATCH_ALL};
180ff0e937bSRaymond Chen static devfsadm_enumerate_t whost_rules[1] =
181ff0e937bSRaymond Chen 	{"^usb$/^whost([0-9]+)$", 1, MATCH_ALL};
182ff0e937bSRaymond Chen static devfsadm_enumerate_t hwarc_rules[1] =
183ff0e937bSRaymond Chen 	{"^usb$/^hwarc([0-9]+)$", 1, MATCH_ALL};
184ff0e937bSRaymond Chen static devfsadm_enumerate_t wusb_ca_rules[1] =
185ff0e937bSRaymond Chen 	{"^usb$/^wusb_ca([0-9]+)$", 1, MATCH_ALL};
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(usb_remove_cbt);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate int
minor_init(void)1907c478bd9Sstevel@tonic-gate minor_init(void)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_init\n");
1937c478bd9Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate int
minor_fini(void)1977c478bd9Sstevel@tonic-gate minor_fini(void)
1987c478bd9Sstevel@tonic-gate {
1997c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_link: minor_fini\n");
2007c478bd9Sstevel@tonic-gate 	return (DEVFSADM_SUCCESS);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate typedef enum {
204fcd69270SAlexander Pyhalov 	DRIVER_HUBD,
205fcd69270SAlexander Pyhalov 	DRIVER_OHCI,
206fcd69270SAlexander Pyhalov 	DRIVER_EHCI,
207fcd69270SAlexander Pyhalov 	DRIVER_UHCI,
208fcd69270SAlexander Pyhalov 	DRIVER_XHCI,
209fcd69270SAlexander Pyhalov 	DRIVER_USB_AC,
210fcd69270SAlexander Pyhalov 	DRIVER_USB_AS,
211fcd69270SAlexander Pyhalov 	DRIVER_HID,
212fcd69270SAlexander Pyhalov 	DRIVER_USB_MID,
213fcd69270SAlexander Pyhalov 	DRIVER_DDIVS_USBC,
214fcd69270SAlexander Pyhalov 	DRIVER_SCSA2USB,
215fcd69270SAlexander Pyhalov 	DRIVER_USBPRN,
216fcd69270SAlexander Pyhalov 	DRIVER_UGEN,
217fcd69270SAlexander Pyhalov 	DRIVER_VIDEO,
218fcd69270SAlexander Pyhalov 	DRIVER_HWAHC,
219fcd69270SAlexander Pyhalov 	DRIVER_HWARC,
220fcd69270SAlexander Pyhalov 	DRIVER_WUSB_CA,
221fcd69270SAlexander Pyhalov 	DRIVER_UNKNOWN
2227c478bd9Sstevel@tonic-gate } driver_defs_t;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate typedef struct {
2257c478bd9Sstevel@tonic-gate 	char	*driver_name;
226fcd69270SAlexander Pyhalov 	driver_defs_t	index;
2277c478bd9Sstevel@tonic-gate } driver_name_table_entry_t;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate driver_name_table_entry_t driver_name_table[] = {
2307c478bd9Sstevel@tonic-gate 	{ "hubd",	DRIVER_HUBD },
2317c478bd9Sstevel@tonic-gate 	{ "ohci",	DRIVER_OHCI },
2327c478bd9Sstevel@tonic-gate 	{ "ehci",	DRIVER_EHCI },
2337c478bd9Sstevel@tonic-gate 	{ "uhci",	DRIVER_UHCI },
234fcd69270SAlexander Pyhalov 	{ "xhci",	DRIVER_XHCI },
2357c478bd9Sstevel@tonic-gate 	{ "usb_ac",	DRIVER_USB_AC },
2367c478bd9Sstevel@tonic-gate 	{ "usb_as",	DRIVER_USB_AS },
2377c478bd9Sstevel@tonic-gate 	{ "hid",	DRIVER_HID },
2387c478bd9Sstevel@tonic-gate 	{ "usb_mid",	DRIVER_USB_MID },
2397c478bd9Sstevel@tonic-gate 	{ "ddivs_usbc",	DRIVER_DDIVS_USBC },
2407c478bd9Sstevel@tonic-gate 	{ "scsa2usb",	DRIVER_SCSA2USB },
2417c478bd9Sstevel@tonic-gate 	{ "usbprn",	DRIVER_USBPRN },
2427c478bd9Sstevel@tonic-gate 	{ "ugen",	DRIVER_UGEN },
243c77a61a7Syz 	{ "usbvc",	DRIVER_VIDEO },
244ff0e937bSRaymond Chen 	{ "hwahc",	DRIVER_HWAHC },
245ff0e937bSRaymond Chen 	{ "hwarc",	DRIVER_HWARC },
246ff0e937bSRaymond Chen 	{ "wusb_ca",	DRIVER_WUSB_CA },
2477c478bd9Sstevel@tonic-gate 	{ NULL,		DRIVER_UNKNOWN }
2487c478bd9Sstevel@tonic-gate };
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate /*
2517c478bd9Sstevel@tonic-gate  * This function is called for every usb minor node.
2527c478bd9Sstevel@tonic-gate  * Calls enumerate to assign a logical usb id, and then
2537c478bd9Sstevel@tonic-gate  * devfsadm_mklink to make the link.
2547c478bd9Sstevel@tonic-gate  */
2557c478bd9Sstevel@tonic-gate static int
usb_process(di_minor_t minor,di_node_t node)2567c478bd9Sstevel@tonic-gate usb_process(di_minor_t minor, di_node_t node)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t rules[1];
2597c478bd9Sstevel@tonic-gate 	char *l_path, *p_path, *buf, *devfspath;
2607c478bd9Sstevel@tonic-gate 	char *minor_nm, *drvr_nm, *name = (char *)NULL;
261fcd69270SAlexander Pyhalov 	int i;
262fcd69270SAlexander Pyhalov 	driver_defs_t index;
26345916cd2Sjpk 	int flags = 0;
2647c478bd9Sstevel@tonic-gate 	int create_secondary_link = 0;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	minor_nm = di_minor_name(minor);
2677c478bd9Sstevel@tonic-gate 	drvr_nm = di_driver_name(node);
2687c478bd9Sstevel@tonic-gate 	if ((minor_nm == NULL) || (drvr_nm == NULL)) {
2697c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: minor=%s node=%s type=%s\n",
273ff0e937bSRaymond Chen 	    minor_nm, di_node_name(node), di_minor_nodetype(minor));
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
2767c478bd9Sstevel@tonic-gate 	if (devfspath == NULL) {
2777c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid,
2787c478bd9Sstevel@tonic-gate 		    "USB_process: devfspath is	NULL\n");
2797c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	l_path = (char *)malloc(PATH_MAX);
2837c478bd9Sstevel@tonic-gate 	if (l_path == NULL) {
2847c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2857c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
2867c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	p_path = (char *)malloc(PATH_MAX);
2907c478bd9Sstevel@tonic-gate 	if (p_path == NULL) {
2917c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: malloc() failed\n");
2927c478bd9Sstevel@tonic-gate 		di_devfs_path_free(devfspath);
2937c478bd9Sstevel@tonic-gate 		free(l_path);
2947c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	(void) strcpy(p_path, devfspath);
2987c478bd9Sstevel@tonic-gate 	(void) strcat(p_path, ":");
2997c478bd9Sstevel@tonic-gate 	(void) strcat(p_path, minor_nm);
3007c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: path %s\n", p_path);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	for (i = 0; ; i++) {
3057c478bd9Sstevel@tonic-gate 		if ((driver_name_table[i].driver_name == NULL) ||
3067c478bd9Sstevel@tonic-gate 		    (strcmp(drvr_nm, driver_name_table[i].driver_name) == 0)) {
3077c478bd9Sstevel@tonic-gate 			index = driver_name_table[i].index;
3087c478bd9Sstevel@tonic-gate 			break;
3097c478bd9Sstevel@tonic-gate 		}
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (strcmp(di_minor_nodetype(minor), DDI_NT_UGEN) == 0) {
3137c478bd9Sstevel@tonic-gate 		ugen_create_link(p_path, minor_nm, node, minor);
3147c478bd9Sstevel@tonic-gate 		free(l_path);
3157c478bd9Sstevel@tonic-gate 		free(p_path);
3167c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
319*a61ed2ceSHans Rosenfeld 	if (strcmp(di_minor_nodetype(minor), DDI_NT_CCID_ATTACHMENT_POINT) ==
320*a61ed2ceSHans Rosenfeld 	    0) {
321*a61ed2ceSHans Rosenfeld 		ccid_create_link(p_path, minor_nm, node, minor);
322*a61ed2ceSHans Rosenfeld 		free(l_path);
323*a61ed2ceSHans Rosenfeld 		free(p_path);
324*a61ed2ceSHans Rosenfeld 		return (DEVFSADM_CONTINUE);
325*a61ed2ceSHans Rosenfeld 	}
326*a61ed2ceSHans Rosenfeld 
3277c478bd9Sstevel@tonic-gate 	/* Figure out which rules to apply */
3287c478bd9Sstevel@tonic-gate 	switch (index) {
3297c478bd9Sstevel@tonic-gate 	case DRIVER_HUBD:
3307c478bd9Sstevel@tonic-gate 	case DRIVER_OHCI:
3317c478bd9Sstevel@tonic-gate 	case DRIVER_EHCI:
3327c478bd9Sstevel@tonic-gate 	case DRIVER_UHCI:
333fcd69270SAlexander Pyhalov 	case DRIVER_XHCI:
3347c478bd9Sstevel@tonic-gate 		rules[0] = hub_rules[0];	/* For HUBs */
3357c478bd9Sstevel@tonic-gate 		name = "hub";
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 		break;
3387c478bd9Sstevel@tonic-gate 	case DRIVER_USB_AC:
3397c478bd9Sstevel@tonic-gate 		if (strcmp(minor_nm, "sound,audio") == 0) {
3407c478bd9Sstevel@tonic-gate 			rules[0] = audio_rules[0];
3417c478bd9Sstevel@tonic-gate 			name = "audio";		/* For audio */
3427c478bd9Sstevel@tonic-gate 			create_secondary_link = 1;
3437c478bd9Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "sound,audioctl") == 0) {
3447c478bd9Sstevel@tonic-gate 			rules[0] = audio_control_rules[0];
3457c478bd9Sstevel@tonic-gate 			name = "audio-control";		/* For audio */
3467c478bd9Sstevel@tonic-gate 			create_secondary_link = 1;
3477c478bd9Sstevel@tonic-gate 		} else if (strcmp(minor_nm, "mux") == 0) {
3487c478bd9Sstevel@tonic-gate 			rules[0] = audio_mux_rules[0];
3497c478bd9Sstevel@tonic-gate 			name = "audio-mux";		/* For audio */
3507c478bd9Sstevel@tonic-gate 		} else {
3517c478bd9Sstevel@tonic-gate 			free(l_path);
3527c478bd9Sstevel@tonic-gate 			free(p_path);
3537c478bd9Sstevel@tonic-gate 			return (DEVFSADM_CONTINUE);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 		break;
3567c478bd9Sstevel@tonic-gate 	case DRIVER_USB_AS:
3577c478bd9Sstevel@tonic-gate 		rules[0] = audio_stream_rules[0];
3587c478bd9Sstevel@tonic-gate 		name = "audio-stream";		/* For audio */
3597c478bd9Sstevel@tonic-gate 		break;
360c77a61a7Syz 	case DRIVER_VIDEO:
361c77a61a7Syz 		rules[0] = video_rules[0];
362c77a61a7Syz 		name = "video";			/* For video */
363c77a61a7Syz 		create_secondary_link = 1;
364c77a61a7Syz 		break;
3657c478bd9Sstevel@tonic-gate 	case DRIVER_HID:
3667c478bd9Sstevel@tonic-gate 		rules[0] = hid_rules[0];
3677c478bd9Sstevel@tonic-gate 		name = "hid";			/* For HIDs */
3687c478bd9Sstevel@tonic-gate 		break;
3697c478bd9Sstevel@tonic-gate 	case DRIVER_USB_MID:
3707c478bd9Sstevel@tonic-gate 		rules[0] = device_rules[0];
3717c478bd9Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
3727c478bd9Sstevel@tonic-gate 		break;
3737c478bd9Sstevel@tonic-gate 	case DRIVER_DDIVS_USBC:
3747c478bd9Sstevel@tonic-gate 		rules[0] = ddivs_usbc_rules[0];
3757c478bd9Sstevel@tonic-gate 		name = "device";		/* For other USB devices */
3767c478bd9Sstevel@tonic-gate 		break;
3777c478bd9Sstevel@tonic-gate 	case DRIVER_SCSA2USB:
3787c478bd9Sstevel@tonic-gate 		rules[0] = mass_storage_rules[0];
3797c478bd9Sstevel@tonic-gate 		name = "mass-storage";		/* For mass-storage devices */
3807c478bd9Sstevel@tonic-gate 		break;
3817c478bd9Sstevel@tonic-gate 	case DRIVER_USBPRN:
3827c478bd9Sstevel@tonic-gate 		rules[0] = usbprn_rules[0];
3837c478bd9Sstevel@tonic-gate 		name = "printer";
3847c478bd9Sstevel@tonic-gate 		break;
385ff0e937bSRaymond Chen 	case DRIVER_HWAHC:
386ff0e937bSRaymond Chen 		if (strcmp(minor_nm, "hwahc") == 0) {
387ff0e937bSRaymond Chen 			rules[0] = whost_rules[0];
388ff0e937bSRaymond Chen 			name = "whost";		/* For HWA HC */
389ff0e937bSRaymond Chen 		} else if (strcmp(minor_nm, "hubd") == 0) {
390ff0e937bSRaymond Chen 			rules[0] = hub_rules[0];
391ff0e937bSRaymond Chen 			name = "hub";		/* For HWA HC */
392ff0e937bSRaymond Chen 		} else {
393ff0e937bSRaymond Chen 			free(l_path);
394ff0e937bSRaymond Chen 			free(p_path);
395ff0e937bSRaymond Chen 			return (DEVFSADM_CONTINUE);
396ff0e937bSRaymond Chen 		}
397ff0e937bSRaymond Chen 		break;
398ff0e937bSRaymond Chen 	case DRIVER_HWARC:
399ff0e937bSRaymond Chen 		rules[0] = hwarc_rules[0];
400ff0e937bSRaymond Chen 		name = "hwarc";		/* For UWB HWA Radio Controllers */
401ff0e937bSRaymond Chen 		break;
402ff0e937bSRaymond Chen 	case DRIVER_WUSB_CA:
403ff0e937bSRaymond Chen 		rules[0] = wusb_ca_rules[0];
404ff0e937bSRaymond Chen 		name = "wusb_ca";	/* for wusb cable association */
405ff0e937bSRaymond Chen 		break;
4067c478bd9Sstevel@tonic-gate 	default:
4077c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: unknown driver=%s\n",
4087c478bd9Sstevel@tonic-gate 		    drvr_nm);
4097c478bd9Sstevel@tonic-gate 		free(l_path);
4107c478bd9Sstevel@tonic-gate 		free(p_path);
4117c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
4127c478bd9Sstevel@tonic-gate 	}
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/*
4157c478bd9Sstevel@tonic-gate 	 *  build the physical path from the components.
4167c478bd9Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
4177c478bd9Sstevel@tonic-gate 	 */
4187c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) {
4197c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "usb_process: exit/continue\n");
4207c478bd9Sstevel@tonic-gate 		free(l_path);
4217c478bd9Sstevel@tonic-gate 		free(p_path);
4227c478bd9Sstevel@tonic-gate 		return (DEVFSADM_CONTINUE);
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	(void) snprintf(l_path, PATH_MAX, "usb/%s%s", name, buf);
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "usb_process: p_path=%s buf=%s\n",
4287c478bd9Sstevel@tonic-gate 	    p_path, buf);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	free(buf);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
4337c478bd9Sstevel@tonic-gate 
43445916cd2Sjpk 	(void) devfsadm_mklink(l_path, node, minor, flags);
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	if (create_secondary_link) {
4377c478bd9Sstevel@tonic-gate 		/*
4387c478bd9Sstevel@tonic-gate 		 * Create secondary links to make newly hotplugged
4397c478bd9Sstevel@tonic-gate 		 * usb audio device the primary device.
4407c478bd9Sstevel@tonic-gate 		 */
4417c478bd9Sstevel@tonic-gate 		if (strcmp(name, "audio") == 0) {
4427c478bd9Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audio", l_path, 0);
4437c478bd9Sstevel@tonic-gate 		} else if (strcmp(name, "audio-control") == 0) {
4447c478bd9Sstevel@tonic-gate 			(void) devfsadm_secondary_link("audioctl", l_path, 0);
445c77a61a7Syz 		} else if (strcmp(name, "video") == 0) {
446c77a61a7Syz 			(void) devfsadm_secondary_link(l_path + 4, l_path, 0);
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	free(p_path);
4517c478bd9Sstevel@tonic-gate 	free(l_path);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	return (DEVFSADM_CONTINUE);
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate static void
ugen_create_link(char * p_path,char * node_name,di_node_t node,di_minor_t minor)4577c478bd9Sstevel@tonic-gate ugen_create_link(char *p_path, char *node_name,
4587c478bd9Sstevel@tonic-gate     di_node_t node, di_minor_t minor)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate 	char *buf, s[MAXPATHLEN];
4617c478bd9Sstevel@tonic-gate 	char *lasts = s;
4627c478bd9Sstevel@tonic-gate 	char *vid, *pid;
4637c478bd9Sstevel@tonic-gate 	char *minor_name;
4647c478bd9Sstevel@tonic-gate 	char ugen_RE[128];
4657c478bd9Sstevel@tonic-gate 	devfsadm_enumerate_t ugen_rules[1];
4667c478bd9Sstevel@tonic-gate 	char l_path[PATH_MAX];
46745916cd2Sjpk 	int flags = 0;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "ugen_create_link: p_path=%s name=%s\n",
4707c478bd9Sstevel@tonic-gate 	    p_path, node_name);
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	(void) strlcpy(s, node_name, sizeof (s));
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	/* get vid, pid and minor name strings */
4757c478bd9Sstevel@tonic-gate 	vid = strtok_r(lasts, ".", &lasts);
4767c478bd9Sstevel@tonic-gate 	pid = strtok_r(NULL, ".", &lasts);
4777c478bd9Sstevel@tonic-gate 	minor_name = lasts;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if ((vid == NULL) || (pid == NULL) || (minor_name == NULL)) {
4807c478bd9Sstevel@tonic-gate 		return;
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	/* create regular expression contain vid and pid */
4847c478bd9Sstevel@tonic-gate 	(void) snprintf(ugen_RE, sizeof (ugen_RE),
4857c478bd9Sstevel@tonic-gate 	    "^usb$/^%s\\.%s$/^([0-9]+)$", vid, pid);
4867c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid,
4877c478bd9Sstevel@tonic-gate 	    "ugen_create_link: ugen_RE=%s minor_name=%s\n",
4887c478bd9Sstevel@tonic-gate 	    ugen_RE, minor_name);
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	bzero(ugen_rules, sizeof (ugen_rules));
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	ugen_rules[0].re = ugen_RE;
4937c478bd9Sstevel@tonic-gate 	ugen_rules[0].subexp = 1;
4947c478bd9Sstevel@tonic-gate 	ugen_rules[0].flags = MATCH_ADDR;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/*
4977c478bd9Sstevel@tonic-gate 	 *  build the physical path from the components.
4987c478bd9Sstevel@tonic-gate 	 *  find the logical usb id, and stuff it in buf
4997c478bd9Sstevel@tonic-gate 	 */
5007c478bd9Sstevel@tonic-gate 	if (devfsadm_enumerate_int(p_path, 0, &buf, ugen_rules, 1)) {
5017c478bd9Sstevel@tonic-gate 		devfsadm_print(debug_mid, "ugen_create_link: exit/continue\n");
5027c478bd9Sstevel@tonic-gate 		return;
5037c478bd9Sstevel@tonic-gate 	}
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	(void) snprintf(l_path, sizeof (l_path), "usb/%s.%s/%s/%s",
5067c478bd9Sstevel@tonic-gate 	    vid, pid, buf, minor_name);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
5097c478bd9Sstevel@tonic-gate 
51045916cd2Sjpk 	(void) devfsadm_mklink(l_path, node, minor, flags);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	free(buf);
5137c478bd9Sstevel@tonic-gate }
514*a61ed2ceSHans Rosenfeld 
515*a61ed2ceSHans Rosenfeld /*
516*a61ed2ceSHans Rosenfeld  * Create a CCID related link.
517*a61ed2ceSHans Rosenfeld  */
518*a61ed2ceSHans Rosenfeld static void
ccid_create_link(char * p_path,char * minor_nm,di_node_t node,di_minor_t minor)519*a61ed2ceSHans Rosenfeld ccid_create_link(char *p_path, char *minor_nm, di_node_t node, di_minor_t minor)
520*a61ed2ceSHans Rosenfeld {
521*a61ed2ceSHans Rosenfeld 	char l_path[MAXPATHLEN];
522*a61ed2ceSHans Rosenfeld 
523*a61ed2ceSHans Rosenfeld 	(void) snprintf(l_path, sizeof (l_path), "ccid/ccid%d/%s",
524*a61ed2ceSHans Rosenfeld 	    di_instance(node), minor_nm);
525*a61ed2ceSHans Rosenfeld 
526*a61ed2ceSHans Rosenfeld 	devfsadm_print(debug_mid, "mklink %s -> %s\n", l_path, p_path);
527*a61ed2ceSHans Rosenfeld 
528*a61ed2ceSHans Rosenfeld 	(void) devfsadm_mklink(l_path, node, minor, 0);
529*a61ed2ceSHans Rosenfeld }
530