1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <regex.h> 30 #include <devfsadm.h> 31 #include <strings.h> 32 #include <stdlib.h> 33 #include <limits.h> 34 #include <stdio.h> 35 36 #define MAX_AUDIO_LINK 100 37 #define RE_SIZE 64 38 39 static void check_audio_link(char *secondary_link, 40 const char *primary_link_format); 41 static int audio_process(di_minor_t minor, di_node_t node); 42 43 static devfsadm_create_t audio_cbt[] = { 44 { "audio", "ddi_audio", NULL, 45 TYPE_EXACT, ILEVEL_0, audio_process 46 } 47 }; 48 49 DEVFSADM_CREATE_INIT_V0(audio_cbt); 50 51 /* 52 * the following can't be one big RE with a bunch of alterations "|" 53 * because recurse_dev_re() would not work. 54 */ 55 static devfsadm_remove_t audio_remove_cbt[] = { 56 { "audio", 57 "^audio(ctl)?$", 58 RM_POST|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_link 59 }, 60 { "audio", 61 "^sound/[0-9]+.*$", 62 RM_PRE|RM_HOT|RM_ALWAYS, ILEVEL_0, devfsadm_rm_all 63 }, 64 { "audio", 65 "^isdn/[0-9]+/mgt$", 66 RM_PRE, ILEVEL_0, devfsadm_rm_all 67 }, 68 { "audio", 69 "^isdn/[0-9]+/aux/0(ctl)?$", 70 RM_PRE, ILEVEL_0, devfsadm_rm_all 71 }, 72 { "audio", 73 "^isdn/[0-9]+/(nt)|(te)/((dtrace)|(mgt)|(b1)|(b2)|(d))$", 74 RM_PRE, ILEVEL_0, devfsadm_rm_all 75 } 76 }; 77 78 DEVFSADM_REMOVE_INIT_V0(audio_remove_cbt); 79 80 static regex_t isdn_re; 81 82 #define ISDN_RE "((nt)|(te)|(aux))\\,((0)|(0ctl)|(d)|(b1)|(b2)|(mgt)|(dtrace))" 83 #define F 1 84 #define S 5 85 86 int 87 minor_init(void) 88 { 89 if (0 != regcomp(&isdn_re, ISDN_RE, REG_EXTENDED)) { 90 devfsadm_errprint("SUNW_audio_link: minor_init: regular " 91 "expression bad: '%s'\n", ISDN_RE); 92 return (DEVFSADM_FAILURE); 93 } else { 94 return (DEVFSADM_SUCCESS); 95 } 96 } 97 98 int 99 minor_fini(void) 100 { 101 regfree(&isdn_re); 102 check_audio_link("audio", "sound/%d"); 103 check_audio_link("audioctl", "sound/%dctl"); 104 return (DEVFSADM_SUCCESS); 105 } 106 107 108 #define COPYSUB(to, from, pm, pos) (void) strncpy(to, &from[pm[pos].rm_so], \ 109 pm[pos].rm_eo - pm[pos].rm_so); \ 110 to[pm[pos].rm_eo - pm[pos].rm_so] = 0; 111 112 /* 113 * This function is called for every audio node. 114 * Calls enumerate to assign a logical unit id, and then 115 * devfsadm_mklink to make the link. 116 */ 117 static int 118 audio_process(di_minor_t minor, di_node_t node) 119 { 120 char path[PATH_MAX + 1]; 121 char *buf; 122 char *mn; 123 char m1[10]; 124 char m2[10]; 125 char *devfspath; 126 char re_string[RE_SIZE+1]; 127 devfsadm_enumerate_t rules[1] = {NULL}; 128 regmatch_t pmatch[12]; 129 char *au_mn; 130 131 132 mn = di_minor_name(minor); 133 134 if ((devfspath = di_devfs_path(node)) == NULL) { 135 return (DEVFSADM_CONTINUE); 136 } 137 (void) strcpy(path, devfspath); 138 (void) strcat(path, ":"); 139 (void) strcat(path, mn); 140 di_devfs_path_free(devfspath); 141 142 if (strstr(mn, "sound,") != NULL) { 143 (void) snprintf(re_string, RE_SIZE, "%s", "^sound$/^([0-9]+)"); 144 } else { 145 (void) strcpy(re_string, "isdn/([0-9]+)"); 146 } 147 148 /* 149 * We want a match against the physical path 150 * without the minor name component. 151 */ 152 rules[0].re = re_string; 153 rules[0].subexp = 1; 154 rules[0].flags = MATCH_ADDR; 155 156 /* 157 * enumerate finds the logical audio id, and stuffs 158 * it in buf 159 */ 160 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 161 return (DEVFSADM_CONTINUE); 162 } 163 164 path[0] = '\0'; 165 166 if (strstr(mn, "sound,") != NULL) { 167 (void) strcpy(path, "sound/"); 168 (void) strcat(path, buf); 169 170 /* if this is a minor node, tack on the correct suffix */ 171 au_mn = strchr(mn, ','); 172 if (strcmp(++au_mn, "audio") != 0 && 173 strcmp(au_mn, "sbpro") != 0) { 174 175 /* 176 * audioctl/sbproctl are special cases. They are handled 177 * by stripping off the audio/sbpro from the node name 178 */ 179 if (strcmp(au_mn, "audioctl") == 0 || 180 strcmp(au_mn, "sbproctl") == 0) 181 au_mn = strstr(au_mn, "ctl"); 182 (void) strcat(path, au_mn); 183 } 184 } 185 186 if (regexec(&isdn_re, mn, sizeof (pmatch) / sizeof (pmatch[0]), 187 pmatch, 0) == 0) { 188 COPYSUB(m1, mn, pmatch, F); 189 COPYSUB(m2, mn, pmatch, S); 190 (void) strcpy(path, "isdn/"); 191 (void) strcat(path, buf); 192 (void) strcat(path, "/"); 193 (void) strcat(path, m1); 194 (void) strcat(path, "/"); 195 (void) strcat(path, m2); 196 } 197 198 if (strstr("mgt,mgt", mn) != NULL) { 199 (void) strcpy(path, "isdn/"); 200 (void) strcat(path, buf); 201 (void) strcat(path, "/mgt"); 202 } 203 204 free(buf); 205 206 if (path[0] == '\0') { 207 devfsadm_errprint("SUNW_audio_link: audio_process: can't find" 208 " match for'%s'\n", mn); 209 return (DEVFSADM_CONTINUE); 210 } 211 212 (void) devfsadm_mklink(path, node, minor, 0); 213 return (DEVFSADM_CONTINUE); 214 } 215 216 217 static void 218 check_audio_link(char *secondary_link, const char *primary_link_format) 219 { 220 char primary_link[PATH_MAX + 1]; 221 int i; 222 223 /* if link is present, return */ 224 if (devfsadm_link_valid(secondary_link) == DEVFSADM_TRUE) { 225 return; 226 } 227 228 for (i = 0; i < MAX_AUDIO_LINK; i++) { 229 (void) sprintf(primary_link, primary_link_format, i); 230 if (devfsadm_link_valid(primary_link) == DEVFSADM_TRUE) { 231 (void) devfsadm_secondary_link(secondary_link, 232 primary_link, 0); 233 break; 234 } 235 } 236 } 237