2005-04-17 02:20:36 +04:00
/*
* class . c - basic device class management
*
* Copyright ( c ) 2002 - 3 Patrick Mochel
* Copyright ( c ) 2002 - 3 Open Source Development Labs
* Copyright ( c ) 2003 - 2004 Greg Kroah - Hartman
* Copyright ( c ) 2003 - 2004 IBM Corp .
*
* This file is released under the GPLv2
*
*/
# include <linux/device.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/kdev_t.h>
2005-03-15 22:54:21 +03:00
# include <linux/err.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
2007-05-22 00:08:01 +04:00
# include <linux/genhd.h>
2005-04-17 02:20:36 +04:00
# include "base.h"
# define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
2007-04-14 00:15:19 +04:00
# define to_class(obj) container_of(obj, struct class, subsys.kobj)
2005-04-17 02:20:36 +04:00
2008-01-25 09:50:12 +03:00
static ssize_t class_attr_show ( struct kobject * kobj , struct attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
2008-01-25 09:50:12 +03:00
struct class_attribute * class_attr = to_class_attr ( attr ) ;
struct class * dc = to_class ( kobj ) ;
2005-04-29 10:23:47 +04:00
ssize_t ret = - EIO ;
2005-04-17 02:20:36 +04:00
if ( class_attr - > show )
ret = class_attr - > show ( dc , buf ) ;
return ret ;
}
2008-01-25 09:50:12 +03:00
static ssize_t class_attr_store ( struct kobject * kobj , struct attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2008-01-25 09:50:12 +03:00
struct class_attribute * class_attr = to_class_attr ( attr ) ;
struct class * dc = to_class ( kobj ) ;
2005-04-29 10:23:47 +04:00
ssize_t ret = - EIO ;
2005-04-17 02:20:36 +04:00
if ( class_attr - > store )
ret = class_attr - > store ( dc , buf , count ) ;
return ret ;
}
2008-01-25 09:50:12 +03:00
static void class_release ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
struct class * class = to_class ( kobj ) ;
pr_debug ( " class '%s': release. \n " , class - > name ) ;
if ( class - > class_release )
class - > class_release ( class ) ;
else
pr_debug ( " class '%s' does not have a release() function, "
" be careful \n " , class - > name ) ;
}
static struct sysfs_ops class_sysfs_ops = {
. show = class_attr_show ,
. store = class_attr_store ,
} ;
2007-10-11 20:47:49 +04:00
static struct kobj_type class_ktype = {
2005-04-17 02:20:36 +04:00
. sysfs_ops = & class_sysfs_ops ,
. release = class_release ,
} ;
/* Hotplug events for classes go to the class_obj subsys */
2007-10-30 07:22:26 +03:00
static struct kset * class_kset ;
2005-04-17 02:20:36 +04:00
2008-01-25 09:50:12 +03:00
int class_create_file ( struct class * cls , const struct class_attribute * attr )
2005-04-17 02:20:36 +04:00
{
int error ;
2008-01-25 09:50:12 +03:00
if ( cls )
2007-04-14 00:15:19 +04:00
error = sysfs_create_file ( & cls - > subsys . kobj , & attr - > attr ) ;
2008-01-25 09:50:12 +03:00
else
2005-04-17 02:20:36 +04:00
error = - EINVAL ;
return error ;
}
2008-01-25 09:50:12 +03:00
void class_remove_file ( struct class * cls , const struct class_attribute * attr )
2005-04-17 02:20:36 +04:00
{
if ( cls )
2007-04-14 00:15:19 +04:00
sysfs_remove_file ( & cls - > subsys . kobj , & attr - > attr ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-02 18:59:59 +04:00
static struct class * class_get ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
if ( cls )
2008-01-25 09:50:12 +03:00
return container_of ( kset_get ( & cls - > subsys ) ,
struct class , subsys ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-01-25 09:50:12 +03:00
static void class_put ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
2005-10-28 09:25:43 +04:00
if ( cls )
2007-09-13 02:06:57 +04:00
kset_put ( & cls - > subsys ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 09:50:12 +03:00
static int add_class_attrs ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
int i ;
int error = 0 ;
if ( cls - > class_attrs ) {
for ( i = 0 ; attr_name ( cls - > class_attrs [ i ] ) ; i + + ) {
2008-01-25 09:50:12 +03:00
error = class_create_file ( cls , & cls - > class_attrs [ i ] ) ;
2005-04-17 02:20:36 +04:00
if ( error )
2008-01-25 09:50:12 +03:00
goto error ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-25 09:50:12 +03:00
done :
2005-04-17 02:20:36 +04:00
return error ;
2008-01-25 09:50:12 +03:00
error :
2005-04-17 02:20:36 +04:00
while ( - - i > = 0 )
2008-01-25 09:50:12 +03:00
class_remove_file ( cls , & cls - > class_attrs [ i ] ) ;
goto done ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 09:50:12 +03:00
static void remove_class_attrs ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
int i ;
if ( cls - > class_attrs ) {
for ( i = 0 ; attr_name ( cls - > class_attrs [ i ] ) ; i + + )
2008-01-25 09:50:12 +03:00
class_remove_file ( cls , & cls - > class_attrs [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-25 09:50:12 +03:00
int class_register ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
int error ;
pr_debug ( " device class '%s': registering \n " , cls - > name ) ;
INIT_LIST_HEAD ( & cls - > children ) ;
2006-06-14 23:14:34 +04:00
INIT_LIST_HEAD ( & cls - > devices ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & cls - > interfaces ) ;
2007-03-14 05:25:56 +03:00
kset_init ( & cls - > class_dirs ) ;
2005-04-17 02:20:36 +04:00
init_MUTEX ( & cls - > sem ) ;
2007-04-14 00:15:19 +04:00
error = kobject_set_name ( & cls - > subsys . kobj , " %s " , cls - > name ) ;
2005-04-17 02:20:36 +04:00
if ( error )
return error ;
2008-01-27 23:12:43 +03:00
# if defined(CONFIG_SYSFS_DEPRECATED) && defined(CONFIG_BLOCK)
2007-05-22 00:08:01 +04:00
/* let the block class directory show up in the root of sysfs */
if ( cls ! = & block_class )
cls - > subsys . kobj . kset = class_kset ;
# else
2007-10-30 07:22:26 +03:00
cls - > subsys . kobj . kset = class_kset ;
2007-05-22 00:08:01 +04:00
# endif
2007-10-16 20:11:44 +04:00
cls - > subsys . kobj . ktype = & class_ktype ;
2005-04-17 02:20:36 +04:00
2007-11-07 02:03:30 +03:00
error = kset_register ( & cls - > subsys ) ;
2005-04-17 02:20:36 +04:00
if ( ! error ) {
error = add_class_attrs ( class_get ( cls ) ) ;
class_put ( cls ) ;
}
return error ;
}
2008-01-25 09:50:12 +03:00
void class_unregister ( struct class * cls )
2005-04-17 02:20:36 +04:00
{
pr_debug ( " device class '%s': unregistering \n " , cls - > name ) ;
remove_class_attrs ( cls ) ;
2007-11-07 02:03:30 +03:00
kset_unregister ( & cls - > subsys ) ;
2005-04-17 02:20:36 +04:00
}
2005-03-15 22:54:21 +03:00
static void class_create_release ( struct class * cls )
{
2008-03-05 03:41:05 +03:00
pr_debug ( " %s called for %s \n " , __func__ , cls - > name ) ;
2005-03-15 22:54:21 +03:00
kfree ( cls ) ;
}
static void class_device_create_release ( struct class_device * class_dev )
{
2008-03-05 03:41:05 +03:00
pr_debug ( " %s called for %s \n " , __func__ , class_dev - > class_id ) ;
2005-03-15 22:54:21 +03:00
kfree ( class_dev ) ;
}
2005-10-28 09:25:43 +04:00
/* needed to allow these devices to have parent class devices */
2005-11-16 11:00:00 +03:00
static int class_device_create_uevent ( struct class_device * class_dev ,
2007-08-14 17:15:12 +04:00
struct kobj_uevent_env * env )
2005-10-28 09:25:43 +04:00
{
2008-03-05 03:41:05 +03:00
pr_debug ( " %s called for %s \n " , __func__ , class_dev - > class_id ) ;
2005-10-28 09:25:43 +04:00
return 0 ;
}
2005-03-23 21:02:56 +03:00
/**
* class_create - create a struct class structure
* @ owner : pointer to the module that is to " own " this struct class
* @ name : pointer to a string for the name of this class .
*
* This is used to create a struct class pointer that can then be used
* in calls to class_device_create ( ) .
*
* Note , the pointer created here is to be destroyed when finished by
* making a call to class_destroy ( ) .
*/
2006-09-13 17:34:05 +04:00
struct class * class_create ( struct module * owner , const char * name )
2005-03-15 22:54:21 +03:00
{
struct class * cls ;
int retval ;
2005-09-13 12:25:01 +04:00
cls = kzalloc ( sizeof ( * cls ) , GFP_KERNEL ) ;
2005-03-15 22:54:21 +03:00
if ( ! cls ) {
retval = - ENOMEM ;
goto error ;
}
cls - > name = name ;
cls - > owner = owner ;
cls - > class_release = class_create_release ;
cls - > release = class_device_create_release ;
retval = class_register ( cls ) ;
if ( retval )
goto error ;
return cls ;
error :
kfree ( cls ) ;
return ERR_PTR ( retval ) ;
}
2005-03-23 21:02:56 +03:00
/**
* class_destroy - destroys a struct class structure
2006-09-29 12:59:13 +04:00
* @ cls : pointer to the struct class that is to be destroyed
2005-03-23 21:02:56 +03:00
*
* Note , the pointer to be destroyed must have been created with a call
* to class_create ( ) .
*/
2005-03-15 22:54:21 +03:00
void class_destroy ( struct class * cls )
{
if ( ( cls = = NULL ) | | ( IS_ERR ( cls ) ) )
return ;
class_unregister ( cls ) ;
}
2005-04-17 02:20:36 +04:00
/* Class Device Stuff */
2008-01-25 09:50:12 +03:00
int class_device_create_file ( struct class_device * class_dev ,
const struct class_device_attribute * attr )
2005-04-17 02:20:36 +04:00
{
int error = - EINVAL ;
if ( class_dev )
error = sysfs_create_file ( & class_dev - > kobj , & attr - > attr ) ;
return error ;
}
2008-01-25 09:50:12 +03:00
void class_device_remove_file ( struct class_device * class_dev ,
const struct class_device_attribute * attr )
2005-04-17 02:20:36 +04:00
{
if ( class_dev )
sysfs_remove_file ( & class_dev - > kobj , & attr - > attr ) ;
}
2007-10-31 22:51:29 +03:00
int class_device_create_bin_file ( struct class_device * class_dev ,
struct bin_attribute * attr )
{
int error = - EINVAL ;
if ( class_dev )
error = sysfs_create_bin_file ( & class_dev - > kobj , attr ) ;
return error ;
}
void class_device_remove_bin_file ( struct class_device * class_dev ,
struct bin_attribute * attr )
{
if ( class_dev )
sysfs_remove_bin_file ( & class_dev - > kobj , attr ) ;
}
2008-01-25 09:50:12 +03:00
static ssize_t class_device_attr_show ( struct kobject * kobj ,
struct attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2008-01-25 09:50:12 +03:00
struct class_device_attribute * class_dev_attr = to_class_dev_attr ( attr ) ;
struct class_device * cd = to_class_dev ( kobj ) ;
2005-04-17 02:20:36 +04:00
ssize_t ret = 0 ;
if ( class_dev_attr - > show )
ret = class_dev_attr - > show ( cd , buf ) ;
return ret ;
}
2008-01-25 09:50:12 +03:00
static ssize_t class_device_attr_store ( struct kobject * kobj ,
struct attribute * attr ,
const char * buf , size_t count )
2005-04-17 02:20:36 +04:00
{
2008-01-25 09:50:12 +03:00
struct class_device_attribute * class_dev_attr = to_class_dev_attr ( attr ) ;
struct class_device * cd = to_class_dev ( kobj ) ;
2005-04-17 02:20:36 +04:00
ssize_t ret = 0 ;
if ( class_dev_attr - > store )
ret = class_dev_attr - > store ( cd , buf , count ) ;
return ret ;
}
static struct sysfs_ops class_dev_sysfs_ops = {
. show = class_device_attr_show ,
. store = class_device_attr_store ,
} ;
2008-01-25 09:50:12 +03:00
static void class_dev_release ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
struct class_device * cd = to_class_dev ( kobj ) ;
2008-01-25 09:50:12 +03:00
struct class * cls = cd - > class ;
2005-04-17 02:20:36 +04:00
pr_debug ( " device class '%s': release. \n " , cd - > class_id ) ;
2005-10-28 09:25:43 +04:00
if ( cd - > release )
cd - > release ( cd ) ;
else if ( cls - > release )
2005-04-17 02:20:36 +04:00
cls - > release ( cd ) ;
else {
2008-01-25 09:50:12 +03:00
printk ( KERN_ERR " Class Device '%s' does not have a release() "
" function, it is broken and must be fixed. \n " ,
2005-04-17 02:20:36 +04:00
cd - > class_id ) ;
WARN_ON ( 1 ) ;
}
}
2007-10-11 20:47:49 +04:00
static struct kobj_type class_device_ktype = {
2005-04-17 02:20:36 +04:00
. sysfs_ops = & class_dev_sysfs_ops ,
. release = class_dev_release ,
} ;
2005-11-16 11:00:00 +03:00
static int class_uevent_filter ( struct kset * kset , struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
struct kobj_type * ktype = get_ktype ( kobj ) ;
2007-10-11 20:47:49 +04:00
if ( ktype = = & class_device_ktype ) {
2005-04-17 02:20:36 +04:00
struct class_device * class_dev = to_class_dev ( kobj ) ;
if ( class_dev - > class )
return 1 ;
}
return 0 ;
}
2005-11-16 11:00:00 +03:00
static const char * class_uevent_name ( struct kset * kset , struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
struct class_device * class_dev = to_class_dev ( kobj ) ;
return class_dev - > class - > name ;
}
2006-09-14 13:23:28 +04:00
# ifdef CONFIG_SYSFS_DEPRECATED
char * make_class_name ( const char * name , struct kobject * kobj )
{
char * class_name ;
int size ;
size = strlen ( name ) + strlen ( kobject_name ( kobj ) ) + 2 ;
class_name = kmalloc ( size , GFP_KERNEL ) ;
if ( ! class_name )
2006-11-27 12:35:05 +03:00
return NULL ;
2006-09-14 13:23:28 +04:00
strcpy ( class_name , name ) ;
strcat ( class_name , " : " ) ;
strcat ( class_name , kobject_name ( kobj ) ) ;
return class_name ;
}
static int make_deprecated_class_device_links ( struct class_device * class_dev )
{
char * class_name ;
int error ;
if ( ! class_dev - > dev )
return 0 ;
class_name = make_class_name ( class_dev - > class - > name , & class_dev - > kobj ) ;
2006-11-27 12:35:05 +03:00
if ( class_name )
error = sysfs_create_link ( & class_dev - > dev - > kobj ,
& class_dev - > kobj , class_name ) ;
else
error = - ENOMEM ;
2006-09-14 13:23:28 +04:00
kfree ( class_name ) ;
return error ;
}
static void remove_deprecated_class_device_links ( struct class_device * class_dev )
{
char * class_name ;
if ( ! class_dev - > dev )
return ;
class_name = make_class_name ( class_dev - > class - > name , & class_dev - > kobj ) ;
2006-11-27 12:35:05 +03:00
if ( class_name )
sysfs_remove_link ( & class_dev - > dev - > kobj , class_name ) ;
2006-09-14 13:23:28 +04:00
kfree ( class_name ) ;
}
# else
static inline int make_deprecated_class_device_links ( struct class_device * cd )
{ return 0 ; }
static void remove_deprecated_class_device_links ( struct class_device * cd )
{ }
# endif
2007-08-14 17:15:12 +04:00
static int class_uevent ( struct kset * kset , struct kobject * kobj ,
struct kobj_uevent_env * env )
2005-04-17 02:20:36 +04:00
{
struct class_device * class_dev = to_class_dev ( kobj ) ;
2007-05-01 15:46:26 +04:00
struct device * dev = class_dev - > dev ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
2008-03-05 03:41:05 +03:00
pr_debug ( " %s - name = %s \n " , __func__ , class_dev - > class_id ) ;
2005-04-17 02:20:36 +04:00
if ( MAJOR ( class_dev - > devt ) ) {
2007-08-14 17:15:12 +04:00
add_uevent_var ( env , " MAJOR=%u " , MAJOR ( class_dev - > devt ) ) ;
2005-04-17 02:20:36 +04:00
2007-08-14 17:15:12 +04:00
add_uevent_var ( env , " MINOR=%u " , MINOR ( class_dev - > devt ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-01 15:46:26 +04:00
if ( dev ) {
const char * path = kobject_get_path ( & dev - > kobj , GFP_KERNEL ) ;
if ( path ) {
2007-08-14 17:15:12 +04:00
add_uevent_var ( env , " PHYSDEVPATH=%s " , path ) ;
2007-05-01 15:46:26 +04:00
kfree ( path ) ;
}
if ( dev - > bus )
2007-08-14 17:15:12 +04:00
add_uevent_var ( env , " PHYSDEVBUS=%s " , dev - > bus - > name ) ;
2007-05-01 15:46:26 +04:00
if ( dev - > driver )
2008-01-25 09:50:12 +03:00
add_uevent_var ( env , " PHYSDEVDRIVER=%s " ,
dev - > driver - > name ) ;
2007-05-01 15:46:26 +04:00
}
2005-11-16 11:00:00 +03:00
if ( class_dev - > uevent ) {
2005-10-28 09:25:43 +04:00
/* have the class device specific function add its stuff */
2007-08-14 17:15:12 +04:00
retval = class_dev - > uevent ( class_dev , env ) ;
2005-10-28 09:25:43 +04:00
if ( retval )
2005-11-16 11:00:00 +03:00
pr_debug ( " class_dev->uevent() returned %d \n " , retval ) ;
} else if ( class_dev - > class - > uevent ) {
2005-10-28 09:25:43 +04:00
/* have the class specific function add its stuff */
2007-08-14 17:15:12 +04:00
retval = class_dev - > class - > uevent ( class_dev , env ) ;
2005-10-28 09:25:43 +04:00
if ( retval )
2005-11-16 11:00:00 +03:00
pr_debug ( " class->uevent() returned %d \n " , retval ) ;
2005-04-17 02:20:36 +04:00
}
return retval ;
}
2005-11-16 11:00:00 +03:00
static struct kset_uevent_ops class_uevent_ops = {
. filter = class_uevent_filter ,
. name = class_uevent_name ,
. uevent = class_uevent ,
2005-04-17 02:20:36 +04:00
} ;
2007-11-03 02:19:59 +03:00
/*
* DO NOT copy how this is created , kset_create_and_add ( ) should be
* called , but this is a hold - over from the old - way and will be deleted
* entirely soon .
*/
static struct kset class_obj_subsys = {
. uevent_ops = & class_uevent_ops ,
} ;
2005-04-17 02:20:36 +04:00
2008-01-25 09:50:12 +03:00
static int class_device_add_attrs ( struct class_device * cd )
2005-04-17 02:20:36 +04:00
{
int i ;
int error = 0 ;
2008-01-25 09:50:12 +03:00
struct class * cls = cd - > class ;
2005-04-17 02:20:36 +04:00
if ( cls - > class_dev_attrs ) {
for ( i = 0 ; attr_name ( cls - > class_dev_attrs [ i ] ) ; i + + ) {
error = class_device_create_file ( cd ,
2008-01-25 09:50:12 +03:00
& cls - > class_dev_attrs [ i ] ) ;
2005-04-17 02:20:36 +04:00
if ( error )
2008-01-25 09:50:12 +03:00
goto err ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-25 09:50:12 +03:00
done :
2005-04-17 02:20:36 +04:00
return error ;
2008-01-25 09:50:12 +03:00
err :
2005-04-17 02:20:36 +04:00
while ( - - i > = 0 )
2008-01-25 09:50:12 +03:00
class_device_remove_file ( cd , & cls - > class_dev_attrs [ i ] ) ;
goto done ;
2005-04-17 02:20:36 +04:00
}
2008-01-25 09:50:12 +03:00
static void class_device_remove_attrs ( struct class_device * cd )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-01-25 09:50:12 +03:00
struct class * cls = cd - > class ;
2005-04-17 02:20:36 +04:00
if ( cls - > class_dev_attrs ) {
for ( i = 0 ; attr_name ( cls - > class_dev_attrs [ i ] ) ; i + + )
2008-01-25 09:50:12 +03:00
class_device_remove_file ( cd , & cls - > class_dev_attrs [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
}
2008-01-25 09:50:12 +03:00
static int class_device_add_groups ( struct class_device * cd )
2006-05-07 04:55:11 +04:00
{
int i ;
int error = 0 ;
if ( cd - > groups ) {
for ( i = 0 ; cd - > groups [ i ] ; i + + ) {
error = sysfs_create_group ( & cd - > kobj , cd - > groups [ i ] ) ;
if ( error ) {
while ( - - i > = 0 )
2008-01-25 09:50:12 +03:00
sysfs_remove_group ( & cd - > kobj ,
cd - > groups [ i ] ) ;
2006-05-07 04:55:11 +04:00
goto out ;
}
}
}
out :
return error ;
}
2008-01-25 09:50:12 +03:00
static void class_device_remove_groups ( struct class_device * cd )
2006-05-07 04:55:11 +04:00
{
int i ;
2008-01-25 09:50:12 +03:00
if ( cd - > groups )
for ( i = 0 ; cd - > groups [ i ] ; i + + )
2006-05-07 04:55:11 +04:00
sysfs_remove_group ( & cd - > kobj , cd - > groups [ i ] ) ;
}
2005-04-17 02:20:36 +04:00
static ssize_t show_dev ( struct class_device * class_dev , char * buf )
{
return print_dev_t ( buf , class_dev - > devt ) ;
}
2007-06-13 22:45:17 +04:00
static struct class_device_attribute class_devt_attr =
__ATTR ( dev , S_IRUGO , show_dev , NULL ) ;
2005-10-01 16:49:43 +04:00
static ssize_t store_uevent ( struct class_device * class_dev ,
const char * buf , size_t count )
{
2005-11-16 11:00:00 +03:00
kobject_uevent ( & class_dev - > kobj , KOBJ_ADD ) ;
2005-10-01 16:49:43 +04:00
return count ;
}
2007-06-13 22:45:17 +04:00
static struct class_device_attribute class_uevent_attr =
__ATTR ( uevent , S_IWUSR , NULL , store_uevent ) ;
2005-04-17 02:20:36 +04:00
void class_device_initialize ( struct class_device * class_dev )
{
2007-10-16 20:11:44 +04:00
class_dev - > kobj . kset = & class_obj_subsys ;
2007-12-18 09:05:35 +03:00
kobject_init ( & class_dev - > kobj , & class_device_ktype ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & class_dev - > node ) ;
}
int class_device_add ( struct class_device * class_dev )
{
2005-10-28 09:25:43 +04:00
struct class * parent_class = NULL ;
struct class_device * parent_class_dev = NULL ;
struct class_interface * class_intf ;
int error = - EINVAL ;
2005-04-17 02:20:36 +04:00
class_dev = class_device_get ( class_dev ) ;
if ( ! class_dev )
return - EINVAL ;
2005-10-28 09:25:43 +04:00
if ( ! strlen ( class_dev - > class_id ) )
2006-04-26 20:53:14 +04:00
goto out1 ;
2005-04-17 02:20:36 +04:00
2005-10-28 09:25:43 +04:00
parent_class = class_get ( class_dev - > class ) ;
if ( ! parent_class )
2006-04-26 20:53:14 +04:00
goto out1 ;
2005-10-28 09:25:43 +04:00
parent_class_dev = class_device_get ( class_dev - > parent ) ;
2005-04-17 02:20:36 +04:00
pr_debug ( " CLASS: registering class device: ID = '%s' \n " ,
class_dev - > class_id ) ;
/* first, register with generic layer. */
2005-10-28 09:25:43 +04:00
if ( parent_class_dev )
class_dev - > kobj . parent = & parent_class_dev - > kobj ;
else
2007-04-14 00:15:19 +04:00
class_dev - > kobj . parent = & parent_class - > subsys . kobj ;
2005-04-17 02:20:36 +04:00
2007-12-18 09:05:35 +03:00
error = kobject_add ( & class_dev - > kobj , class_dev - > kobj . parent ,
" %s " , class_dev - > class_id ) ;
2005-10-28 09:25:43 +04:00
if ( error )
2006-04-26 20:53:14 +04:00
goto out2 ;
2005-04-17 02:20:36 +04:00
2005-03-15 22:54:21 +03:00
/* add the needed attributes to this device */
2006-09-22 13:37:00 +04:00
error = sysfs_create_link ( & class_dev - > kobj ,
2007-04-14 00:15:19 +04:00
& parent_class - > subsys . kobj , " subsystem " ) ;
2006-09-22 13:37:00 +04:00
if ( error )
goto out3 ;
2007-06-13 22:45:17 +04:00
error = class_device_create_file ( class_dev , & class_uevent_attr ) ;
2006-04-26 20:53:14 +04:00
if ( error )
goto out3 ;
2005-10-01 16:49:43 +04:00
2005-03-15 22:54:21 +03:00
if ( MAJOR ( class_dev - > devt ) ) {
2007-06-13 22:45:17 +04:00
error = class_device_create_file ( class_dev , & class_devt_attr ) ;
if ( error )
2006-04-26 20:53:14 +04:00
goto out4 ;
2005-03-15 22:54:21 +03:00
}
2006-04-26 20:53:14 +04:00
error = class_device_add_attrs ( class_dev ) ;
if ( error )
goto out5 ;
2005-07-10 10:21:24 +04:00
if ( class_dev - > dev ) {
2006-04-26 20:53:14 +04:00
error = sysfs_create_link ( & class_dev - > kobj ,
& class_dev - > dev - > kobj , " device " ) ;
if ( error )
goto out6 ;
2005-07-10 10:21:24 +04:00
}
2005-03-15 22:54:21 +03:00
2006-04-26 20:53:14 +04:00
error = class_device_add_groups ( class_dev ) ;
2006-09-14 13:23:28 +04:00
if ( error )
goto out7 ;
error = make_deprecated_class_device_links ( class_dev ) ;
2006-04-26 20:53:14 +04:00
if ( error )
goto out8 ;
2006-05-07 04:55:11 +04:00
2005-11-16 11:00:00 +03:00
kobject_uevent ( & class_dev - > kobj , KOBJ_ADD ) ;
2005-09-15 11:01:37 +04:00
2005-03-15 22:54:21 +03:00
/* notify any interfaces this device is now here */
2006-04-03 23:31:53 +04:00
down ( & parent_class - > sem ) ;
list_add_tail ( & class_dev - > node , & parent_class - > children ) ;
list_for_each_entry ( class_intf , & parent_class - > interfaces , node ) {
if ( class_intf - > add )
class_intf - > add ( class_dev , class_intf ) ;
2005-04-17 02:20:36 +04:00
}
2006-04-03 23:31:53 +04:00
up ( & parent_class - > sem ) ;
2005-03-15 22:54:21 +03:00
2006-04-26 20:53:14 +04:00
goto out1 ;
out8 :
2006-09-14 13:23:28 +04:00
class_device_remove_groups ( class_dev ) ;
2006-04-26 20:53:14 +04:00
out7 :
if ( class_dev - > dev )
sysfs_remove_link ( & class_dev - > kobj , " device " ) ;
out6 :
class_device_remove_attrs ( class_dev ) ;
out5 :
2007-06-13 22:45:17 +04:00
if ( MAJOR ( class_dev - > devt ) )
class_device_remove_file ( class_dev , & class_devt_attr ) ;
2006-04-26 20:53:14 +04:00
out4 :
2007-06-13 22:45:17 +04:00
class_device_remove_file ( class_dev , & class_uevent_attr ) ;
2006-04-26 20:53:14 +04:00
out3 :
kobject_del ( & class_dev - > kobj ) ;
out2 :
2008-01-25 09:50:12 +03:00
if ( parent_class_dev )
2005-10-28 09:25:43 +04:00
class_device_put ( parent_class_dev ) ;
2006-04-26 20:53:14 +04:00
class_put ( parent_class ) ;
out1 :
2005-04-17 02:20:36 +04:00
class_device_put ( class_dev ) ;
return error ;
}
int class_device_register ( struct class_device * class_dev )
{
class_device_initialize ( class_dev ) ;
return class_device_add ( class_dev ) ;
}
2005-03-23 21:02:56 +03:00
/**
* class_device_create - creates a class device and registers it with sysfs
2006-09-29 12:59:13 +04:00
* @ cls : pointer to the struct class that this device should be registered to .
2008-01-25 09:50:12 +03:00
* @ parent : pointer to the parent struct class_device of this new device , if
* any .
2006-09-29 12:59:13 +04:00
* @ devt : the dev_t for the char device to be added .
2008-01-25 09:50:12 +03:00
* @ device : a pointer to a struct device that is assiociated with this class
* device .
2005-03-23 21:02:56 +03:00
* @ fmt : string for the class device ' s name
*
* This function can be used by char device classes . A struct
* class_device will be created in sysfs , registered to the specified
2005-10-28 09:25:43 +04:00
* class .
* A " dev " file will be created , showing the dev_t for the device , if
* the dev_t is not 0 , 0.
* If a pointer to a parent struct class_device is passed in , the newly
* created struct class_device will be a child of that device in sysfs .
* The pointer to the struct class_device will be returned from the
* call . Any further sysfs files that might be required can be created
* using this pointer .
2005-03-23 21:02:56 +03:00
*
* Note : the struct class passed to this function must have previously
* been created with a call to class_create ( ) .
*/
2005-10-28 09:25:43 +04:00
struct class_device * class_device_create ( struct class * cls ,
struct class_device * parent ,
dev_t devt ,
2006-08-10 09:18:18 +04:00
struct device * device ,
const char * fmt , . . . )
2005-03-15 22:54:21 +03:00
{
va_list args ;
struct class_device * class_dev = NULL ;
int retval = - ENODEV ;
if ( cls = = NULL | | IS_ERR ( cls ) )
goto error ;
2005-09-13 12:25:01 +04:00
class_dev = kzalloc ( sizeof ( * class_dev ) , GFP_KERNEL ) ;
2005-03-15 22:54:21 +03:00
if ( ! class_dev ) {
retval = - ENOMEM ;
goto error ;
}
class_dev - > devt = devt ;
class_dev - > dev = device ;
class_dev - > class = cls ;
2005-10-28 09:25:43 +04:00
class_dev - > parent = parent ;
class_dev - > release = class_device_create_release ;
2005-11-16 11:00:00 +03:00
class_dev - > uevent = class_device_create_uevent ;
2005-03-15 22:54:21 +03:00
va_start ( args , fmt ) ;
vsnprintf ( class_dev - > class_id , BUS_ID_SIZE , fmt , args ) ;
va_end ( args ) ;
retval = class_device_register ( class_dev ) ;
if ( retval )
goto error ;
return class_dev ;
error :
kfree ( class_dev ) ;
return ERR_PTR ( retval ) ;
}
2005-04-17 02:20:36 +04:00
void class_device_del ( struct class_device * class_dev )
{
2005-10-28 09:25:43 +04:00
struct class * parent_class = class_dev - > class ;
struct class_device * parent_device = class_dev - > parent ;
struct class_interface * class_intf ;
2005-04-17 02:20:36 +04:00
2005-10-28 09:25:43 +04:00
if ( parent_class ) {
down ( & parent_class - > sem ) ;
2005-04-17 02:20:36 +04:00
list_del_init ( & class_dev - > node ) ;
2005-10-28 09:25:43 +04:00
list_for_each_entry ( class_intf , & parent_class - > interfaces , node )
2005-04-17 02:20:36 +04:00
if ( class_intf - > remove )
2005-09-15 11:01:36 +04:00
class_intf - > remove ( class_dev , class_intf ) ;
2005-10-28 09:25:43 +04:00
up ( & parent_class - > sem ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-10 10:21:24 +04:00
if ( class_dev - > dev ) {
2006-09-14 13:23:28 +04:00
remove_deprecated_class_device_links ( class_dev ) ;
2005-04-17 02:20:36 +04:00
sysfs_remove_link ( & class_dev - > kobj , " device " ) ;
2005-07-10 10:21:24 +04:00
}
2006-06-15 17:31:56 +04:00
sysfs_remove_link ( & class_dev - > kobj , " subsystem " ) ;
2007-06-13 22:45:17 +04:00
class_device_remove_file ( class_dev , & class_uevent_attr ) ;
if ( MAJOR ( class_dev - > devt ) )
class_device_remove_file ( class_dev , & class_devt_attr ) ;
2005-04-17 02:20:36 +04:00
class_device_remove_attrs ( class_dev ) ;
2006-05-07 04:55:11 +04:00
class_device_remove_groups ( class_dev ) ;
2005-04-17 02:20:36 +04:00
2005-11-16 11:00:00 +03:00
kobject_uevent ( & class_dev - > kobj , KOBJ_REMOVE ) ;
2005-04-17 02:20:36 +04:00
kobject_del ( & class_dev - > kobj ) ;
2005-10-28 09:25:43 +04:00
class_device_put ( parent_device ) ;
class_put ( parent_class ) ;
2005-04-17 02:20:36 +04:00
}
void class_device_unregister ( struct class_device * class_dev )
{
pr_debug ( " CLASS: Unregistering class device. ID = '%s' \n " ,
class_dev - > class_id ) ;
class_device_del ( class_dev ) ;
class_device_put ( class_dev ) ;
}
2005-03-23 21:02:56 +03:00
/**
* class_device_destroy - removes a class device that was created with class_device_create ( )
* @ cls : the pointer to the struct class that this device was registered * with .
2006-09-29 12:59:13 +04:00
* @ devt : the dev_t of the device that was previously registered .
2005-03-23 21:02:56 +03:00
*
* This call unregisters and cleans up a class device that was created with a
* call to class_device_create ( )
*/
2005-03-15 22:54:21 +03:00
void class_device_destroy ( struct class * cls , dev_t devt )
{
struct class_device * class_dev = NULL ;
struct class_device * class_dev_tmp ;
down ( & cls - > sem ) ;
list_for_each_entry ( class_dev_tmp , & cls - > children , node ) {
if ( class_dev_tmp - > devt = = devt ) {
class_dev = class_dev_tmp ;
break ;
}
}
up ( & cls - > sem ) ;
if ( class_dev )
class_device_unregister ( class_dev ) ;
}
2008-01-25 09:50:12 +03:00
struct class_device * class_device_get ( struct class_device * class_dev )
2005-04-17 02:20:36 +04:00
{
if ( class_dev )
return to_class_dev ( kobject_get ( & class_dev - > kobj ) ) ;
return NULL ;
}
void class_device_put ( struct class_device * class_dev )
{
2005-10-28 09:25:43 +04:00
if ( class_dev )
kobject_put ( & class_dev - > kobj ) ;
2005-04-17 02:20:36 +04:00
}
2008-01-22 10:27:08 +03:00
/**
* class_for_each_device - device iterator
* @ class : the class we ' re iterating
* @ data : data for the callback
* @ fn : function to be called for each device
*
* Iterate over @ class ' s list of devices , and call @ fn for each ,
* passing it @ data .
*
* We check the return of @ fn each time . If it returns anything
* other than 0 , we break out and return that value .
*
* Note , we hold class - > sem in this function , so it can not be
* re - acquired in @ fn , otherwise it will self - deadlocking . For
* example , calls to add or remove class members would be verboten .
*/
int class_for_each_device ( struct class * class , void * data ,
int ( * fn ) ( struct device * , void * ) )
{
struct device * dev ;
int error = 0 ;
if ( ! class )
return - EINVAL ;
down ( & class - > sem ) ;
list_for_each_entry ( dev , & class - > devices , node ) {
dev = get_device ( dev ) ;
if ( dev ) {
error = fn ( dev , data ) ;
put_device ( dev ) ;
} else
error = - ENODEV ;
if ( error )
break ;
}
up ( & class - > sem ) ;
return error ;
}
EXPORT_SYMBOL_GPL ( class_for_each_device ) ;
/**
* class_find_device - device iterator for locating a particular device
* @ class : the class we ' re iterating
* @ data : data for the match function
* @ match : function to check device
*
* This is similar to the class_for_each_dev ( ) function above , but it
* returns a reference to a device that is ' found ' for later use , as
* determined by the @ match callback .
*
* The callback should return 0 if the device doesn ' t match and non - zero
* if it does . If the callback returns non - zero , this function will
* return to the caller and not iterate over any more devices .
2008-01-30 22:51:08 +03:00
*
2008-01-22 10:27:08 +03:00
* Note , you will need to drop the reference with put_device ( ) after use .
*
* We hold class - > sem in this function , so it can not be
* re - acquired in @ match , otherwise it will self - deadlocking . For
* example , calls to add or remove class members would be verboten .
*/
struct device * class_find_device ( struct class * class , void * data ,
int ( * match ) ( struct device * , void * ) )
{
struct device * dev ;
int found = 0 ;
if ( ! class )
return NULL ;
down ( & class - > sem ) ;
list_for_each_entry ( dev , & class - > devices , node ) {
dev = get_device ( dev ) ;
if ( dev ) {
if ( match ( dev , data ) ) {
found = 1 ;
break ;
} else
put_device ( dev ) ;
} else
break ;
}
up ( & class - > sem ) ;
return found ? dev : NULL ;
}
EXPORT_SYMBOL_GPL ( class_find_device ) ;
/**
* class_find_child - device iterator for locating a particular class_device
* @ class : the class we ' re iterating
* @ data : data for the match function
* @ match : function to check class_device
*
* This function returns a reference to a class_device that is ' found ' for
* later use , as determined by the @ match callback .
*
* The callback should return 0 if the class_device doesn ' t match and non - zero
* if it does . If the callback returns non - zero , this function will
* return to the caller and not iterate over any more class_devices .
*
* Note , you will need to drop the reference with class_device_put ( ) after use .
*
* We hold class - > sem in this function , so it can not be
* re - acquired in @ match , otherwise it will self - deadlocking . For
* example , calls to add or remove class members would be verboten .
*/
struct class_device * class_find_child ( struct class * class , void * data ,
int ( * match ) ( struct class_device * , void * ) )
{
struct class_device * dev ;
int found = 0 ;
if ( ! class )
return NULL ;
down ( & class - > sem ) ;
list_for_each_entry ( dev , & class - > children , node ) {
dev = class_device_get ( dev ) ;
if ( dev ) {
if ( match ( dev , data ) ) {
found = 1 ;
break ;
} else
class_device_put ( dev ) ;
} else
break ;
}
up ( & class - > sem ) ;
return found ? dev : NULL ;
}
EXPORT_SYMBOL_GPL ( class_find_child ) ;
2005-04-17 02:20:36 +04:00
int class_interface_register ( struct class_interface * class_intf )
{
struct class * parent ;
struct class_device * class_dev ;
2006-09-13 17:34:05 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
if ( ! class_intf | | ! class_intf - > class )
return - ENODEV ;
parent = class_get ( class_intf - > class ) ;
if ( ! parent )
return - EINVAL ;
down ( & parent - > sem ) ;
list_add_tail ( & class_intf - > node , & parent - > interfaces ) ;
if ( class_intf - > add ) {
list_for_each_entry ( class_dev , & parent - > children , node )
2005-09-15 11:01:36 +04:00
class_intf - > add ( class_dev , class_intf ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-13 17:34:05 +04:00
if ( class_intf - > add_dev ) {
list_for_each_entry ( dev , & parent - > devices , node )
class_intf - > add_dev ( dev , class_intf ) ;
}
2005-04-17 02:20:36 +04:00
up ( & parent - > sem ) ;
return 0 ;
}
void class_interface_unregister ( struct class_interface * class_intf )
{
2008-01-25 09:50:12 +03:00
struct class * parent = class_intf - > class ;
2005-04-17 02:20:36 +04:00
struct class_device * class_dev ;
2006-09-13 17:34:05 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
if ( ! parent )
return ;
down ( & parent - > sem ) ;
list_del_init ( & class_intf - > node ) ;
if ( class_intf - > remove ) {
list_for_each_entry ( class_dev , & parent - > children , node )
2005-09-15 11:01:36 +04:00
class_intf - > remove ( class_dev , class_intf ) ;
2005-04-17 02:20:36 +04:00
}
2006-09-13 17:34:05 +04:00
if ( class_intf - > remove_dev ) {
list_for_each_entry ( dev , & parent - > devices , node )
class_intf - > remove_dev ( dev , class_intf ) ;
}
2005-04-17 02:20:36 +04:00
up ( & parent - > sem ) ;
class_put ( parent ) ;
}
int __init classes_init ( void )
{
2007-10-30 07:22:26 +03:00
class_kset = kset_create_and_add ( " class " , NULL , NULL ) ;
if ( ! class_kset )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
/* ick, this is ugly, the things we go through to keep from showing up
* in sysfs . . . */
2007-09-26 22:12:00 +04:00
kset_init ( & class_obj_subsys ) ;
2007-12-20 04:09:39 +03:00
kobject_set_name ( & class_obj_subsys . kobj , " class_obj " ) ;
2007-04-14 00:15:19 +04:00
if ( ! class_obj_subsys . kobj . parent )
class_obj_subsys . kobj . parent = & class_obj_subsys . kobj ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( class_create_file ) ;
EXPORT_SYMBOL_GPL ( class_remove_file ) ;
EXPORT_SYMBOL_GPL ( class_register ) ;
EXPORT_SYMBOL_GPL ( class_unregister ) ;
2005-03-15 22:54:21 +03:00
EXPORT_SYMBOL_GPL ( class_create ) ;
EXPORT_SYMBOL_GPL ( class_destroy ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL_GPL ( class_device_register ) ;
EXPORT_SYMBOL_GPL ( class_device_unregister ) ;
EXPORT_SYMBOL_GPL ( class_device_initialize ) ;
EXPORT_SYMBOL_GPL ( class_device_add ) ;
EXPORT_SYMBOL_GPL ( class_device_del ) ;
EXPORT_SYMBOL_GPL ( class_device_get ) ;
EXPORT_SYMBOL_GPL ( class_device_put ) ;
2005-03-15 22:54:21 +03:00
EXPORT_SYMBOL_GPL ( class_device_create ) ;
EXPORT_SYMBOL_GPL ( class_device_destroy ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL_GPL ( class_device_create_file ) ;
EXPORT_SYMBOL_GPL ( class_device_remove_file ) ;
2007-10-31 22:51:29 +03:00
EXPORT_SYMBOL_GPL ( class_device_create_bin_file ) ;
EXPORT_SYMBOL_GPL ( class_device_remove_bin_file ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL_GPL ( class_interface_register ) ;
EXPORT_SYMBOL_GPL ( class_interface_unregister ) ;