1 /* 2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * drm_ioctl.h -- IOCTL processing for DRM -*- linux-c -*- 8 * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com 9 */ 10 /* 11 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 13 * All Rights Reserved. 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a 16 * copy of this software and associated documentation files (the "Software"), 17 * to deal in the Software without restriction, including without limitation 18 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 * and/or sell copies of the Software, and to permit persons to whom the 20 * Software is furnished to do so, subject to the following conditions: 21 * 22 * The above copyright notice and this permission notice (including the next 23 * paragraph) shall be included in all copies or substantial portions of the 24 * Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 29 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 30 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 31 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 32 * OTHER DEALINGS IN THE SOFTWARE. 33 * 34 * Authors: 35 * Rickard E. (Rik) Faith <faith@valinux.com> 36 * Gareth Hughes <gareth@valinux.com> 37 * 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include "drmP.h" 43 44 /* 45 * Beginning in revision 1.1 of the DRM interface, getunique will return 46 * a unique in the form pci:oooo:bb:dd.f (o=domain, b=bus, d=device, f=function) 47 * before setunique has been called. The format for the bus-specific part of 48 * the unique is not defined for any other bus. 49 */ 50 /*ARGSUSED*/ 51 int 52 drm_getunique(DRM_IOCTL_ARGS) 53 { 54 DRM_DEVICE; 55 drm_unique_t u1; 56 57 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 58 drm_unique32_t u32; 59 60 DRM_COPY_FROM_USER_IOCTL(u32, 61 (drm_unique32_t *)data, 62 sizeof (drm_unique32_t)); 63 u1.unique_len = u32.unique_len; 64 u1.unique = (char __user *)(uintptr_t)u32.unique; 65 } else 66 DRM_COPY_FROM_USER_IOCTL( 67 u1, (drm_unique_t *)data, sizeof (u1)); 68 69 if (u1.unique_len >= dev->unique_len) { 70 if (dev->unique_len == 0) { 71 DRM_ERROR("drm_getunique: dev->unique_len = 0"); 72 return (DRM_ERR(EFAULT)); 73 } 74 if (DRM_COPY_TO_USER(u1.unique, dev->unique, dev->unique_len)) 75 return (DRM_ERR(EFAULT)); 76 } 77 u1.unique_len = dev->unique_len; 78 79 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 80 drm_unique32_t u32; 81 82 u32.unique_len = u1.unique_len; 83 u32.unique = (caddr32_t)(uintptr_t)u1.unique; 84 DRM_COPY_TO_USER_IOCTL((drm_unique32_t *)data, u32, 85 sizeof (drm_unique32_t)); 86 } else 87 DRM_COPY_TO_USER_IOCTL((drm_unique_t *)data, u1, sizeof (u1)); 88 89 return (0); 90 } 91 92 /* 93 * Deprecated in DRM version 1.1, and will return EBUSY when setversion has 94 * requested version 1.1 or greater. 95 */ 96 /*ARGSUSED*/ 97 int 98 drm_setunique(DRM_IOCTL_ARGS) 99 { 100 return (DRM_ERR(EINVAL)); 101 } 102 103 104 static int 105 drm_set_busid(drm_device_t *dev) 106 { 107 DRM_LOCK(); 108 109 if (dev->unique != NULL) { 110 DRM_UNLOCK(); 111 return (DRM_ERR(EBUSY)); 112 } 113 114 dev->unique_len = 20; 115 dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); 116 if (dev->unique == NULL) { 117 DRM_UNLOCK(); 118 return (DRM_ERR(ENOMEM)); 119 } 120 121 (void) snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%1x", 122 dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); 123 124 DRM_UNLOCK(); 125 126 return (0); 127 } 128 129 /*ARGSUSED*/ 130 int 131 drm_getmap(DRM_IOCTL_ARGS) 132 { 133 DRM_DEVICE; 134 drm_map_t map; 135 drm_local_map_t *mapinlist; 136 int idx; 137 int i = 0; 138 139 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 140 drm_map32_t map32; 141 142 DRM_COPY_FROM_USER_IOCTL(map32, 143 (drm_map32_t *)data, 144 sizeof (drm_map32_t)); 145 map.offset = map32.offset; 146 map.size = map32.size; 147 map.type = map32.type; 148 map.flags = map32.flags; 149 map.handle = map32.handle; 150 map.mtrr = map32.mtrr; 151 } else 152 DRM_COPY_FROM_USER_IOCTL(map, (drm_map_t *)data, sizeof (map)); 153 154 idx = map.offset; 155 156 DRM_LOCK(); 157 if (idx < 0) { 158 DRM_UNLOCK(); 159 return (DRM_ERR(EINVAL)); 160 } 161 162 TAILQ_FOREACH(mapinlist, &dev->maplist, link) { 163 if (i == idx) { 164 map.offset = mapinlist->offset.off; 165 map.size = mapinlist->size; 166 map.type = mapinlist->type; 167 map.flags = mapinlist->flags; 168 map.handle = (unsigned long long)(uintptr_t) 169 mapinlist->handle; 170 map.mtrr = mapinlist->mtrr; 171 break; 172 } 173 i++; 174 } 175 176 DRM_UNLOCK(); 177 178 if (mapinlist == NULL) 179 return (DRM_ERR(EINVAL)); 180 181 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 182 drm_map32_t map32; 183 184 map32.offset = map.offset; 185 map32.size = map.size; 186 map32.type = map.type; 187 map32.flags = map.flags; 188 map32.handle = map.handle; 189 map32.mtrr = map.mtrr; 190 DRM_COPY_TO_USER_IOCTL((drm_map32_t *)data, map32, 191 sizeof (drm_map32_t)); 192 } else 193 DRM_COPY_TO_USER_IOCTL((drm_map_t *)data, map, sizeof (map)); 194 195 return (0); 196 } 197 198 /*ARGSUSED*/ 199 int 200 drm_getclient(DRM_IOCTL_ARGS) 201 { 202 DRM_DEVICE; 203 drm_client_t client; 204 drm_file_t *pt; 205 int idx; 206 int i = 0; 207 208 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 209 drm_client32_t client32; 210 211 DRM_COPY_FROM_USER_IOCTL(client32, 212 (drm_client32_t *)data, 213 sizeof (drm_client32_t)); 214 client.idx = client32.idx; 215 client.auth = client32.auth; 216 client.pid = client32.pid; 217 client.uid = client32.uid; 218 client.magic = client32.magic; 219 client.iocs = client32.iocs; 220 } else 221 DRM_COPY_FROM_USER_IOCTL( 222 client, (drm_client_t *)data, sizeof (client)); 223 224 idx = client.idx; 225 DRM_LOCK(); 226 TAILQ_FOREACH(pt, &dev->files, link) { 227 if (i == idx) { 228 client.auth = pt->authenticated; 229 client.pid = pt->pid; 230 client.uid = pt->uid; 231 client.magic = pt->magic; 232 client.iocs = pt->ioctl_count; 233 DRM_UNLOCK(); 234 235 236 if (ddi_model_convert_from(mode & FMODELS) == 237 DDI_MODEL_ILP32) { 238 239 drm_client32_t client32; 240 241 client32.idx = client.idx; 242 client32.auth = client.auth; 243 client32.pid = client.pid; 244 client32.uid = client.uid; 245 client32.magic = client.magic; 246 client32.iocs = client.iocs; 247 248 DRM_COPY_TO_USER_IOCTL((drm_client32_t *)data, 249 client32, 250 sizeof (drm_client32_t)); 251 } else 252 DRM_COPY_TO_USER_IOCTL((drm_client_t *)data, 253 client, sizeof (client)); 254 255 return (0); 256 } 257 i++; 258 } 259 DRM_UNLOCK(); 260 return (DRM_ERR(EINVAL)); 261 } 262 263 /*ARGSUSED*/ 264 int 265 drm_getstats(DRM_IOCTL_ARGS) 266 { 267 DRM_DEVICE; 268 drm_stats_t stats; 269 int i; 270 271 bzero(&stats, sizeof (stats)); 272 273 DRM_LOCK(); 274 275 for (i = 0; i < dev->counters; i++) { 276 if (dev->types[i] == _DRM_STAT_LOCK) { 277 stats.data[i].value 278 = (dev->lock.hw_lock 279 ? dev->lock.hw_lock->lock : 0); 280 } else 281 stats.data[i].value = atomic_read(&dev->counts[i]); 282 stats.data[i].type = dev->types[i]; 283 } 284 285 stats.count = dev->counters; 286 287 DRM_UNLOCK(); 288 289 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 290 drm_stats32_t stats32; 291 stats32.count = stats.count; 292 for (i = 0; i < 15; i++) { 293 stats32.data[i].value = stats.data[i].value; 294 stats32.data[i].type = stats.data[i].type; 295 } 296 DRM_COPY_TO_USER_IOCTL((drm_stats32_t *)data, stats32, 297 sizeof (drm_stats32_t)); 298 } else 299 DRM_COPY_TO_USER_IOCTL( 300 (drm_stats_t *)data, stats, sizeof (stats)); 301 302 return (0); 303 } 304 305 #define DRM_IF_MAJOR 1 306 #define DRM_IF_MINOR 2 307 308 /*ARGSUSED*/ 309 int 310 drm_setversion(DRM_IOCTL_ARGS) 311 { 312 DRM_DEVICE; 313 drm_set_version_t sv; 314 drm_set_version_t retv; 315 int if_version; 316 317 DRM_COPY_FROM_USER_IOCTL(sv, (drm_set_version_t *)data, sizeof (sv)); 318 319 retv.drm_di_major = DRM_IF_MAJOR; 320 retv.drm_di_minor = DRM_IF_MINOR; 321 retv.drm_dd_major = dev->driver_major; 322 retv.drm_dd_minor = dev->driver_minor; 323 324 DRM_COPY_TO_USER_IOCTL((drm_set_version_t *)data, retv, sizeof (sv)); 325 326 if (sv.drm_di_major != -1) { 327 if (sv.drm_di_major != DRM_IF_MAJOR || 328 sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) 329 return (DRM_ERR(EINVAL)); 330 if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_dd_minor); 331 dev->if_version = DRM_MAX(if_version, dev->if_version); 332 if (sv.drm_di_minor >= 1) { 333 /* 334 * Version 1.1 includes tying of DRM to specific device 335 */ 336 (void) drm_set_busid(dev); 337 } 338 } 339 340 if (sv.drm_dd_major != -1) { 341 if (sv.drm_dd_major != dev->driver_major || 342 sv.drm_dd_minor < 0 || sv.drm_dd_minor > dev->driver_minor) 343 return (DRM_ERR(EINVAL)); 344 } 345 return (0); 346 } 347 348 349 /*ARGSUSED*/ 350 int 351 drm_noop(DRM_IOCTL_ARGS) 352 { 353 DRM_DEBUG("drm_noop\n"); 354 return (0); 355 } 356 357 /*ARGSUSED*/ 358 int 359 drm_version(DRM_IOCTL_ARGS) 360 { 361 DRM_DEVICE; 362 drm_version_t version; 363 int len; 364 365 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 366 drm_version32_t version32; 367 368 DRM_COPY_FROM_USER_IOCTL(version32, 369 (drm_version32_t *)data, 370 sizeof (drm_version32_t)); 371 version.version_major = version32.version_major; 372 version.version_minor = version32.version_minor; 373 version.version_patchlevel = version32.version_patchlevel; 374 version.name_len = version32.name_len; 375 version.name = (char __user *)(uintptr_t)version32.name; 376 version.date_len = version32.date_len; 377 version.date = (char __user *)(uintptr_t)version32.date; 378 version.desc_len = version32.desc_len; 379 version.desc = (char __user *)(uintptr_t)version32.desc; 380 } else 381 DRM_COPY_FROM_USER_IOCTL( 382 version, (drm_version_t *)data, sizeof (version)); 383 384 #define DRM_COPY(name, value) \ 385 len = strlen(value); \ 386 if (len > name##_len) len = name##_len; \ 387 name##_len = strlen(value); \ 388 if (len && name) { \ 389 if (DRM_COPY_TO_USER(name, value, len)) \ 390 return (DRM_ERR(EFAULT)); \ 391 } 392 393 version.version_major = dev->driver_major; 394 version.version_minor = dev->driver_minor; 395 version.version_patchlevel = dev->driver_patchlevel; 396 397 DRM_COPY(version.name, dev->driver_name); 398 DRM_COPY(version.date, dev->driver_date); 399 DRM_COPY(version.desc, dev->driver_desc); 400 401 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 402 drm_version32_t version32; 403 404 version32.version_major = version.version_major; 405 version32.version_minor = version.version_minor; 406 version32.version_patchlevel = version.version_patchlevel; 407 version32.name_len = version.name_len; 408 version32.name = (caddr32_t)(uintptr_t)version.name; 409 version32.date_len = version.date_len; 410 version32.date = (caddr32_t)(uintptr_t)version.date; 411 version32.desc_len = version.desc_len; 412 version32.desc = (caddr32_t)(uintptr_t)version.desc; 413 DRM_COPY_TO_USER_IOCTL((drm_version32_t *)data, version32, 414 sizeof (drm_version32_t)); 415 } else 416 DRM_COPY_TO_USER_IOCTL( 417 (drm_version_t *)data, version, sizeof (version)); 418 419 return (0); 420 } 421