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