2005-04-17 02:20:36 +04:00
/**
2005-09-25 08:28:13 +04:00
* \ file drm_drawable . c
2005-04-17 02:20:36 +04:00
* IOCTLs for drawables
*
* \ author Rickard E . ( Rik ) Faith < faith @ valinux . com >
* \ author Gareth Hughes < gareth @ valinux . com >
2006-10-24 17:04:19 +04:00
* \ author Michel Dänzer < michel @ tungstengraphics . com >
2005-04-17 02:20:36 +04:00
*/
/*
* Created : Tue Feb 2 08 : 37 : 54 1999 by faith @ valinux . com
*
* Copyright 1999 Precision Insight , Inc . , Cedar Park , Texas .
* Copyright 2000 VA Linux Systems , Inc . , Sunnyvale , California .
2006-10-24 17:18:49 +04:00
* Copyright 2006 Tungsten Graphics , Inc . , Bismarck , North Dakota .
2005-04-17 02:20:36 +04:00
* 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"
2006-10-24 17:18:49 +04:00
/**
* Allocate drawable ID and memory to store information about it .
*/
2006-10-24 17:04:19 +04:00
int drm_adddraw ( DRM_IOCTL_ARGS )
2005-04-17 02:20:36 +04:00
{
2006-10-24 17:04:19 +04:00
DRM_DEVICE ;
unsigned long irqflags ;
2006-10-24 17:18:49 +04:00
int i , j ;
u32 * bitfield = dev - > drw_bitfield ;
unsigned int bitfield_length = dev - > drw_bitfield_length ;
2007-07-11 09:27:12 +04:00
struct drm_drawable_info * * info = dev - > drw_info ;
2006-10-24 17:18:49 +04:00
unsigned int info_length = dev - > drw_info_length ;
2007-07-11 09:27:12 +04:00
struct drm_draw draw ;
2005-04-17 02:20:36 +04:00
2006-10-24 17:18:49 +04:00
for ( i = 0 , j = 0 ; i < bitfield_length ; i + + ) {
if ( bitfield [ i ] = = ~ 0 )
2006-10-24 17:04:19 +04:00
continue ;
2006-10-24 17:18:49 +04:00
for ( ; j < 8 * sizeof ( * bitfield ) ; j + + )
if ( ! ( bitfield [ i ] & ( 1 < < j ) ) )
2006-10-24 17:04:19 +04:00
goto done ;
}
done :
2006-10-24 17:18:49 +04:00
if ( i = = bitfield_length ) {
bitfield_length + + ;
bitfield = drm_alloc ( bitfield_length * sizeof ( * bitfield ) ,
DRM_MEM_BUFS ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:18:49 +04:00
if ( ! bitfield ) {
2006-10-24 17:04:19 +04:00
DRM_ERROR ( " Failed to allocate new drawable bitfield \n " ) ;
return DRM_ERR ( ENOMEM ) ;
}
2006-10-24 17:18:49 +04:00
if ( 8 * sizeof ( * bitfield ) * bitfield_length > info_length ) {
info_length + = 8 * sizeof ( * bitfield ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:18:49 +04:00
info = drm_alloc ( info_length * sizeof ( * info ) ,
DRM_MEM_BUFS ) ;
if ( ! info ) {
2006-10-24 17:04:19 +04:00
DRM_ERROR ( " Failed to allocate new drawable info "
" array \n " ) ;
2006-10-24 17:18:49 +04:00
drm_free ( bitfield ,
bitfield_length * sizeof ( * bitfield ) ,
DRM_MEM_BUFS ) ;
2006-10-24 17:04:19 +04:00
return DRM_ERR ( ENOMEM ) ;
}
}
2006-10-24 17:18:49 +04:00
bitfield [ i ] = 0 ;
2006-10-24 17:04:19 +04:00
}
2006-10-24 17:20:15 +04:00
draw . handle = i * 8 * sizeof ( * bitfield ) + j + 1 ;
2005-04-17 02:20:36 +04:00
DRM_DEBUG ( " %d \n " , draw . handle ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:18:49 +04:00
spin_lock_irqsave ( & dev - > drw_lock , irqflags ) ;
bitfield [ i ] | = 1 < < j ;
2006-10-24 17:20:15 +04:00
info [ draw . handle - 1 ] = NULL ;
2006-10-24 17:18:49 +04:00
if ( bitfield ! = dev - > drw_bitfield ) {
memcpy ( bitfield , dev - > drw_bitfield , dev - > drw_bitfield_length *
sizeof ( * bitfield ) ) ;
drm_free ( dev - > drw_bitfield , sizeof ( * bitfield ) *
dev - > drw_bitfield_length , DRM_MEM_BUFS ) ;
dev - > drw_bitfield = bitfield ;
dev - > drw_bitfield_length = bitfield_length ;
}
if ( info ! = dev - > drw_info ) {
memcpy ( info , dev - > drw_info , dev - > drw_info_length *
sizeof ( * info ) ) ;
drm_free ( dev - > drw_info , sizeof ( * info ) * dev - > drw_info_length ,
DRM_MEM_BUFS ) ;
dev - > drw_info = info ;
dev - > drw_info_length = info_length ;
}
2006-10-24 17:04:19 +04:00
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2007-07-11 09:27:12 +04:00
DRM_COPY_TO_USER_IOCTL ( ( struct drm_draw __user * ) data , draw , sizeof ( draw ) ) ;
2006-10-24 17:04:19 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-10-24 17:18:49 +04:00
/**
* Free drawable ID and memory to store information about it .
*/
2006-10-24 17:04:19 +04:00
int drm_rmdraw ( DRM_IOCTL_ARGS )
2005-04-17 02:20:36 +04:00
{
2006-10-24 17:04:19 +04:00
DRM_DEVICE ;
2007-07-11 09:27:12 +04:00
struct drm_draw draw ;
2006-10-24 17:28:23 +04:00
int id , idx ;
unsigned int shift ;
2006-10-24 17:04:19 +04:00
unsigned long irqflags ;
2006-10-24 17:18:49 +04:00
u32 * bitfield = dev - > drw_bitfield ;
unsigned int bitfield_length = dev - > drw_bitfield_length ;
2007-07-11 09:27:12 +04:00
struct drm_drawable_info * * info = dev - > drw_info ;
2006-10-24 17:18:49 +04:00
unsigned int info_length = dev - > drw_info_length ;
2006-10-24 17:04:19 +04:00
2007-07-11 09:27:12 +04:00
DRM_COPY_FROM_USER_IOCTL ( draw , ( struct drm_draw __user * ) data ,
2006-10-24 17:04:19 +04:00
sizeof ( draw ) ) ;
2006-10-24 17:20:15 +04:00
id = draw . handle - 1 ;
idx = id / ( 8 * sizeof ( * bitfield ) ) ;
shift = id % ( 8 * sizeof ( * bitfield ) ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:20:15 +04:00
if ( idx < 0 | | idx > = bitfield_length | |
2006-10-24 17:18:49 +04:00
! ( bitfield [ idx ] & ( 1 < < shift ) ) ) {
2006-10-24 17:04:19 +04:00
DRM_DEBUG ( " No such drawable %d \n " , draw . handle ) ;
return 0 ;
}
2006-10-24 17:18:49 +04:00
spin_lock_irqsave ( & dev - > drw_lock , irqflags ) ;
bitfield [ idx ] & = ~ ( 1 < < shift ) ;
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:20:15 +04:00
if ( info [ id ] ) {
drm_free ( info [ id ] - > rects , info [ id ] - > num_rects *
2007-07-11 09:27:12 +04:00
sizeof ( struct drm_clip_rect ) , DRM_MEM_BUFS ) ;
2006-10-24 17:20:15 +04:00
drm_free ( info [ id ] , sizeof ( * * info ) , DRM_MEM_BUFS ) ;
}
2006-10-24 17:18:49 +04:00
/* Can we shrink the arrays? */
if ( idx = = bitfield_length - 1 ) {
while ( idx > = 0 & & ! bitfield [ idx ] )
2006-10-24 17:04:19 +04:00
- - idx ;
2006-10-24 17:18:49 +04:00
bitfield_length = idx + 1 ;
2006-10-24 17:04:19 +04:00
2007-05-25 22:37:08 +04:00
bitfield = NULL ;
2006-10-24 17:18:49 +04:00
2007-05-25 22:37:08 +04:00
if ( bitfield_length ) {
if ( bitfield_length ! = dev - > drw_bitfield_length )
bitfield = drm_alloc ( bitfield_length *
sizeof ( * bitfield ) ,
DRM_MEM_BUFS ) ;
if ( ! bitfield ) {
bitfield = dev - > drw_bitfield ;
bitfield_length = dev - > drw_bitfield_length ;
}
2006-10-24 17:04:19 +04:00
}
}
2006-10-24 17:18:49 +04:00
if ( bitfield ! = dev - > drw_bitfield ) {
info_length = 8 * sizeof ( * bitfield ) * bitfield_length ;
2007-05-25 22:37:08 +04:00
if ( info_length ) {
info = drm_alloc ( info_length * sizeof ( * info ) ,
DRM_MEM_BUFS ) ;
2006-10-24 17:18:49 +04:00
2007-05-25 22:37:08 +04:00
if ( ! info ) {
info = dev - > drw_info ;
info_length = dev - > drw_info_length ;
}
} else
info = NULL ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:18:49 +04:00
spin_lock_irqsave ( & dev - > drw_lock , irqflags ) ;
2007-05-25 22:37:08 +04:00
if ( bitfield )
memcpy ( bitfield , dev - > drw_bitfield , bitfield_length *
sizeof ( * bitfield ) ) ;
2006-10-24 17:18:49 +04:00
drm_free ( dev - > drw_bitfield , sizeof ( * bitfield ) *
dev - > drw_bitfield_length , DRM_MEM_BUFS ) ;
dev - > drw_bitfield = bitfield ;
dev - > drw_bitfield_length = bitfield_length ;
if ( info ! = dev - > drw_info ) {
2007-05-25 22:37:08 +04:00
if ( info )
memcpy ( info , dev - > drw_info , info_length *
sizeof ( * info ) ) ;
2006-10-24 17:18:49 +04:00
drm_free ( dev - > drw_info , sizeof ( * info ) *
dev - > drw_info_length , DRM_MEM_BUFS ) ;
dev - > drw_info = info ;
dev - > drw_info_length = info_length ;
}
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
}
2006-10-24 17:04:19 +04:00
DRM_DEBUG ( " %d \n " , draw . handle ) ;
return 0 ;
}
int drm_update_drawable_info ( DRM_IOCTL_ARGS ) {
DRM_DEVICE ;
2007-07-11 09:27:12 +04:00
struct drm_update_draw update ;
2006-10-24 17:18:49 +04:00
unsigned int id , idx , shift ;
u32 * bitfield = dev - > drw_bitfield ;
unsigned long irqflags , bitfield_length = dev - > drw_bitfield_length ;
2007-07-11 09:27:12 +04:00
struct drm_drawable_info * info ;
struct drm_clip_rect * rects ;
2006-10-24 17:18:49 +04:00
int err ;
2006-10-24 17:04:19 +04:00
2007-07-11 09:27:12 +04:00
DRM_COPY_FROM_USER_IOCTL ( update , ( struct drm_update_draw __user * ) data ,
2006-10-24 17:04:19 +04:00
sizeof ( update ) ) ;
2006-10-24 17:20:15 +04:00
id = update . handle - 1 ;
2006-10-24 17:18:49 +04:00
idx = id / ( 8 * sizeof ( * bitfield ) ) ;
shift = id % ( 8 * sizeof ( * bitfield ) ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:20:15 +04:00
if ( idx < 0 | | idx > = bitfield_length | |
! ( bitfield [ idx ] & ( 1 < < shift ) ) ) {
2006-10-24 17:04:19 +04:00
DRM_ERROR ( " No such drawable %d \n " , update . handle ) ;
return DRM_ERR ( EINVAL ) ;
}
info = dev - > drw_info [ id ] ;
if ( ! info ) {
2007-07-11 09:27:12 +04:00
info = drm_calloc ( 1 , sizeof ( struct drm_drawable_info ) , DRM_MEM_BUFS ) ;
2006-10-24 17:04:19 +04:00
if ( ! info ) {
DRM_ERROR ( " Failed to allocate drawable info memory \n " ) ;
return DRM_ERR ( ENOMEM ) ;
}
}
switch ( update . type ) {
case DRM_DRAWABLE_CLIPRECTS :
if ( update . num ! = info - > num_rects ) {
2007-07-11 09:27:12 +04:00
rects = drm_alloc ( update . num * sizeof ( struct drm_clip_rect ) ,
2006-10-24 17:18:49 +04:00
DRM_MEM_BUFS ) ;
} else
rects = info - > rects ;
if ( update . num & & ! rects ) {
DRM_ERROR ( " Failed to allocate cliprect memory \n " ) ;
err = DRM_ERR ( ENOMEM ) ;
goto error ;
2006-10-24 17:04:19 +04:00
}
2006-10-24 17:18:49 +04:00
if ( update . num & & DRM_COPY_FROM_USER ( rects ,
2007-07-11 09:27:12 +04:00
( struct drm_clip_rect __user * )
2006-10-24 17:18:49 +04:00
( unsigned long ) update . data ,
update . num *
sizeof ( * rects ) ) ) {
DRM_ERROR ( " Failed to copy cliprects from userspace \n " ) ;
err = DRM_ERR ( EFAULT ) ;
goto error ;
2006-10-24 17:04:19 +04:00
}
2006-10-24 17:18:49 +04:00
spin_lock_irqsave ( & dev - > drw_lock , irqflags ) ;
if ( rects ! = info - > rects ) {
2006-10-24 17:04:19 +04:00
drm_free ( info - > rects , info - > num_rects *
2007-07-11 09:27:12 +04:00
sizeof ( struct drm_clip_rect ) , DRM_MEM_BUFS ) ;
2006-10-24 17:04:19 +04:00
}
2006-10-24 17:18:49 +04:00
info - > rects = rects ;
info - > num_rects = update . num ;
dev - > drw_info [ id ] = info ;
spin_unlock_irqrestore ( & dev - > drw_lock , irqflags ) ;
2006-10-24 17:04:19 +04:00
DRM_DEBUG ( " Updated %d cliprects for drawable %d \n " ,
info - > num_rects , id ) ;
break ;
default :
DRM_ERROR ( " Invalid update type %d \n " , update . type ) ;
return DRM_ERR ( EINVAL ) ;
}
return 0 ;
2006-10-24 17:18:49 +04:00
error :
if ( ! dev - > drw_info [ id ] )
drm_free ( info , sizeof ( * info ) , DRM_MEM_BUFS ) ;
else if ( rects ! = dev - > drw_info [ id ] - > rects )
drm_free ( rects , update . num *
2007-07-11 09:27:12 +04:00
sizeof ( struct drm_clip_rect ) , DRM_MEM_BUFS ) ;
2006-10-24 17:18:49 +04:00
return err ;
2006-10-24 17:04:19 +04:00
}
/**
* Caller must hold the drawable spinlock !
*/
2007-07-11 09:53:27 +04:00
struct drm_drawable_info * drm_get_drawable_info ( struct drm_device * dev , drm_drawable_t id ) {
2006-10-24 17:18:49 +04:00
u32 * bitfield = dev - > drw_bitfield ;
2006-10-24 17:20:15 +04:00
unsigned int idx , shift ;
id - - ;
idx = id / ( 8 * sizeof ( * bitfield ) ) ;
shift = id % ( 8 * sizeof ( * bitfield ) ) ;
2006-10-24 17:04:19 +04:00
2006-10-24 17:20:15 +04:00
if ( idx < 0 | | idx > = dev - > drw_bitfield_length | |
2006-10-24 17:18:49 +04:00
! ( bitfield [ idx ] & ( 1 < < shift ) ) ) {
2006-10-24 17:04:19 +04:00
DRM_DEBUG ( " No such drawable %d \n " , id ) ;
return NULL ;
}
return dev - > drw_info [ id ] ;
2005-04-17 02:20:36 +04:00
}
2006-10-24 17:04:19 +04:00
EXPORT_SYMBOL ( drm_get_drawable_info ) ;