2007-05-08 11:37:15 +04:00
/*
* display - sysfs . c - Display output driver sysfs interface
*
* Copyright ( C ) 2007 James Simmons < jsimmons @ infradead . org >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/module.h>
# include <linux/display.h>
# include <linux/ctype.h>
# include <linux/idr.h>
# include <linux/err.h>
2008-05-16 00:44:08 +04:00
# include <linux/kdev_t.h>
2007-05-08 11:37:15 +04:00
static ssize_t display_show_name ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " , dsp - > name ) ;
}
static ssize_t display_show_type ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " , dsp - > type ) ;
}
static ssize_t display_show_contrast ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
ssize_t rc = - ENXIO ;
mutex_lock ( & dsp - > lock ) ;
if ( likely ( dsp - > driver ) & & dsp - > driver - > get_contrast )
rc = sprintf ( buf , " %d \n " , dsp - > driver - > get_contrast ( dsp ) ) ;
mutex_unlock ( & dsp - > lock ) ;
return rc ;
}
static ssize_t display_store_contrast ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
ssize_t ret = - EINVAL , size ;
int contrast ;
char * endp ;
contrast = simple_strtoul ( buf , & endp , 0 ) ;
size = endp - buf ;
if ( * endp & & isspace ( * endp ) )
size + + ;
if ( size ! = count )
return ret ;
mutex_lock ( & dsp - > lock ) ;
if ( likely ( dsp - > driver & & dsp - > driver - > set_contrast ) ) {
pr_debug ( " display: set contrast to %d \n " , contrast ) ;
dsp - > driver - > set_contrast ( dsp , contrast ) ;
ret = count ;
}
mutex_unlock ( & dsp - > lock ) ;
return ret ;
}
static ssize_t display_show_max_contrast ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
ssize_t rc = - ENXIO ;
mutex_lock ( & dsp - > lock ) ;
if ( likely ( dsp - > driver ) )
rc = sprintf ( buf , " %d \n " , dsp - > driver - > max_contrast ) ;
mutex_unlock ( & dsp - > lock ) ;
return rc ;
}
static struct device_attribute display_attrs [ ] = {
__ATTR ( name , S_IRUGO , display_show_name , NULL ) ,
__ATTR ( type , S_IRUGO , display_show_type , NULL ) ,
__ATTR ( contrast , S_IRUGO | S_IWUSR , display_show_contrast , display_store_contrast ) ,
__ATTR ( max_contrast , S_IRUGO , display_show_max_contrast , NULL ) ,
} ;
static int display_suspend ( struct device * dev , pm_message_t state )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
mutex_lock ( & dsp - > lock ) ;
if ( likely ( dsp - > driver - > suspend ) )
dsp - > driver - > suspend ( dsp , state ) ;
mutex_unlock ( & dsp - > lock ) ;
return 0 ;
} ;
static int display_resume ( struct device * dev )
{
struct display_device * dsp = dev_get_drvdata ( dev ) ;
mutex_lock ( & dsp - > lock ) ;
if ( likely ( dsp - > driver - > resume ) )
dsp - > driver - > resume ( dsp ) ;
mutex_unlock ( & dsp - > lock ) ;
return 0 ;
} ;
static struct mutex allocated_dsp_lock ;
static DEFINE_IDR ( allocated_dsp ) ;
2007-05-08 11:37:21 +04:00
static struct class * display_class ;
2007-05-08 11:37:15 +04:00
struct display_device * display_device_register ( struct display_driver * driver ,
struct device * parent , void * devdata )
{
struct display_device * new_dev = NULL ;
int ret = - EINVAL ;
if ( unlikely ( ! driver ) )
return ERR_PTR ( ret ) ;
mutex_lock ( & allocated_dsp_lock ) ;
ret = idr_pre_get ( & allocated_dsp , GFP_KERNEL ) ;
mutex_unlock ( & allocated_dsp_lock ) ;
if ( ! ret )
return ERR_PTR ( ret ) ;
new_dev = kzalloc ( sizeof ( struct display_device ) , GFP_KERNEL ) ;
if ( likely ( new_dev ) & & unlikely ( driver - > probe ( new_dev , devdata ) ) ) {
// Reserve the index for this display
mutex_lock ( & allocated_dsp_lock ) ;
ret = idr_get_new ( & allocated_dsp , new_dev , & new_dev - > idx ) ;
mutex_unlock ( & allocated_dsp_lock ) ;
if ( ! ret ) {
2008-07-22 07:03:34 +04:00
new_dev - > dev = device_create ( display_class , parent ,
MKDEV ( 0 , 0 ) , new_dev ,
" display%d " , new_dev - > idx ) ;
2007-05-08 11:37:15 +04:00
if ( ! IS_ERR ( new_dev - > dev ) ) {
new_dev - > parent = parent ;
new_dev - > driver = driver ;
mutex_init ( & new_dev - > lock ) ;
return new_dev ;
}
mutex_lock ( & allocated_dsp_lock ) ;
idr_remove ( & allocated_dsp , new_dev - > idx ) ;
mutex_unlock ( & allocated_dsp_lock ) ;
ret = - EINVAL ;
}
}
kfree ( new_dev ) ;
return ERR_PTR ( ret ) ;
}
EXPORT_SYMBOL ( display_device_register ) ;
void display_device_unregister ( struct display_device * ddev )
{
if ( ! ddev )
return ;
// Free device
mutex_lock ( & ddev - > lock ) ;
device_unregister ( ddev - > dev ) ;
mutex_unlock ( & ddev - > lock ) ;
// Mark device index as avaliable
mutex_lock ( & allocated_dsp_lock ) ;
idr_remove ( & allocated_dsp , ddev - > idx ) ;
mutex_unlock ( & allocated_dsp_lock ) ;
kfree ( ddev ) ;
}
EXPORT_SYMBOL ( display_device_unregister ) ;
static int __init display_class_init ( void )
{
display_class = class_create ( THIS_MODULE , " display " ) ;
if ( IS_ERR ( display_class ) ) {
printk ( KERN_ERR " Failed to create display class \n " ) ;
display_class = NULL ;
return - EINVAL ;
}
display_class - > dev_attrs = display_attrs ;
display_class - > suspend = display_suspend ;
display_class - > resume = display_resume ;
mutex_init ( & allocated_dsp_lock ) ;
return 0 ;
}
static void __exit display_class_exit ( void )
{
class_destroy ( display_class ) ;
}
module_init ( display_class_init ) ;
module_exit ( display_class_exit ) ;
MODULE_DESCRIPTION ( " Display Hardware handling " ) ;
MODULE_AUTHOR ( " James Simmons <jsimmons@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;