2006-01-20 14:08:59 -08:00
2005-04-16 15:20:36 -07:00
/*
* drm_sysfs . c - Modifications to drm_sysfs_class . c to support
* extra sysfs attribute from DRM . Normal drm_sysfs_class
* does not allow adding attributes .
*
* Copyright ( c ) 2004 Jon Smirl < jonsmirl @ gmail . com >
* Copyright ( c ) 2003 - 2004 Greg Kroah - Hartman < greg @ kroah . com >
* Copyright ( c ) 2003 - 2004 IBM Corp .
*
* This file is released under the GPLv2
*
*/
# include <linux/device.h>
# include <linux/kdev_t.h>
# include <linux/err.h>
# include "drm_core.h"
2005-09-05 21:33:44 +10:00
# include "drmP.h"
2005-04-16 15:20:36 -07:00
2008-04-21 16:47:32 +10:00
# define to_drm_minor(d) container_of(d, struct drm_minor, kdev)
2007-11-22 14:02:38 +10:00
/**
* drm_sysfs_suspend - DRM class suspend hook
* @ dev : Linux device to suspend
* @ state : power state to enter
*
* Just figures out what the actual struct drm_device associated with
* @ dev is and calls its suspend hook , if present .
*/
static int drm_sysfs_suspend ( struct device * dev , pm_message_t state )
{
2008-04-21 16:47:32 +10:00
struct drm_minor * drm_minor = to_drm_minor ( dev ) ;
struct drm_device * drm_dev = drm_minor - > dev ;
2007-11-22 14:02:38 +10:00
if ( drm_dev - > driver - > suspend )
2008-02-20 10:02:20 +10:00
return drm_dev - > driver - > suspend ( drm_dev , state ) ;
2007-11-22 14:02:38 +10:00
return 0 ;
}
/**
* drm_sysfs_resume - DRM class resume hook
* @ dev : Linux device to resume
*
* Just figures out what the actual struct drm_device associated with
* @ dev is and calls its resume hook , if present .
*/
static int drm_sysfs_resume ( struct device * dev )
{
2008-04-21 16:47:32 +10:00
struct drm_minor * drm_minor = to_drm_minor ( dev ) ;
struct drm_device * drm_dev = drm_minor - > dev ;
2007-11-22 14:02:38 +10:00
if ( drm_dev - > driver - > resume )
return drm_dev - > driver - > resume ( drm_dev ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
/* Display the version of drm_core. This doesn't work right in current design */
static ssize_t version_show ( struct class * dev , char * buf )
{
return sprintf ( buf , " %s %d.%d.%d %s \n " , CORE_NAME , CORE_MAJOR ,
CORE_MINOR , CORE_PATCHLEVEL , CORE_DATE ) ;
}
static CLASS_ATTR ( version , S_IRUGO , version_show , NULL ) ;
/**
* drm_sysfs_create - create a struct drm_sysfs_class structure
* @ owner : pointer to the module that is to " own " this struct drm_sysfs_class
* @ name : pointer to a string for the name of this class .
*
2007-11-22 14:02:38 +10:00
* This is used to create DRM class pointer that can then be used
2005-04-16 15:20:36 -07:00
* in calls to drm_sysfs_device_add ( ) .
*
* Note , the pointer created here is to be destroyed when finished by making a
* call to drm_sysfs_destroy ( ) .
*/
2006-01-20 14:08:59 -08:00
struct class * drm_sysfs_create ( struct module * owner , char * name )
2005-04-16 15:20:36 -07:00
{
2006-01-20 14:08:59 -08:00
struct class * class ;
2006-10-10 14:23:37 -07:00
int err ;
2006-01-20 14:08:59 -08:00
class = class_create ( owner , name ) ;
2006-12-09 10:49:47 +11:00
if ( IS_ERR ( class ) ) {
err = PTR_ERR ( class ) ;
2006-10-10 14:23:37 -07:00
goto err_out ;
}
2007-11-22 14:02:38 +10:00
class - > suspend = drm_sysfs_suspend ;
class - > resume = drm_sysfs_resume ;
2006-10-10 14:23:37 -07:00
err = class_create_file ( class , & class_attr_version ) ;
if ( err )
goto err_out_class ;
2006-01-20 14:08:59 -08:00
return class ;
2006-10-10 14:23:37 -07:00
err_out_class :
class_destroy ( class ) ;
err_out :
return ERR_PTR ( err ) ;
2005-04-16 15:20:36 -07:00
}
/**
2007-11-22 14:02:38 +10:00
* drm_sysfs_destroy - destroys DRM class
2005-04-16 15:20:36 -07:00
*
2007-11-22 14:02:38 +10:00
* Destroy the DRM device class .
2005-04-16 15:20:36 -07:00
*/
2007-11-22 14:02:38 +10:00
void drm_sysfs_destroy ( void )
2005-04-16 15:20:36 -07:00
{
2007-11-22 14:02:38 +10:00
if ( ( drm_class = = NULL ) | | ( IS_ERR ( drm_class ) ) )
2005-04-16 15:20:36 -07:00
return ;
2007-11-22 14:02:38 +10:00
class_remove_file ( drm_class , & class_attr_version ) ;
class_destroy ( drm_class ) ;
2005-04-16 15:20:36 -07:00
}
2007-11-22 14:02:38 +10:00
static ssize_t show_dri ( struct device * device , struct device_attribute * attr ,
char * buf )
2005-11-11 22:07:35 +11:00
{
2008-04-21 16:47:32 +10:00
struct drm_minor * drm_minor = to_drm_minor ( device ) ;
struct drm_device * drm_dev = drm_minor - > dev ;
if ( drm_dev - > driver - > dri_library_name )
return drm_dev - > driver - > dri_library_name ( drm_dev , buf ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " , drm_dev - > driver - > pci_driver . name ) ;
2005-11-11 22:07:35 +11:00
}
2007-11-22 14:02:38 +10:00
static struct device_attribute device_attrs [ ] = {
2005-11-11 22:07:35 +11:00
__ATTR ( dri_library_name , S_IRUGO , show_dri , NULL ) ,
} ;
2007-11-22 14:02:38 +10:00
/**
* drm_sysfs_device_release - do nothing
* @ dev : Linux device
*
* Normally , this would free the DRM device associated with @ dev , along
* with cleaning up any other stuff . But we do that in the DRM core , so
* this function can just return and hope that the core does its job .
*/
static void drm_sysfs_device_release ( struct device * dev )
{
return ;
}
2005-04-16 15:20:36 -07:00
/**
* drm_sysfs_device_add - adds a class device to sysfs for a character driver
2007-11-22 14:02:38 +10:00
* @ dev : DRM device to be added
* @ head : DRM head in question
2005-04-16 15:20:36 -07:00
*
2007-11-22 14:02:38 +10:00
* Add a DRM device to the DRM ' s device model class . We use @ dev ' s PCI device
* as the parent for the Linux device , and make sure it has a file containing
* the driver we ' re using ( for userspace compatibility ) .
2005-04-16 15:20:36 -07:00
*/
2008-04-21 16:47:32 +10:00
int drm_sysfs_device_add ( struct drm_minor * minor )
2005-04-16 15:20:36 -07:00
{
2007-11-22 14:02:38 +10:00
int err ;
int i , j ;
2008-04-21 16:47:32 +10:00
char * minor_str ;
2007-11-22 14:02:38 +10:00
2008-04-21 16:47:32 +10:00
minor - > kdev . parent = & minor - > dev - > pdev - > dev ;
minor - > kdev . class = drm_class ;
minor - > kdev . release = drm_sysfs_device_release ;
minor - > kdev . devt = minor - > device ;
minor_str = " card%d " ;
2007-11-22 14:02:38 +10:00
2008-04-21 16:47:32 +10:00
snprintf ( minor - > kdev . bus_id , BUS_ID_SIZE , minor_str , minor - > index ) ;
err = device_register ( & minor - > kdev ) ;
2007-11-22 14:02:38 +10:00
if ( err ) {
DRM_ERROR ( " device add failed: %d \n " , err ) ;
2006-10-10 14:23:37 -07:00
goto err_out ;
}
2005-04-16 15:20:36 -07:00
2007-11-22 14:02:38 +10:00
for ( i = 0 ; i < ARRAY_SIZE ( device_attrs ) ; i + + ) {
2008-04-21 16:47:32 +10:00
err = device_create_file ( & minor - > kdev , & device_attrs [ i ] ) ;
2006-10-10 14:23:37 -07:00
if ( err )
goto err_out_files ;
}
2007-11-22 14:02:38 +10:00
return 0 ;
2006-10-10 14:23:37 -07:00
err_out_files :
if ( i > 0 )
for ( j = 0 ; j < i ; j + + )
2008-09-02 10:06:06 +10:00
device_remove_file ( & minor - > kdev , & device_attrs [ j ] ) ;
2008-04-21 16:47:32 +10:00
device_unregister ( & minor - > kdev ) ;
2006-10-10 14:23:37 -07:00
err_out :
2007-11-22 14:02:38 +10:00
return err ;
2005-04-16 15:20:36 -07:00
}
/**
2007-11-22 14:02:38 +10:00
* drm_sysfs_device_remove - remove DRM device
* @ dev : DRM device to remove
2005-04-16 15:20:36 -07:00
*
* This call unregisters and cleans up a class device that was created with a
* call to drm_sysfs_device_add ( )
*/
2008-04-21 16:47:32 +10:00
void drm_sysfs_device_remove ( struct drm_minor * minor )
2005-04-16 15:20:36 -07:00
{
2005-11-11 22:07:35 +11:00
int i ;
2007-11-22 14:02:38 +10:00
for ( i = 0 ; i < ARRAY_SIZE ( device_attrs ) ; i + + )
2008-04-21 16:47:32 +10:00
device_remove_file ( & minor - > kdev , & device_attrs [ i ] ) ;
device_unregister ( & minor - > kdev ) ;
2005-04-16 15:20:36 -07:00
}