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