working dfu framework
This commit is contained in:
parent
588cfbc2c2
commit
fded24a803
@ -1,6 +1,20 @@
|
|||||||
#ifndef AT91_UDP_H_
|
#ifndef AT91_UDP_H_
|
||||||
#define AT91_UDP_H_
|
#define AT91_UDP_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void ep_transfer_send(uint32_t ep,
|
||||||
|
char *data,
|
||||||
|
uint32_t length,
|
||||||
|
void (*complete_cb)(void));
|
||||||
|
|
||||||
|
void ep_transfer_receive(uint32_t ep,
|
||||||
|
char *data,
|
||||||
|
uint32_t length,
|
||||||
|
void (*complete_cb)(void));
|
||||||
|
|
||||||
|
void ep_send_stall(uint32_t ep);
|
||||||
|
|
||||||
void at91_udp_init(void);
|
void at91_udp_init(void);
|
||||||
|
|
||||||
#endif /*AT91_UDP_H_*/
|
#endif /*AT91_UDP_H_*/
|
||||||
|
4
main.c
4
main.c
@ -21,7 +21,6 @@
|
|||||||
#include "at91_dbgu.h"
|
#include "at91_dbgu.h"
|
||||||
#include "at91_pitc.h"
|
#include "at91_pitc.h"
|
||||||
#include "at91_udp.h"
|
#include "at91_udp.h"
|
||||||
#include "at91_pio.h"
|
|
||||||
#include "at91_twi.h"
|
#include "at91_twi.h"
|
||||||
|
|
||||||
#include "memalloc.h"
|
#include "memalloc.h"
|
||||||
@ -57,9 +56,6 @@ int main(void)
|
|||||||
at91_dbgu_init();
|
at91_dbgu_init();
|
||||||
at91_dbgu_puts("==========================================================\n\rGood morning Dave\n\r");
|
at91_dbgu_puts("==========================================================\n\rGood morning Dave\n\r");
|
||||||
|
|
||||||
/* triggers pinchange-isrs */
|
|
||||||
at91_pio_init();
|
|
||||||
|
|
||||||
/* timer */
|
/* timer */
|
||||||
at91_pitc_init();
|
at91_pitc_init();
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ static void dbgu_isr(uint32_t status)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (status & AT91C_US_TXBUFE)
|
if (status & AT91C_US_TXBUFE)
|
||||||
if (fifo_txpdc(txfifo, AT91C_BASE_PDC_DBGU, 16) == 0)
|
if (fifo_txpdc(txfifo, AT91C_BASE_PDC_DBGU, 32) == 0)
|
||||||
*AT91C_DBGU_IDR = AT91C_US_TXBUFE;
|
*AT91C_DBGU_IDR = AT91C_US_TXBUFE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ void at91_dbgu_init(void)
|
|||||||
dbgu->DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
|
dbgu->DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
|
||||||
dbgu->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_RSTSTA;
|
dbgu->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_RSTSTA;
|
||||||
|
|
||||||
txfifo = fifo_alloc(1024);
|
txfifo = fifo_alloc(16384);
|
||||||
|
|
||||||
/* enable TX PDC */
|
/* enable TX PDC */
|
||||||
dbgu->DBGU_PTCR = AT91C_PDC_TXTEN;
|
dbgu->DBGU_PTCR = AT91C_PDC_TXTEN;
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
/***************************************************************************
|
|
||||||
* Copyright (C) 01/2008 by Olaf Rempel *
|
|
||||||
* razzor@kopf-tisch.de *
|
|
||||||
* *
|
|
||||||
* 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; version 2 of the License *
|
|
||||||
* *
|
|
||||||
* 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, write to the *
|
|
||||||
* Free Software Foundation, Inc., *
|
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
||||||
***************************************************************************/
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "AT91SAM7S256.h"
|
|
||||||
#include "board.h"
|
|
||||||
#include "at91_pio.h"
|
|
||||||
|
|
||||||
/* extern symbols, defined in ldscript */
|
|
||||||
extern struct pio_pinchange_isr _pio_isr_table;
|
|
||||||
extern struct pio_pinchange_isr _pio_isr_table_end;
|
|
||||||
|
|
||||||
static void pio_isr(void)
|
|
||||||
{
|
|
||||||
uint32_t status = *AT91C_PIOA_ISR;
|
|
||||||
uint32_t input = *AT91C_PIOA_PDSR;
|
|
||||||
|
|
||||||
struct pio_pinchange_isr *isr;
|
|
||||||
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
|
|
||||||
if (isr->mask & status)
|
|
||||||
isr->func(status, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pio_trigger_isr(uint32_t mask)
|
|
||||||
{
|
|
||||||
uint32_t input = *AT91C_PIOA_PDSR;
|
|
||||||
|
|
||||||
struct pio_pinchange_isr *isr;
|
|
||||||
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
|
|
||||||
if (isr->mask & mask)
|
|
||||||
isr->func(mask, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
void at91_pio_init(void)
|
|
||||||
{
|
|
||||||
/* enable PIO clock */
|
|
||||||
*AT91C_PMC_PCER = (1 << AT91C_ID_PIOA);
|
|
||||||
|
|
||||||
/* enable pinchange interrupts */
|
|
||||||
struct pio_pinchange_isr *isr;
|
|
||||||
for (isr = &_pio_isr_table; isr < &_pio_isr_table_end; isr++)
|
|
||||||
*AT91C_PIOA_IER = isr->mask;
|
|
||||||
|
|
||||||
/* dummy read to clear interrupts */
|
|
||||||
uint32_t dummy = *AT91C_PIOA_ISR;
|
|
||||||
dummy = dummy;
|
|
||||||
|
|
||||||
/* low priority, level triggered, own vector */
|
|
||||||
AT91S_AIC *aic = AT91C_BASE_AIC;
|
|
||||||
aic->AIC_SMR[AT91C_ID_PIOA] = IRQPRIO_PIOA | AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL;
|
|
||||||
aic->AIC_SVR[AT91C_ID_PIOA] = (uint32_t)pio_isr;
|
|
||||||
aic->AIC_IECR = (1 << AT91C_ID_PIOA);
|
|
||||||
}
|
|
291
src/at91_udp.c
291
src/at91_udp.c
@ -18,14 +18,16 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "AT91SAM7S256.h"
|
#include "AT91SAM7S256.h"
|
||||||
#include "at91_pio.h"
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
#include "fifo.h"
|
#include "fifo.h"
|
||||||
|
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "usb_cdc.h"
|
|
||||||
#include "usb_dfu.h"
|
#include "usb_dfu.h"
|
||||||
|
|
||||||
|
/* from dfu.c */
|
||||||
|
extern void ep0_handle_dfu(struct usb_ctrlrequest *req);
|
||||||
|
|
||||||
|
|
||||||
#define csr_clear_flags(csr, flags) \
|
#define csr_clear_flags(csr, flags) \
|
||||||
while ((csr) & (flags)) \
|
while ((csr) & (flags)) \
|
||||||
(csr) &= ~(flags);
|
(csr) &= ~(flags);
|
||||||
@ -74,71 +76,9 @@ static const struct usb_device_descriptor dev_descriptor = {
|
|||||||
.idVendor = USB_VENDOR_ID,
|
.idVendor = USB_VENDOR_ID,
|
||||||
.idProduct = USB_PRODUCT_ID +1,
|
.idProduct = USB_PRODUCT_ID +1,
|
||||||
.bcdDevice = 0x0001,
|
.bcdDevice = 0x0001,
|
||||||
|
.iProduct = 0x01,
|
||||||
.bNumConfigurations = 1,
|
.bNumConfigurations = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string0 = {
|
|
||||||
/* String 0 - Language */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 1 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = { 0x0409 /* English */ },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string1 = {
|
|
||||||
/* String 1 "sam7fc-flash" */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 12 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = {
|
|
||||||
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063, 0x002d, 0x0066,
|
|
||||||
0x006c, 0x0061, 0x0073, 0x0068,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string2 = {
|
|
||||||
/* String 2 "blctrl1-flash" */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = {
|
|
||||||
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0031, 0x002d,
|
|
||||||
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string3 = {
|
|
||||||
/* String 3 "blctrl2-flash" */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = {
|
|
||||||
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0032, 0x002d,
|
|
||||||
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string4 = {
|
|
||||||
/* String 4 "blctrl3-flash" */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = {
|
|
||||||
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0033, 0x002d,
|
|
||||||
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor usb_string5 = {
|
|
||||||
/* String 5 "blctrl4-flash" */
|
|
||||||
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
|
||||||
.bDescriptorType = USB_DT_STRING,
|
|
||||||
.wData = {
|
|
||||||
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0034, 0x002d,
|
|
||||||
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor *usb_strings[] = {
|
|
||||||
&usb_string0, &usb_string1, &usb_string2, &usb_string3,
|
|
||||||
&usb_string4, &usb_string5,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct my_config {
|
struct my_config {
|
||||||
struct usb_config_descriptor cfg;
|
struct usb_config_descriptor cfg;
|
||||||
struct usb_interface_descriptor iface0;
|
struct usb_interface_descriptor iface0;
|
||||||
@ -146,6 +86,7 @@ struct my_config {
|
|||||||
struct usb_interface_descriptor iface2;
|
struct usb_interface_descriptor iface2;
|
||||||
struct usb_interface_descriptor iface3;
|
struct usb_interface_descriptor iface3;
|
||||||
struct usb_interface_descriptor iface4;
|
struct usb_interface_descriptor iface4;
|
||||||
|
struct usb_interface_descriptor iface5;
|
||||||
struct usb_dfu_descriptor dfu;
|
struct usb_dfu_descriptor dfu;
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
@ -154,8 +95,9 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bLength = sizeof(struct usb_config_descriptor),
|
.bLength = sizeof(struct usb_config_descriptor),
|
||||||
.bDescriptorType = USB_DT_CONFIG,
|
.bDescriptorType = USB_DT_CONFIG,
|
||||||
.wTotalLength = sizeof(struct my_config),
|
.wTotalLength = sizeof(struct my_config),
|
||||||
.bNumInterfaces = 1,
|
.bNumInterfaces = 6,
|
||||||
.bConfigurationValue = 1,
|
.bConfigurationValue = 1,
|
||||||
|
.iConfiguration = 0x02,
|
||||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
||||||
.bMaxPower = 50,
|
.bMaxPower = 50,
|
||||||
},
|
},
|
||||||
@ -166,69 +108,161 @@ static const struct my_config cfg_descriptor = {
|
|||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
.bInterfaceProtocol = 0x02,
|
.bInterfaceProtocol = 0x02,
|
||||||
.iInterface = 0x01,
|
.iInterface = 0x03,
|
||||||
},
|
},
|
||||||
.iface1 = {
|
.iface1 = {
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 0,
|
.bInterfaceNumber = 1,
|
||||||
.bAlternateSetting = 1,
|
|
||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
|
||||||
.bInterfaceProtocol = 0x02,
|
|
||||||
.iInterface = 0x02,
|
|
||||||
},
|
|
||||||
.iface2 = {
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
|
||||||
.bInterfaceNumber = 0,
|
|
||||||
.bAlternateSetting = 2,
|
|
||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
|
||||||
.bInterfaceProtocol = 0x02,
|
|
||||||
.iInterface = 0x03,
|
|
||||||
},
|
|
||||||
.iface3 = {
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
|
||||||
.bInterfaceNumber = 0,
|
|
||||||
.bAlternateSetting = 3,
|
|
||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
.bInterfaceProtocol = 0x02,
|
.bInterfaceProtocol = 0x02,
|
||||||
.iInterface = 0x04,
|
.iInterface = 0x04,
|
||||||
},
|
},
|
||||||
.iface4 = {
|
.iface2 = {
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
.bDescriptorType = USB_DT_INTERFACE,
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
.bInterfaceNumber = 0,
|
.bInterfaceNumber = 2,
|
||||||
.bAlternateSetting = 4,
|
|
||||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
.bInterfaceSubClass = 0x01, /* DFU */
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
.bInterfaceProtocol = 0x02,
|
.bInterfaceProtocol = 0x02,
|
||||||
.iInterface = 0x05,
|
.iInterface = 0x05,
|
||||||
},
|
},
|
||||||
|
.iface3 = {
|
||||||
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 3,
|
||||||
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
|
.bInterfaceProtocol = 0x02,
|
||||||
|
.iInterface = 0x06,
|
||||||
|
},
|
||||||
|
.iface4 = {
|
||||||
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 4,
|
||||||
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
|
.bInterfaceProtocol = 0x02,
|
||||||
|
.iInterface = 0x07,
|
||||||
|
},
|
||||||
|
.iface5 = {
|
||||||
|
.bLength = sizeof(struct usb_interface_descriptor),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 5,
|
||||||
|
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||||
|
.bInterfaceSubClass = 0x01, /* DFU */
|
||||||
|
.bInterfaceProtocol = 0x02,
|
||||||
|
.iInterface = 0x08,
|
||||||
|
},
|
||||||
.dfu = {
|
.dfu = {
|
||||||
.bLength = sizeof(struct usb_dfu_descriptor),
|
.bLength = sizeof(struct usb_dfu_descriptor),
|
||||||
.bDescriptorType = USB_TYPE_DFU,
|
.bDescriptorType = USB_TYPE_DFU,
|
||||||
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD,
|
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_CAN_UPLOAD | USB_DFU_MANIFEST_TOL | USB_DFU_WILL_DETACH,
|
||||||
.wDetachTimeOut = 0xff00,
|
.wDetachTimeOut = 0xff00,
|
||||||
.wTransferSize = AT91C_IFLASH_PAGE_SIZE,
|
.wTransferSize = AT91C_IFLASH_PAGE_SIZE,
|
||||||
.bcdDFUVersion = 0x0101,
|
.bcdDFUVersion = 0x0101,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct dfu_status dfu_status = {
|
static const struct usb_string_descriptor usb_string0 = {
|
||||||
.bStatus = DFU_STATUS_OK,
|
/* String 0 - Language */
|
||||||
.bwPollTimeout = {0x00, 0x04, 0x00},
|
.bLength = sizeof(struct usb_string_descriptor) + 1 * sizeof(uint16_t),
|
||||||
.bState = DFU_STATE_dfuIDLE,
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = { 0x0409 /* English */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
static const struct usb_string_descriptor usb_string1 = {
|
||||||
|
/* String 1 "sam7fc" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 6 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string2 = {
|
||||||
|
/* String 2 "device firmware upgrade" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 23 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0064, 0x0065, 0x0076, 0x0069, 0x0063, 0x0065, 0x0020, 0x0066,
|
||||||
|
0x0069, 0x0072, 0x006d, 0x0077, 0x0061, 0x0072, 0x0065, 0x0020,
|
||||||
|
0x0075, 0x0070, 0x0067, 0x0072, 0x0061, 0x0064, 0x0065,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string3 = {
|
||||||
|
/* String 3 "sam7fc-flash" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 12 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063, 0x002d, 0x0066,
|
||||||
|
0x006c, 0x0061, 0x0073, 0x0068,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string4 = {
|
||||||
|
/* String 4 "sam7fc-eeprom" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0073, 0x0061, 0x006d, 0x0037, 0x0066, 0x0063, 0x002d, 0x0065,
|
||||||
|
0x0065, 0x0070, 0x0072, 0x006f, 0x006d,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string5 = {
|
||||||
|
/* String 5 "blctrl1-flash" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0031, 0x002d,
|
||||||
|
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string6 = {
|
||||||
|
/* String 6 "blctrl2-flash" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0032, 0x002d,
|
||||||
|
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string7 = {
|
||||||
|
/* String 7 "blctrl3-flash" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0033, 0x002d,
|
||||||
|
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor usb_string8 = {
|
||||||
|
/* String 8 "blctrl4-flash" */
|
||||||
|
.bLength = sizeof(struct usb_string_descriptor) + 13 * sizeof(uint16_t),
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.wData = {
|
||||||
|
0x0062, 0x006c, 0x0063, 0x0074, 0x0072, 0x006c, 0x0034, 0x002d,
|
||||||
|
0x0066, 0x006c, 0x0061, 0x0073, 0x0068,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor *usb_strings[] = {
|
||||||
|
&usb_string0, &usb_string1, &usb_string2, &usb_string3,
|
||||||
|
&usb_string4, &usb_string5, &usb_string6, &usb_string7,
|
||||||
|
&usb_string8,
|
||||||
|
};
|
||||||
|
|
||||||
|
void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
||||||
void (*complete_cb)(void))
|
void (*complete_cb)(void))
|
||||||
{
|
{
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
// printf("ep_transfer_send(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
||||||
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -251,11 +285,11 @@ static void ep_transfer_send(uint32_t ep, char *data, uint32_t length,
|
|||||||
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
||||||
void (*complete_cb)(void))
|
void (*complete_cb)(void))
|
||||||
{
|
{
|
||||||
struct ep_ctx *ctx = &ep_ctx[ep];
|
struct ep_ctx *ctx = &ep_ctx[ep];
|
||||||
printf("ep_transfer_receive(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
// printf("ep_transfer_receive(%ld) size=%ld flags=0x%x\n\r", ep, length, ctx->flags);
|
||||||
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
if (!(ctx->flags & CTX_TRANSFER) || (ctx->flags & (CTX_IN | CTX_OUT)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -270,7 +304,7 @@ static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* stalls the endpoint */
|
/* stalls the endpoint */
|
||||||
static void ep_send_stall(uint32_t ep)
|
void ep_send_stall(uint32_t ep)
|
||||||
{
|
{
|
||||||
printf("stall\n\r");
|
printf("stall\n\r");
|
||||||
AT91C_UDP_CSR[ep] |= AT91C_UDP_FORCESTALL;
|
AT91C_UDP_CSR[ep] |= AT91C_UDP_FORCESTALL;
|
||||||
@ -324,8 +358,8 @@ static void udp_txcb_setinterface(void)
|
|||||||
|
|
||||||
static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
||||||
{
|
{
|
||||||
printf("typ:0x%02x req:0x%02x val:0x%04x idx:0x%04x len:0x%04x\n\r",
|
// printf("typ:0x%02x req:0x%02x val:0x%04x idx:0x%04x len:0x%04x\n\r",
|
||||||
req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength);
|
// req->bRequestType, req->bRequest, req->wValue, req->wIndex, req->wLength);
|
||||||
|
|
||||||
switch (req->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) {
|
switch (req->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) {
|
||||||
case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): /* 0x00/0x80 */
|
case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): /* 0x00/0x80 */
|
||||||
@ -353,7 +387,6 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
;
|
;
|
||||||
uint8_t index = req->wValue & 0xFF;
|
uint8_t index = req->wValue & 0xFF;
|
||||||
if (index < ARRAY_SIZE(usb_strings)) {
|
if (index < ARRAY_SIZE(usb_strings)) {
|
||||||
printf("get string %d: %p\n\r", index, usb_strings[index]);
|
|
||||||
ep_transfer_send(0, (char *)usb_strings[index],
|
ep_transfer_send(0, (char *)usb_strings[index],
|
||||||
MIN(usb_strings[index]->bLength, req->wLength),
|
MIN(usb_strings[index]->bLength, req->wLength),
|
||||||
NULL);
|
NULL);
|
||||||
@ -362,6 +395,12 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case USB_DT_CS_DEVICE: /* 0x21 */
|
||||||
|
ep_transfer_send(0, (char *)&cfg_descriptor.dfu,
|
||||||
|
MIN(sizeof(cfg_descriptor.dfu), req->wLength),
|
||||||
|
NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ep_send_stall(0);
|
ep_send_stall(0);
|
||||||
break;
|
break;
|
||||||
@ -380,7 +419,6 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */
|
case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */
|
||||||
// TODO: follow current_interface
|
|
||||||
switch (req->bRequest) {
|
switch (req->bRequest) {
|
||||||
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
||||||
current_interface = req->wValue;
|
current_interface = req->wValue;
|
||||||
@ -394,22 +432,7 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
||||||
// TODO: follow current_interface
|
ep0_handle_dfu(req);
|
||||||
switch (req->bRequest) {
|
|
||||||
case USB_REQ_DFU_DETACH: /* 0x00 */
|
|
||||||
ep_transfer_send(0, NULL, 0, NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case USB_REQ_DFU_GETSTATUS: /* 0x03 */
|
|
||||||
ep_transfer_send(0, (char *)&dfu_status,
|
|
||||||
MIN(sizeof(struct dfu_status), req->wLength),
|
|
||||||
NULL);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ep_send_stall(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -468,8 +491,6 @@ static void udp_handle_ep(uint32_t ep)
|
|||||||
} else {
|
} else {
|
||||||
ctx->flags &= ~CTX_IN;
|
ctx->flags &= ~CTX_IN;
|
||||||
|
|
||||||
printf("txcomp\n\r");
|
|
||||||
|
|
||||||
if (transfer->complete_cb)
|
if (transfer->complete_cb)
|
||||||
transfer->complete_cb();
|
transfer->complete_cb();
|
||||||
}
|
}
|
||||||
@ -539,6 +560,8 @@ static void udp_isr(void)
|
|||||||
{
|
{
|
||||||
uint32_t isr = *AT91C_UDP_ISR;
|
uint32_t isr = *AT91C_UDP_ISR;
|
||||||
if (isr & AT91C_UDP_ENDBUSRES) {
|
if (isr & AT91C_UDP_ENDBUSRES) {
|
||||||
|
printf("USB reset\n\r");
|
||||||
|
|
||||||
AT91S_UDP *udp = AT91C_BASE_UDP;
|
AT91S_UDP *udp = AT91C_BASE_UDP;
|
||||||
|
|
||||||
/* reset all endpoints */
|
/* reset all endpoints */
|
||||||
@ -565,11 +588,8 @@ static void udp_isr(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Handle Endpoint Interrupts */
|
/* Handle Endpoint Interrupts */
|
||||||
uint32_t i;
|
if (isr & AT91C_UDP_EPINT0)
|
||||||
for (i = 0; i < 4; i++) {
|
udp_handle_ep(0);
|
||||||
if (isr & *AT91C_UDP_IMR & (1<<i))
|
|
||||||
udp_handle_ep(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clear all unhandled interrupts */
|
/* clear all unhandled interrupts */
|
||||||
*AT91C_UDP_ICR = isr & (AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM |
|
*AT91C_UDP_ICR = isr & (AT91C_UDP_RXSUSP | AT91C_UDP_RXRSM |
|
||||||
@ -583,8 +603,6 @@ void at91_udp_init(void)
|
|||||||
pio->PIO_CODR = UDP_PULLUP;
|
pio->PIO_CODR = UDP_PULLUP;
|
||||||
pio->PIO_PER = UDP_PULLUP;
|
pio->PIO_PER = UDP_PULLUP;
|
||||||
pio->PIO_OER = UDP_PULLUP;
|
pio->PIO_OER = UDP_PULLUP;
|
||||||
// TODO: needed?
|
|
||||||
pio->PIO_PPUDR = UDP_VBUS_MON;
|
|
||||||
|
|
||||||
/* UDPCK (48MHz) = PLLCK / 2 */
|
/* UDPCK (48MHz) = PLLCK / 2 */
|
||||||
*AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
|
*AT91C_CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
|
||||||
@ -610,17 +628,6 @@ void at91_udp_init(void)
|
|||||||
aic->AIC_SVR[AT91C_ID_UDP] = (uint32_t)udp_isr;
|
aic->AIC_SVR[AT91C_ID_UDP] = (uint32_t)udp_isr;
|
||||||
aic->AIC_IECR = (1 << AT91C_ID_UDP);
|
aic->AIC_IECR = (1 << AT91C_ID_UDP);
|
||||||
|
|
||||||
pio_trigger_isr(UDP_VBUS_MON);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void udp_vbus_monitor(uint32_t status, uint32_t input)
|
|
||||||
{
|
|
||||||
if (input & UDP_VBUS_MON)
|
|
||||||
/* usb connected -> enable pullup */
|
/* usb connected -> enable pullup */
|
||||||
*AT91C_PIOA_CODR = UDP_PULLUP;
|
*AT91C_PIOA_CODR = UDP_PULLUP;
|
||||||
else
|
|
||||||
/* usb got diconnected -> disable pullup */
|
|
||||||
*AT91C_PIOA_SODR = UDP_PULLUP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PIO_PINCHANGE_ISR(UDP_VBUS_MON, udp_vbus_monitor);
|
|
||||||
|
338
src/dfu.c
Normal file
338
src/dfu.c
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 01/2008 by Olaf Rempel *
|
||||||
|
* razzor@kopf-tisch.de *
|
||||||
|
* *
|
||||||
|
* 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; version 2 of the License *
|
||||||
|
* *
|
||||||
|
* 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, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "AT91SAM7S256.h"
|
||||||
|
#include "board.h"
|
||||||
|
|
||||||
|
#include "at91_udp.h"
|
||||||
|
|
||||||
|
#include "usb_ch9.h"
|
||||||
|
#include "usb_dfu.h"
|
||||||
|
|
||||||
|
static uint8_t dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
static uint8_t dfu_status = DFU_STATUS_OK;
|
||||||
|
|
||||||
|
#define RET_NOTHING 0
|
||||||
|
#define RET_STALL 1
|
||||||
|
#define RET_ZLP 2
|
||||||
|
|
||||||
|
static void handle_getstatus(void)
|
||||||
|
{
|
||||||
|
struct dfu_status dstat;
|
||||||
|
|
||||||
|
uint32_t fmr = *AT91C_MC_FMR;
|
||||||
|
|
||||||
|
switch (dfu_state) {
|
||||||
|
case DFU_STATE_dfuDNLOAD_SYNC:
|
||||||
|
case DFU_STATE_dfuDNBUSY:
|
||||||
|
if (fmr & AT91C_MC_PROGE) {
|
||||||
|
dfu_status = DFU_STATUS_errPROG;
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
|
||||||
|
} else if (fmr & AT91C_MC_LOCKE) {
|
||||||
|
dfu_status = DFU_STATUS_errWRITE;
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
|
||||||
|
} else if (fmr & AT91C_MC_FRDY) {
|
||||||
|
dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// dfu_state = DFU_STATE_dfuDNBUSY;
|
||||||
|
dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send status response */
|
||||||
|
dstat.bStatus = dfu_status;
|
||||||
|
dstat.bState = dfu_state;
|
||||||
|
dstat.iString = 0;
|
||||||
|
/* FIXME: set dstat.bwPollTimeout */
|
||||||
|
|
||||||
|
ep_transfer_send(0, (char *)&dstat, sizeof(dstat), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_getstate(void)
|
||||||
|
{
|
||||||
|
ep_transfer_send(0, (char *)&dfu_state, sizeof(dfu_state), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t buf[256];
|
||||||
|
|
||||||
|
static void handle_dnload_cb(void)
|
||||||
|
{
|
||||||
|
ep_transfer_send(0, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t handle_dnload(uint16_t index, uint16_t value, uint16_t length)
|
||||||
|
{
|
||||||
|
printf("down:%x-%x-%x\n\r", index, value, length);
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
|
||||||
|
return RET_ZLP;
|
||||||
|
}
|
||||||
|
|
||||||
|
ep_transfer_receive(0, (char *)&buf, length, handle_dnload_cb);
|
||||||
|
return RET_NOTHING;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t handle_upload(uint16_t index, uint16_t value, uint16_t length)
|
||||||
|
{
|
||||||
|
printf("up:%x-%x-%x\n\r", index, value, length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ep0_handle_dfu(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
uint32_t rc, ret = RET_NOTHING;
|
||||||
|
// printf("state:%x\n\r", dfu_state);
|
||||||
|
|
||||||
|
switch (dfu_state) {
|
||||||
|
case DFU_STATE_appIDLE:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_DETACH:
|
||||||
|
dfu_state = DFU_STATE_appDETACH;
|
||||||
|
ret = RET_ZLP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_appDETACH:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_appIDLE;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* FIXME: implement timer to return to appIDLE */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuIDLE:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_DNLOAD:
|
||||||
|
if (req->wLength == 0) {
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
|
||||||
|
ret = handle_dnload(req->wIndex, req->wValue, req->wLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_UPLOAD:
|
||||||
|
dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
|
||||||
|
handle_upload(req->wIndex, req->wValue, req->wLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_ABORT:
|
||||||
|
/* no zlp? */
|
||||||
|
ret = RET_ZLP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuDNLOAD_SYNC:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
/* FIXME: state transition depending on block completeness */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuDNBUSY:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
/* FIXME: only accept getstatus if bwPollTimeout
|
||||||
|
* has elapsed */
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuDNLOAD_IDLE:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_DNLOAD:
|
||||||
|
dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
|
||||||
|
ret = handle_dnload(req->wIndex, req->wValue, req->wLength);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_ABORT:
|
||||||
|
dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
ret = RET_ZLP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuMANIFEST_SYNC:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuMANIFEST:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuMANIFEST_WAIT_RST:
|
||||||
|
/* we should never go here */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuUPLOAD_IDLE:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_UPLOAD:
|
||||||
|
/* state transition if less data then requested */
|
||||||
|
rc = handle_upload(req->wIndex, req->wValue, req->wLength);
|
||||||
|
if (rc >= 0 && rc < req->wLength)
|
||||||
|
dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_ABORT:
|
||||||
|
dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
/* no zlp? */
|
||||||
|
ret = RET_ZLP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DFU_STATE_dfuERROR:
|
||||||
|
switch (req->bRequest) {
|
||||||
|
case USB_REQ_DFU_GETSTATUS:
|
||||||
|
handle_getstatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_CLRSTATUS:
|
||||||
|
dfu_state = DFU_STATE_dfuIDLE;
|
||||||
|
dfu_status = DFU_STATUS_OK;
|
||||||
|
/* no zlp? */
|
||||||
|
ret = RET_ZLP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USB_REQ_DFU_GETSTATE:
|
||||||
|
handle_getstate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
dfu_state = DFU_STATE_dfuERROR;
|
||||||
|
ret = RET_STALL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case RET_NOTHING:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RET_ZLP:
|
||||||
|
ep_transfer_send(0, NULL, 0, NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RET_STALL:
|
||||||
|
ep_send_stall(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user