@ -18,14 +18,7 @@
# include <linux/usb/gadget.h>
# include <linux/usb/composite.h>
# include <linux/compiler.h>
# include <version.h>
# include <g_dnl.h>
# ifdef CONFIG_FASTBOOT_FLASH_MMC
# include <fb_mmc.h>
# endif
# ifdef CONFIG_FASTBOOT_FLASH_NAND
# include <fb_nand.h>
# endif
# define FASTBOOT_INTERFACE_CLASS 0xff
# define FASTBOOT_INTERFACE_SUB_CLASS 0x42
@ -56,8 +49,6 @@ static inline struct f_fastboot *func_to_fastboot(struct usb_function *f)
}
static struct f_fastboot * fastboot_func ;
static unsigned int download_size ;
static unsigned int download_bytes ;
static struct usb_endpoint_descriptor fs_ep_in = {
. bLength = USB_DT_ENDPOINT_SIZE ,
@ -145,7 +136,6 @@ static struct usb_gadget_strings *fastboot_strings[] = {
} ;
static void rx_handler_command ( struct usb_ep * ep , struct usb_request * req ) ;
static int strcmp_l1 ( const char * s1 , const char * s2 ) ;
static void fastboot_complete ( struct usb_ep * ep , struct usb_request * req )
{
@ -355,85 +345,9 @@ static void compl_do_reset(struct usb_ep *ep, struct usb_request *req)
do_reset ( NULL , 0 , 0 , NULL ) ;
}
static void cb_reboot ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
if ( ! strcmp_l1 ( " reboot-bootloader " , cmd ) ) {
if ( fastboot_set_reboot_flag ( ) ) {
fastboot_tx_write_str ( " FAILCannot set reboot flag " ) ;
return ;
}
}
fastboot_func - > in_req - > complete = compl_do_reset ;
fastboot_tx_write_str ( " OKAY " ) ;
}
static int strcmp_l1 ( const char * s1 , const char * s2 )
{
if ( ! s1 | | ! s2 )
return - 1 ;
return strncmp ( s1 , s2 , strlen ( s1 ) ) ;
}
static void cb_getvar ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
char response [ FASTBOOT_RESPONSE_LEN ] ;
const char * s ;
size_t chars_left ;
strcpy ( response , " OKAY " ) ;
chars_left = sizeof ( response ) - strlen ( response ) - 1 ;
strsep ( & cmd , " : " ) ;
if ( ! cmd ) {
pr_err ( " missing variable " ) ;
fastboot_tx_write_str ( " FAILmissing var " ) ;
return ;
}
if ( ! strcmp_l1 ( " version " , cmd ) ) {
strncat ( response , FASTBOOT_VERSION , chars_left ) ;
} else if ( ! strcmp_l1 ( " bootloader-version " , cmd ) ) {
strncat ( response , U_BOOT_VERSION , chars_left ) ;
} else if ( ! strcmp_l1 ( " downloadsize " , cmd ) | |
! strcmp_l1 ( " max-download-size " , cmd ) ) {
char str_num [ 12 ] ;
sprintf ( str_num , " 0x%08x " , CONFIG_FASTBOOT_BUF_SIZE ) ;
strncat ( response , str_num , chars_left ) ;
} else if ( ! strcmp_l1 ( " serialno " , cmd ) ) {
s = env_get ( " serial# " ) ;
if ( s )
strncat ( response , s , chars_left ) ;
else
strcpy ( response , " FAILValue not set " ) ;
} else {
char * envstr ;
envstr = malloc ( strlen ( " fastboot. " ) + strlen ( cmd ) + 1 ) ;
if ( ! envstr ) {
fastboot_tx_write_str ( " FAILmalloc error " ) ;
return ;
}
sprintf ( envstr , " fastboot.%s " , cmd ) ;
s = env_get ( envstr ) ;
if ( s ) {
strncat ( response , s , chars_left ) ;
} else {
printf ( " WARNING: unknown variable: %s \n " , cmd ) ;
strcpy ( response , " FAILVariable not implemented " ) ;
}
free ( envstr ) ;
}
fastboot_tx_write_str ( response ) ;
}
static unsigned int rx_bytes_expected ( struct usb_ep * ep )
{
int rx_remain = download_size - download_bytes ;
int rx_remain = fastboot_data_remaining ( ) ;
unsigned int rem ;
unsigned int maxpacket = ep - > maxpacket ;
@ -455,14 +369,12 @@ static unsigned int rx_bytes_expected(struct usb_ep *ep)
return rx_remain ;
}
# define BYTES_PER_DOT 0x20000
static void rx_handler_dl_image ( struct usb_ep * ep , struct usb_request * req )
{
char response [ FASTBOOT_RESPONSE_LEN ] ;
unsigned int transfer_size = download_size - download_bytes ;
char response [ FASTBOOT_RESPONSE_LEN ] = { 0 } ;
unsigned int transfer_size = fastboot_data_remaining ( ) ;
const unsigned char * buffer = req - > buf ;
unsigned int buffer_size = req - > actual ;
unsigned int pre_dot_num , now_dot_num ;
if ( req - > status ! = 0 ) {
printf ( " Bad status: %d \n " , req - > status ) ;
@ -472,33 +384,19 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
if ( buffer_size < transfer_size )
transfer_size = buffer_size ;
memcpy ( ( void * ) CONFIG_FASTBOOT_BUF_ADDR + download_bytes ,
buffer , transfer_size ) ;
pre_dot_num = download_bytes / BYTES_PER_DOT ;
download_bytes + = transfer_size ;
now_dot_num = download_bytes / BYTES_PER_DOT ;
if ( pre_dot_num ! = now_dot_num ) {
putc ( ' . ' ) ;
if ( ! ( now_dot_num % 74 ) )
putc ( ' \n ' ) ;
}
fastboot_data_download ( buffer , transfer_size , response ) ;
if ( response [ 0 ] ) {
fastboot_tx_write_str ( response ) ;
} else if ( ! fastboot_data_remaining ( ) ) {
fastboot_data_complete ( response ) ;
/* Check if transfer is done */
if ( download_bytes > = download_size ) {
/*
* Reset global transfer variable , keep download_bytes because
* it will be used in the next possible flashing command
* Reset global transfer variable
*/
download_size = 0 ;
req - > complete = rx_handler_command ;
req - > length = EP_BUFFER_SIZE ;
strcpy ( response , " OKAY " ) ;
fastboot_tx_write_str ( response ) ;
printf ( " \n downloading of %d bytes finished \n " , download_bytes ) ;
} else {
req - > length = rx_bytes_expected ( ep ) ;
}
@ -507,197 +405,55 @@ static void rx_handler_dl_image(struct usb_ep *ep, struct usb_request *req)
usb_ep_queue ( ep , req , 0 ) ;
}
static void cb_download ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
char response [ FASTBOOT_RESPONSE_LEN ] ;
strsep ( & cmd , " : " ) ;
download_size = simple_strtoul ( cmd , NULL , 16 ) ;
download_bytes = 0 ;
printf ( " Starting download of %d bytes \n " , download_size ) ;
if ( 0 = = download_size ) {
strcpy ( response , " FAILdata invalid size " ) ;
} else if ( download_size > CONFIG_FASTBOOT_BUF_SIZE ) {
download_size = 0 ;
strcpy ( response , " FAILdata too large " ) ;
} else {
sprintf ( response , " DATA%08x " , download_size ) ;
req - > complete = rx_handler_dl_image ;
req - > length = rx_bytes_expected ( ep ) ;
}
fastboot_tx_write_str ( response ) ;
}
static void do_bootm_on_complete ( struct usb_ep * ep , struct usb_request * req )
{
char boot_addr_start [ 12 ] ;
char * bootm_args [ ] = { " bootm " , boot_addr_start , NULL } ;
puts ( " Booting kernel.. \n " ) ;
sprintf ( boot_addr_start , " 0x%lx " , ( long ) CONFIG_FASTBOOT_BUF_ADDR ) ;
do_bootm ( NULL , 0 , 2 , bootm_args ) ;
/* This only happens if image is somehow faulty so we start over */
do_reset ( NULL , 0 , 0 , NULL ) ;
}
static void cb_boot ( struct usb_ep * ep , struct usb_request * req )
{
fastboot_func - > in_req - > complete = do_bootm_on_complete ;
fastboot_tx_write_str ( " OKAY " ) ;
}
static void do_exit_on_complete ( struct usb_ep * ep , struct usb_request * req )
{
g_dnl_trigger_detach ( ) ;
}
static void cb_continu e( struct usb_ep * ep , struct usb_request * req )
static void do_bootm_on_complete ( struct usb_ep * ep , struct usb_request * req )
{
fastboot_func - > in_req - > complete = do_exit_on_complete ;
fastboot_tx_write_str ( " OKAY " ) ;
fastboot_boot ( ) ;
do_exit_on_complete ( ep , req ) ;
}
# ifdef CONFIG_FASTBOOT_FLASH
static void cb_flash ( struct usb_ep * ep , struct usb_request * req )
static void rx_handler_command ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
char response [ FASTBOOT_RESPONSE_LEN ] ;
char * cmdbuf = req - > buf ;
char response [ FASTBOOT_RESPONSE_LEN ] = { 0 } ;
int cmd = - 1 ;
strsep ( & cmd , " : " ) ;
if ( ! cmd ) {
pr_err ( " missing partition name " ) ;
fastboot_tx_write_str ( " FAILmissing partition name " ) ;
if ( req - > status ! = 0 | | req - > length = = 0 )
return ;
}
fastboot_fail ( " no flash device defined " , response ) ;
# ifdef CONFIG_FASTBOOT_FLASH_MMC
fastboot_mmc_flash_write ( cmd , ( void * ) CONFIG_FASTBOOT_BUF_ADDR ,
download_bytes , response ) ;
# endif
# ifdef CONFIG_FASTBOOT_FLASH_NAND
fastboot_nand_flash_write ( cmd , ( void * ) CONFIG_FASTBOOT_BUF_ADDR ,
download_bytes , response ) ;
# endif
fastboot_tx_write_str ( response ) ;
}
# endif
static void cb_oem ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
# ifdef CONFIG_FASTBOOT_FLASH_MMC
if ( strncmp ( " format " , cmd + 4 , 6 ) = = 0 ) {
char cmdbuf [ 32 ] ;
sprintf ( cmdbuf , " gpt write mmc %x $partitions " ,
CONFIG_FASTBOOT_FLASH_MMC_DEV ) ;
if ( run_command ( cmdbuf , 0 ) )
fastboot_tx_write_str ( " FAIL " ) ;
else
fastboot_tx_write_str ( " OKAY " ) ;
} else
# endif
if ( strncmp ( " unlock " , cmd + 4 , 8 ) = = 0 ) {
fastboot_tx_write_str ( " FAILnot implemented " ) ;
}
else {
fastboot_tx_write_str ( " FAILunknown oem command " ) ;
if ( req - > actual < req - > length ) {
cmdbuf [ req - > actual ] = ' \0 ' ;
cmd = fastboot_handle_command ( cmdbuf , response ) ;
} else {
pr_err ( " buffer overflow " ) ;
fastboot_fail ( " buffer overflow " , response ) ;
}
}
# ifdef CONFIG_FASTBOOT_FLASH
static void cb_erase ( struct usb_ep * ep , struct usb_request * req )
{
char * cmd = req - > buf ;
char response [ FASTBOOT_RESPONSE_LEN ] ;
strsep ( & cmd , " : " ) ;
if ( ! cmd ) {
pr_err ( " missing partition name " ) ;
fastboot_tx_write_str ( " FAILmissing partition name " ) ;
return ;
if ( ! strncmp ( " DATA " , response , 4 ) ) {
req - > complete = rx_handler_dl_image ;
req - > length = rx_bytes_expected ( ep ) ;
}
fastboot_fail ( " no flash device defined " , response ) ;
# ifdef CONFIG_FASTBOOT_FLASH_MMC
fastboot_mmc_erase ( cmd , response ) ;
# endif
# ifdef CONFIG_FASTBOOT_FLASH_NAND
fastboot_nand_erase ( cmd , response ) ;
# endif
fastboot_tx_write_str ( response ) ;
}
# endif
struct cmd_dispatch_info {
char * cmd ;
void ( * cb ) ( struct usb_ep * ep , struct usb_request * req ) ;
} ;
static const struct cmd_dispatch_info cmd_dispatch_info [ ] = {
{
. cmd = " reboot " ,
. cb = cb_reboot ,
} , {
. cmd = " getvar: " ,
. cb = cb_getvar ,
} , {
. cmd = " download: " ,
. cb = cb_download ,
} , {
. cmd = " boot " ,
. cb = cb_boot ,
} , {
. cmd = " continue " ,
. cb = cb_continue ,
} ,
# ifdef CONFIG_FASTBOOT_FLASH
{
. cmd = " flash " ,
. cb = cb_flash ,
} , {
. cmd = " erase " ,
. cb = cb_erase ,
} ,
# endif
{
. cmd = " oem " ,
. cb = cb_oem ,
} ,
} ;
static void rx_handler_command ( struct usb_ep * ep , struct usb_request * req )
{
char * cmdbuf = req - > buf ;
void ( * func_cb ) ( struct usb_ep * ep , struct usb_request * req ) = NULL ;
int i ;
if ( req - > status ! = 0 | | req - > length = = 0 )
return ;
if ( ! strncmp ( " OKAY " , response , 4 ) ) {
switch ( cmd ) {
case FASTBOOT_COMMAND_BOOT :
fastboot_func - > in_req - > complete = do_bootm_on_complete ;
break ;
for ( i = 0 ; i < ARRAY_SIZE ( cmd_dispatch_info ) ; i + + ) {
if ( ! strcmp_l1 ( cmd_dispatch_info [ i ] . cmd , cmdbuf ) ) {
func_cb = cmd_dispatch_info [ i ] . cb ;
case FASTBOOT_COMMAND_CONTINUE :
fastboot_func - > in_req - > complete = do_exit_on_complete ;
break ;
}
}
if ( ! func_cb ) {
pr_err ( " unknown command: %.*s " , req - > actual , cmdbuf ) ;
fastboot_tx_write_str ( " FAILunknown command " ) ;
} else {
if ( req - > actual < req - > length ) {
u8 * buf = ( u8 * ) req - > buf ;
buf [ req - > actual ] = 0 ;
func_cb ( ep , req ) ;
} else {
pr_err ( " buffer overflow " ) ;
fastboot_tx_write_str ( " FAILbuffer overflow " ) ;
case FASTBOOT_COMMAND_REBOOT :
case FASTBOOT_COMMAND_REBOOT_BOOTLOADER :
fastboot_func - > in_req - > complete = compl_do_reset ;
break ;
}
}