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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * Copyright 2012 Joyent, Inc. All rights reserved. 25 */ 26 27 #include <regex.h> 28 #include <devfsadm.h> 29 #include <stdio.h> 30 #include <strings.h> 31 #include <stdlib.h> 32 #include <limits.h> 33 #include <ctype.h> 34 35 /* 36 * Note: separate from misc_link_i386.c because this will later 37 * move to the gfx-drm gate. 38 */ 39 40 static int agp_process(di_minor_t minor, di_node_t node); 41 static int drm_node(di_minor_t minor, di_node_t node); 42 43 static devfsadm_create_t drm_cbt[] = { 44 { "drm", "ddi_display:drm", NULL, 45 TYPE_EXACT, ILEVEL_0, drm_node 46 }, 47 { "agp", "ddi_agp:pseudo", NULL, 48 TYPE_EXACT, ILEVEL_0, agp_process 49 }, 50 { "agp", "ddi_agp:target", NULL, 51 TYPE_EXACT, ILEVEL_0, agp_process 52 }, 53 { "agp", "ddi_agp:cpugart", NULL, 54 TYPE_EXACT, ILEVEL_0, agp_process 55 }, 56 { "agp", "ddi_agp:master", NULL, 57 TYPE_EXACT, ILEVEL_0, agp_process 58 }, 59 }; 60 61 DEVFSADM_CREATE_INIT_V0(drm_cbt); 62 63 /* 64 * For debugging, run devfsadm like this: 65 * devfsadm -V drm_mid -V devfsadm:enum -c drm 66 */ 67 static char *debug_mid = "drm_mid"; 68 69 typedef enum { 70 DRIVER_AGPPSEUDO = 0, 71 DRIVER_AGPTARGET, 72 DRIVER_CPUGART, 73 DRIVER_AGPMASTER_DRM_I915, 74 DRIVER_AGPMASTER_DRM_RADEON, 75 DRIVER_AGPMASTER_VGATEXT, 76 DRIVER_UNKNOWN 77 } driver_defs_t; 78 79 typedef struct { 80 char *driver_name; 81 int index; 82 } driver_name_table_entry_t; 83 84 static driver_name_table_entry_t driver_name_table[] = { 85 { "agpgart", DRIVER_AGPPSEUDO }, 86 { "agptarget", DRIVER_AGPTARGET }, 87 { "amd64_gart", DRIVER_CPUGART }, 88 /* AGP master device managed by drm driver */ 89 { "i915", DRIVER_AGPMASTER_DRM_I915 }, 90 { "radeon", DRIVER_AGPMASTER_DRM_RADEON }, 91 { "vgatext", DRIVER_AGPMASTER_VGATEXT }, 92 { NULL, DRIVER_UNKNOWN } 93 }; 94 95 static devfsadm_enumerate_t agptarget_rules[1] = 96 { "^agp$/^agptarget([0-9]+)$", 1, MATCH_ALL }; 97 static devfsadm_enumerate_t cpugart_rules[1] = 98 { "^agp$/^cpugart([0-9]+)$", 1, MATCH_ALL }; 99 static devfsadm_enumerate_t agpmaster_rules[1] = 100 { "^agp$/^agpmaster([0-9]+)$", 1, MATCH_ALL }; 101 static devfsadm_enumerate_t drm_rules[1] = 102 { "^dri$/^card([0-9]+)$", 1, MATCH_ALL }; 103 104 105 /* 106 * HOT auto cleanup of drm+agp links not desired. 107 */ 108 static devfsadm_remove_t drm_remove_cbt[] = { 109 { "agp", "^agpgart$", RM_POST, 110 ILEVEL_0, devfsadm_rm_all 111 }, 112 { "agp", "^agp/agpmaster[0-9]+$", RM_POST, 113 ILEVEL_0, devfsadm_rm_all 114 }, 115 { "agp", "^agp/agptarget[0-9]+$", RM_POST, 116 ILEVEL_0, devfsadm_rm_all 117 }, 118 { "agp", "^agp/cpugart[0-9]+$", RM_POST, 119 ILEVEL_0, devfsadm_rm_all 120 }, 121 { "drm", "^dri/card[0-9]+$", RM_POST, 122 ILEVEL_0, devfsadm_rm_all 123 }, 124 }; 125 126 DEVFSADM_REMOVE_INIT_V0(drm_remove_cbt); 127 128 static int 129 agp_process(di_minor_t minor, di_node_t node) 130 { 131 char *minor_nm, *drv_nm; 132 char *devfspath; 133 char *I_path, *p_path, *buf; 134 char *name = (char *)NULL; 135 int i, index; 136 devfsadm_enumerate_t rules[1]; 137 138 minor_nm = di_minor_name(minor); 139 drv_nm = di_driver_name(node); 140 141 if ((minor_nm == NULL) || (drv_nm == NULL)) { 142 return (DEVFSADM_CONTINUE); 143 } 144 145 devfsadm_print(debug_mid, "agp_process: minor=%s node=%s\n", 146 minor_nm, di_node_name(node)); 147 148 devfspath = di_devfs_path(node); 149 if (devfspath == NULL) { 150 devfsadm_print(debug_mid, "agp_process: devfspath is NULL\n"); 151 return (DEVFSADM_CONTINUE); 152 } 153 154 I_path = (char *)malloc(PATH_MAX); 155 156 if (I_path == NULL) { 157 di_devfs_path_free(devfspath); 158 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 159 return (DEVFSADM_CONTINUE); 160 } 161 162 p_path = (char *)malloc(PATH_MAX); 163 164 if (p_path == NULL) { 165 devfsadm_print(debug_mid, "agp_process: malloc failed\n"); 166 di_devfs_path_free(devfspath); 167 free(I_path); 168 return (DEVFSADM_CONTINUE); 169 } 170 171 (void) strlcpy(p_path, devfspath, PATH_MAX); 172 (void) strlcat(p_path, ":", PATH_MAX); 173 (void) strlcat(p_path, minor_nm, PATH_MAX); 174 di_devfs_path_free(devfspath); 175 176 devfsadm_print(debug_mid, "agp_process: path %s\n", p_path); 177 178 for (i = 0; ; i++) { 179 if ((driver_name_table[i].driver_name == NULL) || 180 (strcmp(drv_nm, driver_name_table[i].driver_name) == 0)) { 181 index = driver_name_table[i].index; 182 break; 183 } 184 } 185 switch (index) { 186 case DRIVER_AGPPSEUDO: 187 devfsadm_print(debug_mid, 188 "agp_process: psdeudo driver name\n"); 189 name = "agpgart"; 190 (void) snprintf(I_path, PATH_MAX, "%s", name); 191 devfsadm_print(debug_mid, 192 "mklink %s -> %s\n", I_path, p_path); 193 194 (void) devfsadm_mklink(I_path, node, minor, 0); 195 196 free(I_path); 197 free(p_path); 198 return (DEVFSADM_CONTINUE); 199 case DRIVER_AGPTARGET: 200 devfsadm_print(debug_mid, 201 "agp_process: target driver name\n"); 202 rules[0] = agptarget_rules[0]; 203 name = "agptarget"; 204 break; 205 case DRIVER_CPUGART: 206 devfsadm_print(debug_mid, 207 "agp_process: cpugart driver name\n"); 208 rules[0] = cpugart_rules[0]; 209 name = "cpugart"; 210 break; 211 case DRIVER_AGPMASTER_DRM_I915: 212 case DRIVER_AGPMASTER_DRM_RADEON: 213 case DRIVER_AGPMASTER_VGATEXT: 214 devfsadm_print(debug_mid, 215 "agp_process: agpmaster driver name\n"); 216 rules[0] = agpmaster_rules[0]; 217 name = "agpmaster"; 218 break; 219 case DRIVER_UNKNOWN: 220 devfsadm_print(debug_mid, 221 "agp_process: unknown driver name=%s\n", drv_nm); 222 free(I_path); 223 free(p_path); 224 return (DEVFSADM_CONTINUE); 225 } 226 227 if (devfsadm_enumerate_int(p_path, 0, &buf, rules, 1)) { 228 devfsadm_print(debug_mid, "agp_process: exit/coninue\n"); 229 free(I_path); 230 free(p_path); 231 return (DEVFSADM_CONTINUE); 232 } 233 234 235 (void) snprintf(I_path, PATH_MAX, "agp/%s%s", name, buf); 236 237 devfsadm_print(debug_mid, "agp_process: p_path=%s buf=%s\n", 238 p_path, buf); 239 240 free(buf); 241 242 devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path); 243 244 (void) devfsadm_mklink(I_path, node, minor, 0); 245 246 free(p_path); 247 free(I_path); 248 249 return (DEVFSADM_CONTINUE); 250 } 251 252 static int 253 drm_node(di_minor_t minor, di_node_t node) 254 { 255 char *minor_nm, *drv_nm; 256 char *devfspath; 257 char *I_path, *p_path, *buf; 258 char *name = "card"; 259 260 minor_nm = di_minor_name(minor); 261 drv_nm = di_driver_name(node); 262 if ((minor_nm == NULL) || (drv_nm == NULL)) { 263 return (DEVFSADM_CONTINUE); 264 } 265 266 devfsadm_print(debug_mid, "drm_node: minor=%s node=%s type=%s\n", 267 minor_nm, di_node_name(node), di_minor_nodetype(minor)); 268 269 devfspath = di_devfs_path(node); 270 if (devfspath == NULL) { 271 devfsadm_print(debug_mid, "drm_node: devfspath is NULL\n"); 272 return (DEVFSADM_CONTINUE); 273 } 274 275 I_path = (char *)malloc(PATH_MAX); 276 277 if (I_path == NULL) { 278 di_devfs_path_free(devfspath); 279 devfsadm_print(debug_mid, "drm_node: malloc failed\n"); 280 return (DEVFSADM_CONTINUE); 281 } 282 283 p_path = (char *)malloc(PATH_MAX); 284 285 if (p_path == NULL) { 286 devfsadm_print(debug_mid, "drm_node: malloc failed\n"); 287 di_devfs_path_free(devfspath); 288 free(I_path); 289 return (DEVFSADM_CONTINUE); 290 } 291 292 (void) strlcpy(p_path, devfspath, PATH_MAX); 293 (void) strlcat(p_path, ":", PATH_MAX); 294 (void) strlcat(p_path, minor_nm, PATH_MAX); 295 di_devfs_path_free(devfspath); 296 297 devfsadm_print(debug_mid, "drm_node: p_path %s\n", p_path); 298 299 if (devfsadm_enumerate_int(p_path, 0, &buf, drm_rules, 1)) { 300 free(p_path); 301 devfsadm_print(debug_mid, "drm_node: exit/coninue\n"); 302 return (DEVFSADM_CONTINUE); 303 } 304 (void) snprintf(I_path, PATH_MAX, "dri/%s%s", name, buf); 305 306 devfsadm_print(debug_mid, "drm_node: p_path=%s buf=%s\n", 307 p_path, buf); 308 309 free(buf); 310 311 devfsadm_print(debug_mid, "mklink %s -> %s\n", I_path, p_path); 312 (void) devfsadm_mklink(I_path, node, minor, 0); 313 314 free(p_path); 315 free(I_path); 316 317 return (0); 318 }