1 /** 2 * \file drm_ioctl.c 3 * IOCTL processing for DRM 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Gareth Hughes <gareth@valinux.com> 7 */ 8 9 /* 10 * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com 11 * 12 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 13 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 14 * All Rights Reserved. 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a 17 * copy of this software and associated documentation files (the "Software"), 18 * to deal in the Software without restriction, including without limitation 19 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 * and/or sell copies of the Software, and to permit persons to whom the 21 * Software is furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice (including the next 24 * paragraph) shall be included in all copies or substantial portions of the 25 * Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 * OTHER DEALINGS IN THE SOFTWARE. 34 */ 35 36 #include <drm/drmP.h> 37 #include <drm/drm_core.h> 38 39 #include <linux/pci.h> 40 #include <linux/export.h> 41 #ifdef CONFIG_X86 42 #include <asm/mtrr.h> 43 #endif 44 45 /** 46 * Get the bus id. 47 * 48 * \param inode device inode. 49 * \param file_priv DRM file private. 50 * \param cmd command. 51 * \param arg user argument, pointing to a drm_unique structure. 52 * \return zero on success or a negative number on failure. 53 * 54 * Copies the bus id from drm_device::unique into user space. 55 */ 56 int drm_getunique(struct drm_device *dev, void *data, 57 struct drm_file *file_priv) 58 { 59 struct drm_unique *u = data; 60 struct drm_master *master = file_priv->master; 61 62 if (u->unique_len >= master->unique_len) { 63 if (copy_to_user(u->unique, master->unique, master->unique_len)) 64 return -EFAULT; 65 } 66 u->unique_len = master->unique_len; 67 68 return 0; 69 } 70 71 static void 72 drm_unset_busid(struct drm_device *dev, 73 struct drm_master *master) 74 { 75 kfree(dev->devname); 76 dev->devname = NULL; 77 78 kfree(master->unique); 79 master->unique = NULL; 80 master->unique_len = 0; 81 master->unique_size = 0; 82 } 83 84 /** 85 * Set the bus id. 86 * 87 * \param inode device inode. 88 * \param file_priv DRM file private. 89 * \param cmd command. 90 * \param arg user argument, pointing to a drm_unique structure. 91 * \return zero on success or a negative number on failure. 92 * 93 * Copies the bus id from userspace into drm_device::unique, and verifies that 94 * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated 95 * in interface version 1.1 and will return EBUSY when setversion has requested 96 * version 1.1 or greater. 97 */ 98 int drm_setunique(struct drm_device *dev, void *data, 99 struct drm_file *file_priv) 100 { 101 struct drm_unique *u = data; 102 struct drm_master *master = file_priv->master; 103 int ret; 104 105 if (master->unique_len || master->unique) 106 return -EBUSY; 107 108 if (!u->unique_len || u->unique_len > 1024) 109 return -EINVAL; 110 111 if (!dev->driver->bus->set_unique) 112 return -EINVAL; 113 114 ret = dev->driver->bus->set_unique(dev, master, u); 115 if (ret) 116 goto err; 117 118 return 0; 119 120 err: 121 drm_unset_busid(dev, master); 122 return ret; 123 } 124 125 static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) 126 { 127 struct drm_master *master = file_priv->master; 128 int ret; 129 130 if (master->unique != NULL) 131 drm_unset_busid(dev, master); 132 133 ret = dev->driver->bus->set_busid(dev, master); 134 if (ret) 135 goto err; 136 return 0; 137 err: 138 drm_unset_busid(dev, master); 139 return ret; 140 } 141 142 /** 143 * Get a mapping information. 144 * 145 * \param inode device inode. 146 * \param file_priv DRM file private. 147 * \param cmd command. 148 * \param arg user argument, pointing to a drm_map structure. 149 * 150 * \return zero on success or a negative number on failure. 151 * 152 * Searches for the mapping with the specified offset and copies its information 153 * into userspace 154 */ 155 int drm_getmap(struct drm_device *dev, void *data, 156 struct drm_file *file_priv) 157 { 158 struct drm_map *map = data; 159 struct drm_map_list *r_list = NULL; 160 struct list_head *list; 161 int idx; 162 int i; 163 164 idx = map->offset; 165 if (idx < 0) 166 return -EINVAL; 167 168 i = 0; 169 mutex_lock(&dev->struct_mutex); 170 list_for_each(list, &dev->maplist) { 171 if (i == idx) { 172 r_list = list_entry(list, struct drm_map_list, head); 173 break; 174 } 175 i++; 176 } 177 if (!r_list || !r_list->map) { 178 mutex_unlock(&dev->struct_mutex); 179 return -EINVAL; 180 } 181 182 map->offset = r_list->map->offset; 183 map->size = r_list->map->size; 184 map->type = r_list->map->type; 185 map->flags = r_list->map->flags; 186 map->handle = (void *)(unsigned long) r_list->user_token; 187 188 #ifdef CONFIG_X86 189 /* 190 * There appears to be exactly one user of the mtrr index: dritest. 191 * It's easy enough to keep it working on non-PAT systems. 192 */ 193 map->mtrr = phys_wc_to_mtrr_index(r_list->map->mtrr); 194 #else 195 map->mtrr = -1; 196 #endif 197 198 mutex_unlock(&dev->struct_mutex); 199 200 return 0; 201 } 202 203 /** 204 * Get client information. 205 * 206 * \param inode device inode. 207 * \param file_priv DRM file private. 208 * \param cmd command. 209 * \param arg user argument, pointing to a drm_client structure. 210 * 211 * \return zero on success or a negative number on failure. 212 * 213 * Searches for the client with the specified index and copies its information 214 * into userspace 215 */ 216 int drm_getclient(struct drm_device *dev, void *data, 217 struct drm_file *file_priv) 218 { 219 struct drm_client *client = data; 220 221 /* 222 * Hollowed-out getclient ioctl to keep some dead old drm tests/tools 223 * not breaking completely. Userspace tools stop enumerating one they 224 * get -EINVAL, hence this is the return value we need to hand back for 225 * no clients tracked. 226 * 227 * Unfortunately some clients (*cough* libva *cough*) use this in a fun 228 * attempt to figure out whether they're authenticated or not. Since 229 * that's the only thing they care about, give it to the directly 230 * instead of walking one giant list. 231 */ 232 if (client->idx == 0) { 233 client->auth = file_priv->authenticated; 234 client->pid = pid_vnr(file_priv->pid); 235 client->uid = from_kuid_munged(current_user_ns(), 236 file_priv->uid); 237 client->magic = 0; 238 client->iocs = 0; 239 240 return 0; 241 } else { 242 return -EINVAL; 243 } 244 } 245 246 /** 247 * Get statistics information. 248 * 249 * \param inode device inode. 250 * \param file_priv DRM file private. 251 * \param cmd command. 252 * \param arg user argument, pointing to a drm_stats structure. 253 * 254 * \return zero on success or a negative number on failure. 255 */ 256 int drm_getstats(struct drm_device *dev, void *data, 257 struct drm_file *file_priv) 258 { 259 struct drm_stats *stats = data; 260 261 /* Clear stats to prevent userspace from eating its stack garbage. */ 262 memset(stats, 0, sizeof(*stats)); 263 264 return 0; 265 } 266 267 /** 268 * Get device/driver capabilities 269 */ 270 int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 271 { 272 struct drm_get_cap *req = data; 273 274 req->value = 0; 275 switch (req->capability) { 276 case DRM_CAP_DUMB_BUFFER: 277 if (dev->driver->dumb_create) 278 req->value = 1; 279 break; 280 case DRM_CAP_VBLANK_HIGH_CRTC: 281 req->value = 1; 282 break; 283 case DRM_CAP_DUMB_PREFERRED_DEPTH: 284 req->value = dev->mode_config.preferred_depth; 285 break; 286 case DRM_CAP_DUMB_PREFER_SHADOW: 287 req->value = dev->mode_config.prefer_shadow; 288 break; 289 case DRM_CAP_PRIME: 290 req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0; 291 req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0; 292 break; 293 case DRM_CAP_TIMESTAMP_MONOTONIC: 294 req->value = drm_timestamp_monotonic; 295 break; 296 case DRM_CAP_ASYNC_PAGE_FLIP: 297 req->value = dev->mode_config.async_page_flip; 298 break; 299 case DRM_CAP_CURSOR_WIDTH: 300 if (dev->mode_config.cursor_width) 301 req->value = dev->mode_config.cursor_width; 302 else 303 req->value = 64; 304 break; 305 case DRM_CAP_CURSOR_HEIGHT: 306 if (dev->mode_config.cursor_height) 307 req->value = dev->mode_config.cursor_height; 308 else 309 req->value = 64; 310 break; 311 default: 312 return -EINVAL; 313 } 314 return 0; 315 } 316 317 /** 318 * Set device/driver capabilities 319 */ 320 int 321 drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 322 { 323 struct drm_set_client_cap *req = data; 324 325 switch (req->capability) { 326 case DRM_CLIENT_CAP_STEREO_3D: 327 if (req->value > 1) 328 return -EINVAL; 329 file_priv->stereo_allowed = req->value; 330 break; 331 case DRM_CLIENT_CAP_UNIVERSAL_PLANES: 332 if (!drm_universal_planes) 333 return -EINVAL; 334 if (req->value > 1) 335 return -EINVAL; 336 file_priv->universal_planes = req->value; 337 break; 338 default: 339 return -EINVAL; 340 } 341 342 return 0; 343 } 344 345 /** 346 * Setversion ioctl. 347 * 348 * \param inode device inode. 349 * \param file_priv DRM file private. 350 * \param cmd command. 351 * \param arg user argument, pointing to a drm_lock structure. 352 * \return zero on success or negative number on failure. 353 * 354 * Sets the requested interface version 355 */ 356 int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) 357 { 358 struct drm_set_version *sv = data; 359 int if_version, retcode = 0; 360 361 if (sv->drm_di_major != -1) { 362 if (sv->drm_di_major != DRM_IF_MAJOR || 363 sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { 364 retcode = -EINVAL; 365 goto done; 366 } 367 if_version = DRM_IF_VERSION(sv->drm_di_major, 368 sv->drm_di_minor); 369 dev->if_version = max(if_version, dev->if_version); 370 if (sv->drm_di_minor >= 1) { 371 /* 372 * Version 1.1 includes tying of DRM to specific device 373 * Version 1.4 has proper PCI domain support 374 */ 375 retcode = drm_set_busid(dev, file_priv); 376 if (retcode) 377 goto done; 378 } 379 } 380 381 if (sv->drm_dd_major != -1) { 382 if (sv->drm_dd_major != dev->driver->major || 383 sv->drm_dd_minor < 0 || sv->drm_dd_minor > 384 dev->driver->minor) { 385 retcode = -EINVAL; 386 goto done; 387 } 388 } 389 390 done: 391 sv->drm_di_major = DRM_IF_MAJOR; 392 sv->drm_di_minor = DRM_IF_MINOR; 393 sv->drm_dd_major = dev->driver->major; 394 sv->drm_dd_minor = dev->driver->minor; 395 396 return retcode; 397 } 398 399 /** No-op ioctl. */ 400 int drm_noop(struct drm_device *dev, void *data, 401 struct drm_file *file_priv) 402 { 403 DRM_DEBUG("\n"); 404 return 0; 405 } 406 EXPORT_SYMBOL(drm_noop); 407