2007-05-01 10:40:36 +04:00
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/of.h>
2007-05-01 10:49:51 +04:00
# include <linux/of_device.h>
2007-05-01 10:40:36 +04:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mod_devicetable.h>
# include <linux/slab.h>
# include <asm/errno.h>
/**
* of_match_device - Tell if an of_device structure has a matching
* of_match structure
* @ ids : array of of device match structures to search in
* @ dev : the of device structure to match against
*
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices .
*/
const struct of_device_id * of_match_device ( const struct of_device_id * matches ,
const struct of_device * dev )
{
if ( ! dev - > node )
return NULL ;
return of_match_node ( matches , dev - > node ) ;
}
EXPORT_SYMBOL ( of_match_device ) ;
struct of_device * of_dev_get ( struct of_device * dev )
{
struct device * tmp ;
if ( ! dev )
return NULL ;
tmp = get_device ( & dev - > dev ) ;
if ( tmp )
return to_of_device ( tmp ) ;
else
return NULL ;
}
EXPORT_SYMBOL ( of_dev_get ) ;
void of_dev_put ( struct of_device * dev )
{
if ( dev )
put_device ( & dev - > dev ) ;
}
EXPORT_SYMBOL ( of_dev_put ) ;
2008-04-24 17:16:00 +04:00
static ssize_t devspec_show ( struct device * dev ,
2007-05-01 10:40:36 +04:00
struct device_attribute * attr , char * buf )
{
struct of_device * ofdev ;
ofdev = to_of_device ( dev ) ;
2008-04-24 17:16:00 +04:00
return sprintf ( buf , " %s \n " , ofdev - > node - > full_name ) ;
2007-05-01 10:40:36 +04:00
}
2008-08-05 18:30:18 +04:00
static ssize_t name_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct of_device * ofdev ;
ofdev = to_of_device ( dev ) ;
return sprintf ( buf , " %s \n " , ofdev - > node - > name ) ;
}
2008-04-24 17:16:00 +04:00
static ssize_t modalias_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct of_device * ofdev = to_of_device ( dev ) ;
ssize_t len = 0 ;
len = of_device_get_modalias ( ofdev , buf , PAGE_SIZE - 2 ) ;
buf [ len ] = ' \n ' ;
buf [ len + 1 ] = 0 ;
return len + 1 ;
}
struct device_attribute of_platform_device_attrs [ ] = {
__ATTR_RO ( devspec ) ,
2008-08-05 18:30:18 +04:00
__ATTR_RO ( name ) ,
2008-04-24 17:16:00 +04:00
__ATTR_RO ( modalias ) ,
__ATTR_NULL
} ;
2007-05-01 10:40:36 +04:00
/**
* of_release_dev - free an of device structure when all users of it are finished .
* @ dev : device that ' s been disconnected
*
* Will be called only by the device core when all users of this of device are
* done .
*/
void of_release_dev ( struct device * dev )
{
struct of_device * ofdev ;
ofdev = to_of_device ( dev ) ;
of_node_put ( ofdev - > node ) ;
kfree ( ofdev ) ;
}
EXPORT_SYMBOL ( of_release_dev ) ;
int of_device_register ( struct of_device * ofdev )
{
BUG_ON ( ofdev - > node = = NULL ) ;
2008-10-27 00:51:25 +03:00
device_initialize ( & ofdev - > dev ) ;
/* device_add will assume that this device is on the same node as
* the parent . If there is no parent defined , set the node
* explicitly */
if ( ! ofdev - > dev . parent )
set_dev_node ( & ofdev - > dev , of_node_to_nid ( ofdev - > node ) ) ;
return device_add ( & ofdev - > dev ) ;
2007-05-01 10:40:36 +04:00
}
EXPORT_SYMBOL ( of_device_register ) ;
void of_device_unregister ( struct of_device * ofdev )
{
device_unregister ( & ofdev - > dev ) ;
}
EXPORT_SYMBOL ( of_device_unregister ) ;
2008-05-16 05:57:45 +04:00
ssize_t of_device_get_modalias ( struct of_device * ofdev ,
char * str , ssize_t len )
{
const char * compat ;
int cplen , i ;
ssize_t tsize , csize , repend ;
/* Name & Type */
csize = snprintf ( str , len , " of:N%sT%s " ,
ofdev - > node - > name , ofdev - > node - > type ) ;
/* Get compatible property if any */
compat = of_get_property ( ofdev - > node , " compatible " , & cplen ) ;
if ( ! compat )
return csize ;
/* Find true end (we tolerate multiple \0 at the end */
for ( i = ( cplen - 1 ) ; i > = 0 & & ! compat [ i ] ; i - - )
cplen - - ;
if ( ! cplen )
return csize ;
cplen + + ;
/* Check space (need cplen+1 chars including final \0) */
tsize = csize + cplen ;
repend = tsize ;
if ( csize > = len ) /* @ the limit, all is already filled */
return tsize ;
if ( tsize > = len ) { /* limit compat list */
cplen = len - csize - 1 ;
repend = len ;
}
/* Copy and do char replacement */
memcpy ( & str [ csize + 1 ] , compat , cplen ) ;
for ( i = csize ; i < repend ; i + + ) {
char c = str [ i ] ;
if ( c = = ' \0 ' )
str [ i ] = ' C ' ;
else if ( c = = ' ' )
str [ i ] = ' _ ' ;
}
return tsize ;
}