2017-11-07 19:30:07 +03:00
// SPDX-License-Identifier: GPL-2.0
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 .
*/
2019-12-09 22:33:02 +03:00
# include <linux/device/class.h>
2005-04-17 02:20:36 +04:00
# 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>
2022-01-24 12:39:13 +03:00
# include <linux/blkdev.h>
2008-05-28 20:28:39 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include "base.h"
2023-03-25 22:42:33 +03:00
/* /sys/class */
static struct kset * class_kset ;
2005-04-17 02:20:36 +04:00
# define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
2023-03-25 22:42:33 +03:00
/**
* class_to_subsys - Turn a struct class into a struct subsys_private
*
* @ class : pointer to the struct bus_type to look up
*
* The driver core internals need to work on the subsys_private structure , not
* the external struct class pointer . This function walks the list of
* registered classes in the system and finds the matching one and returns the
* internal struct subsys_private that relates to that class .
*
* Note , the reference count of the return value is INCREMENTED if it is not
* NULL . A call to subsys_put ( ) must be done when finished with the pointer in
* order for it to be properly freed .
*/
2023-03-31 12:33:12 +03:00
struct subsys_private * class_to_subsys ( const struct class * class )
2023-03-25 22:42:33 +03:00
{
struct subsys_private * sp = NULL ;
struct kobject * kobj ;
if ( ! class | | ! class_kset )
return NULL ;
spin_lock ( & class_kset - > list_lock ) ;
if ( list_empty ( & class_kset - > list ) )
goto done ;
list_for_each_entry ( kobj , & class_kset - > list , entry ) {
struct kset * kset = container_of ( kobj , struct kset , kobj ) ;
sp = container_of_const ( kset , struct subsys_private , subsys ) ;
if ( sp - > class = = class )
goto done ;
}
sp = NULL ;
done :
sp = subsys_get ( sp ) ;
spin_unlock ( & class_kset - > list_lock ) ;
return sp ;
}
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 ) ;
2010-11-16 01:13:18 +03:00
struct subsys_private * cp = to_subsys_private ( 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 )
2010-01-05 14:48:07 +03:00
ret = class_attr - > show ( cp - > class , class_attr , buf ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2010-11-16 01:13:18 +03:00
struct subsys_private * cp = to_subsys_private ( 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 )
2010-01-05 14:48:07 +03:00
ret = class_attr - > store ( cp - > class , class_attr , buf , count ) ;
2005-04-17 02:20:36 +04:00
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
{
2010-11-16 01:13:18 +03:00
struct subsys_private * cp = to_subsys_private ( kobj ) ;
2023-04-02 20:58:47 +03:00
const struct class * class = cp - > class ;
2005-04-17 02:20:36 +04:00
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 ) ;
2010-02-10 15:32:49 +03:00
2023-04-01 13:09:26 +03:00
lockdep_unregister_key ( & cp - > lock_key ) ;
2010-02-10 15:32:49 +03:00
kfree ( cp ) ;
2005-04-17 02:20:36 +04:00
}
2022-11-21 12:46:45 +03:00
static const struct kobj_ns_type_operations * class_child_ns_type ( const struct kobject * kobj )
2010-03-30 22:31:25 +04:00
{
2023-01-11 12:33:27 +03:00
const struct subsys_private * cp = to_subsys_private ( kobj ) ;
2023-04-02 20:58:47 +03:00
const struct class * class = cp - > class ;
2010-03-30 22:31:25 +04:00
return class - > ns_type ;
}
2010-01-19 04:58:23 +03:00
static const struct sysfs_ops class_sysfs_ops = {
2011-10-13 01:55:08 +04:00
. show = class_attr_show ,
. store = class_attr_store ,
2005-04-17 02:20:36 +04:00
} ;
2023-02-05 01:36:58 +03:00
static const struct kobj_type class_ktype = {
2005-04-17 02:20:36 +04:00
. sysfs_ops = & class_sysfs_ops ,
. release = class_release ,
2010-03-30 22:31:25 +04:00
. child_ns_type = class_child_ns_type ,
2005-04-17 02:20:36 +04:00
} ;
2023-03-13 21:18:39 +03:00
int class_create_file_ns ( const struct class * cls , const struct class_attribute * attr ,
2013-09-12 06:29:04 +04:00
const void * ns )
2005-04-17 02:20:36 +04:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( cls ) ;
2005-04-17 02:20:36 +04:00
int error ;
2015-03-08 13:31:54 +03:00
2023-03-25 22:42:34 +03:00
if ( ! sp )
return - EINVAL ;
error = sysfs_create_file_ns ( & sp - > subsys . kobj , & attr - > attr , ns ) ;
subsys_put ( sp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_create_file_ns ) ;
2005-04-17 02:20:36 +04:00
2023-03-13 21:18:39 +03:00
void class_remove_file_ns ( const struct class * cls , const struct class_attribute * attr ,
2013-09-12 06:29:04 +04:00
const void * ns )
2005-04-17 02:20:36 +04:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( cls ) ;
if ( ! sp )
return ;
sysfs_remove_file_ns ( & sp - > subsys . kobj , & attr - > attr , ns ) ;
subsys_put ( sp ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_remove_file_ns ) ;
2005-04-17 02:20:36 +04:00
2019-01-18 05:34:59 +03:00
static struct device * klist_class_to_dev ( struct klist_node * n )
{
struct device_private * p = to_device_private_class ( n ) ;
return p - > device ;
}
2008-08-25 21:50:19 +04:00
static void klist_class_dev_get ( struct klist_node * n )
{
2019-01-18 05:34:59 +03:00
struct device * dev = klist_class_to_dev ( n ) ;
2008-08-25 21:50:19 +04:00
get_device ( dev ) ;
}
static void klist_class_dev_put ( struct klist_node * n )
{
2019-01-18 05:34:59 +03:00
struct device * dev = klist_class_to_dev ( n ) ;
2008-08-25 21:50:19 +04:00
put_device ( dev ) ;
}
2023-04-02 20:58:47 +03:00
int class_register ( const struct class * cls )
2005-04-17 02:20:36 +04:00
{
2010-11-16 01:13:18 +03:00
struct subsys_private * cp ;
2023-03-24 13:01:31 +03:00
struct lock_class_key * key ;
2005-04-17 02:20:36 +04:00
int error ;
pr_debug ( " device class '%s': registering \n " , cls - > name ) ;
2008-01-23 02:17:41 +03:00
cp = kzalloc ( sizeof ( * cp ) , GFP_KERNEL ) ;
if ( ! cp )
return - ENOMEM ;
2010-11-16 01:13:18 +03:00
klist_init ( & cp - > klist_devices , klist_class_dev_get , klist_class_dev_put ) ;
2011-12-15 02:29:38 +04:00
INIT_LIST_HEAD ( & cp - > interfaces ) ;
2010-11-16 01:13:18 +03:00
kset_init ( & cp - > glue_dirs ) ;
2023-03-24 13:01:31 +03:00
key = & cp - > lock_key ;
lockdep_register_key ( key ) ;
2011-12-15 02:29:38 +04:00
__mutex_init ( & cp - > mutex , " subsys mutex " , key ) ;
2010-11-16 01:13:18 +03:00
error = kobject_set_name ( & cp - > subsys . kobj , " %s " , cls - > name ) ;
2008-01-23 02:17:41 +03:00
if ( error ) {
kfree ( cp ) ;
2005-04-17 02:20:36 +04:00
return error ;
2008-01-23 02:17:41 +03:00
}
2005-04-17 02:20:36 +04:00
2010-11-16 01:13:18 +03:00
cp - > subsys . kobj . kset = class_kset ;
cp - > subsys . kobj . ktype = & class_ktype ;
2008-01-23 02:17:41 +03:00
cp - > class = cls ;
2005-04-17 02:20:36 +04:00
2010-11-16 01:13:18 +03:00
error = kset_register ( & cp - > subsys ) ;
2023-01-20 22:46:57 +03:00
if ( error )
goto err_out ;
2023-03-25 22:42:34 +03:00
error = sysfs_create_groups ( & cp - > subsys . kobj , cls - > class_groups ) ;
2022-10-26 11:28:03 +03:00
if ( error ) {
kobject_del ( & cp - > subsys . kobj ) ;
kfree_const ( cp - > subsys . kobj . name ) ;
2023-01-20 22:46:57 +03:00
goto err_out ;
2022-10-26 11:28:03 +03:00
}
2023-01-20 22:46:57 +03:00
return 0 ;
err_out :
kfree ( cp ) ;
2005-04-17 02:20:36 +04:00
return error ;
}
2023-03-24 13:01:31 +03:00
EXPORT_SYMBOL_GPL ( class_register ) ;
2005-04-17 02:20:36 +04:00
2023-03-25 11:45:26 +03:00
void class_unregister ( const struct class * cls )
2005-04-17 02:20:36 +04:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( cls ) ;
if ( ! sp )
return ;
2005-04-17 02:20:36 +04:00
pr_debug ( " device class '%s': unregistering \n " , cls - > name ) ;
2023-03-25 22:42:34 +03:00
sysfs_remove_groups ( & sp - > subsys . kobj , cls - > class_groups ) ;
kset_unregister ( & sp - > subsys ) ;
subsys_put ( sp ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_unregister ) ;
2005-04-17 02:20:36 +04:00
2023-04-02 20:58:46 +03:00
static void class_create_release ( const struct class * cls )
2005-03-15 22:54:21 +03:00
{
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 ) ;
}
2005-03-23 21:02:56 +03:00
/**
2023-03-24 13:01:31 +03:00
* class_create - create a struct class structure
2005-03-23 21:02:56 +03:00
* @ 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
2008-03-12 22:47:35 +03:00
* in calls to device_create ( ) .
2005-03-23 21:02:56 +03:00
*
2010-03-11 19:11:45 +03:00
* Returns & struct class pointer on success , or ERR_PTR ( ) on error .
*
2005-03-23 21:02:56 +03:00
* Note , the pointer created here is to be destroyed when finished by
* making a call to class_destroy ( ) .
*/
2023-03-24 13:01:31 +03:00
struct class * class_create ( 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 - > class_release = class_create_release ;
2023-03-24 13:01:31 +03:00
retval = class_register ( cls ) ;
2005-03-15 22:54:21 +03:00
if ( retval )
goto error ;
return cls ;
error :
kfree ( cls ) ;
return ERR_PTR ( retval ) ;
}
2023-03-24 13:01:31 +03:00
EXPORT_SYMBOL_GPL ( class_create ) ;
2005-03-15 22:54:21 +03:00
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 ( ) .
*/
2023-03-25 11:45:26 +03:00
void class_destroy ( const struct class * cls )
2005-03-15 22:54:21 +03:00
{
2022-08-22 09:19:22 +03:00
if ( IS_ERR_OR_NULL ( cls ) )
2005-03-15 22:54:21 +03:00
return ;
class_unregister ( cls ) ;
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_destroy ) ;
2005-04-17 02:20:36 +04:00
2008-08-25 21:50:19 +04:00
/**
* class_dev_iter_init - initialize class device iterator
* @ iter : class iterator to initialize
* @ class : the class we wanna iterate over
* @ start : the device to start iterating from , if any
* @ type : device_type of the devices to iterate over , NULL for all
*
* Initialize class iterator @ iter such that it iterates over devices
* of @ class . If @ start is set , the list iteration will start there ,
* otherwise if it is NULL , the iteration starts at the beginning of
* the list .
*/
2023-03-13 21:18:36 +03:00
void class_dev_iter_init ( struct class_dev_iter * iter , const struct class * class ,
const struct device * start , const struct device_type * type )
2008-08-25 21:50:19 +04:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( class ) ;
2008-08-25 21:50:19 +04:00
struct klist_node * start_knode = NULL ;
2023-03-25 22:42:34 +03:00
if ( ! sp )
return ;
2008-08-25 21:50:19 +04:00
if ( start )
2019-01-18 05:34:59 +03:00
start_knode = & start - > p - > knode_class ;
2023-03-25 22:42:34 +03:00
klist_iter_init_node ( & sp - > klist_devices , & iter - > ki , start_knode ) ;
2008-08-25 21:50:19 +04:00
iter - > type = type ;
2023-05-16 22:20:14 +03:00
iter - > sp = sp ;
2008-08-25 21:50:19 +04:00
}
EXPORT_SYMBOL_GPL ( class_dev_iter_init ) ;
/**
* class_dev_iter_next - iterate to the next device
* @ iter : class iterator to proceed
*
* Proceed @ iter to the next device and return it . Returns NULL if
* iteration is complete .
*
* The returned device is referenced and won ' t be released till
* iterator is proceed to the next device or exited . The caller is
* free to do whatever it wants to do with the device including
* calling back into class code .
*/
struct device * class_dev_iter_next ( struct class_dev_iter * iter )
{
struct klist_node * knode ;
struct device * dev ;
while ( 1 ) {
knode = klist_next ( & iter - > ki ) ;
if ( ! knode )
return NULL ;
2019-01-18 05:34:59 +03:00
dev = klist_class_to_dev ( knode ) ;
2008-08-25 21:50:19 +04:00
if ( ! iter - > type | | iter - > type = = dev - > type )
return dev ;
}
}
EXPORT_SYMBOL_GPL ( class_dev_iter_next ) ;
/**
* class_dev_iter_exit - finish iteration
* @ iter : class iterator to finish
*
* Finish an iteration . Always call this function after iteration is
* complete whether the iteration ran till the end or not .
*/
void class_dev_iter_exit ( struct class_dev_iter * iter )
{
klist_iter_exit ( & iter - > ki ) ;
2023-05-16 22:20:14 +03:00
subsys_put ( iter - > sp ) ;
2008-08-25 21:50:19 +04:00
}
EXPORT_SYMBOL_GPL ( class_dev_iter_exit ) ;
2008-01-22 10:27:08 +03:00
/**
* class_for_each_device - device iterator
* @ class : the class we ' re iterating
2008-05-23 01:21:08 +04:00
* @ start : the device to start with in the list , if any .
2008-01-22 10:27:08 +03:00
* @ 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 ,
2008-05-23 01:21:08 +04:00
* passing it @ data . If @ start is set , the list iteration will start
* there , otherwise if it is NULL , the iteration starts at the
* beginning of the list .
2008-01-22 10:27:08 +03:00
*
* We check the return of @ fn each time . If it returns anything
* other than 0 , we break out and return that value .
*
2008-08-25 21:50:19 +04:00
* @ fn is allowed to do anything including calling back into class
* code . There ' s no locking restriction .
2008-01-22 10:27:08 +03:00
*/
2023-03-13 21:18:37 +03:00
int class_for_each_device ( const struct class * class , const struct device * start ,
2008-05-23 01:21:08 +04:00
void * data , int ( * fn ) ( struct device * , void * ) )
2008-01-22 10:27:08 +03:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( class ) ;
2008-08-25 21:50:19 +04:00
struct class_dev_iter iter ;
2008-01-22 10:27:08 +03:00
struct device * dev ;
int error = 0 ;
if ( ! class )
return - EINVAL ;
2023-03-25 22:42:34 +03:00
if ( ! sp ) {
2008-08-07 05:52:44 +04:00
WARN ( 1 , " %s called for class '%s' before it was initialized " ,
__func__ , class - > name ) ;
return - EINVAL ;
}
2008-08-25 21:50:19 +04:00
class_dev_iter_init ( & iter , class , start , NULL ) ;
while ( ( dev = class_dev_iter_next ( & iter ) ) ) {
2008-05-23 01:21:08 +04:00
error = fn ( dev , data ) ;
2008-01-22 10:27:08 +03:00
if ( error )
break ;
}
2008-08-25 21:50:19 +04:00
class_dev_iter_exit ( & iter ) ;
2023-03-25 22:42:34 +03:00
subsys_put ( sp ) ;
2008-01-22 10:27:08 +03:00
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
2008-05-23 01:21:08 +04:00
* @ start : Device to begin with
2008-01-22 10:27:08 +03:00
* @ 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 .
*
2015-09-04 21:49:14 +03:00
* @ match is allowed to do anything including calling back into class
2008-08-25 21:50:19 +04:00
* code . There ' s no locking restriction .
2008-01-22 10:27:08 +03:00
*/
2023-03-13 21:18:38 +03:00
struct device * class_find_device ( const struct class * class , const struct device * start ,
2013-02-01 23:40:17 +04:00
const void * data ,
int ( * match ) ( struct device * , const void * ) )
2008-01-22 10:27:08 +03:00
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp = class_to_subsys ( class ) ;
2008-08-25 21:50:19 +04:00
struct class_dev_iter iter ;
2008-01-22 10:27:08 +03:00
struct device * dev ;
if ( ! class )
return NULL ;
2023-03-25 22:42:34 +03:00
if ( ! sp ) {
2008-08-07 05:52:44 +04:00
WARN ( 1 , " %s called for class '%s' before it was initialized " ,
__func__ , class - > name ) ;
return NULL ;
}
2008-01-22 10:27:08 +03:00
2008-08-25 21:50:19 +04:00
class_dev_iter_init ( & iter , class , start , NULL ) ;
while ( ( dev = class_dev_iter_next ( & iter ) ) ) {
2008-05-23 01:21:08 +04:00
if ( match ( dev , data ) ) {
2008-08-25 21:50:19 +04:00
get_device ( dev ) ;
2008-01-22 10:27:08 +03:00
break ;
2008-08-25 21:50:19 +04:00
}
2008-01-22 10:27:08 +03:00
}
2008-08-25 21:50:19 +04:00
class_dev_iter_exit ( & iter ) ;
2023-03-25 22:42:34 +03:00
subsys_put ( sp ) ;
2008-01-22 10:27:08 +03:00
2008-08-25 21:50:19 +04:00
return dev ;
2008-01-22 10:27:08 +03:00
}
EXPORT_SYMBOL_GPL ( class_find_device ) ;
2005-04-17 02:20:36 +04:00
int class_interface_register ( struct class_interface * class_intf )
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp ;
2023-03-25 22:42:33 +03:00
const struct class * parent ;
2008-08-25 21:50:19 +04:00
struct class_dev_iter iter ;
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 ;
2023-03-25 22:42:34 +03:00
parent = class_intf - > class ;
sp = class_to_subsys ( parent ) ;
if ( ! sp )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2023-03-25 22:42:34 +03:00
/*
* Reference in sp is now incremented and will be dropped when
* the interface is removed in the call to class_interface_unregister ( )
*/
mutex_lock ( & sp - > mutex ) ;
list_add_tail ( & class_intf - > node , & sp - > interfaces ) ;
2006-09-13 17:34:05 +04:00
if ( class_intf - > add_dev ) {
2008-08-25 21:50:19 +04:00
class_dev_iter_init ( & iter , parent , NULL , NULL ) ;
while ( ( dev = class_dev_iter_next ( & iter ) ) )
2023-04-02 20:58:49 +03:00
class_intf - > add_dev ( dev ) ;
2008-08-25 21:50:19 +04:00
class_dev_iter_exit ( & iter ) ;
2006-09-13 17:34:05 +04:00
}
2023-03-25 22:42:34 +03:00
mutex_unlock ( & sp - > mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_interface_register ) ;
2005-04-17 02:20:36 +04:00
void class_interface_unregister ( struct class_interface * class_intf )
{
2023-03-25 22:42:34 +03:00
struct subsys_private * sp ;
2023-04-02 20:58:48 +03:00
const struct class * parent = class_intf - > class ;
2008-08-25 21:50:19 +04:00
struct class_dev_iter iter ;
2006-09-13 17:34:05 +04:00
struct device * dev ;
2005-04-17 02:20:36 +04:00
if ( ! parent )
return ;
2023-03-25 22:42:34 +03:00
sp = class_to_subsys ( parent ) ;
if ( ! sp )
return ;
mutex_lock ( & sp - > mutex ) ;
2005-04-17 02:20:36 +04:00
list_del_init ( & class_intf - > node ) ;
2006-09-13 17:34:05 +04:00
if ( class_intf - > remove_dev ) {
2008-08-25 21:50:19 +04:00
class_dev_iter_init ( & iter , parent , NULL , NULL ) ;
while ( ( dev = class_dev_iter_next ( & iter ) ) )
2023-04-02 20:58:49 +03:00
class_intf - > remove_dev ( dev ) ;
2008-08-25 21:50:19 +04:00
class_dev_iter_exit ( & iter ) ;
2006-09-13 17:34:05 +04:00
}
2023-03-25 22:42:34 +03:00
mutex_unlock ( & sp - > mutex ) ;
2005-04-17 02:20:36 +04:00
2023-03-25 22:42:34 +03:00
/*
* Decrement the reference count twice , once for the class_to_subsys ( )
* call in the start of this function , and the second one from the
* reference increment in class_interface_register ( )
*/
subsys_put ( sp ) ;
subsys_put ( sp ) ;
2005-04-17 02:20:36 +04:00
}
2023-02-14 17:41:17 +03:00
EXPORT_SYMBOL_GPL ( class_interface_unregister ) ;
2005-04-17 02:20:36 +04:00
2023-03-25 11:45:37 +03:00
ssize_t show_class_attr_string ( const struct class * class ,
const struct class_attribute * attr , char * buf )
2010-01-05 14:48:08 +03:00
{
struct class_attribute_string * cs ;
2015-03-08 13:31:54 +03:00
2010-01-05 14:48:08 +03:00
cs = container_of ( attr , struct class_attribute_string , attr ) ;
2020-09-16 23:40:42 +03:00
return sysfs_emit ( buf , " %s \n " , cs - > str ) ;
2010-01-05 14:48:08 +03:00
}
EXPORT_SYMBOL_GPL ( show_class_attr_string ) ;
2009-08-04 14:55:34 +04:00
struct class_compat {
struct kobject * kobj ;
} ;
/**
* class_compat_register - register a compatibility class
* @ name : the name of the class
*
* Compatibility class are meant as a temporary user - space compatibility
* workaround when converting a family of class devices to a bus devices .
*/
struct class_compat * class_compat_register ( const char * name )
{
struct class_compat * cls ;
cls = kmalloc ( sizeof ( struct class_compat ) , GFP_KERNEL ) ;
if ( ! cls )
return NULL ;
cls - > kobj = kobject_create_and_add ( name , & class_kset - > kobj ) ;
if ( ! cls - > kobj ) {
kfree ( cls ) ;
return NULL ;
}
return cls ;
}
EXPORT_SYMBOL_GPL ( class_compat_register ) ;
/**
* class_compat_unregister - unregister a compatibility class
* @ cls : the class to unregister
*/
void class_compat_unregister ( struct class_compat * cls )
{
kobject_put ( cls - > kobj ) ;
kfree ( cls ) ;
}
EXPORT_SYMBOL_GPL ( class_compat_unregister ) ;
/**
* class_compat_create_link - create a compatibility class device link to
* a bus device
* @ cls : the compatibility class
* @ dev : the target bus device
* @ device_link : an optional device to which a " device " link should be created
*/
int class_compat_create_link ( struct class_compat * cls , struct device * dev ,
struct device * device_link )
{
int error ;
error = sysfs_create_link ( cls - > kobj , & dev - > kobj , dev_name ( dev ) ) ;
if ( error )
return error ;
/*
* Optionally add a " device " link ( typically to the parent ) , as a
* class device would have one and we want to provide as much
* backwards compatibility as possible .
*/
if ( device_link ) {
error = sysfs_create_link ( & dev - > kobj , & device_link - > kobj ,
" device " ) ;
if ( error )
sysfs_remove_link ( cls - > kobj , dev_name ( dev ) ) ;
}
return error ;
}
EXPORT_SYMBOL_GPL ( class_compat_create_link ) ;
/**
* class_compat_remove_link - remove a compatibility class device link to
* a bus device
* @ cls : the compatibility class
* @ dev : the target bus device
* @ device_link : an optional device to which a " device " link was previously
* created
*/
void class_compat_remove_link ( struct class_compat * cls , struct device * dev ,
struct device * device_link )
{
if ( device_link )
sysfs_remove_link ( & dev - > kobj , " device " ) ;
sysfs_remove_link ( cls - > kobj , dev_name ( dev ) ) ;
}
EXPORT_SYMBOL_GPL ( class_compat_remove_link ) ;
2023-03-31 12:33:13 +03:00
/**
* class_is_registered - determine if at this moment in time , a class is
* registered in the driver core or not .
* @ class : the class to check
*
* Returns a boolean to state if the class is registered in the driver core
* or not . Note that the value could switch right after this call is made ,
* so only use this in places where you " know " it is safe to do so ( usually
* to determine if the specific class has been registered yet or not ) .
*
* Be careful in using this .
*/
bool class_is_registered ( const struct class * class )
{
struct subsys_private * sp = class_to_subsys ( class ) ;
bool is_initialized = false ;
if ( sp ) {
is_initialized = true ;
subsys_put ( sp ) ;
}
return is_initialized ;
}
EXPORT_SYMBOL_GPL ( class_is_registered ) ;
2005-04-17 02:20:36 +04:00
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
return 0 ;
}