17f4dd379Sjsg /* 27f4dd379Sjsg * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com 37f4dd379Sjsg * 47f4dd379Sjsg * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 57f4dd379Sjsg * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 67f4dd379Sjsg * All Rights Reserved. 77f4dd379Sjsg * 87f4dd379Sjsg * Author Rickard E. (Rik) Faith <faith@valinux.com> 97f4dd379Sjsg * Author Gareth Hughes <gareth@valinux.com> 107f4dd379Sjsg * 117f4dd379Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 127f4dd379Sjsg * copy of this software and associated documentation files (the "Software"), 137f4dd379Sjsg * to deal in the Software without restriction, including without limitation 147f4dd379Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 157f4dd379Sjsg * and/or sell copies of the Software, and to permit persons to whom the 167f4dd379Sjsg * Software is furnished to do so, subject to the following conditions: 177f4dd379Sjsg * 187f4dd379Sjsg * The above copyright notice and this permission notice (including the next 197f4dd379Sjsg * paragraph) shall be included in all copies or substantial portions of the 207f4dd379Sjsg * Software. 217f4dd379Sjsg * 227f4dd379Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 237f4dd379Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 247f4dd379Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 257f4dd379Sjsg * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 267f4dd379Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 277f4dd379Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 287f4dd379Sjsg * OTHER DEALINGS IN THE SOFTWARE. 297f4dd379Sjsg */ 307f4dd379Sjsg 317f4dd379Sjsg #include <sys/filio.h> 327f4dd379Sjsg 337f4dd379Sjsg #include <linux/export.h> 347f4dd379Sjsg #include <linux/nospec.h> 35c349dbc7Sjsg #include <linux/pci.h> 36c349dbc7Sjsg #include <linux/uaccess.h> 377f4dd379Sjsg 38c349dbc7Sjsg #include <drm/drm_auth.h> 39c349dbc7Sjsg #include <drm/drm_crtc.h> 40c349dbc7Sjsg #include <drm/drm_drv.h> 41c349dbc7Sjsg #include <drm/drm_file.h> 42c349dbc7Sjsg #include <drm/drm_ioctl.h> 43c349dbc7Sjsg #include <drm/drm_print.h> 44c349dbc7Sjsg 45c349dbc7Sjsg #include "drm_crtc_internal.h" 46c349dbc7Sjsg #include "drm_internal.h" 47c349dbc7Sjsg #include "drm_legacy.h" 487f4dd379Sjsg 497f4dd379Sjsg /** 507f4dd379Sjsg * DOC: getunique and setversion story 517f4dd379Sjsg * 527f4dd379Sjsg * BEWARE THE DRAGONS! MIND THE TRAPDOORS! 537f4dd379Sjsg * 547f4dd379Sjsg * In an attempt to warn anyone else who's trying to figure out what's going 557f4dd379Sjsg * on here, I'll try to summarize the story. First things first, let's clear up 567f4dd379Sjsg * the names, because the kernel internals, libdrm and the ioctls are all named 577f4dd379Sjsg * differently: 587f4dd379Sjsg * 597f4dd379Sjsg * - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm 607f4dd379Sjsg * through the drmGetBusid function. 617f4dd379Sjsg * - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All 627f4dd379Sjsg * that code is nerved in the kernel with drm_invalid_op(). 637f4dd379Sjsg * - The internal set_busid kernel functions and driver callbacks are 647f4dd379Sjsg * exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is 657f4dd379Sjsg * nerved) allowed userspace to set the busid through the above ioctl. 667f4dd379Sjsg * - Other ioctls and functions involved are named consistently. 677f4dd379Sjsg * 687f4dd379Sjsg * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly 697f4dd379Sjsg * handling pci domains in the busid on ppc. Doing this correctly was only 707f4dd379Sjsg * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's 717f4dd379Sjsg * special with drm 1.2 and 1.3. 727f4dd379Sjsg * 737f4dd379Sjsg * Now the actual horror story of how device lookup in drm works. At large, 747f4dd379Sjsg * there's 2 different ways, either by busid, or by device driver name. 757f4dd379Sjsg * 767f4dd379Sjsg * Opening by busid is fairly simple: 777f4dd379Sjsg * 787f4dd379Sjsg * 1. First call SET_VERSION to make sure pci domains are handled properly. As a 797f4dd379Sjsg * side-effect this fills out the unique name in the master structure. 807f4dd379Sjsg * 2. Call GET_UNIQUE to read out the unique name from the master structure, 817f4dd379Sjsg * which matches the busid thanks to step 1. If it doesn't, proceed to try 827f4dd379Sjsg * the next device node. 837f4dd379Sjsg * 847f4dd379Sjsg * Opening by name is slightly different: 857f4dd379Sjsg * 867f4dd379Sjsg * 1. Directly call VERSION to get the version and to match against the driver 877f4dd379Sjsg * name returned by that ioctl. Note that SET_VERSION is not called, which 881bb76ff1Sjsg * means the unique name for the master node just opening is _not_ filled 897f4dd379Sjsg * out. This despite that with current drm device nodes are always bound to 907f4dd379Sjsg * one device, and can't be runtime assigned like with drm 1.0. 917f4dd379Sjsg * 2. Match driver name. If it mismatches, proceed to the next device node. 927f4dd379Sjsg * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by 937f4dd379Sjsg * checking that the first byte in the string is 0). If that's not the case 947f4dd379Sjsg * libdrm skips and proceeds to the next device node. Probably this is just 957f4dd379Sjsg * copypasta from drm 1.0 times where a set unique name meant that the driver 967f4dd379Sjsg * was in use already, but that's just conjecture. 977f4dd379Sjsg * 987f4dd379Sjsg * Long story short: To keep the open by name logic working, GET_UNIQUE must 997f4dd379Sjsg * _not_ return a unique string when SET_VERSION hasn't been called yet, 1007f4dd379Sjsg * otherwise libdrm breaks. Even when that unique string can't ever change, and 1017f4dd379Sjsg * is totally irrelevant for actually opening the device because runtime 1027f4dd379Sjsg * assignable device instances were only support in drm 1.0, which is long dead. 1037f4dd379Sjsg * But the libdrm code in drmOpenByName somehow survived, hence this can't be 1047f4dd379Sjsg * broken. 1057f4dd379Sjsg */ 1067f4dd379Sjsg 1077f4dd379Sjsg /* 1087f4dd379Sjsg * Get the bus id. 1097f4dd379Sjsg * 1107f4dd379Sjsg * \param inode device inode. 1117f4dd379Sjsg * \param file_priv DRM file private. 1127f4dd379Sjsg * \param cmd command. 1137f4dd379Sjsg * \param arg user argument, pointing to a drm_unique structure. 1147f4dd379Sjsg * \return zero on success or a negative number on failure. 1157f4dd379Sjsg * 1167f4dd379Sjsg * Copies the bus id from drm_device::unique into user space. 1177f4dd379Sjsg */ 1187f4dd379Sjsg int drm_getunique(struct drm_device *dev, void *data, 1197f4dd379Sjsg struct drm_file *file_priv) 1207f4dd379Sjsg { 1217f4dd379Sjsg struct drm_unique *u = data; 122ad8b1aafSjsg struct drm_master *master; 1237f4dd379Sjsg 124ad8b1aafSjsg mutex_lock(&dev->master_mutex); 125ad8b1aafSjsg master = file_priv->master; 126c349dbc7Sjsg if (u->unique_len >= master->unique_len) { 127c349dbc7Sjsg if (copy_to_user(u->unique, master->unique, master->unique_len)) { 128ad8b1aafSjsg mutex_unlock(&dev->master_mutex); 1297f4dd379Sjsg return -EFAULT; 1307f4dd379Sjsg } 131c349dbc7Sjsg } 132c349dbc7Sjsg u->unique_len = master->unique_len; 133ad8b1aafSjsg mutex_unlock(&dev->master_mutex); 134c349dbc7Sjsg 135c349dbc7Sjsg return 0; 136c349dbc7Sjsg } 137c349dbc7Sjsg 138c349dbc7Sjsg static void 139c349dbc7Sjsg drm_unset_busid(struct drm_device *dev, 140c349dbc7Sjsg struct drm_master *master) 141c349dbc7Sjsg { 142c349dbc7Sjsg kfree(master->unique); 143c349dbc7Sjsg master->unique = NULL; 144c349dbc7Sjsg master->unique_len = 0; 145c349dbc7Sjsg } 146c349dbc7Sjsg 147c349dbc7Sjsg static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) 148c349dbc7Sjsg { 149c349dbc7Sjsg struct drm_master *master = file_priv->master; 150c349dbc7Sjsg int ret; 151c349dbc7Sjsg 152c349dbc7Sjsg if (master->unique != NULL) 153c349dbc7Sjsg drm_unset_busid(dev, master); 154c349dbc7Sjsg 155c349dbc7Sjsg #ifdef __linux__ 156c349dbc7Sjsg if (dev->dev && dev_is_pci(dev->dev)) { 157c349dbc7Sjsg #else 158c349dbc7Sjsg if (1) { 159c349dbc7Sjsg #endif 160c349dbc7Sjsg ret = drm_pci_set_busid(dev, master); 161c349dbc7Sjsg if (ret) { 162c349dbc7Sjsg drm_unset_busid(dev, master); 163c349dbc7Sjsg return ret; 164c349dbc7Sjsg } 165c349dbc7Sjsg } else { 166c349dbc7Sjsg WARN_ON(!dev->unique); 167c349dbc7Sjsg master->unique = kstrdup(dev->unique, GFP_KERNEL); 168c349dbc7Sjsg if (master->unique) 169c349dbc7Sjsg master->unique_len = strlen(dev->unique); 170c349dbc7Sjsg } 1717f4dd379Sjsg 1727f4dd379Sjsg return 0; 1737f4dd379Sjsg } 1747f4dd379Sjsg 1757f4dd379Sjsg /* 1767f4dd379Sjsg * Get client information. 1777f4dd379Sjsg * 1787f4dd379Sjsg * \param inode device inode. 1797f4dd379Sjsg * \param file_priv DRM file private. 1807f4dd379Sjsg * \param cmd command. 1817f4dd379Sjsg * \param arg user argument, pointing to a drm_client structure. 1827f4dd379Sjsg * 1837f4dd379Sjsg * \return zero on success or a negative number on failure. 1847f4dd379Sjsg * 1857f4dd379Sjsg * Searches for the client with the specified index and copies its information 1867f4dd379Sjsg * into userspace 1877f4dd379Sjsg */ 1887f4dd379Sjsg int drm_getclient(struct drm_device *dev, void *data, 1897f4dd379Sjsg struct drm_file *file_priv) 1907f4dd379Sjsg { 1917f4dd379Sjsg struct drm_client *client = data; 1927f4dd379Sjsg 1937f4dd379Sjsg /* 1947f4dd379Sjsg * Hollowed-out getclient ioctl to keep some dead old drm tests/tools 1957f4dd379Sjsg * not breaking completely. Userspace tools stop enumerating one they 1967f4dd379Sjsg * get -EINVAL, hence this is the return value we need to hand back for 1977f4dd379Sjsg * no clients tracked. 1987f4dd379Sjsg * 1997f4dd379Sjsg * Unfortunately some clients (*cough* libva *cough*) use this in a fun 2007f4dd379Sjsg * attempt to figure out whether they're authenticated or not. Since 2017f4dd379Sjsg * that's the only thing they care about, give it to the directly 2027f4dd379Sjsg * instead of walking one giant list. 2037f4dd379Sjsg */ 2047f4dd379Sjsg if (client->idx == 0) { 2057f4dd379Sjsg client->auth = file_priv->authenticated; 2067f4dd379Sjsg #ifdef __linux__ 2077f4dd379Sjsg client->pid = task_pid_vnr(current); 2087f4dd379Sjsg client->uid = overflowuid; 2097f4dd379Sjsg #else 2107f4dd379Sjsg client->pid = curproc->p_p->ps_pid; 2117f4dd379Sjsg client->uid = 0xfffe; 2127f4dd379Sjsg #endif 2137f4dd379Sjsg client->magic = 0; 2147f4dd379Sjsg client->iocs = 0; 2157f4dd379Sjsg 2167f4dd379Sjsg return 0; 2177f4dd379Sjsg } else { 2187f4dd379Sjsg return -EINVAL; 2197f4dd379Sjsg } 2207f4dd379Sjsg } 2217f4dd379Sjsg 2227f4dd379Sjsg /* 2237f4dd379Sjsg * Get statistics information. 2247f4dd379Sjsg * 2257f4dd379Sjsg * \param inode device inode. 2267f4dd379Sjsg * \param file_priv DRM file private. 2277f4dd379Sjsg * \param cmd command. 2287f4dd379Sjsg * \param arg user argument, pointing to a drm_stats structure. 2297f4dd379Sjsg * 2307f4dd379Sjsg * \return zero on success or a negative number on failure. 2317f4dd379Sjsg */ 2327f4dd379Sjsg static int drm_getstats(struct drm_device *dev, void *data, 2337f4dd379Sjsg struct drm_file *file_priv) 2347f4dd379Sjsg { 2357f4dd379Sjsg struct drm_stats *stats = data; 2367f4dd379Sjsg 2377f4dd379Sjsg /* Clear stats to prevent userspace from eating its stack garbage. */ 2387f4dd379Sjsg memset(stats, 0, sizeof(*stats)); 2397f4dd379Sjsg 2407f4dd379Sjsg return 0; 2417f4dd379Sjsg } 2427f4dd379Sjsg 2437f4dd379Sjsg /* 2447f4dd379Sjsg * Get device/driver capabilities 2457f4dd379Sjsg */ 2467f4dd379Sjsg static int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 2477f4dd379Sjsg { 2487f4dd379Sjsg struct drm_get_cap *req = data; 2497f4dd379Sjsg struct drm_crtc *crtc; 2507f4dd379Sjsg 2517f4dd379Sjsg req->value = 0; 2527f4dd379Sjsg 2537f4dd379Sjsg /* Only some caps make sense with UMS/render-only drivers. */ 2547f4dd379Sjsg switch (req->capability) { 2557f4dd379Sjsg case DRM_CAP_TIMESTAMP_MONOTONIC: 2567f4dd379Sjsg req->value = 1; 2577f4dd379Sjsg return 0; 2587f4dd379Sjsg case DRM_CAP_PRIME: 259*f005ef32Sjsg req->value = DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT; 2607f4dd379Sjsg return 0; 2617f4dd379Sjsg case DRM_CAP_SYNCOBJ: 2627f4dd379Sjsg req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ); 2637f4dd379Sjsg return 0; 264c349dbc7Sjsg case DRM_CAP_SYNCOBJ_TIMELINE: 265c349dbc7Sjsg req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE); 266c349dbc7Sjsg return 0; 2677f4dd379Sjsg } 2687f4dd379Sjsg 2697f4dd379Sjsg /* Other caps only work with KMS drivers */ 2707f4dd379Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 271c349dbc7Sjsg return -EOPNOTSUPP; 2727f4dd379Sjsg 2737f4dd379Sjsg switch (req->capability) { 2747f4dd379Sjsg case DRM_CAP_DUMB_BUFFER: 2757f4dd379Sjsg if (dev->driver->dumb_create) 2767f4dd379Sjsg req->value = 1; 2777f4dd379Sjsg break; 2787f4dd379Sjsg case DRM_CAP_VBLANK_HIGH_CRTC: 2797f4dd379Sjsg req->value = 1; 2807f4dd379Sjsg break; 2817f4dd379Sjsg case DRM_CAP_DUMB_PREFERRED_DEPTH: 2827f4dd379Sjsg req->value = dev->mode_config.preferred_depth; 2837f4dd379Sjsg break; 2847f4dd379Sjsg case DRM_CAP_DUMB_PREFER_SHADOW: 2857f4dd379Sjsg req->value = dev->mode_config.prefer_shadow; 2867f4dd379Sjsg break; 2877f4dd379Sjsg case DRM_CAP_ASYNC_PAGE_FLIP: 2887f4dd379Sjsg req->value = dev->mode_config.async_page_flip; 2897f4dd379Sjsg break; 2907f4dd379Sjsg case DRM_CAP_PAGE_FLIP_TARGET: 2917f4dd379Sjsg req->value = 1; 2927f4dd379Sjsg drm_for_each_crtc(crtc, dev) { 2937f4dd379Sjsg if (!crtc->funcs->page_flip_target) 2947f4dd379Sjsg req->value = 0; 2957f4dd379Sjsg } 2967f4dd379Sjsg break; 2977f4dd379Sjsg case DRM_CAP_CURSOR_WIDTH: 2987f4dd379Sjsg if (dev->mode_config.cursor_width) 2997f4dd379Sjsg req->value = dev->mode_config.cursor_width; 3007f4dd379Sjsg else 3017f4dd379Sjsg req->value = 64; 3027f4dd379Sjsg break; 3037f4dd379Sjsg case DRM_CAP_CURSOR_HEIGHT: 3047f4dd379Sjsg if (dev->mode_config.cursor_height) 3057f4dd379Sjsg req->value = dev->mode_config.cursor_height; 3067f4dd379Sjsg else 3077f4dd379Sjsg req->value = 64; 3087f4dd379Sjsg break; 3097f4dd379Sjsg case DRM_CAP_ADDFB2_MODIFIERS: 3101bb76ff1Sjsg req->value = !dev->mode_config.fb_modifiers_not_supported; 3117f4dd379Sjsg break; 3127f4dd379Sjsg case DRM_CAP_CRTC_IN_VBLANK_EVENT: 3137f4dd379Sjsg req->value = 1; 3147f4dd379Sjsg break; 3157f4dd379Sjsg default: 3167f4dd379Sjsg return -EINVAL; 3177f4dd379Sjsg } 3187f4dd379Sjsg return 0; 3197f4dd379Sjsg } 3207f4dd379Sjsg 3217f4dd379Sjsg /* 3227f4dd379Sjsg * Set device/driver capabilities 3237f4dd379Sjsg */ 3247f4dd379Sjsg static int 3257f4dd379Sjsg drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 3267f4dd379Sjsg { 3277f4dd379Sjsg struct drm_set_client_cap *req = data; 3287f4dd379Sjsg 329c349dbc7Sjsg /* No render-only settable capabilities for now */ 330c349dbc7Sjsg 331c349dbc7Sjsg /* Below caps that only works with KMS drivers */ 332c349dbc7Sjsg if (!drm_core_check_feature(dev, DRIVER_MODESET)) 333c349dbc7Sjsg return -EOPNOTSUPP; 334c349dbc7Sjsg 3357f4dd379Sjsg switch (req->capability) { 3367f4dd379Sjsg case DRM_CLIENT_CAP_STEREO_3D: 3377f4dd379Sjsg if (req->value > 1) 3387f4dd379Sjsg return -EINVAL; 3397f4dd379Sjsg file_priv->stereo_allowed = req->value; 3407f4dd379Sjsg break; 3417f4dd379Sjsg case DRM_CLIENT_CAP_UNIVERSAL_PLANES: 3427f4dd379Sjsg if (req->value > 1) 3437f4dd379Sjsg return -EINVAL; 3447f4dd379Sjsg file_priv->universal_planes = req->value; 3457f4dd379Sjsg break; 3467f4dd379Sjsg case DRM_CLIENT_CAP_ATOMIC: 3477f4dd379Sjsg if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) 348c349dbc7Sjsg return -EOPNOTSUPP; 349839f7415Sjsg /* The modesetting DDX has a totally broken idea of atomic. */ 350839f7415Sjsg #ifdef __linux__ 351839f7415Sjsg if (current->comm[0] == 'X' && req->value == 1) { 352839f7415Sjsg #else 353839f7415Sjsg if (curproc->p_p->ps_comm[0] == 'X' && req->value == 1) { 354839f7415Sjsg #endif 355839f7415Sjsg pr_info("broken atomic modeset userspace detected, disabling atomic\n"); 356839f7415Sjsg return -EOPNOTSUPP; 357839f7415Sjsg } 358839f7415Sjsg if (req->value > 2) 3597f4dd379Sjsg return -EINVAL; 3607f4dd379Sjsg file_priv->atomic = req->value; 3617f4dd379Sjsg file_priv->universal_planes = req->value; 3627f4dd379Sjsg /* 3637f4dd379Sjsg * No atomic user-space blows up on aspect ratio mode bits. 3647f4dd379Sjsg */ 3657f4dd379Sjsg file_priv->aspect_ratio_allowed = req->value; 3667f4dd379Sjsg break; 3677f4dd379Sjsg case DRM_CLIENT_CAP_ASPECT_RATIO: 3687f4dd379Sjsg if (req->value > 1) 3697f4dd379Sjsg return -EINVAL; 3707f4dd379Sjsg file_priv->aspect_ratio_allowed = req->value; 3717f4dd379Sjsg break; 3727f4dd379Sjsg case DRM_CLIENT_CAP_WRITEBACK_CONNECTORS: 3737f4dd379Sjsg if (!file_priv->atomic) 3747f4dd379Sjsg return -EINVAL; 3757f4dd379Sjsg if (req->value > 1) 3767f4dd379Sjsg return -EINVAL; 3777f4dd379Sjsg file_priv->writeback_connectors = req->value; 3787f4dd379Sjsg break; 3797f4dd379Sjsg default: 3807f4dd379Sjsg return -EINVAL; 3817f4dd379Sjsg } 3827f4dd379Sjsg 3837f4dd379Sjsg return 0; 3847f4dd379Sjsg } 3857f4dd379Sjsg 3867f4dd379Sjsg /* 3877f4dd379Sjsg * Setversion ioctl. 3887f4dd379Sjsg * 3897f4dd379Sjsg * \param inode device inode. 3907f4dd379Sjsg * \param file_priv DRM file private. 3917f4dd379Sjsg * \param cmd command. 3927f4dd379Sjsg * \param arg user argument, pointing to a drm_lock structure. 3937f4dd379Sjsg * \return zero on success or negative number on failure. 3947f4dd379Sjsg * 3957f4dd379Sjsg * Sets the requested interface version 3967f4dd379Sjsg */ 3977f4dd379Sjsg static int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) 3987f4dd379Sjsg { 399c349dbc7Sjsg struct drm_set_version *sv = data; 400c349dbc7Sjsg int if_version, retcode = 0; 4017f4dd379Sjsg 402c349dbc7Sjsg mutex_lock(&dev->master_mutex); 403c349dbc7Sjsg if (sv->drm_di_major != -1) { 404c349dbc7Sjsg if (sv->drm_di_major != DRM_IF_MAJOR || 405c349dbc7Sjsg sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { 406c349dbc7Sjsg retcode = -EINVAL; 407c349dbc7Sjsg goto done; 408c349dbc7Sjsg } 409c349dbc7Sjsg if_version = DRM_IF_VERSION(sv->drm_di_major, 410c349dbc7Sjsg sv->drm_di_minor); 411c349dbc7Sjsg dev->if_version = max(if_version, dev->if_version); 412c349dbc7Sjsg if (sv->drm_di_minor >= 1) { 413c349dbc7Sjsg /* 414c349dbc7Sjsg * Version 1.1 includes tying of DRM to specific device 415c349dbc7Sjsg * Version 1.4 has proper PCI domain support 4167f4dd379Sjsg */ 417c349dbc7Sjsg retcode = drm_set_busid(dev, file_priv); 418c349dbc7Sjsg if (retcode) 419c349dbc7Sjsg goto done; 420c349dbc7Sjsg } 421c349dbc7Sjsg } 422c349dbc7Sjsg 423c349dbc7Sjsg if (sv->drm_dd_major != -1) { 424c349dbc7Sjsg if (sv->drm_dd_major != dev->driver->major || 425c349dbc7Sjsg sv->drm_dd_minor < 0 || sv->drm_dd_minor > 426c349dbc7Sjsg dev->driver->minor) { 427c349dbc7Sjsg retcode = -EINVAL; 428c349dbc7Sjsg goto done; 429c349dbc7Sjsg } 430c349dbc7Sjsg } 431c349dbc7Sjsg 432c349dbc7Sjsg done: 4337f4dd379Sjsg sv->drm_di_major = DRM_IF_MAJOR; 4347f4dd379Sjsg sv->drm_di_minor = DRM_IF_MINOR; 4357f4dd379Sjsg sv->drm_dd_major = dev->driver->major; 4367f4dd379Sjsg sv->drm_dd_minor = dev->driver->minor; 437c349dbc7Sjsg mutex_unlock(&dev->master_mutex); 4387f4dd379Sjsg 439c349dbc7Sjsg return retcode; 4407f4dd379Sjsg } 4417f4dd379Sjsg 4427f4dd379Sjsg /** 4435ca02815Sjsg * drm_noop - DRM no-op ioctl implementation 4447f4dd379Sjsg * @dev: DRM device for the ioctl 4457f4dd379Sjsg * @data: data pointer for the ioctl 4467f4dd379Sjsg * @file_priv: DRM file for the ioctl call 4477f4dd379Sjsg * 4487f4dd379Sjsg * This no-op implementation for drm ioctls is useful for deprecated 4497f4dd379Sjsg * functionality where we can't return a failure code because existing userspace 4507f4dd379Sjsg * checks the result of the ioctl, but doesn't care about the action. 4517f4dd379Sjsg * 4527f4dd379Sjsg * Always returns successfully with 0. 4537f4dd379Sjsg */ 4547f4dd379Sjsg int drm_noop(struct drm_device *dev, void *data, 4557f4dd379Sjsg struct drm_file *file_priv) 4567f4dd379Sjsg { 457*f005ef32Sjsg drm_dbg_core(dev, "\n"); 4587f4dd379Sjsg return 0; 4597f4dd379Sjsg } 4607f4dd379Sjsg EXPORT_SYMBOL(drm_noop); 4617f4dd379Sjsg 4627f4dd379Sjsg /** 4635ca02815Sjsg * drm_invalid_op - DRM invalid ioctl implementation 4647f4dd379Sjsg * @dev: DRM device for the ioctl 4657f4dd379Sjsg * @data: data pointer for the ioctl 4667f4dd379Sjsg * @file_priv: DRM file for the ioctl call 4677f4dd379Sjsg * 4687f4dd379Sjsg * This no-op implementation for drm ioctls is useful for deprecated 4697f4dd379Sjsg * functionality where we really don't want to allow userspace to call the ioctl 4707f4dd379Sjsg * any more. This is the case for old ums interfaces for drivers that 4717f4dd379Sjsg * transitioned to kms gradually and so kept the old legacy tables around. This 4727f4dd379Sjsg * only applies to radeon and i915 kms drivers, other drivers shouldn't need to 4737f4dd379Sjsg * use this function. 4747f4dd379Sjsg * 4757f4dd379Sjsg * Always fails with a return value of -EINVAL. 4767f4dd379Sjsg */ 4777f4dd379Sjsg int drm_invalid_op(struct drm_device *dev, void *data, 4787f4dd379Sjsg struct drm_file *file_priv) 4797f4dd379Sjsg { 4807f4dd379Sjsg return -EINVAL; 4817f4dd379Sjsg } 4827f4dd379Sjsg EXPORT_SYMBOL(drm_invalid_op); 4837f4dd379Sjsg 4847f4dd379Sjsg /* 485c349dbc7Sjsg * Copy and IOCTL return string to user space 486c349dbc7Sjsg */ 487c349dbc7Sjsg static int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) 488c349dbc7Sjsg { 4891bb76ff1Sjsg size_t len; 4901bb76ff1Sjsg 4911bb76ff1Sjsg /* don't attempt to copy a NULL pointer */ 4921bb76ff1Sjsg if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) { 4931bb76ff1Sjsg *buf_len = 0; 4941bb76ff1Sjsg return 0; 4951bb76ff1Sjsg } 496c349dbc7Sjsg 497c349dbc7Sjsg /* don't overflow userbuf */ 498c349dbc7Sjsg len = strlen(value); 499c349dbc7Sjsg if (len > *buf_len) 500c349dbc7Sjsg len = *buf_len; 501c349dbc7Sjsg 502c349dbc7Sjsg /* let userspace know exact length of driver value (which could be 503c349dbc7Sjsg * larger than the userspace-supplied buffer) */ 504c349dbc7Sjsg *buf_len = strlen(value); 505c349dbc7Sjsg 506c349dbc7Sjsg /* finally, try filling in the userbuf */ 507c349dbc7Sjsg if (len && buf) 508c349dbc7Sjsg if (copy_to_user(buf, value, len)) 509c349dbc7Sjsg return -EFAULT; 510c349dbc7Sjsg return 0; 511c349dbc7Sjsg } 512c349dbc7Sjsg 513c349dbc7Sjsg /* 5147f4dd379Sjsg * Get version information 5157f4dd379Sjsg * 5167f4dd379Sjsg * \param inode device inode. 5177f4dd379Sjsg * \param filp file pointer. 5187f4dd379Sjsg * \param cmd command. 5197f4dd379Sjsg * \param arg user argument, pointing to a drm_version structure. 5207f4dd379Sjsg * \return zero on success or negative number on failure. 5217f4dd379Sjsg * 5227f4dd379Sjsg * Fills in the version information in \p arg. 5237f4dd379Sjsg */ 5247f4dd379Sjsg int drm_version(struct drm_device *dev, void *data, 5257f4dd379Sjsg struct drm_file *file_priv) 5267f4dd379Sjsg { 5277f4dd379Sjsg struct drm_version *version = data; 528c349dbc7Sjsg int err; 5297f4dd379Sjsg 5307f4dd379Sjsg version->version_major = dev->driver->major; 5317f4dd379Sjsg version->version_minor = dev->driver->minor; 5327f4dd379Sjsg version->version_patchlevel = dev->driver->patchlevel; 533c349dbc7Sjsg err = drm_copy_field(version->name, &version->name_len, 534c349dbc7Sjsg dev->driver->name); 535c349dbc7Sjsg if (!err) 536c349dbc7Sjsg err = drm_copy_field(version->date, &version->date_len, 537c349dbc7Sjsg dev->driver->date); 538c349dbc7Sjsg if (!err) 539c349dbc7Sjsg err = drm_copy_field(version->desc, &version->desc_len, 540c349dbc7Sjsg dev->driver->desc); 5417f4dd379Sjsg 542c349dbc7Sjsg return err; 543c349dbc7Sjsg } 544c349dbc7Sjsg 5451bb76ff1Sjsg static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) 546c349dbc7Sjsg { 547c349dbc7Sjsg /* ROOT_ONLY is only for CAP_SYS_ADMIN */ 548c349dbc7Sjsg if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN))) 549c349dbc7Sjsg return -EACCES; 550c349dbc7Sjsg 551c349dbc7Sjsg /* AUTH is only for authenticated or render client */ 552c349dbc7Sjsg if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) && 553c349dbc7Sjsg !file_priv->authenticated)) 554c349dbc7Sjsg return -EACCES; 555c349dbc7Sjsg 556c349dbc7Sjsg /* MASTER is only for master or control clients */ 557c349dbc7Sjsg if (unlikely((flags & DRM_MASTER) && 558c349dbc7Sjsg !drm_is_current_master(file_priv))) 559c349dbc7Sjsg return -EACCES; 560c349dbc7Sjsg 561c349dbc7Sjsg /* Render clients must be explicitly allowed */ 562c349dbc7Sjsg if (unlikely(!(flags & DRM_RENDER_ALLOW) && 563c349dbc7Sjsg drm_is_render_client(file_priv))) 564c349dbc7Sjsg return -EACCES; 5657f4dd379Sjsg 5667f4dd379Sjsg return 0; 5677f4dd379Sjsg } 5687f4dd379Sjsg 5697f4dd379Sjsg #define DRM_IOCTL_DEF(ioctl, _func, _flags) \ 570c349dbc7Sjsg [DRM_IOCTL_NR(ioctl)] = { \ 571c349dbc7Sjsg .cmd = ioctl, \ 572c349dbc7Sjsg .func = _func, \ 573c349dbc7Sjsg .flags = _flags, \ 574c349dbc7Sjsg .name = #ioctl \ 575c349dbc7Sjsg } 576c349dbc7Sjsg 577c349dbc7Sjsg #if IS_ENABLED(CONFIG_DRM_LEGACY) 578c349dbc7Sjsg #define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, _func, _flags) 579c349dbc7Sjsg #else 580c349dbc7Sjsg #define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, drm_invalid_op, _flags) 581c349dbc7Sjsg #endif 5827f4dd379Sjsg 5837f4dd379Sjsg /* Ioctl table */ 5847f4dd379Sjsg static const struct drm_ioctl_desc drm_ioctls[] = { 585c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_RENDER_ALLOW), 586c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), 587c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), 5887f4dd379Sjsg #ifdef __linux__ 5895ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_legacy_irq_by_busid, 5905ca02815Sjsg DRM_MASTER|DRM_ROOT_ONLY), 5917f4dd379Sjsg #endif 592c349dbc7Sjsg 593c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, 0), 594c349dbc7Sjsg 595c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), 596c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), 597c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_RENDER_ALLOW), 598c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), 599c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), 6007f4dd379Sjsg 6017f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6027f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6037f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 604c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER), 6057f4dd379Sjsg 6067f4dd379Sjsg #ifdef __linux__ 607c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6087f4dd379Sjsg #else 6097f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GET_PCIINFO, drm_getpciinfo, DRM_UNLOCKED|DRM_RENDER_ALLOW), 6107f4dd379Sjsg #endif 611c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), 612c349dbc7Sjsg 613c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 614c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), 6157f4dd379Sjsg 6167f4dd379Sjsg #ifdef __linux__ 617ad8b1aafSjsg DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0), 618ad8b1aafSjsg DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0), 6197f4dd379Sjsg #else 6207f4dd379Sjsg /* On OpenBSD xorg privdrop has already occurred before this point */ 621c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_noop, DRM_UNLOCKED), 622c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_noop, DRM_UNLOCKED), 6237f4dd379Sjsg #endif 6247f4dd379Sjsg 625c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), 626c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 627c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 628c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH), 629c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 630c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 631c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH), 6327f4dd379Sjsg 6337f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6347f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6357f4dd379Sjsg 636c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_LOCK, drm_legacy_lock, DRM_AUTH), 637c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_legacy_unlock, DRM_AUTH), 6387f4dd379Sjsg 6397f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), 6407f4dd379Sjsg 641c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_legacy_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 642c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_legacy_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 643c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_legacy_infobufs, DRM_AUTH), 644c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_legacy_mapbufs, DRM_AUTH), 645c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_legacy_freebufs, DRM_AUTH), 646c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_DMA, drm_legacy_dma_ioctl, DRM_AUTH), 647c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_legacy_irq_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6487f4dd379Sjsg 649c349dbc7Sjsg #if IS_ENABLED(CONFIG_AGP) && defined(__linux__) 6505ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_legacy_agp_acquire_ioctl, 6515ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6525ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_legacy_agp_release_ioctl, 6535ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6545ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_legacy_agp_enable_ioctl, 6555ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6565ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_legacy_agp_info_ioctl, DRM_AUTH), 6575ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_legacy_agp_alloc_ioctl, 6585ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6595ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_legacy_agp_free_ioctl, 6605ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6615ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_legacy_agp_bind_ioctl, 6625ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6635ca02815Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_legacy_agp_unbind_ioctl, 6645ca02815Sjsg DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6657f4dd379Sjsg #endif 6667f4dd379Sjsg 667c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 668c349dbc7Sjsg DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6697f4dd379Sjsg 6707f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), 6717f4dd379Sjsg 6727f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_legacy_modeset_ctl_ioctl, 0), 6737f4dd379Sjsg 6747f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 6757f4dd379Sjsg 676c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW), 677c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), 678c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), 6797f4dd379Sjsg 680c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0), 6817f4dd379Sjsg 682c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_RENDER_ALLOW), 683c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_RENDER_ALLOW), 6847f4dd379Sjsg 685c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, 0), 686c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, 0), 687c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER), 688c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, 0), 689c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER), 690c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER), 691c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, 0), 692c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), 693c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, 0), 694c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0), 695c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER), 696c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER), 697c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, 0), 698c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER), 699c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, 0), 700c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, 0), 701c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB2, drm_mode_getfb2_ioctl, 0), 702c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), 703c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), 704c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), 705c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), 706c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), 707c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), 708c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0), 709c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, 0), 710c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, 0), 711c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER), 712c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER), 713c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER), 714c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATEPROPBLOB, drm_mode_createblob_ioctl, 0), 715c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROYPROPBLOB, drm_mode_destroyblob_ioctl, 0), 7167f4dd379Sjsg 7177f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_CREATE, drm_syncobj_create_ioctl, 718c349dbc7Sjsg DRM_RENDER_ALLOW), 7197f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_DESTROY, drm_syncobj_destroy_ioctl, 720c349dbc7Sjsg DRM_RENDER_ALLOW), 7217f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, drm_syncobj_handle_to_fd_ioctl, 722c349dbc7Sjsg DRM_RENDER_ALLOW), 7237f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, drm_syncobj_fd_to_handle_ioctl, 724c349dbc7Sjsg DRM_RENDER_ALLOW), 725c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TRANSFER, drm_syncobj_transfer_ioctl, 726c349dbc7Sjsg DRM_RENDER_ALLOW), 7277f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl, 728c349dbc7Sjsg DRM_RENDER_ALLOW), 729c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, drm_syncobj_timeline_wait_ioctl, 730c349dbc7Sjsg DRM_RENDER_ALLOW), 731*f005ef32Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_EVENTFD, drm_syncobj_eventfd_ioctl, 732*f005ef32Sjsg DRM_RENDER_ALLOW), 7337f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_RESET, drm_syncobj_reset_ioctl, 734c349dbc7Sjsg DRM_RENDER_ALLOW), 7357f4dd379Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl, 736c349dbc7Sjsg DRM_RENDER_ALLOW), 737c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, drm_syncobj_timeline_signal_ioctl, 738c349dbc7Sjsg DRM_RENDER_ALLOW), 739c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl, 740c349dbc7Sjsg DRM_RENDER_ALLOW), 741c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, 0), 742c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, 0), 7437f4dd379Sjsg #ifdef __linux__ 744c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER), 745c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER), 746c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER), 747c349dbc7Sjsg DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER), 7487f4dd379Sjsg #endif 7497f4dd379Sjsg }; 7507f4dd379Sjsg 7517f4dd379Sjsg #define DRM_CORE_IOCTL_COUNT ARRAY_SIZE(drm_ioctls) 7527f4dd379Sjsg 7537f4dd379Sjsg int 7547f4dd379Sjsg pledge_ioctl_drm(struct proc *p, long com, dev_t device) 7557f4dd379Sjsg { 7567f4dd379Sjsg struct drm_device *dev = drm_get_device_from_kdev(device); 7577f4dd379Sjsg unsigned int nr = DRM_IOCTL_NR(com); 7587f4dd379Sjsg const struct drm_ioctl_desc *ioctl; 7597f4dd379Sjsg 7607f4dd379Sjsg if (dev == NULL) 7617f4dd379Sjsg return EPERM; 7627f4dd379Sjsg 7637f4dd379Sjsg if (nr < DRM_CORE_IOCTL_COUNT && 7647f4dd379Sjsg ((nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END))) 7657f4dd379Sjsg ioctl = &drm_ioctls[nr]; 7667f4dd379Sjsg else if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END && 7677f4dd379Sjsg nr < DRM_COMMAND_BASE + dev->driver->num_ioctls) 7687f4dd379Sjsg ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; 7697f4dd379Sjsg else 7707f4dd379Sjsg return EPERM; 7717f4dd379Sjsg 7727f4dd379Sjsg if (ioctl->flags & DRM_RENDER_ALLOW) 7737f4dd379Sjsg return 0; 7747f4dd379Sjsg 7757f4dd379Sjsg /* 7767f4dd379Sjsg * These are dangerous, but we have to allow them until we 7777f4dd379Sjsg * have prime/dma-buf support. 7787f4dd379Sjsg */ 7797f4dd379Sjsg switch (com) { 7807f4dd379Sjsg case DRM_IOCTL_GET_MAGIC: 7817f4dd379Sjsg case DRM_IOCTL_GEM_OPEN: 7827f4dd379Sjsg return 0; 7837f4dd379Sjsg } 7847f4dd379Sjsg 785dcff20e6Sjsg /* for amdgpu libdrm */ 786dcff20e6Sjsg if (com == DRM_IOCTL_GET_CLIENT) 787dcff20e6Sjsg return 0; 788dcff20e6Sjsg 7897f4dd379Sjsg return EPERM; 7907f4dd379Sjsg } 7917f4dd379Sjsg 792c349dbc7Sjsg /** 793c349dbc7Sjsg * DOC: driver specific ioctls 794c349dbc7Sjsg * 795c349dbc7Sjsg * First things first, driver private IOCTLs should only be needed for drivers 796c349dbc7Sjsg * supporting rendering. Kernel modesetting is all standardized, and extended 797c349dbc7Sjsg * through properties. There are a few exceptions in some existing drivers, 798c349dbc7Sjsg * which define IOCTL for use by the display DRM master, but they all predate 799c349dbc7Sjsg * properties. 800c349dbc7Sjsg * 801c349dbc7Sjsg * Now if you do have a render driver you always have to support it through 802c349dbc7Sjsg * driver private properties. There's a few steps needed to wire all the things 803c349dbc7Sjsg * up. 804c349dbc7Sjsg * 805c349dbc7Sjsg * First you need to define the structure for your IOCTL in your driver private 806c349dbc7Sjsg * UAPI header in ``include/uapi/drm/my_driver_drm.h``:: 807c349dbc7Sjsg * 808c349dbc7Sjsg * struct my_driver_operation { 809c349dbc7Sjsg * u32 some_thing; 810c349dbc7Sjsg * u32 another_thing; 811c349dbc7Sjsg * }; 812c349dbc7Sjsg * 813c349dbc7Sjsg * Please make sure that you follow all the best practices from 814ad8b1aafSjsg * ``Documentation/process/botching-up-ioctls.rst``. Note that drm_ioctl() 815c349dbc7Sjsg * automatically zero-extends structures, hence make sure you can add more stuff 816c349dbc7Sjsg * at the end, i.e. don't put a variable sized array there. 817c349dbc7Sjsg * 818c349dbc7Sjsg * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(), 819c349dbc7Sjsg * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix:: 820c349dbc7Sjsg * 821c349dbc7Sjsg * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ 822c349dbc7Sjsg * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) 823c349dbc7Sjsg * 824c349dbc7Sjsg * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to 825c349dbc7Sjsg * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire 826c349dbc7Sjsg * up the handlers and set the access rights:: 827c349dbc7Sjsg * 828c349dbc7Sjsg * static const struct drm_ioctl_desc my_driver_ioctls[] = { 829c349dbc7Sjsg * DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation, 830c349dbc7Sjsg * DRM_AUTH|DRM_RENDER_ALLOW), 831c349dbc7Sjsg * }; 832c349dbc7Sjsg * 833c349dbc7Sjsg * And then assign this to the &drm_driver.ioctls field in your driver 834c349dbc7Sjsg * structure. 835c349dbc7Sjsg * 836c349dbc7Sjsg * See the separate chapter on :ref:`file operations<drm_driver_fops>` for how 837c349dbc7Sjsg * the driver-specific IOCTLs are wired up. 8387f4dd379Sjsg */ 839c349dbc7Sjsg 840c349dbc7Sjsg long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, 841c349dbc7Sjsg u32 flags) 842c349dbc7Sjsg { 843c349dbc7Sjsg STUB(); 844c349dbc7Sjsg return -ENOSYS; 845c349dbc7Sjsg #ifdef notyet 846c349dbc7Sjsg struct drm_file *file_priv = file->private_data; 847c349dbc7Sjsg struct drm_device *dev = file_priv->minor->dev; 848c349dbc7Sjsg int retcode; 849c349dbc7Sjsg 850*f005ef32Sjsg /* Update drm_file owner if fd was passed along. */ 851*f005ef32Sjsg drm_file_update_pid(file_priv); 852*f005ef32Sjsg 853c349dbc7Sjsg if (drm_dev_is_unplugged(dev)) 854c349dbc7Sjsg return -ENODEV; 855c349dbc7Sjsg 856c349dbc7Sjsg retcode = drm_ioctl_permit(flags, file_priv); 857c349dbc7Sjsg if (unlikely(retcode)) 858c349dbc7Sjsg return retcode; 859c349dbc7Sjsg 860c349dbc7Sjsg /* Enforce sane locking for modern driver ioctls. */ 861c349dbc7Sjsg if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || 862c349dbc7Sjsg (flags & DRM_UNLOCKED)) 863c349dbc7Sjsg retcode = func(dev, kdata, file_priv); 864c349dbc7Sjsg else { 865c349dbc7Sjsg mutex_lock(&drm_global_mutex); 866c349dbc7Sjsg retcode = func(dev, kdata, file_priv); 867c349dbc7Sjsg mutex_unlock(&drm_global_mutex); 8687f4dd379Sjsg } 869c349dbc7Sjsg return retcode; 870c349dbc7Sjsg #endif 871c349dbc7Sjsg } 872c349dbc7Sjsg EXPORT_SYMBOL(drm_ioctl_kernel); 873c349dbc7Sjsg 874c349dbc7Sjsg /** 875c349dbc7Sjsg * drm_ioctl - ioctl callback implementation for DRM drivers 876c349dbc7Sjsg * @filp: file this ioctl is called on 877c349dbc7Sjsg * @cmd: ioctl cmd number 878c349dbc7Sjsg * @arg: user argument 879c349dbc7Sjsg * 880c349dbc7Sjsg * Looks up the ioctl function in the DRM core and the driver dispatch table, 881c349dbc7Sjsg * stored in &drm_driver.ioctls. It checks for necessary permission by calling 882c349dbc7Sjsg * drm_ioctl_permit(), and dispatches to the respective function. 883c349dbc7Sjsg * 884c349dbc7Sjsg * Returns: 885c349dbc7Sjsg * Zero on success, negative error code on failure. 886c349dbc7Sjsg */ 887c349dbc7Sjsg long drm_ioctl(struct file *filp, 888c349dbc7Sjsg unsigned int cmd, unsigned long arg) 889c349dbc7Sjsg { 890c349dbc7Sjsg STUB(); 891c349dbc7Sjsg return -ENOSYS; 892c349dbc7Sjsg #ifdef notyet 893c349dbc7Sjsg struct drm_file *file_priv = filp->private_data; 894c349dbc7Sjsg struct drm_device *dev; 895c349dbc7Sjsg const struct drm_ioctl_desc *ioctl = NULL; 896c349dbc7Sjsg drm_ioctl_t *func; 897c349dbc7Sjsg unsigned int nr = DRM_IOCTL_NR(cmd); 898c349dbc7Sjsg int retcode = -EINVAL; 899c349dbc7Sjsg char stack_kdata[128]; 900c349dbc7Sjsg char *kdata = NULL; 901c349dbc7Sjsg unsigned int in_size, out_size, drv_size, ksize; 902c349dbc7Sjsg bool is_driver_ioctl; 903c349dbc7Sjsg 904c349dbc7Sjsg dev = file_priv->minor->dev; 905c349dbc7Sjsg 906c349dbc7Sjsg if (drm_dev_is_unplugged(dev)) 907c349dbc7Sjsg return -ENODEV; 908c349dbc7Sjsg 909f1185129Sjsg if (DRM_IOCTL_TYPE(cmd) != DRM_IOCTL_BASE) 910f1185129Sjsg return -ENOTTY; 911f1185129Sjsg 912c349dbc7Sjsg is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END; 913c349dbc7Sjsg 914c349dbc7Sjsg if (is_driver_ioctl) { 915c349dbc7Sjsg /* driver ioctl */ 916c349dbc7Sjsg unsigned int index = nr - DRM_COMMAND_BASE; 917c349dbc7Sjsg 918c349dbc7Sjsg if (index >= dev->driver->num_ioctls) 919c349dbc7Sjsg goto err_i1; 920c349dbc7Sjsg index = array_index_nospec(index, dev->driver->num_ioctls); 921c349dbc7Sjsg ioctl = &dev->driver->ioctls[index]; 922c349dbc7Sjsg } else { 923c349dbc7Sjsg /* core ioctl */ 924c349dbc7Sjsg if (nr >= DRM_CORE_IOCTL_COUNT) 925c349dbc7Sjsg goto err_i1; 926c349dbc7Sjsg nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT); 927c349dbc7Sjsg ioctl = &drm_ioctls[nr]; 928c349dbc7Sjsg } 929c349dbc7Sjsg 930c349dbc7Sjsg drv_size = _IOC_SIZE(ioctl->cmd); 931c349dbc7Sjsg out_size = in_size = _IOC_SIZE(cmd); 932c349dbc7Sjsg if ((cmd & ioctl->cmd & IOC_IN) == 0) 933c349dbc7Sjsg in_size = 0; 934c349dbc7Sjsg if ((cmd & ioctl->cmd & IOC_OUT) == 0) 935c349dbc7Sjsg out_size = 0; 936c349dbc7Sjsg ksize = max(max(in_size, out_size), drv_size); 937c349dbc7Sjsg 938*f005ef32Sjsg drm_dbg_core(dev, "comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n", 939ad8b1aafSjsg current->comm, task_pid_nr(current), 940c349dbc7Sjsg (long)old_encode_dev(file_priv->minor->kdev->devt), 941c349dbc7Sjsg file_priv->authenticated, ioctl->name); 942c349dbc7Sjsg 943c349dbc7Sjsg /* Do not trust userspace, use our own definition */ 944c349dbc7Sjsg func = ioctl->func; 945c349dbc7Sjsg 946c349dbc7Sjsg if (unlikely(!func)) { 947*f005ef32Sjsg drm_dbg_core(dev, "no function\n"); 948c349dbc7Sjsg retcode = -EINVAL; 949c349dbc7Sjsg goto err_i1; 950c349dbc7Sjsg } 951c349dbc7Sjsg 952c349dbc7Sjsg if (ksize <= sizeof(stack_kdata)) { 953c349dbc7Sjsg kdata = stack_kdata; 954c349dbc7Sjsg } else { 955c349dbc7Sjsg kdata = kmalloc(ksize, GFP_KERNEL); 956c349dbc7Sjsg if (!kdata) { 957c349dbc7Sjsg retcode = -ENOMEM; 958c349dbc7Sjsg goto err_i1; 959c349dbc7Sjsg } 960c349dbc7Sjsg } 961c349dbc7Sjsg 962c349dbc7Sjsg if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { 963c349dbc7Sjsg retcode = -EFAULT; 964c349dbc7Sjsg goto err_i1; 965c349dbc7Sjsg } 966c349dbc7Sjsg 967c349dbc7Sjsg if (ksize > in_size) 968c349dbc7Sjsg memset(kdata + in_size, 0, ksize - in_size); 969c349dbc7Sjsg 970c349dbc7Sjsg retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags); 971c349dbc7Sjsg if (copy_to_user((void __user *)arg, kdata, out_size) != 0) 972c349dbc7Sjsg retcode = -EFAULT; 973c349dbc7Sjsg 974c349dbc7Sjsg err_i1: 975c349dbc7Sjsg if (!ioctl) 976*f005ef32Sjsg drm_dbg_core(dev, 977*f005ef32Sjsg "invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", 978ad8b1aafSjsg current->comm, task_pid_nr(current), 979c349dbc7Sjsg (long)old_encode_dev(file_priv->minor->kdev->devt), 980c349dbc7Sjsg file_priv->authenticated, cmd, nr); 981c349dbc7Sjsg 982c349dbc7Sjsg if (kdata != stack_kdata) 983c349dbc7Sjsg kfree(kdata); 984c349dbc7Sjsg if (retcode) 985*f005ef32Sjsg drm_dbg_core(dev, "comm=\"%s\", pid=%d, ret=%d\n", 986*f005ef32Sjsg current->comm, task_pid_nr(current), retcode); 987c349dbc7Sjsg return retcode; 988c349dbc7Sjsg #endif 989c349dbc7Sjsg } 990c349dbc7Sjsg EXPORT_SYMBOL(drm_ioctl); 991c349dbc7Sjsg 992c349dbc7Sjsg /** 993c349dbc7Sjsg * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags 994c349dbc7Sjsg * @nr: ioctl number 995c349dbc7Sjsg * @flags: where to return the ioctl permission flags 996c349dbc7Sjsg * 997c349dbc7Sjsg * This ioctl is only used by the vmwgfx driver to augment the access checks 998c349dbc7Sjsg * done by the drm core and insofar a pretty decent layering violation. This 999c349dbc7Sjsg * shouldn't be used by any drivers. 1000c349dbc7Sjsg * 1001c349dbc7Sjsg * Returns: 1002c349dbc7Sjsg * True if the @nr corresponds to a DRM core ioctl number, false otherwise. 1003c349dbc7Sjsg */ 1004c349dbc7Sjsg bool drm_ioctl_flags(unsigned int nr, unsigned int *flags) 1005c349dbc7Sjsg { 1006c349dbc7Sjsg if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) 1007c349dbc7Sjsg return false; 1008c349dbc7Sjsg 1009c349dbc7Sjsg if (nr >= DRM_CORE_IOCTL_COUNT) 1010c349dbc7Sjsg return false; 1011c349dbc7Sjsg nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT); 1012c349dbc7Sjsg 1013c349dbc7Sjsg *flags = drm_ioctls[nr].flags; 1014c349dbc7Sjsg return true; 1015c349dbc7Sjsg } 1016c349dbc7Sjsg EXPORT_SYMBOL(drm_ioctl_flags); 10177f4dd379Sjsg 10187f4dd379Sjsg int 10197f4dd379Sjsg drm_do_ioctl(struct drm_device *dev, int minor, u_long cmd, caddr_t data) 10207f4dd379Sjsg { 10217f4dd379Sjsg struct drm_file *file_priv; 10227f4dd379Sjsg const struct drm_ioctl_desc *ioctl; 10237f4dd379Sjsg drm_ioctl_t *func; 10247f4dd379Sjsg unsigned int nr = DRM_IOCTL_NR(cmd); 10257f4dd379Sjsg int retcode = -EINVAL; 10267f4dd379Sjsg unsigned int usize, asize; 1027c349dbc7Sjsg caddr_t adata = data; 10287f4dd379Sjsg 1029c349dbc7Sjsg mutex_lock(&dev->filelist_mutex); 10307f4dd379Sjsg file_priv = drm_find_file_by_minor(dev, minor); 1031c349dbc7Sjsg mutex_unlock(&dev->filelist_mutex); 10327f4dd379Sjsg if (file_priv == NULL) { 10337f4dd379Sjsg DRM_ERROR("can't find authenticator\n"); 10347f4dd379Sjsg return -EINVAL; 10357f4dd379Sjsg } 10367f4dd379Sjsg 10377f4dd379Sjsg DRM_DEBUG("pid=%d, cmd=0x%02lx, nr=0x%02x, dev 0x%lx, auth=%d\n", 1038c349dbc7Sjsg curproc->p_p->ps_pid, cmd, (u_int)DRM_IOCTL_NR(cmd), (long)&dev->dev, 10397f4dd379Sjsg file_priv->authenticated); 10407f4dd379Sjsg 10417f4dd379Sjsg switch (cmd) { 10427f4dd379Sjsg case FIOASYNC: 10437f4dd379Sjsg return 0; 10447f4dd379Sjsg } 10457f4dd379Sjsg 10467f4dd379Sjsg if ((nr >= DRM_CORE_IOCTL_COUNT) && 10477f4dd379Sjsg ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END))) 10487f4dd379Sjsg return (-EINVAL); 10497f4dd379Sjsg if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && 10507f4dd379Sjsg (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { 10517f4dd379Sjsg uint32_t drv_size; 10527f4dd379Sjsg ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE]; 1053c349dbc7Sjsg drv_size = IOCPARM_LEN(ioctl->cmd); 10547f4dd379Sjsg usize = asize = IOCPARM_LEN(cmd); 10557f4dd379Sjsg if (drv_size > asize) 10567f4dd379Sjsg asize = drv_size; 10577f4dd379Sjsg } else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE)) { 10587f4dd379Sjsg uint32_t drv_size; 10597f4dd379Sjsg ioctl = &drm_ioctls[nr]; 10607f4dd379Sjsg 1061c349dbc7Sjsg drv_size = IOCPARM_LEN(ioctl->cmd); 10627f4dd379Sjsg usize = asize = IOCPARM_LEN(cmd); 10637f4dd379Sjsg if (drv_size > asize) 10647f4dd379Sjsg asize = drv_size; 10657f4dd379Sjsg cmd = ioctl->cmd; 10667f4dd379Sjsg } else 10677f4dd379Sjsg return (-EINVAL); 10687f4dd379Sjsg 10697f4dd379Sjsg func = ioctl->func; 10707f4dd379Sjsg if (!func) { 10717f4dd379Sjsg DRM_DEBUG("no function\n"); 10727f4dd379Sjsg return (-EINVAL); 10737f4dd379Sjsg } 10747f4dd379Sjsg 1075c349dbc7Sjsg retcode = drm_ioctl_permit(ioctl->flags, file_priv); 1076c349dbc7Sjsg if (unlikely(retcode)) 1077c349dbc7Sjsg return retcode; 10787f4dd379Sjsg 1079c349dbc7Sjsg if (asize > usize) { 1080c349dbc7Sjsg adata = malloc(asize, M_DRM, M_WAITOK | M_ZERO); 1081c349dbc7Sjsg memcpy(adata, data, usize); 1082c349dbc7Sjsg } 10837f4dd379Sjsg 108454be36c5Skettenis /* Enforce sane locking for modern driver ioctls. */ 108554be36c5Skettenis if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || 108654be36c5Skettenis (ioctl->flags & DRM_UNLOCKED)) 1087c349dbc7Sjsg retcode = func(dev, adata, file_priv); 10887f4dd379Sjsg else { 1089c349dbc7Sjsg mutex_lock(&drm_global_mutex); 1090c349dbc7Sjsg retcode = func(dev, adata, file_priv); 1091c349dbc7Sjsg mutex_unlock(&drm_global_mutex); 1092c349dbc7Sjsg } 1093c349dbc7Sjsg 1094c349dbc7Sjsg if (asize > usize) { 1095c349dbc7Sjsg memcpy(data, adata, usize); 1096c349dbc7Sjsg free(adata, M_DRM, asize); 10977f4dd379Sjsg } 10987f4dd379Sjsg 10997f4dd379Sjsg return (retcode); 11007f4dd379Sjsg } 11017f4dd379Sjsg 11027f4dd379Sjsg /* drmioctl is called whenever a process performs an ioctl on /dev/drm. 11037f4dd379Sjsg */ 11047f4dd379Sjsg int 11057f4dd379Sjsg drmioctl(dev_t kdev, u_long cmd, caddr_t data, int flags, struct proc *p) 11067f4dd379Sjsg { 11077f4dd379Sjsg struct drm_device *dev = drm_get_device_from_kdev(kdev); 11087f4dd379Sjsg int error; 11097f4dd379Sjsg 11107f4dd379Sjsg if (dev == NULL) 11117f4dd379Sjsg return ENODEV; 11127f4dd379Sjsg 11137f4dd379Sjsg mtx_enter(&dev->quiesce_mtx); 11147f4dd379Sjsg while (dev->quiesce) 1115d18c2ae1Smpi msleep_nsec(&dev->quiesce, &dev->quiesce_mtx, PZERO, "drmioc", 1116d18c2ae1Smpi INFSLP); 11177f4dd379Sjsg dev->quiesce_count++; 11187f4dd379Sjsg mtx_leave(&dev->quiesce_mtx); 11197f4dd379Sjsg 11207f4dd379Sjsg error = -drm_do_ioctl(dev, minor(kdev), cmd, data); 11217f4dd379Sjsg if (error < 0 && error != ERESTART && error != EJUSTRETURN) 11227f4dd379Sjsg printf("%s: cmd 0x%lx errno %d\n", __func__, cmd, error); 11237f4dd379Sjsg 11247f4dd379Sjsg mtx_enter(&dev->quiesce_mtx); 11257f4dd379Sjsg dev->quiesce_count--; 11267f4dd379Sjsg if (dev->quiesce) 11277f4dd379Sjsg wakeup(&dev->quiesce_count); 11287f4dd379Sjsg mtx_leave(&dev->quiesce_mtx); 11297f4dd379Sjsg 11307f4dd379Sjsg return (error); 11317f4dd379Sjsg } 1132