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