1450N/A/*
1450N/A * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
1450N/A */
1450N/A
1450N/A/*
1450N/A * Copyright (c) 2012 Intel Corporation. All rights reserved.
1450N/A */
1450N/A
1450N/A/**
1450N/A * \file drm_ioctl.c
1450N/A * IOCTL processing for DRM
1450N/A *
1450N/A * \author Rickard E. (Rik) Faith <faith@valinux.com>
1450N/A * \author Gareth Hughes <gareth@valinux.com>
1450N/A */
1450N/A
1450N/A/*
1450N/A * Created: Fri Jan 8 09:01:26 1999 by faith@valinux.com
1450N/A *
1450N/A * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
1450N/A * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
1450N/A * All Rights Reserved.
1450N/A *
1450N/A * Permission is hereby granted, free of charge, to any person obtaining a
1450N/A * copy of this software and associated documentation files (the "Software"),
1450N/A * to deal in the Software without restriction, including without limitation
1450N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1450N/A * and/or sell copies of the Software, and to permit persons to whom the
1450N/A * Software is furnished to do so, subject to the following conditions:
1450N/A *
1450N/A * The above copyright notice and this permission notice (including the next
1450N/A * paragraph) shall be included in all copies or substantial portions of the
1450N/A * Software.
1450N/A *
1450N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1450N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1450N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1450N/A * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1450N/A * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1450N/A * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1450N/A * OTHER DEALINGS IN THE SOFTWARE.
1450N/A */
1450N/A
1450N/A#include "drmP.h"
1450N/A#include "drm_core.h"
1450N/A#include "drm_io32.h"
1450N/A
1450N/A/**
1450N/A * Get the bus id.
1450N/A *
1450N/A * \param inode device inode.
1450N/A * \param file_priv DRM file private.
1450N/A * \param cmd command.
1450N/A * \param arg user argument, pointing to a drm_unique structure.
1450N/A * \return zero on success or a negative number on failure.
1450N/A *
1450N/A * Copies the bus id from drm_device::unique into user space.
1450N/A */
1450N/A/* LINTED */
1450N/Aint drm_getunique(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_unique *u = data;
1450N/A struct drm_master *master = file->master;
1450N/A
1450N/A if (master->unique_len == 0 || master->unique == NULL) {
1450N/A return -EFAULT;
1450N/A }
1450N/A
1450N/A if (u->unique_len >= master->unique_len) {
1450N/A if (u->unique == NULL) {
1450N/A return -EINVAL;
1450N/A }
1450N/A if (DRM_COPY_TO_USER(u->unique, master->unique, master->unique_len))
1450N/A return -EFAULT;
1450N/A }
1450N/A u->unique_len = master->unique_len;
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/A/*
1450N/A * Deprecated in DRM version 1.1, and will return EBUSY when setversion has
1450N/A * requested version 1.1 or greater.
1450N/A */
1450N/A/* LINTED */
1450N/Aint drm_setunique(DRM_IOCTL_ARGS)
1450N/A{
1450N/A return -EINVAL;
1450N/A}
1450N/A
1450N/Astatic int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv)
1450N/A{
1450N/A struct drm_master *master = file_priv->master;
1450N/A int len;
1450N/A
1450N/A if (master->unique != NULL)
1450N/A return -EBUSY;
1450N/A
1450N/A master->unique_len = 40;
1450N/A master->unique_size = master->unique_len;
1450N/A master->unique = kmalloc(master->unique_size, GFP_KERNEL);
1450N/A if (master->unique == NULL)
1450N/A return -ENOMEM;
1450N/A
1450N/A len = snprintf(master->unique, master->unique_len, "pci:%04x:%02x:%02x.%1x",
1450N/A dev->pdev->domain, dev->pdev->bus, dev->pdev->slot, dev->pdev->func);
1450N/A if (len >= master->unique_len)
1450N/A DRM_ERROR("buffer overflow");
1450N/A else
1450N/A master->unique_len = len;
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/A/**
1450N/A * Get a mapping information.
1450N/A *
1450N/A * \param inode device inode.
1450N/A * \param file_priv DRM file private.
1450N/A * \param cmd command.
1450N/A * \param arg user argument, pointing to a drm_map structure.
1450N/A *
1450N/A * \return zero on success or a negative number on failure.
1450N/A *
1450N/A * Searches for the mapping with the specified offset and copies its information
1450N/A * into userspace
1450N/A */
1450N/A/* LINTED */
1450N/Aint drm_getmap(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_map *map = data;
1450N/A struct drm_map_list *r_list = NULL;
1450N/A struct list_head *list;
1450N/A int idx;
1450N/A int i;
1450N/A
1450N/A idx = (int)map->offset;
1450N/A if (idx < 0)
1450N/A return -EINVAL;
1450N/A
1450N/A i = 0;
1450N/A mutex_lock(&dev->struct_mutex);
1450N/A list_for_each(list, &dev->maplist) {
1450N/A if (i == idx) {
1450N/A r_list = list_entry(list, struct drm_map_list, head);
1450N/A break;
1450N/A }
1450N/A i++;
1450N/A }
1450N/A if (!r_list || !r_list->map) {
1450N/A mutex_unlock(&dev->struct_mutex);
1450N/A return -EINVAL;
1450N/A }
1450N/A
1450N/A map->offset = r_list->map->offset;
1450N/A map->size = r_list->map->size;
1450N/A map->type = r_list->map->type;
1450N/A map->flags = r_list->map->flags;
1450N/A map->handle = (unsigned long long)(uintptr_t)r_list->user_token;
1450N/A map->mtrr = r_list->map->mtrr;
1450N/A mutex_unlock(&dev->struct_mutex);
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/A/**
1450N/A * Get client information.
1450N/A *
1450N/A * \param inode device inode.
1450N/A * \param file_priv DRM file private.
1450N/A * \param cmd command.
1450N/A * \param arg user argument, pointing to a drm_client structure.
1450N/A *
1450N/A * \return zero on success or a negative number on failure.
1450N/A *
1450N/A * Searches for the client with the specified index and copies its information
1450N/A * into userspace
1450N/A */
1450N/A/* LINTED */
1450N/Aint drm_getclient(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_client *client = data;
1450N/A struct drm_file *pt;
1450N/A int idx;
1450N/A int i;
1450N/A
1450N/A idx = client->idx;
1450N/A i = 0;
1450N/A
1450N/A mutex_lock(&dev->struct_mutex);
1450N/A list_for_each_entry(pt, struct drm_file, &dev->filelist, lhead){
1450N/A if (i++ >= idx) {
1450N/A client->auth = pt->authenticated;
1450N/A client->pid = pt->pid;
1450N/A client->uid = pt->uid;
1450N/A client->magic = pt->magic;
1450N/A client->iocs = pt->ioctl_count;
1450N/A mutex_unlock(&dev->struct_mutex);
1450N/A
1450N/A return 0;
1450N/A }
1450N/A }
1450N/A mutex_unlock(&dev->struct_mutex);
1450N/A
1450N/A return -EINVAL;
1450N/A}
1450N/A
1450N/A/**
1450N/A * Get statistics information.
1450N/A *
1450N/A * \param inode device inode.
1450N/A * \param file_priv DRM file private.
1450N/A * \param cmd command.
1450N/A * \param arg user argument, pointing to a drm_stats structure.
1450N/A *
1450N/A * \return zero on success or a negative number on failure.
1450N/A */
1450N/A/* LINTED E_FUNC_ARG_UNUSED */
1450N/Aint drm_getstats(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_stats *stats = data;
1450N/A int i;
1450N/A
1450N/A (void) memset(stats, 0, sizeof(*stats));
1450N/A
1450N/A for (i = 0; i < dev->counters; i++) {
1450N/A if (dev->types[i] == _DRM_STAT_LOCK)
1450N/A stats->data[i].value =
1450N/A (file->master->lock.hw_lock ? file->master->lock.hw_lock->lock : 0);
1450N/A else
1450N/A stats->data[i].value = atomic_read(&dev->counts[i]);
1450N/A stats->data[i].type = dev->types[i];
1450N/A }
1450N/A
1450N/A stats->count = dev->counters;
1450N/A
1450N/A return 0;
1450N/A}
1450N/A
1450N/A/**
1450N/A * Get device/driver capabilities
1450N/A */
1450N/A/* LINTED E_FUNC_ARG_UNUSED */
1450N/Aint drm_getcap(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_get_cap *req = data;
1450N/A
1450N/A req->value = 0;
1450N/A switch (req->capability) {
1450N/A case DRM_CAP_DUMB_BUFFER:
1450N/A if (dev->driver->dumb_create)
1450N/A req->value = 1;
1450N/A break;
1450N/A case DRM_CAP_VBLANK_HIGH_CRTC:
1450N/A req->value = 1;
1450N/A break;
1450N/A case DRM_CAP_DUMB_PREFERRED_DEPTH:
1450N/A req->value = dev->mode_config.preferred_depth;
1450N/A break;
1450N/A case DRM_CAP_DUMB_PREFER_SHADOW:
1450N/A req->value = dev->mode_config.prefer_shadow;
1450N/A break;
1450N/A default:
1450N/A return -EINVAL;
1450N/A }
1450N/A return 0;
1450N/A}
1450N/A
1450N/A/**
1450N/A * Setversion ioctl.
1450N/A *
1450N/A * \param inode device inode.
1450N/A * \param file_priv DRM file private.
1450N/A * \param cmd command.
1450N/A * \param arg user argument, pointing to a drm_lock structure.
1450N/A * \return zero on success or negative number on failure.
1450N/A *
1450N/A * Sets the requested interface version
1450N/A */
1450N/A/* LINTED */
1450N/Aint drm_setversion(DRM_IOCTL_ARGS)
1450N/A{
1450N/A struct drm_set_version *sv = data;
1450N/A int if_version, retcode = 0;
1450N/A
1450N/A if (sv->drm_di_major != -1) {
1450N/A if (sv->drm_di_major != DRM_IF_MAJOR ||
1450N/A sv->drm_di_minor < 0 || sv->drm_di_minor > DRM_IF_MINOR) {
1450N/A retcode = -EINVAL;
1450N/A goto done;
1450N/A }
1450N/A if_version = DRM_IF_VERSION(sv->drm_di_major,
1450N/A sv->drm_di_minor);
1450N/A dev->if_version = DRM_MAX(if_version, dev->if_version);
1450N/A if (sv->drm_di_minor >= 1) {
1450N/A /*
1450N/A * Version 1.1 includes tying of DRM to specific device
1450N/A */
1450N/A (void) drm_set_busid(dev, file);
1450N/A }
1450N/A }
1450N/A
1450N/A if (sv->drm_dd_major != -1) {
1450N/A if (sv->drm_dd_major != dev->driver->major ||
1450N/A sv->drm_dd_minor < 0 || sv->drm_dd_minor >
1450N/A dev->driver->minor) {
1450N/A retcode = -EINVAL;
1450N/A goto done;
1450N/A }
1450N/A
1450N/A /* OSOL_drm: if (dev->driver->set_version)
1450N/A dev->driver->set_version(dev, sv); */
1450N/A }
1450N/A
1450N/Adone:
1450N/A sv->drm_di_major = DRM_IF_MAJOR;
1450N/A sv->drm_di_minor = DRM_IF_MINOR;
1450N/A sv->drm_dd_major = dev->driver->major;
1450N/A sv->drm_dd_minor = dev->driver->minor;
1450N/A
1450N/A return retcode;
1450N/A}
1450N/A
1450N/A/** No-op ioctl. */
1450N/A/* LINTED */
1450N/Aint drm_noop(DRM_IOCTL_ARGS)
1450N/A{
1450N/A DRM_DEBUG("\n");
1450N/A return 0;
1450N/A}
1450N/A