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 */ 217c478bd9Sstevel@tonic-gate /* 22*88447a05SGarrett D'Amore * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <regex.h> 277c478bd9Sstevel@tonic-gate #include <devfsadm.h> 287c478bd9Sstevel@tonic-gate #include <strings.h> 29*88447a05SGarrett D'Amore #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <limits.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 33*88447a05SGarrett D'Amore #include <syslog.h> 3445916cd2Sjpk #include <bsm/devalloc.h> 35*88447a05SGarrett D'Amore #include <sys/audio.h> 36*88447a05SGarrett D'Amore #include <sys/soundcard.h> 37*88447a05SGarrett D'Amore #include <unistd.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #define MAX_AUDIO_LINK 100 407c478bd9Sstevel@tonic-gate #define RE_SIZE 64 417c478bd9Sstevel@tonic-gate 4245916cd2Sjpk extern int system_labeled; 4345916cd2Sjpk 447c478bd9Sstevel@tonic-gate static void check_audio_link(char *secondary_link, 457c478bd9Sstevel@tonic-gate const char *primary_link_format); 46*88447a05SGarrett D'Amore 477c478bd9Sstevel@tonic-gate static int audio_process(di_minor_t minor, di_node_t node); 48*88447a05SGarrett D'Amore static int sndstat_process(di_minor_t minor, di_node_t node); 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate static devfsadm_create_t audio_cbt[] = { 517c478bd9Sstevel@tonic-gate { "audio", "ddi_audio", NULL, 527c478bd9Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, audio_process 53*88447a05SGarrett D'Amore }, 54*88447a05SGarrett D'Amore { "pseudo", "ddi_pseudo", "audio", 55*88447a05SGarrett D'Amore TYPE_EXACT|DRV_EXACT, ILEVEL_0, sndstat_process 56*88447a05SGarrett D'Amore }, 577c478bd9Sstevel@tonic-gate }; 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(audio_cbt); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 627c478bd9Sstevel@tonic-gate * the following can't be one big RE with a bunch of alterations "|" 637c478bd9Sstevel@tonic-gate * because recurse_dev_re() would not work. 647c478bd9Sstevel@tonic-gate */ 657c478bd9Sstevel@tonic-gate static devfsadm_remove_t audio_remove_cbt[] = { 66*88447a05SGarrett D'Amore /* 67*88447a05SGarrett D'Amore * Secondary links. 68*88447a05SGarrett D'Amore */ 69*88447a05SGarrett D'Amore 70*88447a05SGarrett D'Amore /* /dev/audio, /dev/audioctl, /dev/dsp */ 71*88447a05SGarrett D'Amore { "audio", "^(audio|audioctl|dsp)$", 727c478bd9Sstevel@tonic-gate RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 737c478bd9Sstevel@tonic-gate }, 74*88447a05SGarrett D'Amore /* /dev/mixer0, /dev/dsp0 */ 75*88447a05SGarrett D'Amore { "audio", "^(mixer|dsp)[0-9]+$", 76*88447a05SGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 77*88447a05SGarrett D'Amore }, 78*88447a05SGarrett D'Amore /* /dev/sound/0, 0ctl */ 79*88447a05SGarrett D'Amore { "audio", "^sound/[0-9]+(ctl)?$", 80*88447a05SGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 81*88447a05SGarrett D'Amore }, 82*88447a05SGarrett D'Amore /* /dev/mixer */ 83*88447a05SGarrett D'Amore { "pseudo", "^(mixer)$", 84*88447a05SGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 85*88447a05SGarrett D'Amore }, 86*88447a05SGarrett D'Amore 87*88447a05SGarrett D'Amore /* 88*88447a05SGarrett D'Amore * Primary links. 89*88447a05SGarrett D'Amore */ 90*88447a05SGarrett D'Amore 91*88447a05SGarrett D'Amore /* /dev/sndstat */ 92*88447a05SGarrett D'Amore { "pseudo", "^sndstat$", 937c478bd9Sstevel@tonic-gate RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 947c478bd9Sstevel@tonic-gate }, 95*88447a05SGarrett D'Amore /* /dev/sound/audio810:0, 0ctl, etc */ 96*88447a05SGarrett D'Amore { "audio", "^sound/.*:[0-9]+(ctl|dsp|mixer)?$", 97*88447a05SGarrett D'Amore RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 987c478bd9Sstevel@tonic-gate }, 997c478bd9Sstevel@tonic-gate }; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt); 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate int 1047c478bd9Sstevel@tonic-gate minor_fini(void) 1057c478bd9Sstevel@tonic-gate { 1067c478bd9Sstevel@tonic-gate check_audio_link("audio", "sound/%d"); 1077c478bd9Sstevel@tonic-gate check_audio_link("audioctl", "sound/%dctl"); 108*88447a05SGarrett D'Amore check_audio_link("dsp", "dsp%d"); 1097c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #define COPYSUB(to, from, pm, pos) (void) strncpy(to, &from[pm[pos].rm_so], \ 1147c478bd9Sstevel@tonic-gate pm[pos].rm_eo - pm[pos].rm_so); \ 1157c478bd9Sstevel@tonic-gate to[pm[pos].rm_eo - pm[pos].rm_so] = 0; 1167c478bd9Sstevel@tonic-gate 117*88447a05SGarrett D'Amore static void 118*88447a05SGarrett D'Amore send_number(long num) 119*88447a05SGarrett D'Amore { 120*88447a05SGarrett D'Amore char buf[PATH_MAX+1]; 121*88447a05SGarrett D'Amore 122*88447a05SGarrett D'Amore /* 123*88447a05SGarrett D'Amore * This is not safe with -r. 124*88447a05SGarrett D'Amore */ 125*88447a05SGarrett D'Amore if (strcmp(devfsadm_root_path(), "/") != 0) 126*88447a05SGarrett D'Amore return; 127*88447a05SGarrett D'Amore 128*88447a05SGarrett D'Amore (void) snprintf(buf, sizeof (buf), "/dev/mixer%ld", num); 129*88447a05SGarrett D'Amore if (device_exists(buf)) { 130*88447a05SGarrett D'Amore int fd; 131*88447a05SGarrett D'Amore 132*88447a05SGarrett D'Amore if ((fd = open(buf, O_RDWR)) < 0) 133*88447a05SGarrett D'Amore return; 134*88447a05SGarrett D'Amore 135*88447a05SGarrett D'Amore (void) ioctl(fd, SNDCTL_SUN_SEND_NUMBER, &num); 136*88447a05SGarrett D'Amore (void) close(fd); 137*88447a05SGarrett D'Amore devfsadm_print(CHATTY_MID, 138*88447a05SGarrett D'Amore "sent devnum audio %ld to %s\n", num, buf); 139*88447a05SGarrett D'Amore } 140*88447a05SGarrett D'Amore } 141*88447a05SGarrett D'Amore 142*88447a05SGarrett D'Amore static void 143*88447a05SGarrett D'Amore send_all(void) 144*88447a05SGarrett D'Amore { 145*88447a05SGarrett D'Amore /* 146*88447a05SGarrett D'Amore * This module traverses /dev/sound to look for nodes that 147*88447a05SGarrett D'Amore * have been previously created. 148*88447a05SGarrett D'Amore */ 149*88447a05SGarrett D'Amore finddevhdl_t fh; 150*88447a05SGarrett D'Amore const char *path; 151*88447a05SGarrett D'Amore 152*88447a05SGarrett D'Amore /* 153*88447a05SGarrett D'Amore * This is not safe with -r. 154*88447a05SGarrett D'Amore */ 155*88447a05SGarrett D'Amore if ((strcmp(devfsadm_root_path(), "/") == 0) && 156*88447a05SGarrett D'Amore (finddev_readdir("/dev", &fh) == 0)) { 157*88447a05SGarrett D'Amore static int doneit = 0; 158*88447a05SGarrett D'Amore 159*88447a05SGarrett D'Amore while ((!doneit) && ((path = finddev_next(fh)) != NULL)) { 160*88447a05SGarrett D'Amore long num; 161*88447a05SGarrett D'Amore char *ep; 162*88447a05SGarrett D'Amore if ((strncmp(path, "mixer", 5) != 0) || 163*88447a05SGarrett D'Amore (!isdigit(path[5]))) { 164*88447a05SGarrett D'Amore continue; 165*88447a05SGarrett D'Amore } 166*88447a05SGarrett D'Amore num = strtol(path + 5, &ep, 10); 167*88447a05SGarrett D'Amore send_number(num); 168*88447a05SGarrett D'Amore } 169*88447a05SGarrett D'Amore finddev_close(fh); 170*88447a05SGarrett D'Amore doneit = 1; 171*88447a05SGarrett D'Amore } 172*88447a05SGarrett D'Amore } 173*88447a05SGarrett D'Amore 174*88447a05SGarrett D'Amore static int 175*88447a05SGarrett D'Amore sndstat_process(di_minor_t minor, di_node_t node) 176*88447a05SGarrett D'Amore { 177*88447a05SGarrett D'Amore char *mn; 178*88447a05SGarrett D'Amore 179*88447a05SGarrett D'Amore mn = di_minor_name(minor); 180*88447a05SGarrett D'Amore 181*88447a05SGarrett D'Amore /* 182*88447a05SGarrett D'Amore * "Special" handling for /dev/sndstat and /dev/mixer. 183*88447a05SGarrett D'Amore */ 184*88447a05SGarrett D'Amore if (strcmp(mn, "sound,sndstat0") == 0) { 185*88447a05SGarrett D'Amore (void) devfsadm_mklink("sndstat", node, minor, 0); 186*88447a05SGarrett D'Amore (void) devfsadm_secondary_link("mixer", "sndstat", 0); 187*88447a05SGarrett D'Amore send_all(); 188*88447a05SGarrett D'Amore } 189*88447a05SGarrett D'Amore 190*88447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 191*88447a05SGarrett D'Amore } 192*88447a05SGarrett D'Amore 1937c478bd9Sstevel@tonic-gate /* 1947c478bd9Sstevel@tonic-gate * This function is called for every audio node. 1957c478bd9Sstevel@tonic-gate * Calls enumerate to assign a logical unit id, and then 1967c478bd9Sstevel@tonic-gate * devfsadm_mklink to make the link. 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate static int 1997c478bd9Sstevel@tonic-gate audio_process(di_minor_t minor, di_node_t node) 2007c478bd9Sstevel@tonic-gate { 20145916cd2Sjpk int flags = 0; 202*88447a05SGarrett D'Amore char devpath[PATH_MAX + 1]; 203*88447a05SGarrett D'Amore char newpath[PATH_MAX + 1]; 2047c478bd9Sstevel@tonic-gate char *buf; 2057c478bd9Sstevel@tonic-gate char *mn; 206*88447a05SGarrett D'Amore char *tmp; 207*88447a05SGarrett D'Amore char *ep; 2087c478bd9Sstevel@tonic-gate char re_string[RE_SIZE+1]; 2097c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[1] = {NULL}; 2107c478bd9Sstevel@tonic-gate 211*88447a05SGarrett D'Amore if (system_labeled) 212*88447a05SGarrett D'Amore flags = DA_ADD|DA_AUDIO; 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate mn = di_minor_name(minor); 2157c478bd9Sstevel@tonic-gate 216*88447a05SGarrett D'Amore if ((tmp = di_devfs_path(node)) == NULL) { 2177c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2187c478bd9Sstevel@tonic-gate } 219*88447a05SGarrett D'Amore (void) snprintf(devpath, sizeof (devpath), "%s:%s", tmp, mn); 220*88447a05SGarrett D'Amore di_devfs_path_free(tmp); 2217c478bd9Sstevel@tonic-gate 222*88447a05SGarrett D'Amore /* 223*88447a05SGarrett D'Amore * "Special" handling for /dev/sndstat and /dev/mixer. 224*88447a05SGarrett D'Amore */ 225*88447a05SGarrett D'Amore if (strcmp(mn, "sound,sndstat0") == 0) { 226*88447a05SGarrett D'Amore (void) strlcpy(newpath, "sound/sndstat", sizeof (newpath)); 227*88447a05SGarrett D'Amore 228*88447a05SGarrett D'Amore (void) devfsadm_mklink(newpath, node, minor, flags); 229*88447a05SGarrett D'Amore (void) devfsadm_secondary_link("sndstat", newpath, flags); 230*88447a05SGarrett D'Amore (void) devfsadm_secondary_link("mixer", newpath, flags); 231*88447a05SGarrett D'Amore send_all(); 232*88447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 235*88447a05SGarrett D'Amore if (strncmp(mn, "sound,", 6) == 0) { 236*88447a05SGarrett D'Amore char base[PATH_MAX + 1]; 237*88447a05SGarrett D'Amore char linksrc[PATH_MAX + 1]; 238*88447a05SGarrett D'Amore char linkdst[PATH_MAX + 1]; 239*88447a05SGarrett D'Amore long num; 240*88447a05SGarrett D'Amore long inst; 241*88447a05SGarrett D'Amore int i; 242*88447a05SGarrett D'Amore char *driver; 243*88447a05SGarrett D'Amore 244*88447a05SGarrett D'Amore /* strlen("sound,") */ 245*88447a05SGarrett D'Amore (void) strlcpy(base, mn + 6, sizeof (base)); 246*88447a05SGarrett D'Amore mn = base; 247*88447a05SGarrett D'Amore 248*88447a05SGarrett D'Amore driver = di_driver_name(node); 249*88447a05SGarrett D'Amore 250*88447a05SGarrett D'Amore /* if driver name override in minor name */ 251*88447a05SGarrett D'Amore if ((tmp = strchr(mn, ',')) != NULL) { 252*88447a05SGarrett D'Amore driver = mn; 253*88447a05SGarrett D'Amore *tmp = '\0'; 254*88447a05SGarrett D'Amore mn = tmp + 1; 255*88447a05SGarrett D'Amore } 256*88447a05SGarrett D'Amore 257*88447a05SGarrett D'Amore /* skip past "audio" portion of the minor name */ 258*88447a05SGarrett D'Amore if (strncmp(mn, "audio", 5) == 0) { 259*88447a05SGarrett D'Amore mn += 5; 260*88447a05SGarrett D'Amore } 261*88447a05SGarrett D'Amore 262*88447a05SGarrett D'Amore /* parse the instance number */ 263*88447a05SGarrett D'Amore for (i = strlen(mn); i; i--) { 264*88447a05SGarrett D'Amore if (!isdigit(mn[i - 1])) 265*88447a05SGarrett D'Amore break; 266*88447a05SGarrett D'Amore } 267*88447a05SGarrett D'Amore inst = strtol(mn + i, &ep, 10); 268*88447a05SGarrett D'Amore mn[i] = 0; /* lop off the instance number */ 269*88447a05SGarrett D'Amore 270*88447a05SGarrett D'Amore /* 271*88447a05SGarrett D'Amore * First we create a node with the driver under /dev/sound. 272*88447a05SGarrett D'Amore * Note that "instance numbers" used by the audio framework 273*88447a05SGarrett D'Amore * are guaranteed to be unique for each driver. 274*88447a05SGarrett D'Amore */ 275*88447a05SGarrett D'Amore (void) snprintf(newpath, sizeof (newpath), "sound/%s:%d%s", 276*88447a05SGarrett D'Amore driver, inst, mn); 277*88447a05SGarrett D'Amore (void) devfsadm_mklink(newpath, node, minor, flags); 278*88447a05SGarrett D'Amore 279*88447a05SGarrett D'Amore /* 280*88447a05SGarrett D'Amore * The rest of this logic is a gross simplification that 281*88447a05SGarrett D'Amore * is made possible by the fact that each audio node will 282*88447a05SGarrett D'Amore * have several different minors associated with it. Rather 283*88447a05SGarrett D'Amore * processing each node separately, we just create the links 284*88447a05SGarrett D'Amore * all at once. 285*88447a05SGarrett D'Amore * 286*88447a05SGarrett D'Amore * This reduces the chances of the various links being out 287*88447a05SGarrett D'Amore * of sync with each other. 288*88447a05SGarrett D'Amore */ 289*88447a05SGarrett D'Amore if (strcmp(mn, "mixer") != 0) { 290*88447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 291*88447a05SGarrett D'Amore } 292*88447a05SGarrett D'Amore 293*88447a05SGarrett D'Amore /* 294*88447a05SGarrett D'Amore * Its the control node, so create the various 295*88447a05SGarrett D'Amore * secondary links. 296*88447a05SGarrett D'Amore */ 297*88447a05SGarrett D'Amore 2987c478bd9Sstevel@tonic-gate /* 2997c478bd9Sstevel@tonic-gate * We want a match against the physical path 3007c478bd9Sstevel@tonic-gate * without the minor name component. 3017c478bd9Sstevel@tonic-gate */ 302*88447a05SGarrett D'Amore (void) snprintf(re_string, RE_SIZE, "%s", "^mixer([0-9]+)"); 3037c478bd9Sstevel@tonic-gate rules[0].re = re_string; 3047c478bd9Sstevel@tonic-gate rules[0].subexp = 1; 305*88447a05SGarrett D'Amore rules[0].flags = MATCH_ALL; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* 3087c478bd9Sstevel@tonic-gate * enumerate finds the logical audio id, and stuffs 3097c478bd9Sstevel@tonic-gate * it in buf 3107c478bd9Sstevel@tonic-gate */ 311*88447a05SGarrett D'Amore (void) strlcpy(devpath, newpath, sizeof (devpath)); 312*88447a05SGarrett D'Amore if (devfsadm_enumerate_int(devpath, 0, &buf, rules, 1)) { 3137c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3147c478bd9Sstevel@tonic-gate } 315*88447a05SGarrett D'Amore num = strtol(buf, &ep, 10); 3167c478bd9Sstevel@tonic-gate free(buf); 3177c478bd9Sstevel@tonic-gate 318*88447a05SGarrett D'Amore /* /dev/sound/0 */ 319*88447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ld", 320*88447a05SGarrett D'Amore driver, inst); 321*88447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "sound/%ld", num); 322*88447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 323*88447a05SGarrett D'Amore 324*88447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ldctl", 325*88447a05SGarrett D'Amore driver, inst); 326*88447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "sound/%ldctl", num); 327*88447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 328*88447a05SGarrett D'Amore 329*88447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%lddsp", 330*88447a05SGarrett D'Amore driver, inst); 331*88447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "dsp%ld", num); 332*88447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 333*88447a05SGarrett D'Amore 334*88447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ldmixer", 335*88447a05SGarrett D'Amore driver, inst); 336*88447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "mixer%ld", num); 337*88447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 338*88447a05SGarrett D'Amore 339*88447a05SGarrett D'Amore /* Send control number */ 340*88447a05SGarrett D'Amore send_number(num); 341*88447a05SGarrett D'Amore 3427c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 345*88447a05SGarrett D'Amore if (strncmp(mn, "internal,", 9) == 0) { 346*88447a05SGarrett D'Amore /* we don't set up internal nodes in /dev */ 3477c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 350*88447a05SGarrett D'Amore devfsadm_errprint("SUNW_audio_link: can't find match for'%s'\n", mn); 351*88447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 352*88447a05SGarrett D'Amore } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate static void 355*88447a05SGarrett D'Amore check_audio_link(char *secondary, const char *primary_format) 3567c478bd9Sstevel@tonic-gate { 357*88447a05SGarrett D'Amore char primary[PATH_MAX + 1]; 3587c478bd9Sstevel@tonic-gate int i; 35945916cd2Sjpk int flags = 0; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* if link is present, return */ 362*88447a05SGarrett D'Amore if (devfsadm_link_valid(secondary) == DEVFSADM_TRUE) { 3637c478bd9Sstevel@tonic-gate return; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 36645916cd2Sjpk if (system_labeled) 36745916cd2Sjpk flags = DA_ADD|DA_AUDIO; 36845916cd2Sjpk 3697c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_AUDIO_LINK; i++) { 370*88447a05SGarrett D'Amore (void) sprintf(primary, primary_format, i); 371*88447a05SGarrett D'Amore if (devfsadm_link_valid(primary) == DEVFSADM_TRUE) { 372*88447a05SGarrett D'Amore /* we read link to get it to the master "real" link */ 373*88447a05SGarrett D'Amore (void) devfsadm_secondary_link(secondary, 374*88447a05SGarrett D'Amore primary, flags); 3757c478bd9Sstevel@tonic-gate break; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate } 379