Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.17-rc4 375 lines 10 kB view raw
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 "drmP.h" 37#include "drm_core.h" 38 39#include "linux/pci.h" 40 41/** 42 * Get the bus id. 43 * 44 * \param inode device inode. 45 * \param filp file pointer. 46 * \param cmd command. 47 * \param arg user argument, pointing to a drm_unique structure. 48 * \return zero on success or a negative number on failure. 49 * 50 * Copies the bus id from drm_device::unique into user space. 51 */ 52int drm_getunique(struct inode *inode, struct file *filp, 53 unsigned int cmd, unsigned long arg) 54{ 55 drm_file_t *priv = filp->private_data; 56 drm_device_t *dev = priv->head->dev; 57 drm_unique_t __user *argp = (void __user *)arg; 58 drm_unique_t u; 59 60 if (copy_from_user(&u, argp, sizeof(u))) 61 return -EFAULT; 62 if (u.unique_len >= dev->unique_len) { 63 if (copy_to_user(u.unique, dev->unique, dev->unique_len)) 64 return -EFAULT; 65 } 66 u.unique_len = dev->unique_len; 67 if (copy_to_user(argp, &u, sizeof(u))) 68 return -EFAULT; 69 return 0; 70} 71 72/** 73 * Set the bus id. 74 * 75 * \param inode device inode. 76 * \param filp file pointer. 77 * \param cmd command. 78 * \param arg user argument, pointing to a drm_unique structure. 79 * \return zero on success or a negative number on failure. 80 * 81 * Copies the bus id from userspace into drm_device::unique, and verifies that 82 * it matches the device this DRM is attached to (EINVAL otherwise). Deprecated 83 * in interface version 1.1 and will return EBUSY when setversion has requested 84 * version 1.1 or greater. 85 */ 86int drm_setunique(struct inode *inode, struct file *filp, 87 unsigned int cmd, unsigned long arg) 88{ 89 drm_file_t *priv = filp->private_data; 90 drm_device_t *dev = priv->head->dev; 91 drm_unique_t u; 92 int domain, bus, slot, func, ret; 93 94 if (dev->unique_len || dev->unique) 95 return -EBUSY; 96 97 if (copy_from_user(&u, (drm_unique_t __user *) arg, sizeof(u))) 98 return -EFAULT; 99 100 if (!u.unique_len || u.unique_len > 1024) 101 return -EINVAL; 102 103 dev->unique_len = u.unique_len; 104 dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER); 105 if (!dev->unique) 106 return -ENOMEM; 107 if (copy_from_user(dev->unique, u.unique, dev->unique_len)) 108 return -EFAULT; 109 110 dev->unique[dev->unique_len] = '\0'; 111 112 dev->devname = 113 drm_alloc(strlen(dev->driver->pci_driver.name) + 114 strlen(dev->unique) + 2, DRM_MEM_DRIVER); 115 if (!dev->devname) 116 return -ENOMEM; 117 118 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, 119 dev->unique); 120 121 /* Return error if the busid submitted doesn't match the device's actual 122 * busid. 123 */ 124 ret = sscanf(dev->unique, "PCI:%d:%d:%d", &bus, &slot, &func); 125 if (ret != 3) 126 return DRM_ERR(EINVAL); 127 domain = bus >> 8; 128 bus &= 0xff; 129 130 if ((domain != dev->pci_domain) || 131 (bus != dev->pci_bus) || 132 (slot != dev->pci_slot) || (func != dev->pci_func)) 133 return -EINVAL; 134 135 return 0; 136} 137 138static int drm_set_busid(drm_device_t * dev) 139{ 140 int len; 141 142 if (dev->unique != NULL) 143 return EBUSY; 144 145 dev->unique_len = 40; 146 dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER); 147 if (dev->unique == NULL) 148 return ENOMEM; 149 150 len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d", 151 dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func); 152 153 if (len > dev->unique_len) 154 DRM_ERROR("Unique buffer overflowed\n"); 155 156 dev->devname = 157 drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len + 158 2, DRM_MEM_DRIVER); 159 if (dev->devname == NULL) 160 return ENOMEM; 161 162 sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name, 163 dev->unique); 164 165 return 0; 166} 167 168/** 169 * Get a mapping information. 170 * 171 * \param inode device inode. 172 * \param filp file pointer. 173 * \param cmd command. 174 * \param arg user argument, pointing to a drm_map structure. 175 * 176 * \return zero on success or a negative number on failure. 177 * 178 * Searches for the mapping with the specified offset and copies its information 179 * into userspace 180 */ 181int drm_getmap(struct inode *inode, struct file *filp, 182 unsigned int cmd, unsigned long arg) 183{ 184 drm_file_t *priv = filp->private_data; 185 drm_device_t *dev = priv->head->dev; 186 drm_map_t __user *argp = (void __user *)arg; 187 drm_map_t map; 188 drm_map_list_t *r_list = NULL; 189 struct list_head *list; 190 int idx; 191 int i; 192 193 if (copy_from_user(&map, argp, sizeof(map))) 194 return -EFAULT; 195 idx = map.offset; 196 197 mutex_lock(&dev->struct_mutex); 198 if (idx < 0) { 199 mutex_unlock(&dev->struct_mutex); 200 return -EINVAL; 201 } 202 203 i = 0; 204 list_for_each(list, &dev->maplist->head) { 205 if (i == idx) { 206 r_list = list_entry(list, drm_map_list_t, head); 207 break; 208 } 209 i++; 210 } 211 if (!r_list || !r_list->map) { 212 mutex_unlock(&dev->struct_mutex); 213 return -EINVAL; 214 } 215 216 map.offset = r_list->map->offset; 217 map.size = r_list->map->size; 218 map.type = r_list->map->type; 219 map.flags = r_list->map->flags; 220 map.handle = (void *)(unsigned long)r_list->user_token; 221 map.mtrr = r_list->map->mtrr; 222 mutex_unlock(&dev->struct_mutex); 223 224 if (copy_to_user(argp, &map, sizeof(map))) 225 return -EFAULT; 226 return 0; 227} 228 229/** 230 * Get client information. 231 * 232 * \param inode device inode. 233 * \param filp file pointer. 234 * \param cmd command. 235 * \param arg user argument, pointing to a drm_client structure. 236 * 237 * \return zero on success or a negative number on failure. 238 * 239 * Searches for the client with the specified index and copies its information 240 * into userspace 241 */ 242int drm_getclient(struct inode *inode, struct file *filp, 243 unsigned int cmd, unsigned long arg) 244{ 245 drm_file_t *priv = filp->private_data; 246 drm_device_t *dev = priv->head->dev; 247 drm_client_t __user *argp = (drm_client_t __user *)arg; 248 drm_client_t client; 249 drm_file_t *pt; 250 int idx; 251 int i; 252 253 if (copy_from_user(&client, argp, sizeof(client))) 254 return -EFAULT; 255 idx = client.idx; 256 mutex_lock(&dev->struct_mutex); 257 for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ; 258 259 if (!pt) { 260 mutex_unlock(&dev->struct_mutex); 261 return -EINVAL; 262 } 263 client.auth = pt->authenticated; 264 client.pid = pt->pid; 265 client.uid = pt->uid; 266 client.magic = pt->magic; 267 client.iocs = pt->ioctl_count; 268 mutex_unlock(&dev->struct_mutex); 269 270 if (copy_to_user(argp, &client, sizeof(client))) 271 return -EFAULT; 272 return 0; 273} 274 275/** 276 * Get statistics information. 277 * 278 * \param inode device inode. 279 * \param filp file pointer. 280 * \param cmd command. 281 * \param arg user argument, pointing to a drm_stats structure. 282 * 283 * \return zero on success or a negative number on failure. 284 */ 285int drm_getstats(struct inode *inode, struct file *filp, 286 unsigned int cmd, unsigned long arg) 287{ 288 drm_file_t *priv = filp->private_data; 289 drm_device_t *dev = priv->head->dev; 290 drm_stats_t stats; 291 int i; 292 293 memset(&stats, 0, sizeof(stats)); 294 295 mutex_lock(&dev->struct_mutex); 296 297 for (i = 0; i < dev->counters; i++) { 298 if (dev->types[i] == _DRM_STAT_LOCK) 299 stats.data[i].value 300 = (dev->lock.hw_lock ? dev->lock.hw_lock->lock : 0); 301 else 302 stats.data[i].value = atomic_read(&dev->counts[i]); 303 stats.data[i].type = dev->types[i]; 304 } 305 306 stats.count = dev->counters; 307 308 mutex_unlock(&dev->struct_mutex); 309 310 if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats))) 311 return -EFAULT; 312 return 0; 313} 314 315/** 316 * Setversion ioctl. 317 * 318 * \param inode device inode. 319 * \param filp file pointer. 320 * \param cmd command. 321 * \param arg user argument, pointing to a drm_lock structure. 322 * \return zero on success or negative number on failure. 323 * 324 * Sets the requested interface version 325 */ 326int drm_setversion(DRM_IOCTL_ARGS) 327{ 328 DRM_DEVICE; 329 drm_set_version_t sv; 330 drm_set_version_t retv; 331 int if_version; 332 drm_set_version_t __user *argp = (void __user *)data; 333 334 DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv)); 335 336 retv.drm_di_major = DRM_IF_MAJOR; 337 retv.drm_di_minor = DRM_IF_MINOR; 338 retv.drm_dd_major = dev->driver->major; 339 retv.drm_dd_minor = dev->driver->minor; 340 341 DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv)); 342 343 if (sv.drm_di_major != -1) { 344 if (sv.drm_di_major != DRM_IF_MAJOR || 345 sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR) 346 return EINVAL; 347 if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor); 348 dev->if_version = DRM_MAX(if_version, dev->if_version); 349 if (sv.drm_di_minor >= 1) { 350 /* 351 * Version 1.1 includes tying of DRM to specific device 352 */ 353 drm_set_busid(dev); 354 } 355 } 356 357 if (sv.drm_dd_major != -1) { 358 if (sv.drm_dd_major != dev->driver->major || 359 sv.drm_dd_minor < 0 360 || sv.drm_dd_minor > dev->driver->minor) 361 return EINVAL; 362 363 if (dev->driver->set_version) 364 dev->driver->set_version(dev, &sv); 365 } 366 return 0; 367} 368 369/** No-op ioctl. */ 370int drm_noop(struct inode *inode, struct file *filp, unsigned int cmd, 371 unsigned long arg) 372{ 373 DRM_DEBUG("\n"); 374 return 0; 375}