@ -990,6 +990,8 @@ int __init platform_bus_init(void)
{
int error ;
early_platform_cleanup ( ) ;
error = device_register ( & platform_bus ) ;
if ( error )
return error ;
@ -1020,3 +1022,240 @@ u64 dma_get_required_mask(struct device *dev)
}
EXPORT_SYMBOL_GPL ( dma_get_required_mask ) ;
# endif
static __initdata LIST_HEAD ( early_platform_driver_list ) ;
static __initdata LIST_HEAD ( early_platform_device_list ) ;
/**
* early_platform_driver_register
* @ edrv : early_platform driver structure
* @ buf : string passed from early_param ( )
*/
int __init early_platform_driver_register ( struct early_platform_driver * epdrv ,
char * buf )
{
unsigned long index ;
int n ;
/* Simply add the driver to the end of the global list.
* Drivers will by default be put on the list in compiled - in order .
*/
if ( ! epdrv - > list . next ) {
INIT_LIST_HEAD ( & epdrv - > list ) ;
list_add_tail ( & epdrv - > list , & early_platform_driver_list ) ;
}
/* If the user has specified device then make sure the driver
* gets prioritized . The driver of the last device specified on
* command line will be put first on the list .
*/
n = strlen ( epdrv - > pdrv - > driver . name ) ;
if ( buf & & ! strncmp ( buf , epdrv - > pdrv - > driver . name , n ) ) {
list_move ( & epdrv - > list , & early_platform_driver_list ) ;
if ( ! strcmp ( buf , epdrv - > pdrv - > driver . name ) )
epdrv - > requested_id = - 1 ;
else if ( buf [ n ] = = ' . ' & & strict_strtoul ( & buf [ n + 1 ] , 10 ,
& index ) = = 0 )
epdrv - > requested_id = index ;
else
epdrv - > requested_id = EARLY_PLATFORM_ID_ERROR ;
}
return 0 ;
}
/**
* early_platform_add_devices - add a numbers of early platform devices
* @ devs : array of early platform devices to add
* @ num : number of early platform devices in array
*/
void __init early_platform_add_devices ( struct platform_device * * devs , int num )
{
struct device * dev ;
int i ;
/* simply add the devices to list */
for ( i = 0 ; i < num ; i + + ) {
dev = & devs [ i ] - > dev ;
if ( ! dev - > devres_head . next ) {
INIT_LIST_HEAD ( & dev - > devres_head ) ;
list_add_tail ( & dev - > devres_head ,
& early_platform_device_list ) ;
}
}
}
/**
* early_platform_driver_register_all
* @ class_str : string to identify early platform driver class
*/
void __init early_platform_driver_register_all ( char * class_str )
{
/* The "class_str" parameter may or may not be present on the kernel
* command line . If it is present then there may be more than one
* matching parameter .
*
* Since we register our early platform drivers using early_param ( )
* we need to make sure that they also get registered in the case
* when the parameter is missing from the kernel command line .
*
* We use parse_early_options ( ) to make sure the early_param ( ) gets
* called at least once . The early_param ( ) may be called more than
* once since the name of the preferred device may be specified on
* the kernel command line . early_platform_driver_register ( ) handles
* this case for us .
*/
parse_early_options ( class_str ) ;
}
/**
* early_platform_match
* @ edrv : early platform driver structure
* @ id : id to match against
*/
static __init struct platform_device *
early_platform_match ( struct early_platform_driver * epdrv , int id )
{
struct platform_device * pd ;
list_for_each_entry ( pd , & early_platform_device_list , dev . devres_head )
if ( platform_match ( & pd - > dev , & epdrv - > pdrv - > driver ) )
if ( pd - > id = = id )
return pd ;
return NULL ;
}
/**
* early_platform_left
* @ edrv : early platform driver structure
* @ id : return true if id or above exists
*/
static __init int early_platform_left ( struct early_platform_driver * epdrv ,
int id )
{
struct platform_device * pd ;
list_for_each_entry ( pd , & early_platform_device_list , dev . devres_head )
if ( platform_match ( & pd - > dev , & epdrv - > pdrv - > driver ) )
if ( pd - > id > = id )
return 1 ;
return 0 ;
}
/**
* early_platform_driver_probe_id
* @ class_str : string to identify early platform driver class
* @ id : id to match against
* @ nr_probe : number of platform devices to successfully probe before exiting
*/
static int __init early_platform_driver_probe_id ( char * class_str ,
int id ,
int nr_probe )
{
struct early_platform_driver * epdrv ;
struct platform_device * match ;
int match_id ;
int n = 0 ;
int left = 0 ;
list_for_each_entry ( epdrv , & early_platform_driver_list , list ) {
/* only use drivers matching our class_str */
if ( strcmp ( class_str , epdrv - > class_str ) )
continue ;
if ( id = = - 2 ) {
match_id = epdrv - > requested_id ;
left = 1 ;
} else {
match_id = id ;
left + = early_platform_left ( epdrv , id ) ;
/* skip requested id */
switch ( epdrv - > requested_id ) {
case EARLY_PLATFORM_ID_ERROR :
case EARLY_PLATFORM_ID_UNSET :
break ;
default :
if ( epdrv - > requested_id = = id )
match_id = EARLY_PLATFORM_ID_UNSET ;
}
}
switch ( match_id ) {
case EARLY_PLATFORM_ID_ERROR :
pr_warning ( " %s: unable to parse %s parameter \n " ,
class_str , epdrv - > pdrv - > driver . name ) ;
/* fall-through */
case EARLY_PLATFORM_ID_UNSET :
match = NULL ;
break ;
default :
match = early_platform_match ( epdrv , match_id ) ;
}
if ( match ) {
if ( epdrv - > pdrv - > probe ( match ) )
pr_warning ( " %s: unable to probe %s early. \n " ,
class_str , match - > name ) ;
else
n + + ;
}
if ( n > = nr_probe )
break ;
}
if ( left )
return n ;
else
return - ENODEV ;
}
/**
* early_platform_driver_probe
* @ class_str : string to identify early platform driver class
* @ nr_probe : number of platform devices to successfully probe before exiting
* @ user_only : only probe user specified early platform devices
*/
int __init early_platform_driver_probe ( char * class_str ,
int nr_probe ,
int user_only )
{
int k , n , i ;
n = 0 ;
for ( i = - 2 ; n < nr_probe ; i + + ) {
k = early_platform_driver_probe_id ( class_str , i , nr_probe - n ) ;
if ( k < 0 )
break ;
n + = k ;
if ( user_only )
break ;
}
return n ;
}
/**
* early_platform_cleanup - clean up early platform code
*/
void __init early_platform_cleanup ( void )
{
struct platform_device * pd , * pd2 ;
/* clean up the devres list used to chain devices */
list_for_each_entry_safe ( pd , pd2 , & early_platform_device_list ,
dev . devres_head ) {
list_del ( & pd - > dev . devres_head ) ;
memset ( & pd - > dev . devres_head , 0 , sizeof ( pd - > dev . devres_head ) ) ;
}
}