2005-10-06 13:22:17 +10:00
# include <linux/string.h>
# include <linux/kernel.h>
2007-05-01 16:40:36 +10:00
# include <linux/of.h>
2005-10-06 13:22:17 +10:00
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mod_devicetable.h>
2005-10-31 13:57:01 +11:00
# include <linux/slab.h>
2008-01-08 05:07:15 +11:00
# include <linux/of_device.h>
2005-10-31 13:57:01 +11:00
2005-10-06 13:22:17 +10:00
# include <asm/errno.h>
2007-09-26 19:44:12 +10:00
# include <asm/dcr.h>
2005-10-06 13:22:17 +10:00
2007-09-26 19:44:12 +10:00
static void of_device_make_bus_id ( struct of_device * dev )
{
static atomic_t bus_no_reg_magic ;
struct device_node * node = dev - > node ;
char * name = dev - > dev . bus_id ;
const u32 * reg ;
u64 addr ;
int magic ;
/*
* If it ' s a DCR based device , use ' d ' for native DCRs
* and ' D ' for MMIO DCRs .
*/
# ifdef CONFIG_PPC_DCR
reg = of_get_property ( node , " dcr-reg " , NULL ) ;
if ( reg ) {
# ifdef CONFIG_PPC_DCR_NATIVE
snprintf ( name , BUS_ID_SIZE , " d%x.%s " ,
* reg , node - > name ) ;
# else /* CONFIG_PPC_DCR_NATIVE */
addr = of_translate_dcr_address ( node , * reg , NULL ) ;
if ( addr ! = OF_BAD_ADDR ) {
snprintf ( name , BUS_ID_SIZE ,
" D%llx.%s " , ( unsigned long long ) addr ,
node - > name ) ;
return ;
}
# endif /* !CONFIG_PPC_DCR_NATIVE */
}
# endif /* CONFIG_PPC_DCR */
/*
* For MMIO , get the physical address
*/
reg = of_get_property ( node , " reg " , NULL ) ;
if ( reg ) {
addr = of_translate_address ( node , reg ) ;
if ( addr ! = OF_BAD_ADDR ) {
snprintf ( name , BUS_ID_SIZE ,
" %llx.%s " , ( unsigned long long ) addr ,
node - > name ) ;
return ;
}
}
/*
* No BusID , use the node name and add a globally incremented
* counter ( and pray . . . )
*/
magic = atomic_add_return ( 1 , & bus_no_reg_magic ) ;
snprintf ( name , BUS_ID_SIZE , " %s.%d " , node - > name , magic - 1 ) ;
}
struct of_device * of_device_alloc ( struct device_node * np ,
const char * bus_id ,
struct device * parent )
{
struct of_device * dev ;
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev )
return NULL ;
dev - > node = of_node_get ( np ) ;
dev - > dev . dma_mask = & dev - > dma_mask ;
dev - > dev . parent = parent ;
dev - > dev . release = of_release_dev ;
dev - > dev . archdata . of_node = np ;
dev - > dev . archdata . numa_node = of_node_to_nid ( np ) ;
if ( bus_id )
strlcpy ( dev - > dev . bus_id , bus_id , BUS_ID_SIZE ) ;
else
of_device_make_bus_id ( dev ) ;
return dev ;
}
EXPORT_SYMBOL ( of_device_alloc ) ;
2007-08-14 15:15:12 +02:00
int of_device_uevent ( struct device * dev , struct kobj_uevent_env * env )
2007-02-12 23:13:25 +01:00
{
struct of_device * ofdev ;
const char * compat ;
2007-08-14 15:15:12 +02:00
int seen = 0 , cplen , sl ;
2007-02-12 23:13:25 +01:00
if ( ! dev )
return - ENODEV ;
ofdev = to_of_device ( dev ) ;
2007-08-14 15:15:12 +02:00
if ( add_uevent_var ( env , " OF_NAME=%s " , ofdev - > node - > name ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
2007-08-14 15:15:12 +02:00
if ( add_uevent_var ( env , " OF_TYPE=%s " , ofdev - > node - > type ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
/* Since the compatible field can contain pretty much anything
* it ' s not really legal to split it out with commas . We split it
* up using a number of environment variables instead . */
2007-04-13 17:14:22 +10:00
compat = of_get_property ( ofdev - > node , " compatible " , & cplen ) ;
2007-02-12 23:13:25 +01:00
while ( compat & & * compat & & cplen > 0 ) {
2007-08-14 15:15:12 +02:00
if ( add_uevent_var ( env , " OF_COMPATIBLE_%d=%s " , seen , compat ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
sl = strlen ( compat ) + 1 ;
compat + = sl ;
cplen - = sl ;
seen + + ;
}
2007-08-14 15:15:12 +02:00
if ( add_uevent_var ( env , " OF_COMPATIBLE_N=%d " , seen ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
/* modalias is trickier, we add it in 2 steps */
2007-08-14 15:15:12 +02:00
if ( add_uevent_var ( env , " MODALIAS= " ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
2007-08-14 15:15:12 +02:00
sl = of_device_get_modalias ( ofdev , & env - > buf [ env - > buflen - 1 ] ,
sizeof ( env - > buf ) - env - > buflen ) ;
if ( sl > = ( sizeof ( env - > buf ) - env - > buflen ) )
2007-02-12 23:13:25 +01:00
return - ENOMEM ;
2007-08-14 15:15:12 +02:00
env - > buflen + = sl ;
2007-02-12 23:13:25 +01:00
return 0 ;
}
EXPORT_SYMBOL ( of_device_uevent ) ;
2007-05-07 01:38:46 +10:00
EXPORT_SYMBOL ( of_device_get_modalias ) ;