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 2005 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 <stdio.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <limits.h> 35 #include <ctype.h> 36 37 static int lp(di_minor_t minor, di_node_t node); 38 static int serial_dialout(di_minor_t minor, di_node_t node); 39 static int serial(di_minor_t minor, di_node_t node); 40 static int diskette(di_minor_t minor, di_node_t node); 41 static int vt00(di_minor_t minor, di_node_t node); 42 static int kdmouse(di_minor_t minor, di_node_t node); 43 static int bmc(di_minor_t minor, di_node_t node); 44 static int agp_process(di_minor_t minor, di_node_t node); 45 46 static devfsadm_create_t misc_cbt[] = { 47 { "vt00", "ddi_display", NULL, 48 TYPE_EXACT, ILEVEL_0, vt00 49 }, 50 { "mouse", "ddi_mouse", "mouse8042", 51 TYPE_EXACT | DRV_EXACT, ILEVEL_0, kdmouse 52 }, 53 { "pseudo", "ddi_pseudo", "bmc", 54 TYPE_EXACT | DRV_EXACT, ILEVEL_0, bmc, 55 }, 56 { "disk", "ddi_block:diskette", NULL, 57 TYPE_EXACT, ILEVEL_1, diskette 58 }, 59 { "parallel", "ddi_printer", NULL, 60 TYPE_EXACT, ILEVEL_1, lp 61 }, 62 { "serial", "ddi_serial:mb", NULL, 63 TYPE_EXACT, ILEVEL_1, serial 64 }, 65 { "serial", "ddi_serial:dialout,mb", NULL, 66 TYPE_EXACT, ILEVEL_1, serial_dialout 67 }, 68 {"agp", "ddi_agp:pseudo", NULL, 69 TYPE_EXACT, ILEVEL_0, agp_process 70 }, 71 {"agp", "ddi_agp:target", NULL, 72 TYPE_EXACT, ILEVEL_0, agp_process 73 }, 74 {"agp", "ddi_agp:cpugart", NULL, 75 TYPE_EXACT, ILEVEL_0, agp_process 76 }, 77 {"agp", "ddi_agp:master", NULL, 78 TYPE_EXACT, ILEVEL_0, agp_process 79 } 80 }; 81 82 DEVFSADM_CREATE_INIT_V0(misc_cbt); 83 84 static char *debug_mid = "agp_mid"; 85 86 typedef enum { 87 DRIVER_AGPPSEUDO = 0, 88 DRIVER_AGPTARGET, 89 DRIVER_CPUGART, 90 DRIVER_AGPMASTER, 91 DRIVER_UNKNOWN 92 } driver_defs_t; 93 94 typedef struct { 95 char *driver_name; 96 int index; 97 } driver_name_table_entry_t; 98 99 static driver_name_table_entry_t driver_name_table[] = { 100 { "agpgart", DRIVER_AGPPSEUDO }, 101 { "agptarget", DRIVER_AGPTARGET }, 102 { "amd64_gart", DRIVER_CPUGART }, 103 { "vgatext", DRIVER_AGPMASTER }, 104 { NULL, DRIVER_UNKNOWN } 105 }; 106 107 static devfsadm_enumerate_t agptarget_rules[1] = 108 { "^agp$/^agptarget([0-9]+)$", 1, MATCH_ALL }; 109 static devfsadm_enumerate_t cpugart_rules[1] = 110 { "^agp$/^cpugart([0-9]+)$", 1, MATCH_ALL }; 111 static devfsadm_enumerate_t agpmaster_rules[1] = 112 { "^agp$/^agpmaster([0-9]+)$", 1, MATCH_ALL }; 113 114 static devfsadm_remove_t misc_remove_cbt[] = { 115 { "vt", "vt[0-9][0-9]", RM_PRE|RM_ALWAYS, 116 ILEVEL_0, devfsadm_rm_all 117 } 118 }; 119 120 DEVFSADM_REMOVE_INIT_V0(misc_remove_cbt); 121 122 /* 123 * Handles minor node type "ddi_display", in addition to generic processing 124 * done by display(). 125 * 126 * This creates a /dev/vt00 link to /dev/fb, for backwards compatibility. 127 */ 128 /* ARGSUSED */ 129 int 130 vt00(di_minor_t minor, di_node_t node) 131 { 132 (void) devfsadm_secondary_link("vt00", "fb", 0); 133 return (DEVFSADM_CONTINUE); 134 } 135 136 /* 137 * type=ddi_block:diskette;addr=0,0;minor=c diskette 138 * type=ddi_block:diskette;addr=0,0;minor=c,raw rdiskette 139 * type=ddi_block:diskette;addr1=0;minor=c diskette\A2 140 * type=ddi_block:diskette;addr1=0;minor=c,raw rdiskette\A2 141 */ 142 static int 143 diskette(di_minor_t minor, di_node_t node) 144 { 145 char *a2; 146 char link[PATH_MAX]; 147 char *addr = di_bus_addr(node); 148 char *mn = di_minor_name(minor); 149 150 if (strcmp(addr, "0,0") == 0) { 151 if (strcmp(mn, "c") == 0) { 152 (void) devfsadm_mklink("diskette", node, minor, 0); 153 } else if (strcmp(mn, "c,raw") == 0) { 154 (void) devfsadm_mklink("rdiskette", node, minor, 0); 155 } 156 157 } 158 159 if (addr[0] == '0') { 160 if ((a2 = strchr(addr, ',')) != NULL) { 161 a2++; 162 if (strcmp(mn, "c") == 0) { 163 (void) strcpy(link, "diskette"); 164 (void) strcat(link, a2); 165 (void) devfsadm_mklink(link, node, minor, 0); 166 } else if (strcmp(mn, "c,raw") == 0) { 167 (void) strcpy(link, "rdiskette"); 168 (void) strcat(link, a2); 169 (void) devfsadm_mklink(link, node, minor, 0); 170 } 171 } 172 } 173 174 return (DEVFSADM_CONTINUE); 175 } 176 177 /* 178 * type=ddi_printer;name=lp;addr=1,3bc lp0 179 * type=ddi_printer;name=lp;addr=1,378 lp1 180 * type=ddi_printer;name=lp;addr=1,278 lp2 181 */ 182 static int 183 lp(di_minor_t minor, di_node_t node) 184 { 185 char *addr = di_bus_addr(node); 186 char *buf; 187 char path[PATH_MAX + 1]; 188 devfsadm_enumerate_t rules[1] = {"^ecpp([0-9]+)$", 1, MATCH_ALL}; 189 190 if (strcmp(addr, "1,3bc") == 0) { 191 (void) devfsadm_mklink("lp0", node, minor, 0); 192 193 } else if (strcmp(addr, "1,378") == 0) { 194 (void) devfsadm_mklink("lp1", node, minor, 0); 195 196 } else if (strcmp(addr, "1,278") == 0) { 197 (void) devfsadm_mklink("lp2", node, minor, 0); 198 } 199 200 if (strcmp(di_driver_name(node), "ecpp") != 0) { 201 return (DEVFSADM_CONTINUE); 202 } 203 204 if ((buf = di_devfs_path(node)) == NULL) { 205 return (DEVFSADM_CONTINUE); 206 } 207 208 (void) snprintf(path, sizeof (path), "%s:%s", 209 buf, di_minor_name(minor)); 210 211 di_devfs_path_free(buf); 212 213 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1)) { 214 return (DEVFSADM_CONTINUE); 215 } 216 217 (void) snprintf(path, sizeof (path), "ecpp%s", buf); 218 free(buf); 219 (void) devfsadm_mklink(path, node, minor, 0); 220 return (DEVFSADM_CONTINUE); 221 } 222 223 /* 224 * type=ddi_serial:mb;minor=a tty00 225 * type=ddi_serial:mb;minor=b tty01 226 * type=ddi_serial:mb;minor=c tty02 227 * type=ddi_serial:mb;minor=d tty03 228 */ 229 static int 230 serial(di_minor_t minor, di_node_t node) 231 { 232 233 char *mn = di_minor_name(minor); 234 char link[PATH_MAX]; 235 236 (void) strcpy(link, "tty"); 237 (void) strcat(link, mn); 238 (void) devfsadm_mklink(link, node, minor, 0); 239 240 if (strcmp(mn, "a") == 0) { 241 (void) devfsadm_mklink("tty00", node, minor, 0); 242 243 } else if (strcmp(mn, "b") == 0) { 244 (void) devfsadm_mklink("tty01", node, minor, 0); 245 246 } else if (strcmp(mn, "c") == 0) { 247 (void) devfsadm_mklink("tty02", node, minor, 0); 248 249 } else if (strcmp(mn, "d") == 0) { 250 (void) devfsadm_mklink("tty03", node, minor, 0); 251 } 252 return (DEVFSADM_CONTINUE); 253 } 254 255 /* 256 * type=ddi_serial:dialout,mb;minor=a,cu ttyd0 257 * type=ddi_serial:dialout,mb;minor=b,cu ttyd1 258 * type=ddi_serial:dialout,mb;minor=c,cu ttyd2 259 * type=ddi_serial:dialout,mb;minor=d,cu ttyd3 260 */ 261 static int 262 serial_dialout(di_minor_t minor, di_node_t node) 263 { 264 char *mn = di_minor_name(minor); 265 266 if (strcmp(mn, "a,cu") == 0) { 267 (void) devfsadm_mklink("ttyd0", node, minor, 0); 268 (void) devfsadm_mklink("cua0", node, minor, 0); 269 270 } else if (strcmp(mn, "b,cu") == 0) { 271 (void) devfsadm_mklink("ttyd1", node, minor, 0); 272 (void) devfsadm_mklink("cua1", node, minor, 0); 273 274 } else if (strcmp(mn, "c,cu") == 0) { 275 (void) devfsadm_mklink("ttyd2", node, minor, 0); 276 (void) devfsadm_mklink("cua2", node, minor, 0); 277 278 } else if (strcmp(mn, "d,cu") == 0) { 279 (void) devfsadm_mklink("ttyd3", node, minor, 0); 280 (void) devfsadm_mklink("cua3", node, minor, 0); 281 } 282 return (DEVFSADM_CONTINUE); 283 } 284 285 static int 286 kdmouse(di_minor_t minor, di_node_t node) 287 { 288 (void) devfsadm_mklink("kdmouse", node, minor, 0); 289 return (DEVFSADM_CONTINUE); 290 } 291 292 static int 293 bmc(di_minor_t minor, di_node_t node) 294 { 295 (void) devfsadm_mklink("bmc", node, minor, 0); 296 return (DEVFSADM_CONTINUE); 297 } 298 static int 299 agp_process(di_minor_t minor, di_node_t node) 300 { 301 char *minor_nm, *drv_nm; 302 char *devfspath; 303 char *I_path, *p_path, *buf; 304 char *name = (char *)NULL; 305 int i, index; 306 devfsadm_enumerate_t rules[1]; 307 308 minor_nm = di_minor_name(minor); 309 drv_nm = di_driver_name(node); 310 311 if ((minor_nm == NULL) || (drv_nm == NULL)) { 312 return (DEVFSADM_CONTINUE); 313 } 314 315 devfsadm_print(debug_mid, "agp_process: minor=%s node=%s\n", 316 minor_nm, di_node_name(node)); 317 318 devfspath = di_devfs_path(node); 319 if (devfspath == NULL) { 320 devfsadm_print(debug_mid, "agp_process: devfspath is NULL\n"); 321 return (DEVFSADM_CONTINUE); 322 } 323 324 I_path = (char *)malloc(PATH_MAX); 325 326 if (I_path == NULL) { 327 di_devfs_path_free(devfspath); 328 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 329 return (DEVFSADM_CONTINUE); 330 } 331 332 p_path = (char *)malloc(PATH_MAX); 333 334 if (p_path == NULL) { 335 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 336 di_devfs_path_free(devfspath); 337 free(I_path); 338 return (DEVFSADM_CONTINUE); 339 } 340 341 (void) strlcpy(p_path, devfspath, PATH_MAX); 342 (void) strlcat(p_path, ":", PATH_MAX); 343 (void) strlcat(p_path, minor_nm, PATH_MAX); 344 di_devfs_path_free(devfspath); 345 346 devfsadm_print(debug_mid, "agp_process: path %s\n", p_path); 347 348 for (i = 0; ; i++) { 349 if ((driver_name_table[i].driver_name == NULL) || 350 (strcmp(drv_nm, driver_name_table[i].driver_name) == 0)) { 351 index = driver_name_table[i].index; 352 break; 353 } 354 } 355 switch (index) { 356 case DRIVER_AGPPSEUDO: 357 devfsadm_print(debug_mid, 358 "agp_process: psdeudo driver name\n"); 359 name = "agpgart"; 360 (void) snprintf(I_path, PATH_MAX, "%s", name); 361 devfsadm_print(debug_mid, 362 "mklink %s -> %s\n", I_path, p_path); 363 364 (void) devfsadm_mklink(I_path, node, minor, 0); 365 366 free(I_path); 367 free(p_path); 368 return (DEVFSADM_CONTINUE); 369 case DRIVER_AGPTARGET: 370 devfsadm_print(debug_mid, 371 "agp_process: target driver name\n"); 372 rules[0] = agptarget_rules[0]; 373 name = "agptarget"; 374 break; 375 case DRIVER_CPUGART: 376 devfsadm_print(debug_mid, 377 "agp_process: cpugart driver name\n"); 378 rules[0] = cpugart_rules[0]; 379 name = "cpugart"; 380 break; 381 case DRIVER_AGPMASTER: 382 devfsadm_print(debug_mid, 383 "agp_process: agpmaster driver name\n"); 384 rules[0] = agpmaster_rules[0]; 385 name = "agpmaster"; 386 break; 387 case DRIVER_UNKNOWN: 388 devfsadm_print(debug_mid, 389 "agp_process: unknown driver name=%s\n", drv_nm); 390 free(I_path); 391 free(p_path); 392 return (DEVFSADM_CONTINUE); 393 } 394 395 if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) { 396 devfsadm_print(debug_mid, "agp_process: exit/coninue\n"); 397 free(I_path); 398 free(p_path); 399 return (DEVFSADM_CONTINUE); 400 } 401 402 403 (void) snprintf(I_path, PATH_MAX, "agp/%s%s", name, buf); 404 405 devfsadm_print(debug_mid, "agp_process: p_path=%s buf=%s\n", 406 p_path, buf); 407 408 free(buf); 409 410 devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path); 411 412 (void) devfsadm_mklink(I_path, node, minor, 0); 413 414 free(p_path); 415 free(I_path); 416 417 return (DEVFSADM_CONTINUE); 418 } 419