162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. 562306a36Sopenharmony_ci * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 662306a36Sopenharmony_ci * All Rights Reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author Rickard E. (Rik) Faith <faith@valinux.com> 962306a36Sopenharmony_ci * Author Gareth Hughes <gareth@valinux.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 1262306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 1362306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 1462306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1562306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1662306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the next 1962306a36Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 2062306a36Sopenharmony_ci * Software. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 2362306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2462306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2562306a36Sopenharmony_ci * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2662306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2762306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2862306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <linux/export.h> 3262306a36Sopenharmony_ci#include <linux/nospec.h> 3362306a36Sopenharmony_ci#include <linux/pci.h> 3462306a36Sopenharmony_ci#include <linux/uaccess.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include <drm/drm_auth.h> 3762306a36Sopenharmony_ci#include <drm/drm_crtc.h> 3862306a36Sopenharmony_ci#include <drm/drm_drv.h> 3962306a36Sopenharmony_ci#include <drm/drm_file.h> 4062306a36Sopenharmony_ci#include <drm/drm_ioctl.h> 4162306a36Sopenharmony_ci#include <drm/drm_print.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "drm_crtc_internal.h" 4462306a36Sopenharmony_ci#include "drm_internal.h" 4562306a36Sopenharmony_ci#include "drm_legacy.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/** 4862306a36Sopenharmony_ci * DOC: getunique and setversion story 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * BEWARE THE DRAGONS! MIND THE TRAPDOORS! 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * In an attempt to warn anyone else who's trying to figure out what's going 5362306a36Sopenharmony_ci * on here, I'll try to summarize the story. First things first, let's clear up 5462306a36Sopenharmony_ci * the names, because the kernel internals, libdrm and the ioctls are all named 5562306a36Sopenharmony_ci * differently: 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * - GET_UNIQUE ioctl, implemented by drm_getunique is wrapped up in libdrm 5862306a36Sopenharmony_ci * through the drmGetBusid function. 5962306a36Sopenharmony_ci * - The libdrm drmSetBusid function is backed by the SET_UNIQUE ioctl. All 6062306a36Sopenharmony_ci * that code is nerved in the kernel with drm_invalid_op(). 6162306a36Sopenharmony_ci * - The internal set_busid kernel functions and driver callbacks are 6262306a36Sopenharmony_ci * exclusively use by the SET_VERSION ioctl, because only drm 1.0 (which is 6362306a36Sopenharmony_ci * nerved) allowed userspace to set the busid through the above ioctl. 6462306a36Sopenharmony_ci * - Other ioctls and functions involved are named consistently. 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * For anyone wondering what's the difference between drm 1.1 and 1.4: Correctly 6762306a36Sopenharmony_ci * handling pci domains in the busid on ppc. Doing this correctly was only 6862306a36Sopenharmony_ci * implemented in libdrm in 2010, hence can't be nerved yet. No one knows what's 6962306a36Sopenharmony_ci * special with drm 1.2 and 1.3. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Now the actual horror story of how device lookup in drm works. At large, 7262306a36Sopenharmony_ci * there's 2 different ways, either by busid, or by device driver name. 7362306a36Sopenharmony_ci * 7462306a36Sopenharmony_ci * Opening by busid is fairly simple: 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * 1. First call SET_VERSION to make sure pci domains are handled properly. As a 7762306a36Sopenharmony_ci * side-effect this fills out the unique name in the master structure. 7862306a36Sopenharmony_ci * 2. Call GET_UNIQUE to read out the unique name from the master structure, 7962306a36Sopenharmony_ci * which matches the busid thanks to step 1. If it doesn't, proceed to try 8062306a36Sopenharmony_ci * the next device node. 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Opening by name is slightly different: 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * 1. Directly call VERSION to get the version and to match against the driver 8562306a36Sopenharmony_ci * name returned by that ioctl. Note that SET_VERSION is not called, which 8662306a36Sopenharmony_ci * means the unique name for the master node just opening is _not_ filled 8762306a36Sopenharmony_ci * out. This despite that with current drm device nodes are always bound to 8862306a36Sopenharmony_ci * one device, and can't be runtime assigned like with drm 1.0. 8962306a36Sopenharmony_ci * 2. Match driver name. If it mismatches, proceed to the next device node. 9062306a36Sopenharmony_ci * 3. Call GET_UNIQUE, and check whether the unique name has length zero (by 9162306a36Sopenharmony_ci * checking that the first byte in the string is 0). If that's not the case 9262306a36Sopenharmony_ci * libdrm skips and proceeds to the next device node. Probably this is just 9362306a36Sopenharmony_ci * copypasta from drm 1.0 times where a set unique name meant that the driver 9462306a36Sopenharmony_ci * was in use already, but that's just conjecture. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * Long story short: To keep the open by name logic working, GET_UNIQUE must 9762306a36Sopenharmony_ci * _not_ return a unique string when SET_VERSION hasn't been called yet, 9862306a36Sopenharmony_ci * otherwise libdrm breaks. Even when that unique string can't ever change, and 9962306a36Sopenharmony_ci * is totally irrelevant for actually opening the device because runtime 10062306a36Sopenharmony_ci * assignable device instances were only support in drm 1.0, which is long dead. 10162306a36Sopenharmony_ci * But the libdrm code in drmOpenByName somehow survived, hence this can't be 10262306a36Sopenharmony_ci * broken. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Get the bus id. 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * \param inode device inode. 10962306a36Sopenharmony_ci * \param file_priv DRM file private. 11062306a36Sopenharmony_ci * \param cmd command. 11162306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_unique structure. 11262306a36Sopenharmony_ci * \return zero on success or a negative number on failure. 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * Copies the bus id from drm_device::unique into user space. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ciint drm_getunique(struct drm_device *dev, void *data, 11762306a36Sopenharmony_ci struct drm_file *file_priv) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct drm_unique *u = data; 12062306a36Sopenharmony_ci struct drm_master *master; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci mutex_lock(&dev->master_mutex); 12362306a36Sopenharmony_ci master = file_priv->master; 12462306a36Sopenharmony_ci if (u->unique_len >= master->unique_len) { 12562306a36Sopenharmony_ci if (copy_to_user(u->unique, master->unique, master->unique_len)) { 12662306a36Sopenharmony_ci mutex_unlock(&dev->master_mutex); 12762306a36Sopenharmony_ci return -EFAULT; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci u->unique_len = master->unique_len; 13162306a36Sopenharmony_ci mutex_unlock(&dev->master_mutex); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void 13762306a36Sopenharmony_cidrm_unset_busid(struct drm_device *dev, 13862306a36Sopenharmony_ci struct drm_master *master) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci kfree(master->unique); 14162306a36Sopenharmony_ci master->unique = NULL; 14262306a36Sopenharmony_ci master->unique_len = 0; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct drm_master *master = file_priv->master; 14862306a36Sopenharmony_ci int ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (master->unique != NULL) 15162306a36Sopenharmony_ci drm_unset_busid(dev, master); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (dev->dev && dev_is_pci(dev->dev)) { 15462306a36Sopenharmony_ci ret = drm_pci_set_busid(dev, master); 15562306a36Sopenharmony_ci if (ret) { 15662306a36Sopenharmony_ci drm_unset_busid(dev, master); 15762306a36Sopenharmony_ci return ret; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci } else { 16062306a36Sopenharmony_ci WARN_ON(!dev->unique); 16162306a36Sopenharmony_ci master->unique = kstrdup(dev->unique, GFP_KERNEL); 16262306a36Sopenharmony_ci if (master->unique) 16362306a36Sopenharmony_ci master->unique_len = strlen(dev->unique); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* 17062306a36Sopenharmony_ci * Get client information. 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * \param inode device inode. 17362306a36Sopenharmony_ci * \param file_priv DRM file private. 17462306a36Sopenharmony_ci * \param cmd command. 17562306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_client structure. 17662306a36Sopenharmony_ci * 17762306a36Sopenharmony_ci * \return zero on success or a negative number on failure. 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Searches for the client with the specified index and copies its information 18062306a36Sopenharmony_ci * into userspace 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ciint drm_getclient(struct drm_device *dev, void *data, 18362306a36Sopenharmony_ci struct drm_file *file_priv) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct drm_client *client = data; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * Hollowed-out getclient ioctl to keep some dead old drm tests/tools 18962306a36Sopenharmony_ci * not breaking completely. Userspace tools stop enumerating one they 19062306a36Sopenharmony_ci * get -EINVAL, hence this is the return value we need to hand back for 19162306a36Sopenharmony_ci * no clients tracked. 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Unfortunately some clients (*cough* libva *cough*) use this in a fun 19462306a36Sopenharmony_ci * attempt to figure out whether they're authenticated or not. Since 19562306a36Sopenharmony_ci * that's the only thing they care about, give it to the directly 19662306a36Sopenharmony_ci * instead of walking one giant list. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci if (client->idx == 0) { 19962306a36Sopenharmony_ci client->auth = file_priv->authenticated; 20062306a36Sopenharmony_ci client->pid = task_pid_vnr(current); 20162306a36Sopenharmony_ci client->uid = overflowuid; 20262306a36Sopenharmony_ci client->magic = 0; 20362306a36Sopenharmony_ci client->iocs = 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci } else { 20762306a36Sopenharmony_ci return -EINVAL; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* 21262306a36Sopenharmony_ci * Get statistics information. 21362306a36Sopenharmony_ci * 21462306a36Sopenharmony_ci * \param inode device inode. 21562306a36Sopenharmony_ci * \param file_priv DRM file private. 21662306a36Sopenharmony_ci * \param cmd command. 21762306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_stats structure. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * \return zero on success or a negative number on failure. 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic int drm_getstats(struct drm_device *dev, void *data, 22262306a36Sopenharmony_ci struct drm_file *file_priv) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct drm_stats *stats = data; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Clear stats to prevent userspace from eating its stack garbage. */ 22762306a36Sopenharmony_ci memset(stats, 0, sizeof(*stats)); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* 23362306a36Sopenharmony_ci * Get device/driver capabilities 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistatic int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct drm_get_cap *req = data; 23862306a36Sopenharmony_ci struct drm_crtc *crtc; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci req->value = 0; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* Only some caps make sense with UMS/render-only drivers. */ 24362306a36Sopenharmony_ci switch (req->capability) { 24462306a36Sopenharmony_ci case DRM_CAP_TIMESTAMP_MONOTONIC: 24562306a36Sopenharmony_ci req->value = 1; 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci case DRM_CAP_PRIME: 24862306a36Sopenharmony_ci req->value = DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT; 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci case DRM_CAP_SYNCOBJ: 25162306a36Sopenharmony_ci req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ); 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci case DRM_CAP_SYNCOBJ_TIMELINE: 25462306a36Sopenharmony_ci req->value = drm_core_check_feature(dev, DRIVER_SYNCOBJ_TIMELINE); 25562306a36Sopenharmony_ci return 0; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* Other caps only work with KMS drivers */ 25962306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 26062306a36Sopenharmony_ci return -EOPNOTSUPP; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci switch (req->capability) { 26362306a36Sopenharmony_ci case DRM_CAP_DUMB_BUFFER: 26462306a36Sopenharmony_ci if (dev->driver->dumb_create) 26562306a36Sopenharmony_ci req->value = 1; 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci case DRM_CAP_VBLANK_HIGH_CRTC: 26862306a36Sopenharmony_ci req->value = 1; 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci case DRM_CAP_DUMB_PREFERRED_DEPTH: 27162306a36Sopenharmony_ci req->value = dev->mode_config.preferred_depth; 27262306a36Sopenharmony_ci break; 27362306a36Sopenharmony_ci case DRM_CAP_DUMB_PREFER_SHADOW: 27462306a36Sopenharmony_ci req->value = dev->mode_config.prefer_shadow; 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case DRM_CAP_ASYNC_PAGE_FLIP: 27762306a36Sopenharmony_ci req->value = dev->mode_config.async_page_flip; 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case DRM_CAP_PAGE_FLIP_TARGET: 28062306a36Sopenharmony_ci req->value = 1; 28162306a36Sopenharmony_ci drm_for_each_crtc(crtc, dev) { 28262306a36Sopenharmony_ci if (!crtc->funcs->page_flip_target) 28362306a36Sopenharmony_ci req->value = 0; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci break; 28662306a36Sopenharmony_ci case DRM_CAP_CURSOR_WIDTH: 28762306a36Sopenharmony_ci if (dev->mode_config.cursor_width) 28862306a36Sopenharmony_ci req->value = dev->mode_config.cursor_width; 28962306a36Sopenharmony_ci else 29062306a36Sopenharmony_ci req->value = 64; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case DRM_CAP_CURSOR_HEIGHT: 29362306a36Sopenharmony_ci if (dev->mode_config.cursor_height) 29462306a36Sopenharmony_ci req->value = dev->mode_config.cursor_height; 29562306a36Sopenharmony_ci else 29662306a36Sopenharmony_ci req->value = 64; 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci case DRM_CAP_ADDFB2_MODIFIERS: 29962306a36Sopenharmony_ci req->value = !dev->mode_config.fb_modifiers_not_supported; 30062306a36Sopenharmony_ci break; 30162306a36Sopenharmony_ci case DRM_CAP_CRTC_IN_VBLANK_EVENT: 30262306a36Sopenharmony_ci req->value = 1; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci default: 30562306a36Sopenharmony_ci return -EINVAL; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* 31162306a36Sopenharmony_ci * Set device/driver capabilities 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_cistatic int 31462306a36Sopenharmony_cidrm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct drm_set_client_cap *req = data; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* No render-only settable capabilities for now */ 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Below caps that only works with KMS drivers */ 32162306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_MODESET)) 32262306a36Sopenharmony_ci return -EOPNOTSUPP; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci switch (req->capability) { 32562306a36Sopenharmony_ci case DRM_CLIENT_CAP_STEREO_3D: 32662306a36Sopenharmony_ci if (req->value > 1) 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci file_priv->stereo_allowed = req->value; 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case DRM_CLIENT_CAP_UNIVERSAL_PLANES: 33162306a36Sopenharmony_ci if (req->value > 1) 33262306a36Sopenharmony_ci return -EINVAL; 33362306a36Sopenharmony_ci file_priv->universal_planes = req->value; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci case DRM_CLIENT_CAP_ATOMIC: 33662306a36Sopenharmony_ci if (!drm_core_check_feature(dev, DRIVER_ATOMIC)) 33762306a36Sopenharmony_ci return -EOPNOTSUPP; 33862306a36Sopenharmony_ci /* The modesetting DDX has a totally broken idea of atomic. */ 33962306a36Sopenharmony_ci if (current->comm[0] == 'X' && req->value == 1) { 34062306a36Sopenharmony_ci pr_info("broken atomic modeset userspace detected, disabling atomic\n"); 34162306a36Sopenharmony_ci return -EOPNOTSUPP; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci if (req->value > 2) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci file_priv->atomic = req->value; 34662306a36Sopenharmony_ci file_priv->universal_planes = req->value; 34762306a36Sopenharmony_ci /* 34862306a36Sopenharmony_ci * No atomic user-space blows up on aspect ratio mode bits. 34962306a36Sopenharmony_ci */ 35062306a36Sopenharmony_ci file_priv->aspect_ratio_allowed = req->value; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case DRM_CLIENT_CAP_ASPECT_RATIO: 35362306a36Sopenharmony_ci if (req->value > 1) 35462306a36Sopenharmony_ci return -EINVAL; 35562306a36Sopenharmony_ci file_priv->aspect_ratio_allowed = req->value; 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case DRM_CLIENT_CAP_WRITEBACK_CONNECTORS: 35862306a36Sopenharmony_ci if (!file_priv->atomic) 35962306a36Sopenharmony_ci return -EINVAL; 36062306a36Sopenharmony_ci if (req->value > 1) 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci file_priv->writeback_connectors = req->value; 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci default: 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/* 37262306a36Sopenharmony_ci * Setversion ioctl. 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * \param inode device inode. 37562306a36Sopenharmony_ci * \param file_priv DRM file private. 37662306a36Sopenharmony_ci * \param cmd command. 37762306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_lock structure. 37862306a36Sopenharmony_ci * \return zero on success or negative number on failure. 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * Sets the requested interface version 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_cistatic int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct drm_set_version *sv = data; 38562306a36Sopenharmony_ci int if_version, retcode = 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci mutex_lock(&dev->master_mutex); 38862306a36Sopenharmony_ci if (sv->drm_di_major != -1) { 38962306a36Sopenharmony_ci if (sv->drm_di_major != DRM_IF_MAJOR || 39062306a36Sopenharmony_ci sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) { 39162306a36Sopenharmony_ci retcode = -EINVAL; 39262306a36Sopenharmony_ci goto done; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci if_version = DRM_IF_VERSION(sv->drm_di_major, 39562306a36Sopenharmony_ci sv->drm_di_minor); 39662306a36Sopenharmony_ci dev->if_version = max(if_version, dev->if_version); 39762306a36Sopenharmony_ci if (sv->drm_di_minor >= 1) { 39862306a36Sopenharmony_ci /* 39962306a36Sopenharmony_ci * Version 1.1 includes tying of DRM to specific device 40062306a36Sopenharmony_ci * Version 1.4 has proper PCI domain support 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci retcode = drm_set_busid(dev, file_priv); 40362306a36Sopenharmony_ci if (retcode) 40462306a36Sopenharmony_ci goto done; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (sv->drm_dd_major != -1) { 40962306a36Sopenharmony_ci if (sv->drm_dd_major != dev->driver->major || 41062306a36Sopenharmony_ci sv->drm_dd_minor < 0 || sv->drm_dd_minor > 41162306a36Sopenharmony_ci dev->driver->minor) { 41262306a36Sopenharmony_ci retcode = -EINVAL; 41362306a36Sopenharmony_ci goto done; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cidone: 41862306a36Sopenharmony_ci sv->drm_di_major = DRM_IF_MAJOR; 41962306a36Sopenharmony_ci sv->drm_di_minor = DRM_IF_MINOR; 42062306a36Sopenharmony_ci sv->drm_dd_major = dev->driver->major; 42162306a36Sopenharmony_ci sv->drm_dd_minor = dev->driver->minor; 42262306a36Sopenharmony_ci mutex_unlock(&dev->master_mutex); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci return retcode; 42562306a36Sopenharmony_ci} 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci/** 42862306a36Sopenharmony_ci * drm_noop - DRM no-op ioctl implementation 42962306a36Sopenharmony_ci * @dev: DRM device for the ioctl 43062306a36Sopenharmony_ci * @data: data pointer for the ioctl 43162306a36Sopenharmony_ci * @file_priv: DRM file for the ioctl call 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * This no-op implementation for drm ioctls is useful for deprecated 43462306a36Sopenharmony_ci * functionality where we can't return a failure code because existing userspace 43562306a36Sopenharmony_ci * checks the result of the ioctl, but doesn't care about the action. 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * Always returns successfully with 0. 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ciint drm_noop(struct drm_device *dev, void *data, 44062306a36Sopenharmony_ci struct drm_file *file_priv) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci drm_dbg_core(dev, "\n"); 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ciEXPORT_SYMBOL(drm_noop); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/** 44862306a36Sopenharmony_ci * drm_invalid_op - DRM invalid ioctl implementation 44962306a36Sopenharmony_ci * @dev: DRM device for the ioctl 45062306a36Sopenharmony_ci * @data: data pointer for the ioctl 45162306a36Sopenharmony_ci * @file_priv: DRM file for the ioctl call 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * This no-op implementation for drm ioctls is useful for deprecated 45462306a36Sopenharmony_ci * functionality where we really don't want to allow userspace to call the ioctl 45562306a36Sopenharmony_ci * any more. This is the case for old ums interfaces for drivers that 45662306a36Sopenharmony_ci * transitioned to kms gradually and so kept the old legacy tables around. This 45762306a36Sopenharmony_ci * only applies to radeon and i915 kms drivers, other drivers shouldn't need to 45862306a36Sopenharmony_ci * use this function. 45962306a36Sopenharmony_ci * 46062306a36Sopenharmony_ci * Always fails with a return value of -EINVAL. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ciint drm_invalid_op(struct drm_device *dev, void *data, 46362306a36Sopenharmony_ci struct drm_file *file_priv) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci return -EINVAL; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ciEXPORT_SYMBOL(drm_invalid_op); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * Copy and IOCTL return string to user space 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic int drm_copy_field(char __user *buf, size_t *buf_len, const char *value) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci size_t len; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci /* don't attempt to copy a NULL pointer */ 47762306a36Sopenharmony_ci if (WARN_ONCE(!value, "BUG: the value to copy was not set!")) { 47862306a36Sopenharmony_ci *buf_len = 0; 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* don't overflow userbuf */ 48362306a36Sopenharmony_ci len = strlen(value); 48462306a36Sopenharmony_ci if (len > *buf_len) 48562306a36Sopenharmony_ci len = *buf_len; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* let userspace know exact length of driver value (which could be 48862306a36Sopenharmony_ci * larger than the userspace-supplied buffer) */ 48962306a36Sopenharmony_ci *buf_len = strlen(value); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* finally, try filling in the userbuf */ 49262306a36Sopenharmony_ci if (len && buf) 49362306a36Sopenharmony_ci if (copy_to_user(buf, value, len)) 49462306a36Sopenharmony_ci return -EFAULT; 49562306a36Sopenharmony_ci return 0; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/* 49962306a36Sopenharmony_ci * Get version information 50062306a36Sopenharmony_ci * 50162306a36Sopenharmony_ci * \param inode device inode. 50262306a36Sopenharmony_ci * \param filp file pointer. 50362306a36Sopenharmony_ci * \param cmd command. 50462306a36Sopenharmony_ci * \param arg user argument, pointing to a drm_version structure. 50562306a36Sopenharmony_ci * \return zero on success or negative number on failure. 50662306a36Sopenharmony_ci * 50762306a36Sopenharmony_ci * Fills in the version information in \p arg. 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ciint drm_version(struct drm_device *dev, void *data, 51062306a36Sopenharmony_ci struct drm_file *file_priv) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct drm_version *version = data; 51362306a36Sopenharmony_ci int err; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci version->version_major = dev->driver->major; 51662306a36Sopenharmony_ci version->version_minor = dev->driver->minor; 51762306a36Sopenharmony_ci version->version_patchlevel = dev->driver->patchlevel; 51862306a36Sopenharmony_ci err = drm_copy_field(version->name, &version->name_len, 51962306a36Sopenharmony_ci dev->driver->name); 52062306a36Sopenharmony_ci if (!err) 52162306a36Sopenharmony_ci err = drm_copy_field(version->date, &version->date_len, 52262306a36Sopenharmony_ci dev->driver->date); 52362306a36Sopenharmony_ci if (!err) 52462306a36Sopenharmony_ci err = drm_copy_field(version->desc, &version->desc_len, 52562306a36Sopenharmony_ci dev->driver->desc); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return err; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci /* ROOT_ONLY is only for CAP_SYS_ADMIN */ 53362306a36Sopenharmony_ci if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN))) 53462306a36Sopenharmony_ci return -EACCES; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* AUTH is only for authenticated or render client */ 53762306a36Sopenharmony_ci if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) && 53862306a36Sopenharmony_ci !file_priv->authenticated)) 53962306a36Sopenharmony_ci return -EACCES; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* MASTER is only for master or control clients */ 54262306a36Sopenharmony_ci if (unlikely((flags & DRM_MASTER) && 54362306a36Sopenharmony_ci !drm_is_current_master(file_priv))) 54462306a36Sopenharmony_ci return -EACCES; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* Render clients must be explicitly allowed */ 54762306a36Sopenharmony_ci if (unlikely(!(flags & DRM_RENDER_ALLOW) && 54862306a36Sopenharmony_ci drm_is_render_client(file_priv))) 54962306a36Sopenharmony_ci return -EACCES; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci#define DRM_IOCTL_DEF(ioctl, _func, _flags) \ 55562306a36Sopenharmony_ci [DRM_IOCTL_NR(ioctl)] = { \ 55662306a36Sopenharmony_ci .cmd = ioctl, \ 55762306a36Sopenharmony_ci .func = _func, \ 55862306a36Sopenharmony_ci .flags = _flags, \ 55962306a36Sopenharmony_ci .name = #ioctl \ 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_LEGACY) 56362306a36Sopenharmony_ci#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, _func, _flags) 56462306a36Sopenharmony_ci#else 56562306a36Sopenharmony_ci#define DRM_LEGACY_IOCTL_DEF(ioctl, _func, _flags) DRM_IOCTL_DEF(ioctl, drm_invalid_op, _flags) 56662306a36Sopenharmony_ci#endif 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* Ioctl table */ 56962306a36Sopenharmony_cistatic const struct drm_ioctl_desc drm_ioctls[] = { 57062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_VERSION, drm_version, DRM_RENDER_ALLOW), 57162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GET_UNIQUE, drm_getunique, 0), 57262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GET_MAGIC, drm_getmagic, 0), 57362306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_IRQ_BUSID, drm_legacy_irq_by_busid, 57462306a36Sopenharmony_ci DRM_MASTER|DRM_ROOT_ONLY), 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_MAP, drm_legacy_getmap_ioctl, 0), 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, 0), 57962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, 0), 58062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_RENDER_ALLOW), 58162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), 58262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER), 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_invalid_op, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 58562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_BLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 58662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_UNBLOCK, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 58762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_AUTH_MAGIC, drm_authmagic, DRM_MASTER), 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_MAP, drm_legacy_addmap_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 59062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_MAP, drm_legacy_rmmap_ioctl, DRM_AUTH), 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SET_SAREA_CTX, drm_legacy_setsareactx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 59362306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_SAREA_CTX, drm_legacy_getsareactx, DRM_AUTH), 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SET_MASTER, drm_setmaster_ioctl, 0), 59662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_DROP_MASTER, drm_dropmaster_ioctl, 0), 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_CTX, drm_legacy_addctx, DRM_AUTH|DRM_ROOT_ONLY), 59962306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RM_CTX, drm_legacy_rmctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MOD_CTX, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60162306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_GET_CTX, drm_legacy_getctx, DRM_AUTH), 60262306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SWITCH_CTX, drm_legacy_switchctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60362306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_NEW_CTX, drm_legacy_newctx, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60462306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_RES_CTX, drm_legacy_resctx, DRM_AUTH), 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_ADD_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_RM_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_LOCK, drm_legacy_lock, DRM_AUTH), 61062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_UNLOCK, drm_legacy_unlock, DRM_AUTH), 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_FINISH, drm_noop, DRM_AUTH), 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_ADD_BUFS, drm_legacy_addbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 61562306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MARK_BUFS, drm_legacy_markbufs, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 61662306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_INFO_BUFS, drm_legacy_infobufs, DRM_AUTH), 61762306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_MAP_BUFS, drm_legacy_mapbufs, DRM_AUTH), 61862306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_FREE_BUFS, drm_legacy_freebufs, DRM_AUTH), 61962306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_DMA, drm_legacy_dma_ioctl, DRM_AUTH), 62062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_CONTROL, drm_legacy_irq_control, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP) 62362306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ACQUIRE, drm_legacy_agp_acquire_ioctl, 62462306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 62562306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_RELEASE, drm_legacy_agp_release_ioctl, 62662306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 62762306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ENABLE, drm_legacy_agp_enable_ioctl, 62862306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 62962306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_INFO, drm_legacy_agp_info_ioctl, DRM_AUTH), 63062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_ALLOC, drm_legacy_agp_alloc_ioctl, 63162306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 63262306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_FREE, drm_legacy_agp_free_ioctl, 63362306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 63462306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_BIND, drm_legacy_agp_bind_ioctl, 63562306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 63662306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_AGP_UNBIND, drm_legacy_agp_unbind_ioctl, 63762306a36Sopenharmony_ci DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 63862306a36Sopenharmony_ci#endif 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_legacy_sg_alloc, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 64162306a36Sopenharmony_ci DRM_LEGACY_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_legacy_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank_ioctl, DRM_UNLOCKED), 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_legacy_modeset_ctl_ioctl, 0), 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_UPDATE_DRAW, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GEM_CLOSE, drm_gem_close_ioctl, DRM_RENDER_ALLOW), 65062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GEM_FLINK, drm_gem_flink_ioctl, DRM_AUTH), 65162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_GEM_OPEN, drm_gem_open_ioctl, DRM_AUTH), 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETRESOURCES, drm_mode_getresources, 0), 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_PRIME_HANDLE_TO_FD, drm_prime_handle_to_fd_ioctl, DRM_RENDER_ALLOW), 65662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_PRIME_FD_TO_HANDLE, drm_prime_fd_to_handle_ioctl, DRM_RENDER_ALLOW), 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANERESOURCES, drm_mode_getplane_res, 0), 65962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCRTC, drm_mode_getcrtc, 0), 66062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETCRTC, drm_mode_setcrtc, DRM_MASTER), 66162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPLANE, drm_mode_getplane, 0), 66262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPLANE, drm_mode_setplane, DRM_MASTER), 66362306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR, drm_mode_cursor_ioctl, DRM_MASTER), 66462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETGAMMA, drm_mode_gamma_get_ioctl, 0), 66562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETGAMMA, drm_mode_gamma_set_ioctl, DRM_MASTER), 66662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETENCODER, drm_mode_getencoder, 0), 66762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETCONNECTOR, drm_mode_getconnector, 0), 66862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATTACHMODE, drm_noop, DRM_MASTER), 66962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_DETACHMODE, drm_noop, DRM_MASTER), 67062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPERTY, drm_mode_getproperty_ioctl, 0), 67162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_SETPROPERTY, drm_connector_property_set_ioctl, DRM_MASTER), 67262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETPROPBLOB, drm_mode_getblob_ioctl, 0), 67362306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB, drm_mode_getfb, 0), 67462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GETFB2, drm_mode_getfb2_ioctl, 0), 67562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB, drm_mode_addfb_ioctl, 0), 67662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_ADDFB2, drm_mode_addfb2_ioctl, 0), 67762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_RMFB, drm_mode_rmfb_ioctl, 0), 67862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_PAGE_FLIP, drm_mode_page_flip_ioctl, DRM_MASTER), 67962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_DIRTYFB, drm_mode_dirtyfb_ioctl, DRM_MASTER), 68062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_DUMB, drm_mode_create_dumb_ioctl, 0), 68162306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, 0), 68262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROY_DUMB, drm_mode_destroy_dumb_ioctl, 0), 68362306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, 0), 68462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER), 68562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER), 68662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER), 68762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATEPROPBLOB, drm_mode_createblob_ioctl, 0), 68862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_DESTROYPROPBLOB, drm_mode_destroyblob_ioctl, 0), 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_CREATE, drm_syncobj_create_ioctl, 69162306a36Sopenharmony_ci DRM_RENDER_ALLOW), 69262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_DESTROY, drm_syncobj_destroy_ioctl, 69362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 69462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, drm_syncobj_handle_to_fd_ioctl, 69562306a36Sopenharmony_ci DRM_RENDER_ALLOW), 69662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, drm_syncobj_fd_to_handle_ioctl, 69762306a36Sopenharmony_ci DRM_RENDER_ALLOW), 69862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TRANSFER, drm_syncobj_transfer_ioctl, 69962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 70062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_WAIT, drm_syncobj_wait_ioctl, 70162306a36Sopenharmony_ci DRM_RENDER_ALLOW), 70262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_WAIT, drm_syncobj_timeline_wait_ioctl, 70362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 70462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_EVENTFD, drm_syncobj_eventfd_ioctl, 70562306a36Sopenharmony_ci DRM_RENDER_ALLOW), 70662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_RESET, drm_syncobj_reset_ioctl, 70762306a36Sopenharmony_ci DRM_RENDER_ALLOW), 70862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_SIGNAL, drm_syncobj_signal_ioctl, 70962306a36Sopenharmony_ci DRM_RENDER_ALLOW), 71062306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_TIMELINE_SIGNAL, drm_syncobj_timeline_signal_ioctl, 71162306a36Sopenharmony_ci DRM_RENDER_ALLOW), 71262306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_SYNCOBJ_QUERY, drm_syncobj_query_ioctl, 71362306a36Sopenharmony_ci DRM_RENDER_ALLOW), 71462306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_CRTC_GET_SEQUENCE, drm_crtc_get_sequence_ioctl, 0), 71562306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_CRTC_QUEUE_SEQUENCE, drm_crtc_queue_sequence_ioctl, 0), 71662306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_CREATE_LEASE, drm_mode_create_lease_ioctl, DRM_MASTER), 71762306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_LIST_LESSEES, drm_mode_list_lessees_ioctl, DRM_MASTER), 71862306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_GET_LEASE, drm_mode_get_lease_ioctl, DRM_MASTER), 71962306a36Sopenharmony_ci DRM_IOCTL_DEF(DRM_IOCTL_MODE_REVOKE_LEASE, drm_mode_revoke_lease_ioctl, DRM_MASTER), 72062306a36Sopenharmony_ci}; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE(drm_ioctls) 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/** 72562306a36Sopenharmony_ci * DOC: driver specific ioctls 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * First things first, driver private IOCTLs should only be needed for drivers 72862306a36Sopenharmony_ci * supporting rendering. Kernel modesetting is all standardized, and extended 72962306a36Sopenharmony_ci * through properties. There are a few exceptions in some existing drivers, 73062306a36Sopenharmony_ci * which define IOCTL for use by the display DRM master, but they all predate 73162306a36Sopenharmony_ci * properties. 73262306a36Sopenharmony_ci * 73362306a36Sopenharmony_ci * Now if you do have a render driver you always have to support it through 73462306a36Sopenharmony_ci * driver private properties. There's a few steps needed to wire all the things 73562306a36Sopenharmony_ci * up. 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * First you need to define the structure for your IOCTL in your driver private 73862306a36Sopenharmony_ci * UAPI header in ``include/uapi/drm/my_driver_drm.h``:: 73962306a36Sopenharmony_ci * 74062306a36Sopenharmony_ci * struct my_driver_operation { 74162306a36Sopenharmony_ci * u32 some_thing; 74262306a36Sopenharmony_ci * u32 another_thing; 74362306a36Sopenharmony_ci * }; 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * Please make sure that you follow all the best practices from 74662306a36Sopenharmony_ci * ``Documentation/process/botching-up-ioctls.rst``. Note that drm_ioctl() 74762306a36Sopenharmony_ci * automatically zero-extends structures, hence make sure you can add more stuff 74862306a36Sopenharmony_ci * at the end, i.e. don't put a variable sized array there. 74962306a36Sopenharmony_ci * 75062306a36Sopenharmony_ci * Then you need to define your IOCTL number, using one of DRM_IO(), DRM_IOR(), 75162306a36Sopenharmony_ci * DRM_IOW() or DRM_IOWR(). It must start with the DRM_IOCTL\_ prefix:: 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * ##define DRM_IOCTL_MY_DRIVER_OPERATION \ 75462306a36Sopenharmony_ci * DRM_IOW(DRM_COMMAND_BASE, struct my_driver_operation) 75562306a36Sopenharmony_ci * 75662306a36Sopenharmony_ci * DRM driver private IOCTL must be in the range from DRM_COMMAND_BASE to 75762306a36Sopenharmony_ci * DRM_COMMAND_END. Finally you need an array of &struct drm_ioctl_desc to wire 75862306a36Sopenharmony_ci * up the handlers and set the access rights:: 75962306a36Sopenharmony_ci * 76062306a36Sopenharmony_ci * static const struct drm_ioctl_desc my_driver_ioctls[] = { 76162306a36Sopenharmony_ci * DRM_IOCTL_DEF_DRV(MY_DRIVER_OPERATION, my_driver_operation, 76262306a36Sopenharmony_ci * DRM_AUTH|DRM_RENDER_ALLOW), 76362306a36Sopenharmony_ci * }; 76462306a36Sopenharmony_ci * 76562306a36Sopenharmony_ci * And then assign this to the &drm_driver.ioctls field in your driver 76662306a36Sopenharmony_ci * structure. 76762306a36Sopenharmony_ci * 76862306a36Sopenharmony_ci * See the separate chapter on :ref:`file operations<drm_driver_fops>` for how 76962306a36Sopenharmony_ci * the driver-specific IOCTLs are wired up. 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cilong drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata, 77362306a36Sopenharmony_ci u32 flags) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct drm_file *file_priv = file->private_data; 77662306a36Sopenharmony_ci struct drm_device *dev = file_priv->minor->dev; 77762306a36Sopenharmony_ci int retcode; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* Update drm_file owner if fd was passed along. */ 78062306a36Sopenharmony_ci drm_file_update_pid(file_priv); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (drm_dev_is_unplugged(dev)) 78362306a36Sopenharmony_ci return -ENODEV; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci retcode = drm_ioctl_permit(flags, file_priv); 78662306a36Sopenharmony_ci if (unlikely(retcode)) 78762306a36Sopenharmony_ci return retcode; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci /* Enforce sane locking for modern driver ioctls. */ 79062306a36Sopenharmony_ci if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) || 79162306a36Sopenharmony_ci (flags & DRM_UNLOCKED)) 79262306a36Sopenharmony_ci retcode = func(dev, kdata, file_priv); 79362306a36Sopenharmony_ci else { 79462306a36Sopenharmony_ci mutex_lock(&drm_global_mutex); 79562306a36Sopenharmony_ci retcode = func(dev, kdata, file_priv); 79662306a36Sopenharmony_ci mutex_unlock(&drm_global_mutex); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci return retcode; 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_ioctl_kernel); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci/** 80362306a36Sopenharmony_ci * drm_ioctl - ioctl callback implementation for DRM drivers 80462306a36Sopenharmony_ci * @filp: file this ioctl is called on 80562306a36Sopenharmony_ci * @cmd: ioctl cmd number 80662306a36Sopenharmony_ci * @arg: user argument 80762306a36Sopenharmony_ci * 80862306a36Sopenharmony_ci * Looks up the ioctl function in the DRM core and the driver dispatch table, 80962306a36Sopenharmony_ci * stored in &drm_driver.ioctls. It checks for necessary permission by calling 81062306a36Sopenharmony_ci * drm_ioctl_permit(), and dispatches to the respective function. 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * Returns: 81362306a36Sopenharmony_ci * Zero on success, negative error code on failure. 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_cilong drm_ioctl(struct file *filp, 81662306a36Sopenharmony_ci unsigned int cmd, unsigned long arg) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct drm_file *file_priv = filp->private_data; 81962306a36Sopenharmony_ci struct drm_device *dev; 82062306a36Sopenharmony_ci const struct drm_ioctl_desc *ioctl = NULL; 82162306a36Sopenharmony_ci drm_ioctl_t *func; 82262306a36Sopenharmony_ci unsigned int nr = DRM_IOCTL_NR(cmd); 82362306a36Sopenharmony_ci int retcode = -EINVAL; 82462306a36Sopenharmony_ci char stack_kdata[128]; 82562306a36Sopenharmony_ci char *kdata = NULL; 82662306a36Sopenharmony_ci unsigned int in_size, out_size, drv_size, ksize; 82762306a36Sopenharmony_ci bool is_driver_ioctl; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci dev = file_priv->minor->dev; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (drm_dev_is_unplugged(dev)) 83262306a36Sopenharmony_ci return -ENODEV; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (DRM_IOCTL_TYPE(cmd) != DRM_IOCTL_BASE) 83562306a36Sopenharmony_ci return -ENOTTY; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci is_driver_ioctl = nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (is_driver_ioctl) { 84062306a36Sopenharmony_ci /* driver ioctl */ 84162306a36Sopenharmony_ci unsigned int index = nr - DRM_COMMAND_BASE; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci if (index >= dev->driver->num_ioctls) 84462306a36Sopenharmony_ci goto err_i1; 84562306a36Sopenharmony_ci index = array_index_nospec(index, dev->driver->num_ioctls); 84662306a36Sopenharmony_ci ioctl = &dev->driver->ioctls[index]; 84762306a36Sopenharmony_ci } else { 84862306a36Sopenharmony_ci /* core ioctl */ 84962306a36Sopenharmony_ci if (nr >= DRM_CORE_IOCTL_COUNT) 85062306a36Sopenharmony_ci goto err_i1; 85162306a36Sopenharmony_ci nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT); 85262306a36Sopenharmony_ci ioctl = &drm_ioctls[nr]; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci drv_size = _IOC_SIZE(ioctl->cmd); 85662306a36Sopenharmony_ci out_size = in_size = _IOC_SIZE(cmd); 85762306a36Sopenharmony_ci if ((cmd & ioctl->cmd & IOC_IN) == 0) 85862306a36Sopenharmony_ci in_size = 0; 85962306a36Sopenharmony_ci if ((cmd & ioctl->cmd & IOC_OUT) == 0) 86062306a36Sopenharmony_ci out_size = 0; 86162306a36Sopenharmony_ci ksize = max(max(in_size, out_size), drv_size); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci drm_dbg_core(dev, "comm=\"%s\" pid=%d, dev=0x%lx, auth=%d, %s\n", 86462306a36Sopenharmony_ci current->comm, task_pid_nr(current), 86562306a36Sopenharmony_ci (long)old_encode_dev(file_priv->minor->kdev->devt), 86662306a36Sopenharmony_ci file_priv->authenticated, ioctl->name); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* Do not trust userspace, use our own definition */ 86962306a36Sopenharmony_ci func = ioctl->func; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci if (unlikely(!func)) { 87262306a36Sopenharmony_ci drm_dbg_core(dev, "no function\n"); 87362306a36Sopenharmony_ci retcode = -EINVAL; 87462306a36Sopenharmony_ci goto err_i1; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (ksize <= sizeof(stack_kdata)) { 87862306a36Sopenharmony_ci kdata = stack_kdata; 87962306a36Sopenharmony_ci } else { 88062306a36Sopenharmony_ci kdata = kmalloc(ksize, GFP_KERNEL); 88162306a36Sopenharmony_ci if (!kdata) { 88262306a36Sopenharmony_ci retcode = -ENOMEM; 88362306a36Sopenharmony_ci goto err_i1; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (copy_from_user(kdata, (void __user *)arg, in_size) != 0) { 88862306a36Sopenharmony_ci retcode = -EFAULT; 88962306a36Sopenharmony_ci goto err_i1; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (ksize > in_size) 89362306a36Sopenharmony_ci memset(kdata + in_size, 0, ksize - in_size); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci retcode = drm_ioctl_kernel(filp, func, kdata, ioctl->flags); 89662306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, kdata, out_size) != 0) 89762306a36Sopenharmony_ci retcode = -EFAULT; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci err_i1: 90062306a36Sopenharmony_ci if (!ioctl) 90162306a36Sopenharmony_ci drm_dbg_core(dev, 90262306a36Sopenharmony_ci "invalid ioctl: comm=\"%s\", pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n", 90362306a36Sopenharmony_ci current->comm, task_pid_nr(current), 90462306a36Sopenharmony_ci (long)old_encode_dev(file_priv->minor->kdev->devt), 90562306a36Sopenharmony_ci file_priv->authenticated, cmd, nr); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (kdata != stack_kdata) 90862306a36Sopenharmony_ci kfree(kdata); 90962306a36Sopenharmony_ci if (retcode) 91062306a36Sopenharmony_ci drm_dbg_core(dev, "comm=\"%s\", pid=%d, ret=%d\n", 91162306a36Sopenharmony_ci current->comm, task_pid_nr(current), retcode); 91262306a36Sopenharmony_ci return retcode; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ciEXPORT_SYMBOL(drm_ioctl); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci/** 91762306a36Sopenharmony_ci * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags 91862306a36Sopenharmony_ci * @nr: ioctl number 91962306a36Sopenharmony_ci * @flags: where to return the ioctl permission flags 92062306a36Sopenharmony_ci * 92162306a36Sopenharmony_ci * This ioctl is only used by the vmwgfx driver to augment the access checks 92262306a36Sopenharmony_ci * done by the drm core and insofar a pretty decent layering violation. This 92362306a36Sopenharmony_ci * shouldn't be used by any drivers. 92462306a36Sopenharmony_ci * 92562306a36Sopenharmony_ci * Returns: 92662306a36Sopenharmony_ci * True if the @nr corresponds to a DRM core ioctl number, false otherwise. 92762306a36Sopenharmony_ci */ 92862306a36Sopenharmony_cibool drm_ioctl_flags(unsigned int nr, unsigned int *flags) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) 93162306a36Sopenharmony_ci return false; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (nr >= DRM_CORE_IOCTL_COUNT) 93462306a36Sopenharmony_ci return false; 93562306a36Sopenharmony_ci nr = array_index_nospec(nr, DRM_CORE_IOCTL_COUNT); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci *flags = drm_ioctls[nr].flags; 93862306a36Sopenharmony_ci return true; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ciEXPORT_SYMBOL(drm_ioctl_flags); 941