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 struct drm_file *pt; 221 int idx; 222 int i; 223 224 idx = client->idx; 225 i = 0; 226 227 mutex_lock(&dev->struct_mutex); 228 list_for_each_entry(pt, &dev->filelist, lhead) { 229 if (i++ >= idx) { 230 client->auth = pt->authenticated; 231 client->pid = pid_vnr(pt->pid); 232 client->uid = from_kuid_munged(current_user_ns(), pt->uid); 233 client->magic = pt->magic; 234 client->iocs = pt->ioctl_count; 235 mutex_unlock(&dev->struct_mutex); 236 237 return 0; 238 } 239 } 240 mutex_unlock(&dev->struct_mutex); 241 242 return -EINVAL; 243 } 244 245 /** 246 * Get statistics information. 247 * 248 * \param inode device inode. 249 * \param file_priv DRM file private. 250 * \param cmd command. 251 * \param arg user argument, pointing to a drm_stats structure. 252 * 253 * \return zero on success or a negative number on failure. 254 */ 255 int drm_getstats(struct drm_device *dev, void *data, 256 struct drm_file *file_priv) 257 { 258 struct drm_stats *stats = data; 259 int i; 260 261 memset(stats, 0, sizeof(*stats)); 262 263 for (i = 0; i < dev->counters; i++) { 264 if (dev->types[i] == _DRM_STAT_LOCK) 265 stats->data[i].value = 266 (file_priv->master->lock.hw_lock ? file_priv->master->lock.hw_lock->lock : 0); 267 else 268 stats->data[i].value = atomic_read(&dev->counts[i]); 269 stats->data[i].type = dev->types[i]; 270 } 271 272 stats->count = dev->counters; 273 274 return 0; 275 } 276 277 /** 278 * Get device/driver capabilities 279 */ 280 int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 281 { 282 struct drm_get_cap *req = data; 283 284 req->value = 0; 285 switch (req->capability) { 286 case DRM_CAP_DUMB_BUFFER: 287 if (dev->driver->dumb_create) 288 req->value = 1; 289 break; 290 case DRM_CAP_VBLANK_HIGH_CRTC: 291 req->value = 1; 292 break; 293 case DRM_CAP_DUMB_PREFERRED_DEPTH: 294 req->value = dev->mode_config.preferred_depth; 295 break; 296 case DRM_CAP_DUMB_PREFER_SHADOW: 297 req->value = dev->mode_config.prefer_shadow; 298 break; 299 case DRM_CAP_PRIME: 300 req->value |= dev->driver->prime_fd_to_handle ? DRM_PRIME_CAP_IMPORT : 0; 301 req->value |= dev->driver->prime_handle_to_fd ? DRM_PRIME_CAP_EXPORT : 0; 302 break; 303 case DRM_CAP_TIMESTAMP_MONOTONIC: 304 req->value = drm_timestamp_monotonic; 305 break; 306 default: 307 return -EINVAL; 308 } 309 return 0; 310 } 311 312 /** 313 * Setversion ioctl. 314 * 315 * \param inode device inode. 316 * \param file_priv DRM file private. 317 * \param cmd command. 318 * \param arg user argument, pointing to a drm_lock structure. 319 * \return zero on success or negative number on failure. 320 * 321 * Sets the requested interface version 322 */ 323 int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) 324 { 325 struct drm_set_version *sv = data; 326 int if_version, retcode = 0; 327 328 if (sv->drm_di_major != -1) { 329 if (sv->drm_di_major != DRM_IF_MAJOR || 330 sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { 331 retcode = -EINVAL; 332 goto done; 333 } 334 if_version = DRM_IF_VERSION(sv->drm_di_major, 335 sv->drm_di_minor); 336 dev->if_version = max(if_version, dev->if_version); 337 if (sv->drm_di_minor >= 1) { 338 /* 339 * Version 1.1 includes tying of DRM to specific device 340 * Version 1.4 has proper PCI domain support 341 */ 342 retcode = drm_set_busid(dev, file_priv); 343 if (retcode) 344 goto done; 345 } 346 } 347 348 if (sv->drm_dd_major != -1) { 349 if (sv->drm_dd_major != dev->driver->major || 350 sv->drm_dd_minor < 0 || sv->drm_dd_minor > 351 dev->driver->minor) { 352 retcode = -EINVAL; 353 goto done; 354 } 355 356 if (dev->driver->set_version) 357 dev->driver->set_version(dev, sv); 358 } 359 360 done: 361 sv->drm_di_major = DRM_IF_MAJOR; 362 sv->drm_di_minor = DRM_IF_MINOR; 363 sv->drm_dd_major = dev->driver->major; 364 sv->drm_dd_minor = dev->driver->minor; 365 366 return retcode; 367 } 368 369 /** No-op ioctl. */ 370 int drm_noop(struct drm_device *dev, void *data, 371 struct drm_file *file_priv) 372 { 373 DRM_DEBUG("\n"); 374 return 0; 375 } 376 EXPORT_SYMBOL(drm_noop); 377