2006-03-31 14:31:04 +04:00
/*
* LED Class Core
*
* Copyright ( C ) 2005 John Lenz < lenz @ cs . wisc . edu >
2007-07-09 02:19:31 +04:00
* Copyright ( C ) 2005 - 2007 Richard Purdie < rpurdie @ openedhand . com >
2006-03-31 14:31:04 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/list.h>
# include <linux/spinlock.h>
# include <linux/device.h>
# include <linux/sysdev.h>
# include <linux/timer.h>
# include <linux/err.h>
2006-05-15 20:44:17 +04:00
# include <linux/ctype.h>
2006-03-31 14:31:04 +04:00
# include <linux/leds.h>
# include "leds.h"
static struct class * leds_class ;
2008-03-18 12:47:48 +03:00
static void led_update_brightness ( struct led_classdev * led_cdev )
{
if ( led_cdev - > brightness_get )
led_cdev - > brightness = led_cdev - > brightness_get ( led_cdev ) ;
}
2007-07-09 02:19:31 +04:00
static ssize_t led_brightness_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2006-03-31 14:31:04 +04:00
{
2007-07-09 02:19:31 +04:00
struct led_classdev * led_cdev = dev_get_drvdata ( dev ) ;
2006-03-31 14:31:04 +04:00
/* no lock needed for this */
2008-03-18 12:47:48 +03:00
led_update_brightness ( led_cdev ) ;
2006-03-31 14:31:04 +04:00
2008-10-13 13:41:39 +04:00
return sprintf ( buf , " %u \n " , led_cdev - > brightness ) ;
2006-03-31 14:31:04 +04:00
}
2007-07-09 02:19:31 +04:00
static ssize_t led_brightness_store ( struct device * dev ,
struct device_attribute * attr , const char * buf , size_t size )
2006-03-31 14:31:04 +04:00
{
2007-07-09 02:19:31 +04:00
struct led_classdev * led_cdev = dev_get_drvdata ( dev ) ;
2006-03-31 14:31:04 +04:00
ssize_t ret = - EINVAL ;
char * after ;
unsigned long state = simple_strtoul ( buf , & after , 10 ) ;
2006-05-15 20:44:17 +04:00
size_t count = after - buf ;
2006-03-31 14:31:04 +04:00
2006-05-15 20:44:17 +04:00
if ( * after & & isspace ( * after ) )
count + + ;
if ( count = = size ) {
ret = count ;
2008-03-09 23:54:37 +03:00
if ( state = = LED_OFF )
led_trigger_remove ( led_cdev ) ;
2006-03-31 14:31:04 +04:00
led_set_brightness ( led_cdev , state ) ;
}
return ret ;
}
2007-07-09 02:19:31 +04:00
static DEVICE_ATTR ( brightness , 0644 , led_brightness_show , led_brightness_store ) ;
2006-03-31 14:31:05 +04:00
# ifdef CONFIG_LEDS_TRIGGERS
2007-07-09 02:19:31 +04:00
static DEVICE_ATTR ( trigger , 0644 , led_trigger_show , led_trigger_store ) ;
2006-03-31 14:31:05 +04:00
# endif
2006-03-31 14:31:04 +04:00
/**
* led_classdev_suspend - suspend an led_classdev .
* @ led_cdev : the led_classdev to suspend .
*/
void led_classdev_suspend ( struct led_classdev * led_cdev )
{
led_cdev - > flags | = LED_SUSPENDED ;
led_cdev - > brightness_set ( led_cdev , 0 ) ;
}
EXPORT_SYMBOL_GPL ( led_classdev_suspend ) ;
/**
* led_classdev_resume - resume an led_classdev .
* @ led_cdev : the led_classdev to resume .
*/
void led_classdev_resume ( struct led_classdev * led_cdev )
{
led_cdev - > brightness_set ( led_cdev , led_cdev - > brightness ) ;
led_cdev - > flags & = ~ LED_SUSPENDED ;
}
EXPORT_SYMBOL_GPL ( led_classdev_resume ) ;
/**
* led_classdev_register - register a new object of led_classdev class .
* @ dev : The device to register .
* @ led_cdev : the led_classdev structure for this device .
*/
int led_classdev_register ( struct device * parent , struct led_classdev * led_cdev )
{
2006-10-17 11:10:20 +04:00
int rc ;
2008-07-22 07:03:34 +04:00
led_cdev - > dev = device_create ( leds_class , parent , 0 , led_cdev ,
" %s " , led_cdev - > name ) ;
2008-04-29 12:03:09 +04:00
if ( IS_ERR ( led_cdev - > dev ) )
2007-07-09 02:19:31 +04:00
return PTR_ERR ( led_cdev - > dev ) ;
2006-03-31 14:31:04 +04:00
/* register the attributes */
2007-07-09 02:19:31 +04:00
rc = device_create_file ( led_cdev - > dev , & dev_attr_brightness ) ;
2006-10-17 11:10:20 +04:00
if ( rc )
goto err_out ;
2006-03-31 14:31:04 +04:00
2008-10-21 02:16:17 +04:00
# ifdef CONFIG_LEDS_TRIGGERS
init_rwsem ( & led_cdev - > trigger_lock ) ;
# endif
2006-03-31 14:31:04 +04:00
/* add to the list of leds */
2008-01-01 02:09:44 +03:00
down_write ( & leds_list_lock ) ;
2006-03-31 14:31:04 +04:00
list_add_tail ( & led_cdev - > node , & leds_list ) ;
2008-01-01 02:09:44 +03:00
up_write ( & leds_list_lock ) ;
2006-03-31 14:31:04 +04:00
2008-03-18 12:47:48 +03:00
led_update_brightness ( led_cdev ) ;
2006-03-31 14:31:05 +04:00
# ifdef CONFIG_LEDS_TRIGGERS
2007-07-09 02:19:31 +04:00
rc = device_create_file ( led_cdev - > dev , & dev_attr_trigger ) ;
2006-10-17 11:10:20 +04:00
if ( rc )
goto err_out_led_list ;
2006-03-31 14:31:05 +04:00
2006-10-17 11:10:20 +04:00
led_trigger_set_default ( led_cdev ) ;
2006-03-31 14:31:05 +04:00
# endif
2006-03-31 14:31:04 +04:00
printk ( KERN_INFO " Registered led device: %s \n " ,
2007-07-09 02:19:31 +04:00
led_cdev - > name ) ;
2006-03-31 14:31:04 +04:00
return 0 ;
2006-10-17 11:10:20 +04:00
# ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list :
2007-07-09 02:19:31 +04:00
device_remove_file ( led_cdev - > dev , & dev_attr_brightness ) ;
2006-10-17 11:10:20 +04:00
list_del ( & led_cdev - > node ) ;
# endif
err_out :
2007-07-09 02:19:31 +04:00
device_unregister ( led_cdev - > dev ) ;
2006-10-17 11:10:20 +04:00
return rc ;
2006-03-31 14:31:04 +04:00
}
EXPORT_SYMBOL_GPL ( led_classdev_register ) ;
/**
2008-10-21 02:04:36 +04:00
* led_classdev_unregister - unregisters a object of led_properties class .
2006-10-04 01:31:30 +04:00
* @ led_cdev : the led device to unregister
2006-03-31 14:31:04 +04:00
*
* Unregisters a previously registered via led_classdev_register object .
*/
2008-03-23 22:28:24 +03:00
void led_classdev_unregister ( struct led_classdev * led_cdev )
2006-03-31 14:31:04 +04:00
{
2007-07-09 02:19:31 +04:00
device_remove_file ( led_cdev - > dev , & dev_attr_brightness ) ;
2006-03-31 14:31:05 +04:00
# ifdef CONFIG_LEDS_TRIGGERS
2007-07-09 02:19:31 +04:00
device_remove_file ( led_cdev - > dev , & dev_attr_trigger ) ;
2007-11-10 16:29:04 +03:00
down_write ( & led_cdev - > trigger_lock ) ;
2006-03-31 14:31:05 +04:00
if ( led_cdev - > trigger )
led_trigger_set ( led_cdev , NULL ) ;
2007-11-10 16:29:04 +03:00
up_write ( & led_cdev - > trigger_lock ) ;
2006-03-31 14:31:05 +04:00
# endif
2006-03-31 14:31:04 +04:00
2008-03-23 22:28:24 +03:00
device_unregister ( led_cdev - > dev ) ;
2006-03-31 14:31:04 +04:00
2008-01-01 02:09:44 +03:00
down_write ( & leds_list_lock ) ;
2006-03-31 14:31:04 +04:00
list_del ( & led_cdev - > node ) ;
2008-01-01 02:09:44 +03:00
up_write ( & leds_list_lock ) ;
2006-03-31 14:31:04 +04:00
}
2008-03-23 22:28:24 +03:00
EXPORT_SYMBOL_GPL ( led_classdev_unregister ) ;
2006-03-31 14:31:04 +04:00
static int __init leds_init ( void )
{
leds_class = class_create ( THIS_MODULE , " leds " ) ;
if ( IS_ERR ( leds_class ) )
return PTR_ERR ( leds_class ) ;
return 0 ;
}
static void __exit leds_exit ( void )
{
class_destroy ( leds_class ) ;
}
subsys_initcall ( leds_init ) ;
module_exit ( leds_exit ) ;
MODULE_AUTHOR ( " John Lenz, Richard Purdie " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " LED Class Interface " ) ;