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 /* 2288447a05SGarrett 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> 2988447a05SGarrett D'Amore #include <ctype.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <limits.h> 327c478bd9Sstevel@tonic-gate #include <stdio.h> 3388447a05SGarrett D'Amore #include <syslog.h> 3445916cd2Sjpk #include <bsm/devalloc.h> 3588447a05SGarrett D'Amore #include <sys/audio.h> 3688447a05SGarrett D'Amore #include <sys/soundcard.h> 3788447a05SGarrett 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); 4688447a05SGarrett D'Amore 477c478bd9Sstevel@tonic-gate static int audio_process(di_minor_t minor, di_node_t node); 4888447a05SGarrett 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 5388447a05SGarrett D'Amore }, 5488447a05SGarrett D'Amore { "pseudo", "ddi_pseudo", "audio", 5588447a05SGarrett D'Amore TYPE_EXACT|DRV_EXACT, ILEVEL_0, sndstat_process 5688447a05SGarrett 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[] = { 6688447a05SGarrett D'Amore /* 6788447a05SGarrett D'Amore * Secondary links. 6888447a05SGarrett D'Amore */ 6988447a05SGarrett D'Amore 7088447a05SGarrett D'Amore /* /dev/audio, /dev/audioctl, /dev/dsp */ 71*92e8aa2fSGarrett D'Amore { "audio", "^audio$", 72*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 737c478bd9Sstevel@tonic-gate }, 74*92e8aa2fSGarrett D'Amore { "audio", "^audioctl$", 75*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 7688447a05SGarrett D'Amore }, 77*92e8aa2fSGarrett D'Amore { "audio", "^dsp$", 78*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 7988447a05SGarrett D'Amore }, 80*92e8aa2fSGarrett D'Amore { "audio", "^mixer", 81*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 8288447a05SGarrett D'Amore }, 83*92e8aa2fSGarrett D'Amore { "audio", "^sndstat$", 847c478bd9Sstevel@tonic-gate RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 857c478bd9Sstevel@tonic-gate }, 86*92e8aa2fSGarrett D'Amore { "audio", "^mixer[0-9]+$", 87*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 88*92e8aa2fSGarrett D'Amore }, 89*92e8aa2fSGarrett D'Amore { "audio", "^dsp[0-9]+$", 90*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 91*92e8aa2fSGarrett D'Amore }, 92*92e8aa2fSGarrett D'Amore { "audio", "^sound/[0-9]+$", 93*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 94*92e8aa2fSGarrett D'Amore }, 95*92e8aa2fSGarrett D'Amore { "audio", "^sound/[0-9]+ctl$", 96*92e8aa2fSGarrett D'Amore RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 977c478bd9Sstevel@tonic-gate }, 987c478bd9Sstevel@tonic-gate }; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate int 1037c478bd9Sstevel@tonic-gate minor_fini(void) 1047c478bd9Sstevel@tonic-gate { 1057c478bd9Sstevel@tonic-gate check_audio_link("audio", "sound/%d"); 1067c478bd9Sstevel@tonic-gate check_audio_link("audioctl", "sound/%dctl"); 10788447a05SGarrett D'Amore check_audio_link("dsp", "dsp%d"); 1087c478bd9Sstevel@tonic-gate return (DEVFSADM_SUCCESS); 1097c478bd9Sstevel@tonic-gate } 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate #define COPYSUB(to, from, pm, pos) (void) strncpy(to, &from[pm[pos].rm_so], \ 1137c478bd9Sstevel@tonic-gate pm[pos].rm_eo - pm[pos].rm_so); \ 1147c478bd9Sstevel@tonic-gate to[pm[pos].rm_eo - pm[pos].rm_so] = 0; 1157c478bd9Sstevel@tonic-gate 11688447a05SGarrett D'Amore static void 11788447a05SGarrett D'Amore send_number(long num) 11888447a05SGarrett D'Amore { 11988447a05SGarrett D'Amore char buf[PATH_MAX+1]; 12088447a05SGarrett D'Amore 12188447a05SGarrett D'Amore /* 12288447a05SGarrett D'Amore * This is not safe with -r. 12388447a05SGarrett D'Amore */ 12488447a05SGarrett D'Amore if (strcmp(devfsadm_root_path(), "/") != 0) 12588447a05SGarrett D'Amore return; 12688447a05SGarrett D'Amore 12788447a05SGarrett D'Amore (void) snprintf(buf, sizeof (buf), "/dev/mixer%ld", num); 12888447a05SGarrett D'Amore if (device_exists(buf)) { 12988447a05SGarrett D'Amore int fd; 13088447a05SGarrett D'Amore 13188447a05SGarrett D'Amore if ((fd = open(buf, O_RDWR)) < 0) 13288447a05SGarrett D'Amore return; 13388447a05SGarrett D'Amore 13488447a05SGarrett D'Amore (void) ioctl(fd, SNDCTL_SUN_SEND_NUMBER, &num); 13588447a05SGarrett D'Amore (void) close(fd); 13688447a05SGarrett D'Amore devfsadm_print(CHATTY_MID, 13788447a05SGarrett D'Amore "sent devnum audio %ld to %s\n", num, buf); 13888447a05SGarrett D'Amore } 13988447a05SGarrett D'Amore } 14088447a05SGarrett D'Amore 14188447a05SGarrett D'Amore static void 14288447a05SGarrett D'Amore send_all(void) 14388447a05SGarrett D'Amore { 14488447a05SGarrett D'Amore /* 14588447a05SGarrett D'Amore * This module traverses /dev/sound to look for nodes that 14688447a05SGarrett D'Amore * have been previously created. 14788447a05SGarrett D'Amore */ 14888447a05SGarrett D'Amore finddevhdl_t fh; 14988447a05SGarrett D'Amore const char *path; 15088447a05SGarrett D'Amore 15188447a05SGarrett D'Amore /* 15288447a05SGarrett D'Amore * This is not safe with -r. 15388447a05SGarrett D'Amore */ 15488447a05SGarrett D'Amore if ((strcmp(devfsadm_root_path(), "/") == 0) && 15588447a05SGarrett D'Amore (finddev_readdir("/dev", &fh) == 0)) { 15688447a05SGarrett D'Amore static int doneit = 0; 15788447a05SGarrett D'Amore 15888447a05SGarrett D'Amore while ((!doneit) && ((path = finddev_next(fh)) != NULL)) { 15988447a05SGarrett D'Amore long num; 16088447a05SGarrett D'Amore char *ep; 16188447a05SGarrett D'Amore if ((strncmp(path, "mixer", 5) != 0) || 16288447a05SGarrett D'Amore (!isdigit(path[5]))) { 16388447a05SGarrett D'Amore continue; 16488447a05SGarrett D'Amore } 16588447a05SGarrett D'Amore num = strtol(path + 5, &ep, 10); 16688447a05SGarrett D'Amore send_number(num); 16788447a05SGarrett D'Amore } 16888447a05SGarrett D'Amore finddev_close(fh); 16988447a05SGarrett D'Amore doneit = 1; 17088447a05SGarrett D'Amore } 17188447a05SGarrett D'Amore } 17288447a05SGarrett D'Amore 17388447a05SGarrett D'Amore static int 17488447a05SGarrett D'Amore sndstat_process(di_minor_t minor, di_node_t node) 17588447a05SGarrett D'Amore { 17688447a05SGarrett D'Amore char *mn; 17788447a05SGarrett D'Amore 17888447a05SGarrett D'Amore mn = di_minor_name(minor); 17988447a05SGarrett D'Amore 18088447a05SGarrett D'Amore /* 18188447a05SGarrett D'Amore * "Special" handling for /dev/sndstat and /dev/mixer. 18288447a05SGarrett D'Amore */ 18388447a05SGarrett D'Amore if (strcmp(mn, "sound,sndstat0") == 0) { 18488447a05SGarrett D'Amore (void) devfsadm_mklink("sndstat", node, minor, 0); 18588447a05SGarrett D'Amore (void) devfsadm_secondary_link("mixer", "sndstat", 0); 18688447a05SGarrett D'Amore send_all(); 18788447a05SGarrett D'Amore } 18888447a05SGarrett D'Amore 18988447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 19088447a05SGarrett D'Amore } 19188447a05SGarrett D'Amore 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * This function is called for every audio node. 1947c478bd9Sstevel@tonic-gate * Calls enumerate to assign a logical unit id, and then 1957c478bd9Sstevel@tonic-gate * devfsadm_mklink to make the link. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate static int 1987c478bd9Sstevel@tonic-gate audio_process(di_minor_t minor, di_node_t node) 1997c478bd9Sstevel@tonic-gate { 20045916cd2Sjpk int flags = 0; 20188447a05SGarrett D'Amore char devpath[PATH_MAX + 1]; 20288447a05SGarrett D'Amore char newpath[PATH_MAX + 1]; 2037c478bd9Sstevel@tonic-gate char *buf; 2047c478bd9Sstevel@tonic-gate char *mn; 20588447a05SGarrett D'Amore char *tmp; 20688447a05SGarrett D'Amore char *ep; 2077c478bd9Sstevel@tonic-gate char re_string[RE_SIZE+1]; 2087c478bd9Sstevel@tonic-gate devfsadm_enumerate_t rules[1] = {NULL}; 2097c478bd9Sstevel@tonic-gate 21088447a05SGarrett D'Amore if (system_labeled) 21188447a05SGarrett D'Amore flags = DA_ADD|DA_AUDIO; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate mn = di_minor_name(minor); 2147c478bd9Sstevel@tonic-gate 21588447a05SGarrett D'Amore if ((tmp = di_devfs_path(node)) == NULL) { 2167c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2177c478bd9Sstevel@tonic-gate } 21888447a05SGarrett D'Amore (void) snprintf(devpath, sizeof (devpath), "%s:%s", tmp, mn); 21988447a05SGarrett D'Amore di_devfs_path_free(tmp); 2207c478bd9Sstevel@tonic-gate 22188447a05SGarrett D'Amore /* 22288447a05SGarrett D'Amore * "Special" handling for /dev/sndstat and /dev/mixer. 22388447a05SGarrett D'Amore */ 22488447a05SGarrett D'Amore if (strcmp(mn, "sound,sndstat0") == 0) { 22588447a05SGarrett D'Amore (void) strlcpy(newpath, "sound/sndstat", sizeof (newpath)); 22688447a05SGarrett D'Amore 22788447a05SGarrett D'Amore (void) devfsadm_mklink(newpath, node, minor, flags); 22888447a05SGarrett D'Amore (void) devfsadm_secondary_link("sndstat", newpath, flags); 22988447a05SGarrett D'Amore (void) devfsadm_secondary_link("mixer", newpath, flags); 23088447a05SGarrett D'Amore send_all(); 23188447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 23488447a05SGarrett D'Amore if (strncmp(mn, "sound,", 6) == 0) { 23588447a05SGarrett D'Amore char base[PATH_MAX + 1]; 23688447a05SGarrett D'Amore char linksrc[PATH_MAX + 1]; 23788447a05SGarrett D'Amore char linkdst[PATH_MAX + 1]; 23888447a05SGarrett D'Amore long num; 23988447a05SGarrett D'Amore long inst; 24088447a05SGarrett D'Amore int i; 24188447a05SGarrett D'Amore char *driver; 24288447a05SGarrett D'Amore 24388447a05SGarrett D'Amore /* strlen("sound,") */ 24488447a05SGarrett D'Amore (void) strlcpy(base, mn + 6, sizeof (base)); 24588447a05SGarrett D'Amore mn = base; 24688447a05SGarrett D'Amore 24788447a05SGarrett D'Amore driver = di_driver_name(node); 24888447a05SGarrett D'Amore 24988447a05SGarrett D'Amore /* if driver name override in minor name */ 25088447a05SGarrett D'Amore if ((tmp = strchr(mn, ',')) != NULL) { 25188447a05SGarrett D'Amore driver = mn; 25288447a05SGarrett D'Amore *tmp = '\0'; 25388447a05SGarrett D'Amore mn = tmp + 1; 25488447a05SGarrett D'Amore } 25588447a05SGarrett D'Amore 25688447a05SGarrett D'Amore /* skip past "audio" portion of the minor name */ 25788447a05SGarrett D'Amore if (strncmp(mn, "audio", 5) == 0) { 25888447a05SGarrett D'Amore mn += 5; 25988447a05SGarrett D'Amore } 26088447a05SGarrett D'Amore 26188447a05SGarrett D'Amore /* parse the instance number */ 26288447a05SGarrett D'Amore for (i = strlen(mn); i; i--) { 26388447a05SGarrett D'Amore if (!isdigit(mn[i - 1])) 26488447a05SGarrett D'Amore break; 26588447a05SGarrett D'Amore } 26688447a05SGarrett D'Amore inst = strtol(mn + i, &ep, 10); 26788447a05SGarrett D'Amore mn[i] = 0; /* lop off the instance number */ 26888447a05SGarrett D'Amore 26988447a05SGarrett D'Amore /* 27088447a05SGarrett D'Amore * First we create a node with the driver under /dev/sound. 27188447a05SGarrett D'Amore * Note that "instance numbers" used by the audio framework 27288447a05SGarrett D'Amore * are guaranteed to be unique for each driver. 27388447a05SGarrett D'Amore */ 27488447a05SGarrett D'Amore (void) snprintf(newpath, sizeof (newpath), "sound/%s:%d%s", 27588447a05SGarrett D'Amore driver, inst, mn); 27688447a05SGarrett D'Amore (void) devfsadm_mklink(newpath, node, minor, flags); 27788447a05SGarrett D'Amore 27888447a05SGarrett D'Amore /* 27988447a05SGarrett D'Amore * The rest of this logic is a gross simplification that 28088447a05SGarrett D'Amore * is made possible by the fact that each audio node will 28188447a05SGarrett D'Amore * have several different minors associated with it. Rather 28288447a05SGarrett D'Amore * processing each node separately, we just create the links 28388447a05SGarrett D'Amore * all at once. 28488447a05SGarrett D'Amore * 28588447a05SGarrett D'Amore * This reduces the chances of the various links being out 28688447a05SGarrett D'Amore * of sync with each other. 28788447a05SGarrett D'Amore */ 28888447a05SGarrett D'Amore if (strcmp(mn, "mixer") != 0) { 28988447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 29088447a05SGarrett D'Amore } 29188447a05SGarrett D'Amore 29288447a05SGarrett D'Amore /* 29388447a05SGarrett D'Amore * Its the control node, so create the various 29488447a05SGarrett D'Amore * secondary links. 29588447a05SGarrett D'Amore */ 29688447a05SGarrett D'Amore 2977c478bd9Sstevel@tonic-gate /* 2987c478bd9Sstevel@tonic-gate * We want a match against the physical path 2997c478bd9Sstevel@tonic-gate * without the minor name component. 3007c478bd9Sstevel@tonic-gate */ 30188447a05SGarrett D'Amore (void) snprintf(re_string, RE_SIZE, "%s", "^mixer([0-9]+)"); 3027c478bd9Sstevel@tonic-gate rules[0].re = re_string; 3037c478bd9Sstevel@tonic-gate rules[0].subexp = 1; 30488447a05SGarrett D'Amore rules[0].flags = MATCH_ALL; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * enumerate finds the logical audio id, and stuffs 3087c478bd9Sstevel@tonic-gate * it in buf 3097c478bd9Sstevel@tonic-gate */ 31088447a05SGarrett D'Amore (void) strlcpy(devpath, newpath, sizeof (devpath)); 31188447a05SGarrett D'Amore if (devfsadm_enumerate_int(devpath, 0, &buf, rules, 1)) { 3127c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3137c478bd9Sstevel@tonic-gate } 31488447a05SGarrett D'Amore num = strtol(buf, &ep, 10); 3157c478bd9Sstevel@tonic-gate free(buf); 3167c478bd9Sstevel@tonic-gate 31788447a05SGarrett D'Amore /* /dev/sound/0 */ 31888447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ld", 31988447a05SGarrett D'Amore driver, inst); 32088447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "sound/%ld", num); 32188447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 32288447a05SGarrett D'Amore 32388447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ldctl", 32488447a05SGarrett D'Amore driver, inst); 32588447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "sound/%ldctl", num); 32688447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 32788447a05SGarrett D'Amore 32888447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%lddsp", 32988447a05SGarrett D'Amore driver, inst); 33088447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "dsp%ld", num); 33188447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 33288447a05SGarrett D'Amore 33388447a05SGarrett D'Amore (void) snprintf(linksrc, sizeof (linksrc), "sound/%s:%ldmixer", 33488447a05SGarrett D'Amore driver, inst); 33588447a05SGarrett D'Amore (void) snprintf(linkdst, sizeof (linkdst), "mixer%ld", num); 33688447a05SGarrett D'Amore (void) devfsadm_secondary_link(linkdst, linksrc, flags); 33788447a05SGarrett D'Amore 33888447a05SGarrett D'Amore /* Send control number */ 33988447a05SGarrett D'Amore send_number(num); 34088447a05SGarrett D'Amore 3417c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 34488447a05SGarrett D'Amore if (strncmp(mn, "internal,", 9) == 0) { 34588447a05SGarrett D'Amore /* we don't set up internal nodes in /dev */ 3467c478bd9Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate 34988447a05SGarrett D'Amore devfsadm_errprint("SUNW_audio_link: can't find match for'%s'\n", mn); 35088447a05SGarrett D'Amore return (DEVFSADM_CONTINUE); 35188447a05SGarrett D'Amore } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate static void 35488447a05SGarrett D'Amore check_audio_link(char *secondary, const char *primary_format) 3557c478bd9Sstevel@tonic-gate { 35688447a05SGarrett D'Amore char primary[PATH_MAX + 1]; 3577c478bd9Sstevel@tonic-gate int i; 35845916cd2Sjpk int flags = 0; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* if link is present, return */ 36188447a05SGarrett D'Amore if (devfsadm_link_valid(secondary) == DEVFSADM_TRUE) { 3627c478bd9Sstevel@tonic-gate return; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 36545916cd2Sjpk if (system_labeled) 36645916cd2Sjpk flags = DA_ADD|DA_AUDIO; 36745916cd2Sjpk 3687c478bd9Sstevel@tonic-gate for (i = 0; i < MAX_AUDIO_LINK; i++) { 36988447a05SGarrett D'Amore (void) sprintf(primary, primary_format, i); 37088447a05SGarrett D'Amore if (devfsadm_link_valid(primary) == DEVFSADM_TRUE) { 37188447a05SGarrett D'Amore /* we read link to get it to the master "real" link */ 37288447a05SGarrett D'Amore (void) devfsadm_secondary_link(secondary, 37388447a05SGarrett D'Amore primary, flags); 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate } 378