DFU: include more common infrastructure for download and upload handling

This commit is contained in:
Harald Welte 2012-01-07 17:38:11 +01:00
parent 541bc5bdae
commit 141a11409e
2 changed files with 124 additions and 7 deletions

View File

@ -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);

View File

@ -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;