@ -11,6 +11,286 @@
# include <dm/device-internal.h>
# include <dm/lists.h>
static const char * if_typename_str [ IF_TYPE_COUNT ] = {
[ IF_TYPE_IDE ] = " ide " ,
[ IF_TYPE_SCSI ] = " scsi " ,
[ IF_TYPE_ATAPI ] = " atapi " ,
[ IF_TYPE_USB ] = " usb " ,
[ IF_TYPE_DOC ] = " doc " ,
[ IF_TYPE_MMC ] = " mmc " ,
[ IF_TYPE_SD ] = " sd " ,
[ IF_TYPE_SATA ] = " sata " ,
[ IF_TYPE_HOST ] = " host " ,
[ IF_TYPE_SYSTEMACE ] = " ace " ,
} ;
static enum uclass_id if_type_uclass_id [ IF_TYPE_COUNT ] = {
[ IF_TYPE_IDE ] = UCLASS_INVALID ,
[ IF_TYPE_SCSI ] = UCLASS_INVALID ,
[ IF_TYPE_ATAPI ] = UCLASS_INVALID ,
[ IF_TYPE_USB ] = UCLASS_MASS_STORAGE ,
[ IF_TYPE_DOC ] = UCLASS_INVALID ,
[ IF_TYPE_MMC ] = UCLASS_MMC ,
[ IF_TYPE_SD ] = UCLASS_INVALID ,
[ IF_TYPE_SATA ] = UCLASS_AHCI ,
[ IF_TYPE_HOST ] = UCLASS_ROOT ,
[ IF_TYPE_SYSTEMACE ] = UCLASS_INVALID ,
} ;
static enum if_type if_typename_to_iftype ( const char * if_typename )
{
int i ;
for ( i = 0 ; i < IF_TYPE_COUNT ; i + + ) {
if ( if_typename_str [ i ] & &
! strcmp ( if_typename , if_typename_str [ i ] ) )
return i ;
}
return IF_TYPE_UNKNOWN ;
}
static enum uclass_id if_type_to_uclass_id ( enum if_type if_type )
{
return if_type_uclass_id [ if_type ] ;
}
struct blk_desc * blk_get_devnum_by_type ( enum if_type if_type , int devnum )
{
struct blk_desc * desc ;
struct udevice * dev ;
int ret ;
ret = blk_get_device ( if_type , devnum , & dev ) ;
if ( ret )
return NULL ;
desc = dev_get_uclass_platdata ( dev ) ;
return desc ;
}
/*
* This function is complicated with driver model . We look up the interface
* name in a local table . This gives us an interface type which we can match
* against the uclass of the block device ' s parent .
*/
struct blk_desc * blk_get_devnum_by_typename ( const char * if_typename , int devnum )
{
enum uclass_id uclass_id ;
enum if_type if_type ;
struct udevice * dev ;
struct uclass * uc ;
int ret ;
if_type = if_typename_to_iftype ( if_typename ) ;
if ( if_type = = IF_TYPE_UNKNOWN ) {
debug ( " %s: Unknown interface type '%s' \n " , __func__ ,
if_typename ) ;
return NULL ;
}
uclass_id = if_type_to_uclass_id ( if_type ) ;
if ( uclass_id = = UCLASS_INVALID ) {
debug ( " %s: Unknown uclass for interface type' \n " ,
if_typename_str [ if_type ] ) ;
return NULL ;
}
ret = uclass_get ( UCLASS_BLK , & uc ) ;
if ( ret )
return NULL ;
uclass_foreach_dev ( dev , uc ) {
struct blk_desc * desc = dev_get_uclass_platdata ( dev ) ;
debug ( " %s: if_type=%d, devnum=%d: %s, %d, %d \n " , __func__ ,
if_type , devnum , dev - > name , desc - > if_type , desc - > devnum ) ;
if ( desc - > devnum ! = devnum )
continue ;
/* Find out the parent device uclass */
if ( device_get_uclass_id ( dev - > parent ) ! = uclass_id ) {
debug ( " %s: parent uclass %d, this dev %d \n " , __func__ ,
device_get_uclass_id ( dev - > parent ) , uclass_id ) ;
continue ;
}
if ( device_probe ( dev ) )
return NULL ;
debug ( " %s: Device desc %p \n " , __func__ , desc ) ;
return desc ;
}
debug ( " %s: No device found \n " , __func__ ) ;
return NULL ;
}
/**
* get_desc ( ) - Get the block device descriptor for the given device number
*
* @ if_type : Interface type
* @ devnum : Device number ( 0 = first )
* @ descp : Returns block device descriptor on success
* @ return 0 on success , - ENODEV if there is no such device and no device
* with a higher device number , - ENOENT if there is no such device but there
* is one with a higher number , or other - ve on other error .
*/
static int get_desc ( enum if_type if_type , int devnum , struct blk_desc * * descp )
{
bool found_more = false ;
struct udevice * dev ;
struct uclass * uc ;
int ret ;
* descp = NULL ;
ret = uclass_get ( UCLASS_BLK , & uc ) ;
if ( ret )
return ret ;
uclass_foreach_dev ( dev , uc ) {
struct blk_desc * desc = dev_get_uclass_platdata ( dev ) ;
debug ( " %s: if_type=%d, devnum=%d: %s, %d, %d \n " , __func__ ,
if_type , devnum , dev - > name , desc - > if_type , desc - > devnum ) ;
if ( desc - > if_type = = if_type ) {
if ( desc - > devnum = = devnum ) {
ret = device_probe ( dev ) ;
if ( ret )
return ret ;
} else if ( desc - > devnum > devnum ) {
found_more = true ;
}
}
}
return found_more ? - ENOENT : - ENODEV ;
}
int blk_list_part ( enum if_type if_type )
{
struct blk_desc * desc ;
int devnum , ok ;
int ret ;
for ( ok = 0 , devnum = 0 ; ; + + devnum ) {
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret = = - ENODEV )
break ;
else if ( ret )
continue ;
if ( desc - > part_type ! = PART_TYPE_UNKNOWN ) {
+ + ok ;
if ( devnum )
putc ( ' \n ' ) ;
part_print ( desc ) ;
}
}
if ( ! ok )
return - ENODEV ;
return 0 ;
}
int blk_print_part_devnum ( enum if_type if_type , int devnum )
{
struct blk_desc * desc ;
int ret ;
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret )
return ret ;
if ( desc - > type = = DEV_TYPE_UNKNOWN )
return - ENOENT ;
part_print ( desc ) ;
return 0 ;
}
void blk_list_devices ( enum if_type if_type )
{
struct blk_desc * desc ;
int ret ;
int i ;
for ( i = 0 ; ; + + i ) {
ret = get_desc ( if_type , i , & desc ) ;
if ( ret = = - ENODEV )
break ;
else if ( ret )
continue ;
if ( desc - > type = = DEV_TYPE_UNKNOWN )
continue ; /* list only known devices */
printf ( " Device %d: " , i ) ;
dev_print ( desc ) ;
}
}
int blk_print_device_num ( enum if_type if_type , int devnum )
{
struct blk_desc * desc ;
int ret ;
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret )
return ret ;
printf ( " \n IDE device %d: " , devnum ) ;
dev_print ( desc ) ;
return 0 ;
}
int blk_show_device ( enum if_type if_type , int devnum )
{
struct blk_desc * desc ;
int ret ;
printf ( " \n Device %d: " , devnum ) ;
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret = = - ENODEV | | ret = = - ENOENT ) {
printf ( " unknown device \n " ) ;
return - ENODEV ;
}
if ( ret )
return ret ;
dev_print ( desc ) ;
if ( desc - > type = = DEV_TYPE_UNKNOWN )
return - ENOENT ;
return 0 ;
}
ulong blk_read_devnum ( enum if_type if_type , int devnum , lbaint_t start ,
lbaint_t blkcnt , void * buffer )
{
struct blk_desc * desc ;
ulong n ;
int ret ;
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret )
return ret ;
n = blk_dread ( desc , start , blkcnt , buffer ) ;
if ( IS_ERR_VALUE ( n ) )
return n ;
/* flush cache after read */
flush_cache ( ( ulong ) buffer , blkcnt * desc - > blksz ) ;
return n ;
}
ulong blk_write_devnum ( enum if_type if_type , int devnum , lbaint_t start ,
lbaint_t blkcnt , const void * buffer )
{
struct blk_desc * desc ;
int ret ;
ret = get_desc ( if_type , devnum , & desc ) ;
if ( ret )
return ret ;
return blk_dwrite ( desc , start , blkcnt , buffer ) ;
}
int blk_first_device ( int if_type , struct udevice * * devp )
{
struct blk_desc * desc ;