working dfu framework
This commit is contained in:
parent
588cfbc2c2
commit
fded24a803
@ -1,6 +1,20 @@
|
||||
#ifndef 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);
|
||||
|
||||
#endif /*AT91_UDP_H_*/
|
||||
|
4
main.c
4
main.c
@ -21,7 +21,6 @@
|
||||
#include "at91_dbgu.h"
|
||||
#include "at91_pitc.h"
|
||||
#include "at91_udp.h"
|
||||
#include "at91_pio.h"
|
||||
#include "at91_twi.h"
|
||||
|
||||
#include "memalloc.h"
|
||||
@ -57,9 +56,6 @@ int main(void)
|
||||
at91_dbgu_init();
|
||||
at91_dbgu_puts("==========================================================\n\rGood morning Dave\n\r");
|
||||
|
||||
/* triggers pinchange-isrs */
|
||||
at91_pio_init();
|
||||
|
||||
/* timer */
|
||||
at91_pitc_init();
|
||||
|
||||
|
@ -44,7 +44,7 @@ static void dbgu_isr(uint32_t status)
|
||||
}
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ void at91_dbgu_init(void)
|
||||
dbgu->DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
|
||||
dbgu->DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN | AT91C_US_RSTSTA;
|
||||
|
||||
txfifo = fifo_alloc(1024);
|
||||
txfifo = fifo_alloc(16384);
|
||||
|
||||
/* enable TX PDC */
|
||||
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);
|
||||
}
|
295
src/at91_udp.c
295
src/at91_udp.c
@ -18,14 +18,16 @@
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include "AT91SAM7S256.h"
|
||||
#include "at91_pio.h"
|
||||
#include "board.h"
|
||||
#include "fifo.h"
|
||||
|
||||
#include "usb_ch9.h"
|
||||
#include "usb_cdc.h"
|
||||
#include "usb_dfu.h"
|
||||
|
||||
/* from dfu.c */
|
||||
extern void ep0_handle_dfu(struct usb_ctrlrequest *req);
|
||||
|
||||
|
||||
#define csr_clear_flags(csr, flags) \
|
||||
while ((csr) & (flags)) \
|
||||
(csr) &= ~(flags);
|
||||
@ -74,71 +76,9 @@ static const struct usb_device_descriptor dev_descriptor = {
|
||||
.idVendor = USB_VENDOR_ID,
|
||||
.idProduct = USB_PRODUCT_ID +1,
|
||||
.bcdDevice = 0x0001,
|
||||
.iProduct = 0x01,
|
||||
.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 usb_config_descriptor cfg;
|
||||
struct usb_interface_descriptor iface0;
|
||||
@ -146,6 +86,7 @@ struct my_config {
|
||||
struct usb_interface_descriptor iface2;
|
||||
struct usb_interface_descriptor iface3;
|
||||
struct usb_interface_descriptor iface4;
|
||||
struct usb_interface_descriptor iface5;
|
||||
struct usb_dfu_descriptor dfu;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
@ -154,8 +95,9 @@ static const struct my_config cfg_descriptor = {
|
||||
.bLength = sizeof(struct usb_config_descriptor),
|
||||
.bDescriptorType = USB_DT_CONFIG,
|
||||
.wTotalLength = sizeof(struct my_config),
|
||||
.bNumInterfaces = 1,
|
||||
.bNumInterfaces = 6,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0x02,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER | USB_CONFIG_ATT_WAKEUP,
|
||||
.bMaxPower = 50,
|
||||
},
|
||||
@ -166,69 +108,161 @@ static const struct my_config cfg_descriptor = {
|
||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||
.bInterfaceSubClass = 0x01, /* DFU */
|
||||
.bInterfaceProtocol = 0x02,
|
||||
.iInterface = 0x01,
|
||||
.iInterface = 0x03,
|
||||
},
|
||||
.iface1 = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.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,
|
||||
.bInterfaceNumber = 1,
|
||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||
.bInterfaceSubClass = 0x01, /* DFU */
|
||||
.bInterfaceProtocol = 0x02,
|
||||
.iInterface = 0x04,
|
||||
},
|
||||
.iface4 = {
|
||||
.iface2 = {
|
||||
.bLength = sizeof(struct usb_interface_descriptor),
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 4,
|
||||
.bInterfaceNumber = 2,
|
||||
.bInterfaceClass = USB_CLASS_APP_SPEC,
|
||||
.bInterfaceSubClass = 0x01, /* DFU */
|
||||
.bInterfaceProtocol = 0x02,
|
||||
.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 = {
|
||||
.bLength = sizeof(struct usb_dfu_descriptor),
|
||||
.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,
|
||||
.wTransferSize = AT91C_IFLASH_PAGE_SIZE,
|
||||
.bcdDFUVersion = 0x0101,
|
||||
},
|
||||
};
|
||||
|
||||
static struct dfu_status dfu_status = {
|
||||
.bStatus = DFU_STATUS_OK,
|
||||
.bwPollTimeout = {0x00, 0x04, 0x00},
|
||||
.bState = DFU_STATE_dfuIDLE,
|
||||
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 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))
|
||||
{
|
||||
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)))
|
||||
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;
|
||||
}
|
||||
|
||||
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))
|
||||
{
|
||||
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)))
|
||||
return;
|
||||
|
||||
@ -270,7 +304,7 @@ static void ep_transfer_receive(uint32_t ep, char *data, uint32_t length,
|
||||
}
|
||||
|
||||
/* stalls the endpoint */
|
||||
static void ep_send_stall(uint32_t ep)
|
||||
void ep_send_stall(uint32_t ep)
|
||||
{
|
||||
printf("stall\n\r");
|
||||
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)
|
||||
{
|
||||
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);
|
||||
// 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);
|
||||
|
||||
switch (req->bRequestType & (USB_TYPE_MASK | USB_RECIP_MASK)) {
|
||||
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;
|
||||
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],
|
||||
MIN(usb_strings[index]->bLength, req->wLength),
|
||||
NULL);
|
||||
@ -362,6 +395,12 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
||||
}
|
||||
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:
|
||||
ep_send_stall(0);
|
||||
break;
|
||||
@ -380,7 +419,6 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
||||
break;
|
||||
|
||||
case (USB_TYPE_STANDARD | USB_RECIP_INTERFACE): /* 0x01/0x81 */
|
||||
// TODO: follow current_interface
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_INTERFACE: /* 0x0b */
|
||||
current_interface = req->wValue;
|
||||
@ -394,22 +432,7 @@ static void ep_handle_ctrlrequest(struct usb_ctrlrequest *req)
|
||||
break;
|
||||
|
||||
case (USB_TYPE_CLASS | USB_RECIP_INTERFACE): /* 0x21/0xA1 */
|
||||
// TODO: follow current_interface
|
||||
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;
|
||||
}
|
||||
ep0_handle_dfu(req);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -468,8 +491,6 @@ static void udp_handle_ep(uint32_t ep)
|
||||
} else {
|
||||
ctx->flags &= ~CTX_IN;
|
||||
|
||||
printf("txcomp\n\r");
|
||||
|
||||
if (transfer->complete_cb)
|
||||
transfer->complete_cb();
|
||||
}
|
||||
@ -539,6 +560,8 @@ static void udp_isr(void)
|
||||
{
|
||||
uint32_t isr = *AT91C_UDP_ISR;
|
||||
if (isr & AT91C_UDP_ENDBUSRES) {
|
||||
printf("USB reset\n\r");
|
||||
|
||||
AT91S_UDP *udp = AT91C_BASE_UDP;
|
||||
|
||||
/* reset all endpoints */
|
||||
@ -565,11 +588,8 @@ static void udp_isr(void)
|
||||
}
|
||||
|
||||
/* Handle Endpoint Interrupts */
|
||||
uint32_t i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (isr & *AT91C_UDP_IMR & (1<<i))
|
||||
udp_handle_ep(i);
|
||||
}
|
||||
if (isr & AT91C_UDP_EPINT0)
|
||||
udp_handle_ep(0);
|
||||
|
||||
/* clear all unhandled interrupts */
|
||||
*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_PER = UDP_PULLUP;
|
||||
pio->PIO_OER = UDP_PULLUP;
|
||||
// TODO: needed?
|
||||
pio->PIO_PPUDR = UDP_VBUS_MON;
|
||||
|
||||
/* UDPCK (48MHz) = PLLCK / 2 */
|
||||
*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_IECR = (1 << AT91C_ID_UDP);
|
||||
|
||||
pio_trigger_isr(UDP_VBUS_MON);
|
||||
/* usb connected -> enable pullup */
|
||||
*AT91C_PIOA_CODR = UDP_PULLUP;
|
||||
}
|
||||
|
||||
static void udp_vbus_monitor(uint32_t status, uint32_t input)
|
||||
{
|
||||
if (input & UDP_VBUS_MON)
|
||||
/* usb connected -> enable 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