diff options
| author | Harald Welte <laforge@gnumonks.org> | 2012-01-07 17:38:11 +0100 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2012-01-07 17:38:11 +0100 | 
| commit | 141a11409e125abeca98d069eec6fcfee480d5fd (patch) | |
| tree | 926227c0bf397ca2f28b8e9faea9cc0b83abe19d /usb | |
| parent | 541bc5bdaea55365b290f2995fc865371577dc0d (diff) | |
DFU: include more common infrastructure for download and upload handling
Diffstat (limited to 'usb')
| -rw-r--r-- | usb/device/dfu/dfu.h | 7 | ||||
| -rw-r--r-- | usb/device/dfu/dfu_driver.c | 124 | 
2 files changed, 124 insertions, 7 deletions
| diff --git a/usb/device/dfu/dfu.h b/usb/device/dfu/dfu.h index 34afa4a..bf07d43 100644 --- a/usb/device/dfu/dfu.h +++ b/usb/device/dfu/dfu.h @@ -116,13 +116,16 @@ struct dfu {  	uint8_t status;  	uint32_t state;  	int past_manifest; +	unsigned int total_bytes;  };  extern struct dfu dfu;  /* call-backs by the board/SOC */ -extern int USBDFU_handle_dnload(uint16_t val, uint16_t len, int first); -extern int USBDFU_handle_upload(uint16_t val, uint16_t len, int first); +extern int USBDFU_handle_dnload(uint8_t altif, unsigned int offset, +				uint8_t *data, unsigned int len); +extern int USBDFU_handle_upload(uint8_t altif, unsigned int offset, +				uint8_t *data, unsigned int req_len);  void USBDFU_Runtime_RequestHandler(const USBGenericRequest *request);  void USBDFU_DFU_RequestHandler(const USBGenericRequest *request); diff --git a/usb/device/dfu/dfu_driver.c b/usb/device/dfu/dfu_driver.c index f7705ac..53f690c 100644 --- a/usb/device/dfu/dfu_driver.c +++ b/usb/device/dfu/dfu_driver.c @@ -41,6 +41,7 @@ static USBDDriver usbdDriver;  __dfudata struct dfu dfu = {    	.state = DFU_STATE_appIDLE,  	.past_manifest = 0, +	.total_bytes = 0,  };  static __dfufunc void handle_getstatus(void) @@ -82,6 +83,119 @@ static void TerminateCtrlInWithNull(void *pArg,                 (void *)  0);  } +static uint8_t dfu_buf[BOARD_DFU_PAGE_SIZE]; + +/* download of a single page has completed */ +static void dnload_cb(void *arg, unsigned char status, unsigned int transferred, +		      unsigned int remaining) +{ +	int rc; + +	TRACE_DEBUG("COMPLETE\n\r"); + +	if (status != USBD_STATUS_SUCCESS) { +		TRACE_ERROR("USBD download callback status %d\n\r", status); +		USBD_Stall(0); +		return; +	} + +	rc = USBDFU_handle_dnload(0, dfu.total_bytes, dfu_buf, transferred); +	switch (rc) { +	case DFU_RET_ZLP: +		dfu.total_bytes += transferred; +		dfu.state = DFU_STATE_dfuDNLOAD_IDLE; +		TerminateCtrlInWithNull(0,0,0,0); +		break; +	case DFU_RET_STALL: +		dfu.state = DFU_STATE_dfuERROR; +		USBD_Stall(0); +		break; +	case DFU_RET_NOTHING: +		break; +	} + +} + +static int handle_dnload(uint16_t val, uint16_t len, int first) +{ +	int rc; + +	if (len > BOARD_DFU_PAGE_SIZE) { +		TRACE_ERROR("DFU length exceeds flash page size\n\r"); +		dfu.state = DFU_STATE_dfuERROR; +		dfu.status = DFU_STATUS_errADDRESS; +		return DFU_RET_STALL; +	} + +	if (len & 0x03) { +		TRACE_ERROR("DFU length not four-byte-aligned\n\r"); +		dfu.state = DFU_STATE_dfuERROR; +		dfu.status = DFU_STATUS_errADDRESS; +		return DFU_RET_STALL; +	} + +	if (first) +		dfu.total_bytes = 0; + +	if (len == 0) { +		TRACE_DEBUG("zero-size write -> MANIFEST_SYNC\n\r"); +		dfu.state = DFU_STATE_dfuMANIFEST_SYNC; +		return DFU_RET_ZLP; +	} + +	/* else: actually read data */ +	rc = USBD_Read(0, dfu_buf, len, &dnload_cb, 0); +	if (rc == USBD_STATUS_SUCCESS) +		return DFU_RET_NOTHING; +	else +		return DFU_RET_STALL; +} + +/* upload of a single page has completed */ +static void upload_cb(void *arg, unsigned char status, unsigned int transferred, +		      unsigned int remaining) +{ +	int rc; + +	TRACE_DEBUG("COMPLETE\n\r"); + +	if (status != USBD_STATUS_SUCCESS) { +		TRACE_ERROR("USBD upload callback status %d\n\r", status); +		USBD_Stall(0); +		return; +	} + +	dfu.total_bytes += transferred; +} + +static int handle_upload(uint16_t val, uint16_t len, int first) +{ +	int rc; + +	if (first) +		dfu.total_bytes = 0; + +	if (len > BOARD_DFU_PAGE_SIZE) { +		TRACE_ERROR("DFU length exceeds flash page size\n\r"); +		dfu.state = DFU_STATE_dfuERROR; +		dfu.status = DFU_STATUS_errADDRESS; +		return DFU_RET_STALL; +	} + +	/* FIXME: altif */ +	rc = USBDFU_handle_upload(0, dfu.total_bytes, dfu_buf, len); +	if (rc < 0) { +		TRACE_ERROR("application handle_upload() returned %d\n\r", rc); +		return DFU_RET_STALL; +	} + +	rc = USBD_Write(0, dfu_buf, rc, &upload_cb, 0); +	if (rc == USBD_STATUS_SUCCESS) +		return DFU_RET_NOTHING; +	else +		return DFU_RET_STALL; +} +  /* this function gets daisy-chained into processing EP0 requests */  void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)  { @@ -90,7 +204,7 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)  	uint16_t val = USBGenericRequest_GetValue(request);  	int rc, ret; -	TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n", +	TRACE_DEBUG("type=0x%x, recipient=0x%x val=0x%x len=%u\n\r",  			USBGenericRequest_GetType(request),  			USBGenericRequest_GetRecipient(request),  			val, len); @@ -166,11 +280,11 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)  				goto out;  			}  			dfu.state = DFU_STATE_dfuDNLOAD_SYNC; -			ret = USBDFU_handle_dnload(val, len, 1); +			ret = handle_dnload(val, len, 1);  			break;  		case USB_REQ_DFU_UPLOAD:  			dfu.state = DFU_STATE_dfuUPLOAD_IDLE; -			USBDFU_handle_upload(val, len, 1); +			handle_upload(val, len, 1);  			break;  		case USB_REQ_DFU_ABORT:  			/* no zlp? */ @@ -221,7 +335,7 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)  		switch (req) {  		case USB_REQ_DFU_DNLOAD:  			dfu.state = DFU_STATE_dfuDNLOAD_SYNC; -			ret = USBDFU_handle_dnload(val, len, 0); +			ret = handle_dnload(val, len, 0);  			break;  		case USB_REQ_DFU_ABORT:  			dfu.state = DFU_STATE_dfuIDLE; @@ -284,7 +398,7 @@ void USBDFU_DFU_RequestHandler(const USBGenericRequest *request)  		switch (req) {  		case USB_REQ_DFU_UPLOAD:  			/* state transition if less data then requested */ -			rc = USBDFU_handle_upload(val, len, 0); +			rc = handle_upload(val, len, 0);  			if (rc >= 0 && rc < len)  				dfu.state = DFU_STATE_dfuIDLE;  			break; | 
