2005-04-16 15:20:36 -07:00
/**
2005-09-25 14:28:13 +10:00
* \ file drm_ioctl . c
2005-04-16 15:20:36 -07:00
* IOCTL processing for DRM
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
*/
/*
* Created : Fri Jan 8 09 : 01 : 26 1999 by faith @ valinux . com
*
* Copyright 1999 Precision Insight , Inc . , Cedar Park , Texas .
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
* All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice ( including the next
* paragraph ) shall be included in all copies or substantial portions of the
* Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* VA LINUX SYSTEMS AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*/
# include "drmP.h"
# include "drm_core.h"
# include "linux/pci.h"
/**
* Get the bus id .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_unique structure .
* \ return zero on success or a negative number on failure .
*
* Copies the bus id from drm_device : : unique into user space .
*/
2007-09-03 12:06:45 +10:00
int drm_getunique ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_unique * u = data ;
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2005-04-16 15:20:36 -07:00
2008-11-28 14:22:24 +10:00
if ( u - > unique_len > = master - > unique_len ) {
if ( copy_to_user ( u - > unique , master - > unique , master - > unique_len ) )
2005-04-16 15:20:36 -07:00
return - EFAULT ;
}
2008-11-28 14:22:24 +10:00
u - > unique_len = master - > unique_len ;
2007-09-03 12:06:45 +10:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2010-08-04 11:09:42 +01:00
static void
drm_unset_busid ( struct drm_device * dev ,
struct drm_master * master )
{
kfree ( dev - > devname ) ;
dev - > devname = NULL ;
kfree ( master - > unique ) ;
master - > unique = NULL ;
master - > unique_len = 0 ;
master - > unique_size = 0 ;
}
2005-04-16 15:20:36 -07:00
/**
* Set the bus id .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_unique structure .
* \ return zero on success or a negative number on failure .
*
* Copies the bus id from userspace into drm_device : : unique , and verifies that
* it matches the device this DRM is attached to ( EINVAL otherwise ) . Deprecated
* in interface version 1.1 and will return EBUSY when setversion has requested
* version 1.1 or greater .
*/
2007-09-03 12:06:45 +10:00
int drm_setunique ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_unique * u = data ;
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2010-12-15 03:16:38 +10:00
int ret ;
2005-04-16 15:20:36 -07:00
2008-11-28 14:22:24 +10:00
if ( master - > unique_len | | master - > unique )
2005-09-25 14:28:13 +10:00
return - EBUSY ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
if ( ! u - > unique_len | | u - > unique_len > 1024 )
2005-09-25 14:28:13 +10:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
2010-12-15 03:16:38 +10:00
if ( ! dev - > driver - > bus - > set_unique )
return - EINVAL ;
2005-09-25 14:28:13 +10:00
2010-12-15 03:16:38 +10:00
ret = dev - > driver - > bus - > set_unique ( dev , master , u ) ;
if ( ret )
2010-08-04 11:09:42 +01:00
goto err ;
2005-04-16 15:20:36 -07:00
return 0 ;
2010-08-04 11:09:42 +01:00
err :
drm_unset_busid ( dev , master ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
2008-11-28 14:22:24 +10:00
static int drm_set_busid ( struct drm_device * dev , struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2008-11-28 14:22:24 +10:00
struct drm_master * master = file_priv - > master ;
2010-12-15 03:16:38 +10:00
int ret ;
2010-08-04 11:09:42 +01:00
if ( master - > unique ! = NULL )
drm_unset_busid ( dev , master ) ;
2006-01-02 21:19:39 +11:00
2010-12-15 03:16:38 +10:00
ret = dev - > driver - > bus - > set_busid ( dev , master ) ;
if ( ret )
goto err ;
2005-04-16 15:20:36 -07:00
return 0 ;
2010-08-04 11:09:42 +01:00
err :
drm_unset_busid ( dev , master ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
/**
* Get a mapping information .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_map structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*
* Searches for the mapping with the specified offset and copies its information
* into userspace
*/
2007-09-03 12:06:45 +10:00
int drm_getmap ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_map * map = data ;
2007-07-11 16:53:40 +10:00
struct drm_map_list * r_list = NULL ;
2005-04-16 15:20:36 -07:00
struct list_head * list ;
2005-09-25 14:28:13 +10:00
int idx ;
int i ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
idx = map - > offset ;
2005-04-16 15:20:36 -07:00
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( idx < 0 ) {
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
i = 0 ;
2007-05-26 05:01:51 +10:00
list_for_each ( list , & dev - > maplist ) {
2005-09-25 14:28:13 +10:00
if ( i = = idx ) {
2007-07-11 16:53:40 +10:00
r_list = list_entry ( list , struct drm_map_list , head ) ;
2005-04-16 15:20:36 -07:00
break ;
}
i + + ;
}
2005-09-25 14:28:13 +10:00
if ( ! r_list | | ! r_list - > map ) {
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return - EINVAL ;
}
2007-09-03 12:06:45 +10:00
map - > offset = r_list - > map - > offset ;
map - > size = r_list - > map - > size ;
map - > type = r_list - > map - > type ;
map - > flags = r_list - > map - > flags ;
map - > handle = ( void * ) ( unsigned long ) r_list - > user_token ;
map - > mtrr = r_list - > map - > mtrr ;
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
/**
* Get client information .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_client structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*
* Searches for the client with the specified index and copies its information
* into userspace
*/
2007-09-03 12:06:45 +10:00
int drm_getclient ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_client * client = data ;
2007-07-11 15:53:27 +10:00
struct drm_file * pt ;
2005-09-25 14:28:13 +10:00
int idx ;
int i ;
2005-04-16 15:20:36 -07:00
2007-09-03 12:06:45 +10:00
idx = client - > idx ;
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2007-11-05 12:50:58 +10:00
2007-05-26 05:01:51 +10:00
i = 0 ;
list_for_each_entry ( pt , & dev - > filelist , lhead ) {
2007-11-22 18:46:54 +10:00
if ( i + + > = idx ) {
client - > auth = pt - > authenticated ;
client - > pid = pt - > pid ;
client - > uid = pt - > uid ;
client - > magic = pt - > magic ;
client - > iocs = pt - > ioctl_count ;
mutex_unlock ( & dev - > struct_mutex ) ;
return 0 ;
}
2007-05-26 05:01:51 +10:00
}
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
2007-11-22 18:46:54 +10:00
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
/**
* Get statistics information .
*
2005-04-16 15:20:36 -07:00
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_stats structure .
2005-09-25 14:28:13 +10:00
*
2005-04-16 15:20:36 -07:00
* \ return zero on success or a negative number on failure .
*/
2007-09-03 12:06:45 +10:00
int drm_getstats ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_stats * stats = data ;
2005-09-25 14:28:13 +10:00
int i ;
2005-04-16 15:20:36 -07:00
2007-11-05 12:53:09 +10:00
memset ( stats , 0 , sizeof ( * stats ) ) ;
2005-09-25 14:28:13 +10:00
2006-02-02 19:37:46 +11:00
mutex_lock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < dev - > counters ; i + + ) {
if ( dev - > types [ i ] = = _DRM_STAT_LOCK )
2007-09-03 12:06:45 +10:00
stats - > data [ i ] . value =
2008-11-28 14:22:24 +10:00
( file_priv - > master - > lock . hw_lock ? file_priv - > master - > lock . hw_lock - > lock : 0 ) ;
2005-09-25 14:28:13 +10:00
else
2007-09-03 12:06:45 +10:00
stats - > data [ i ] . value = atomic_read ( & dev - > counts [ i ] ) ;
stats - > data [ i ] . type = dev - > types [ i ] ;
2005-04-16 15:20:36 -07:00
}
2005-09-25 14:28:13 +10:00
2007-09-03 12:06:45 +10:00
stats - > count = dev - > counters ;
2005-04-16 15:20:36 -07:00
2006-02-02 19:37:46 +11:00
mutex_unlock ( & dev - > struct_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2011-02-21 11:17:35 +10:00
/**
* Get device / driver capabilities
*/
int drm_getcap ( struct drm_device * dev , void * data , struct drm_file * file_priv )
{
struct drm_get_cap * req = data ;
req - > value = 0 ;
2011-03-04 14:50:28 +10:00
switch ( req - > capability ) {
case DRM_CAP_DUMB_BUFFER :
if ( dev - > driver - > dumb_create )
req - > value = 1 ;
break ;
2011-03-24 20:54:35 +10:00
case DRM_CAP_VBLANK_HIGH_CRTC :
2011-03-18 16:58:04 -05:00
req - > value = 1 ;
break ;
2011-03-04 14:50:28 +10:00
default :
return - EINVAL ;
}
2011-02-21 11:17:35 +10:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
/**
* Setversion ioctl .
*
* \ param inode device inode .
2007-08-25 20:23:09 +10:00
* \ param file_priv DRM file private .
2005-04-16 15:20:36 -07:00
* \ param cmd command .
* \ param arg user argument , pointing to a drm_lock structure .
* \ return zero on success or negative number on failure .
*
* Sets the requested interface version
*/
2007-09-03 12:06:45 +10:00
int drm_setversion ( struct drm_device * dev , void * data , struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
2007-09-03 12:06:45 +10:00
struct drm_set_version * sv = data ;
int if_version , retcode = 0 ;
if ( sv - > drm_di_major ! = - 1 ) {
if ( sv - > drm_di_major ! = DRM_IF_MAJOR | |
sv - > drm_di_minor < 0 | | sv - > drm_di_minor > DRM_IF_MINOR ) {
retcode = - EINVAL ;
goto done ;
}
if_version = DRM_IF_VERSION ( sv - > drm_di_major ,
sv - > drm_di_minor ) ;
2006-08-07 20:07:43 +10:00
dev - > if_version = max ( if_version , dev - > if_version ) ;
2007-09-03 12:06:45 +10:00
if ( sv - > drm_di_minor > = 1 ) {
2005-04-16 15:20:36 -07:00
/*
* Version 1.1 includes tying of DRM to specific device
2010-08-06 13:55:10 +10:00
* Version 1.4 has proper PCI domain support
2005-04-16 15:20:36 -07:00
*/
2010-08-04 11:09:42 +01:00
retcode = drm_set_busid ( dev , file_priv ) ;
if ( retcode )
goto done ;
2005-04-16 15:20:36 -07:00
}
}
2007-09-03 12:06:45 +10:00
if ( sv - > drm_dd_major ! = - 1 ) {
if ( sv - > drm_dd_major ! = dev - > driver - > major | |
sv - > drm_dd_minor < 0 | | sv - > drm_dd_minor >
dev - > driver - > minor ) {
retcode = - EINVAL ;
goto done ;
}
2005-04-16 15:20:36 -07:00
if ( dev - > driver - > set_version )
2007-09-03 12:06:45 +10:00
dev - > driver - > set_version ( dev , sv ) ;
2005-04-16 15:20:36 -07:00
}
2007-09-03 12:06:45 +10:00
done :
sv - > drm_di_major = DRM_IF_MAJOR ;
sv - > drm_di_minor = DRM_IF_MINOR ;
sv - > drm_dd_major = dev - > driver - > major ;
sv - > drm_dd_minor = dev - > driver - > minor ;
return retcode ;
2005-04-16 15:20:36 -07:00
}
/** No-op ioctl. */
2007-09-03 12:06:45 +10:00
int drm_noop ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
2005-04-16 15:20:36 -07:00
{
DRM_DEBUG ( " \n " ) ;
return 0 ;
}