2014-08-15 17:53:43 +00:00
/* Copyright (c) 2011,2012 Simon Schubert <2@0x2c.org>.
2015-04-05 06:21:11 +00:00
* Modifications by Jacob Alexander 2014 - 2015 < haata @ kiibohd . com >
2014-08-15 17:53:43 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
// ----- Local Includes -----
# include "usb.h"
# include "dfu.h"
2015-04-27 07:57:34 +00:00
# include "debug.h"
2014-08-15 17:53:43 +00:00
// ----- Functions -----
void dfu_write_done ( enum dfu_status err , struct dfu_ctx * ctx )
{
2015-03-09 01:40:01 +00:00
ctx - > status = err ;
if ( ctx - > status = = DFU_STATUS_OK ) {
switch ( ctx - > state ) {
case DFU_STATE_dfuDNBUSY :
ctx - > state = DFU_STATE_dfuDNLOAD_IDLE ;
break ;
default :
break ;
}
} else {
ctx - > state = DFU_STATE_dfuERROR ;
}
2014-08-15 17:53:43 +00:00
}
static void dfu_dnload_complete ( void * buf , ssize_t len , void * cbdata )
{
2015-03-09 01:40:01 +00:00
struct dfu_ctx * ctx = cbdata ;
2014-08-15 17:53:43 +00:00
2015-03-09 01:40:01 +00:00
if ( len > 0 )
ctx - > state = DFU_STATE_dfuDNBUSY ;
else
ctx - > state = DFU_STATE_dfuMANIFEST ;
ctx - > status = ctx - > finish_write ( buf , ctx - > off , len ) ;
ctx - > off + = len ;
ctx - > len = len ;
2014-08-15 17:53:43 +00:00
2015-03-09 01:40:01 +00:00
if ( ctx - > status ! = DFU_STATUS_async )
dfu_write_done ( ctx - > status , ctx ) ;
2014-08-15 17:53:43 +00:00
2015-03-09 01:40:01 +00:00
usb_handle_control_status ( ctx - > state = = DFU_STATE_dfuERROR ) ;
2014-08-15 17:53:43 +00:00
}
static void dfu_reset_system ( void * buf , ssize_t len , void * cbdata )
{
2015-03-09 01:40:01 +00:00
SOFTWARE_RESET ( ) ;
2014-08-15 17:53:43 +00:00
}
static int dfu_handle_control ( struct usb_ctrl_req_t * req , void * data )
{
2015-03-09 01:40:01 +00:00
struct dfu_ctx * ctx = data ;
int fail = 1 ;
2016-07-24 06:46:37 +00:00
switch ( ( enum dfu_ctrl_req_code ) req - > bRequest )
2015-04-27 07:57:34 +00:00
{
2015-03-09 01:40:01 +00:00
case USB_CTRL_REQ_DFU_DNLOAD : {
void * buf ;
2016-07-24 06:46:37 +00:00
switch ( ctx - > state )
{
2015-03-09 01:40:01 +00:00
case DFU_STATE_dfuIDLE :
ctx - > off = 0 ;
break ;
case DFU_STATE_dfuDNLOAD_IDLE :
break ;
default :
goto err ;
}
/**
* XXX we are not allowed to STALL here , and we need to eat all transferred data .
* better not allow setup_write to break the protocol .
*/
2016-07-24 06:46:37 +00:00
ctx - > status = ctx - > setup_write ( ctx - > off , req - > wLength , & buf ) ;
if ( ctx - > status ! = DFU_STATUS_OK )
{
2015-03-09 01:40:01 +00:00
ctx - > state = DFU_STATE_dfuERROR ;
goto err_have_status ;
}
2016-07-24 06:46:37 +00:00
if ( req - > wLength > 0 )
{
usb_ep0_rx ( buf , req - > wLength , dfu_dnload_complete , ctx ) ;
}
2015-03-09 01:40:01 +00:00
else
2016-07-24 06:46:37 +00:00
{
dfu_dnload_complete ( NULL , 0 , ctx ) ;
}
2015-03-09 01:40:01 +00:00
goto out_no_status ;
}
2015-04-05 06:21:11 +00:00
case USB_CTRL_REQ_DFU_UPLOAD : {
2016-07-24 06:46:37 +00:00
# if defined(_mk20dx256vlh7_) // Kiibohd-dfu
2015-04-05 06:21:11 +00:00
void * buf ;
2015-04-27 07:57:34 +00:00
size_t len = 0 ;
2015-04-05 06:21:11 +00:00
2015-04-27 07:57:34 +00:00
switch ( ctx - > state )
{
2015-04-05 06:21:11 +00:00
case DFU_STATE_dfuIDLE :
break ;
case DFU_STATE_dfuUPLOAD_IDLE :
break ;
default :
goto err ;
}
2016-07-24 06:46:37 +00:00
// Compute the requested offset
ctx - > off = USB_DFU_TRANSFER_SIZE * req - > wValue ;
2015-04-27 07:57:34 +00:00
// Find which sector to read
2016-07-24 06:46:37 +00:00
ctx - > status = ctx - > setup_read ( ctx - > off , & len , & buf ) ;
# ifdef FLASH_DEBUG
print ( " UPLOAD req: " ) ;
printHex ( req - > wValue ) ;
print ( " off: " ) ;
2015-04-27 07:57:34 +00:00
printHex ( ctx - > off ) ;
print ( " len: " ) ;
printHex ( len ) ;
2016-07-24 06:46:37 +00:00
print ( " reqlen: " ) ;
printHex ( req - > wLength ) ;
2015-04-27 07:57:34 +00:00
print ( " addr: " ) ;
printHex ( ( uint32_t ) buf ) ;
2016-07-24 06:46:37 +00:00
# endif
2015-04-27 07:57:34 +00:00
if ( ctx - > status ! = DFU_STATUS_OK | | len > req - > wLength )
{
2015-04-05 06:21:11 +00:00
ctx - > state = DFU_STATE_dfuERROR ;
goto err_have_status ;
}
2015-04-27 07:57:34 +00:00
// Send bytes to Host
2016-07-24 06:46:37 +00:00
// Successfully transferred data to USB
if ( usb_ep0_tx ( buf , len , len , NULL , NULL ) ! = - 1 )
2015-04-27 07:57:34 +00:00
{
2016-07-24 06:46:37 +00:00
ctx - > state = len < req - > wLength
? DFU_STATE_dfuIDLE
: DFU_STATE_dfuUPLOAD_IDLE ;
fail = 0 ;
2015-04-27 07:57:34 +00:00
}
2016-07-24 06:46:37 +00:00
// Problem transferring via USB
2015-04-05 06:21:11 +00:00
else
2015-04-27 07:57:34 +00:00
{
2016-07-24 06:46:37 +00:00
ctx - > state = DFU_STATE_dfuERROR ;
2015-04-27 07:57:34 +00:00
}
2016-07-24 06:46:37 +00:00
# ifdef FLASH_DEBUG
print ( " state: " ) ;
printHex ( ctx - > state ) ;
print ( NL ) ;
# endif
2015-04-27 07:57:34 +00:00
2016-07-24 06:46:37 +00:00
goto out ;
# else
ctx - > state = DFU_STATE_dfuERROR ;
goto out ;
# endif
2015-04-05 06:21:11 +00:00
}
2015-03-09 01:40:01 +00:00
case USB_CTRL_REQ_DFU_GETSTATUS : {
struct dfu_status_t st ;
st . bState = ctx - > state ;
st . bStatus = ctx - > status ;
st . bwPollTimeout = 1000 ; /* XXX */
2015-04-05 06:21:11 +00:00
2015-03-09 01:40:01 +00:00
/**
* If we ' re in DFU_STATE_dfuMANIFEST , we just finished
* the download , and we ' re just about to send our last
* status report . Once the report has been sent , go
* and reset the system to put the new firmware into
* effect .
*/
2016-07-24 22:48:30 +00:00
usb_ep0_tx_cp ( & st , sizeof ( st ) , req - > wLength , NULL , NULL ) ;
switch ( ctx - > state )
{
case DFU_STATE_dfuMANIFEST :
ctx - > state = DFU_STATE_dfuMANIFEST_WAIT_RESET ;
break ;
case DFU_STATE_dfuMANIFEST_WAIT_RESET :
ctx - > state = DFU_STATE_dfuIDLE ;
2015-03-09 01:40:01 +00:00
usb_handle_control_status_cb ( dfu_reset_system ) ;
goto out_no_status ;
2016-07-24 22:48:30 +00:00
default :
break ;
2015-03-09 01:40:01 +00:00
}
break ;
}
case USB_CTRL_REQ_DFU_CLRSTATUS :
ctx - > state = DFU_STATE_dfuIDLE ;
ctx - > status = DFU_STATUS_OK ;
break ;
case USB_CTRL_REQ_DFU_GETSTATE : {
uint8_t st = ctx - > state ;
2016-07-24 22:48:30 +00:00
usb_ep0_tx_cp ( & st , sizeof ( st ) , req - > wLength , NULL , NULL ) ;
2015-03-09 01:40:01 +00:00
break ;
}
case USB_CTRL_REQ_DFU_ABORT :
2016-07-24 22:48:30 +00:00
switch ( ctx - > state )
{
2015-03-09 01:40:01 +00:00
case DFU_STATE_dfuIDLE :
case DFU_STATE_dfuDNLOAD_IDLE :
2015-04-05 06:21:11 +00:00
case DFU_STATE_dfuUPLOAD_IDLE :
2015-03-09 01:40:01 +00:00
ctx - > state = DFU_STATE_dfuIDLE ;
break ;
default :
goto err ;
}
break ;
default :
return ( 0 ) ;
}
fail = 0 ;
goto out ;
2014-08-15 17:53:43 +00:00
err :
2015-03-09 01:40:01 +00:00
ctx - > status = DFU_STATUS_errSTALLEDPKT ;
2014-08-15 17:53:43 +00:00
err_have_status :
2015-03-09 01:40:01 +00:00
ctx - > state = DFU_STATE_dfuERROR ;
2014-08-15 17:53:43 +00:00
out :
2015-03-09 01:40:01 +00:00
usb_handle_control_status ( fail ) ;
2014-08-15 17:53:43 +00:00
out_no_status :
2015-03-09 01:40:01 +00:00
return ( 1 ) ;
2014-08-15 17:53:43 +00:00
}
2015-04-27 07:57:34 +00:00
void dfu_init ( dfu_setup_read_t setup_read , dfu_setup_write_t setup_write , dfu_finish_write_t finish_write , struct dfu_ctx * ctx )
2014-08-15 17:53:43 +00:00
{
2015-03-09 01:40:01 +00:00
ctx - > state = DFU_STATE_dfuIDLE ;
2016-07-24 06:46:37 +00:00
# if defined(_mk20dx256vlh7_) // Kiibohd-dfu
2015-04-27 07:57:34 +00:00
ctx - > setup_read = setup_read ;
2016-07-24 06:46:37 +00:00
# endif
2015-03-09 01:40:01 +00:00
ctx - > setup_write = setup_write ;
ctx - > finish_write = finish_write ;
usb_attach_function ( & dfu_function , & ctx - > header ) ;
2014-08-15 17:53:43 +00:00
}
const struct usbd_function dfu_function = {
2015-03-09 01:40:01 +00:00
. control = dfu_handle_control ,
. interface_count = USB_FUNCTION_DFU_IFACE_COUNT ,
2014-08-15 17:53:43 +00:00
} ;