summaryrefslogtreecommitdiff
path: root/openpicc/dfu
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc/dfu')
-rw-r--r--openpicc/dfu/dbgu.c140
-rw-r--r--openpicc/dfu/dbgu.h25
-rw-r--r--openpicc/dfu/dfu.c938
-rw-r--r--openpicc/dfu/dfu.h143
-rw-r--r--openpicc/dfu/usb_strings_dfu.h120
-rw-r--r--openpicc/dfu/usb_strings_dfu.txt5
6 files changed, 1371 insertions, 0 deletions
diff --git a/openpicc/dfu/dbgu.c b/openpicc/dfu/dbgu.c
new file mode 100644
index 0000000..ded704b
--- /dev/null
+++ b/openpicc/dfu/dbgu.c
@@ -0,0 +1,140 @@
+/* AT91SAM7 debug function implementation for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.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; either version 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <lib_AT91SAM7.h>
+#include <board.h>
+#include <dfu/dbgu.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#define USART_SYS_LEVEL 4
+void AT91F_DBGU_Ready(void)
+{
+ while (!(AT91C_BASE_DBGU->DBGU_CSR & AT91C_US_TXEMPTY)) ;
+}
+
+static void DBGU_irq_handler(void)
+{
+ static char value;
+
+ AT91F_DBGU_Get(&value);
+ switch (value) {
+ case '9':
+ AT91F_DBGU_Printk("Resetting SAM7\n\r");
+ AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
+ AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST);
+ break;
+ default:
+ AT91F_DBGU_Printk("\n\r");
+ }
+}
+
+void AT91F_DBGU_Init(void)
+{
+ /* Open PIO for DBGU */
+ AT91F_DBGU_CfgPIO();
+ /* Enable Transmitter & receivier */
+ ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR =
+ AT91C_US_RSTTX | AT91C_US_RSTRX;
+
+ /* Configure DBGU */
+ AT91F_US_Configure(AT91C_BASE_DBGU,
+ MCK, AT91C_US_ASYNC_MODE,
+ AT91C_DBGU_BAUD, 0);
+
+ /* Enable Transmitter & receivier */
+ ((AT91PS_USART) AT91C_BASE_DBGU)->US_CR =
+ AT91C_US_RXEN | AT91C_US_TXEN;
+
+ /* Enable USART IT error and AT91C_US_ENDRX */
+ AT91F_US_EnableIt((AT91PS_USART) AT91C_BASE_DBGU, AT91C_US_RXRDY);
+
+ /* open interrupt */
+
+ AT91F_AIC_ConfigureIt(AT91C_ID_SYS, USART_SYS_LEVEL,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL,
+ DBGU_irq_handler);
+ AT91F_AIC_EnableIt(AT91C_ID_SYS);
+
+}
+
+void AT91F_DBGU_Printk(char *buffer)
+{
+ while (*buffer != '\0') {
+ while (!AT91F_US_TxReady((AT91PS_USART) AT91C_BASE_DBGU)) ;
+ AT91F_US_PutChar((AT91PS_USART) AT91C_BASE_DBGU, *buffer++);
+ }
+}
+
+int AT91F_DBGU_Get(char *val)
+{
+ if ((AT91F_US_RxReady((AT91PS_USART) AT91C_BASE_DBGU)) == 0)
+ return (0);
+ else {
+ *val = AT91F_US_GetChar((AT91PS_USART) AT91C_BASE_DBGU);
+ return (-1);
+ }
+}
+
+#ifdef DEBUG
+
+void AT91F_DBGU_Frame(char *buffer)
+{
+ unsigned char len;
+
+ for (len = 0; buffer[len] != '\0'; len++) { }
+
+ AT91F_US_SendFrame((AT91PS_USART) AT91C_BASE_DBGU,
+ (unsigned char *)buffer, len, 0, 0);
+}
+
+
+const char *
+hexdump(const void *data, unsigned int len)
+{
+ static char string[256];
+ unsigned char *d = (unsigned char *) data;
+ unsigned int i, left;
+
+ string[0] = '\0';
+ left = sizeof(string);
+ for (i = 0; len--; i += 3) {
+ if (i >= sizeof(string) -4)
+ break;
+ snprintf(string+i, 4, " %02x", *d++);
+ }
+ return string;
+}
+
+static char dbg_buf[2048];
+void debugp(const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ vsnprintf(dbg_buf, sizeof(dbg_buf)-1, format, ap);
+ va_end(ap);
+
+ dbg_buf[sizeof(dbg_buf)-1] = '\0';
+ //AT91F_DBGU_Frame(dbg_buf);
+ AT91F_DBGU_Printk(dbg_buf);
+}
+
+#endif
diff --git a/openpicc/dfu/dbgu.h b/openpicc/dfu/dbgu.h
new file mode 100644
index 0000000..5ec8a49
--- /dev/null
+++ b/openpicc/dfu/dbgu.h
@@ -0,0 +1,25 @@
+#ifndef dbgu_h
+#define dbgu_h
+
+#define AT91C_DBGU_BAUD 115200
+
+#define DEBUGP(x, args ...) debugp(x, ## args)
+#define DEBUGPCR(x, args ...) DEBUGP(x "\r\n", ## args)
+#define DEBUGPCRF(x, args ...) DEBUGPCR("%s(%d): " x, __FUNCTION__, __LINE__, ## args)
+
+extern void AT91F_DBGU_Init(void);
+extern void AT91F_DBGU_Printk(char *buffer);
+extern int AT91F_DBGU_Get(char *val);
+extern void AT91F_DBGU_Ready(void);
+
+#ifdef DEBUG
+extern void debugp(const char *format, ...);
+extern const char *hexdump(const void *data, unsigned int len);
+extern void AT91F_DBGU_Frame(char *buffer);
+#else
+#define debugp(x, args ...)
+#define hexdump(x, args ...)
+#define AT91F_DBGU_Frame(x)
+#endif
+
+#endif /* dbgu_h */
diff --git a/openpicc/dfu/dfu.c b/openpicc/dfu/dfu.c
new file mode 100644
index 0000000..af09a62
--- /dev/null
+++ b/openpicc/dfu/dfu.c
@@ -0,0 +1,938 @@
+/* USB Device Firmware Update Implementation for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <errno.h>
+#include <usb_ch9.h>
+#include <usb_dfu.h>
+#include <board.h>
+#include <lib_AT91SAM7.h>
+
+#include "usb_strings_dfu.h"
+
+#include <dfu/dfu.h>
+#include <dfu/dbgu.h>
+#include <application/flash.h>
+//#include <os/pcd_enumerate.h>
+//#include "../openpcd.h"
+
+#include <compile.h>
+
+#define SAM7DFU_SIZE 0x4000
+
+/* If debug is enabled, we need to access debug functions from flash
+ * and therefore have to omit flashing */
+#define DEBUG_DFU_NOFLASH
+
+#ifdef DEBUG
+#define DEBUG_DFU_EP0
+//#define DEBUG_DFU_RECV
+#endif
+
+#ifdef DEBUG_DFU_EP0
+#define DEBUGE DEBUGP
+#else
+#define DEBUGE(x, args ...)
+#endif
+
+#ifdef DEBUG_DFU_RECV
+#define DEBUGR DEBUGP
+#else
+#define DEBUGR(x, args ...)
+#endif
+
+#define RET_NOTHING 0
+#define RET_ZLP 1
+#define RET_STALL 2
+
+#define led1on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1)
+#define led1off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1)
+
+#define led2on() AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
+#define led2off() AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2)
+
+static void __dfufunc udp_init(void)
+{
+ /* Set the PLL USB Divider */
+ AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1;
+
+ /* Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock */
+ AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
+
+ /* Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the
+ * corresponding PIO Set in PIO mode and Configure in Output */
+#if defined(PCD)
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
+#endif
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4);
+}
+
+/* Send Data through the control endpoint */
+static void __dfufunc udp_ep0_send_data(const char *pData, u_int32_t length)
+{
+ AT91PS_UDP pUdp = AT91C_BASE_UDP;
+ u_int32_t cpt = 0;
+ AT91_REG csr;
+
+ DEBUGE("send_data: %u bytes ", length);
+
+ do {
+ cpt = MIN(length, 8);
+ length -= cpt;
+
+ while (cpt--)
+ pUdp->UDP_FDR[0] = *pData++;
+
+ if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) {
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
+ while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
+ }
+
+ pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
+ do {
+ csr = pUdp->UDP_CSR[0];
+
+ /* Data IN stage has been stopped by a status OUT */
+ if (csr & AT91C_UDP_RX_DATA_BK0) {
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
+ DEBUGE("stopped by status out ");
+ return;
+ }
+ } while (!(csr & AT91C_UDP_TXCOMP));
+
+ } while (length);
+
+ if (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) {
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
+ while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
+ }
+}
+
+static void udp_ep0_recv_clean(void)
+{
+ unsigned int i;
+ u_int8_t dummy;
+ const AT91PS_UDP pUdp = AT91C_BASE_UDP;
+
+ while (!(pUdp->UDP_CSR[0] & AT91C_UDP_RX_DATA_BK0)) ;
+
+ for (i = 0; i < (pUdp->UDP_CSR[0] >> 16); i++)
+ dummy = pUdp->UDP_FDR[0];
+
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
+}
+
+/* receive data from EP0 */
+static int __dfufunc udp_ep0_recv_data(u_int8_t *data, u_int16_t len)
+{
+ AT91PS_UDP pUdp = AT91C_BASE_UDP;
+ AT91_REG csr;
+ u_int16_t i, num_rcv;
+ u_int32_t num_rcv_total = 0;
+
+ do {
+ /* FIXME: do we need to check whether we've been interrupted
+ * by a RX SETUP stage? */
+ do {
+ csr = pUdp->UDP_CSR[0];
+ DEBUGR("CSR=%08x ", csr);
+ } while (!(csr & AT91C_UDP_RX_DATA_BK0)) ;
+
+ num_rcv = pUdp->UDP_CSR[0] >> 16;
+
+ /* make sure we don't read more than requested */
+ if (num_rcv_total + num_rcv > len)
+ num_rcv = num_rcv_total - len;
+
+ DEBUGR("num_rcv = %u ", num_rcv);
+ for (i = 0; i < num_rcv; i++)
+ *data++ = pUdp->UDP_FDR[0];
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
+
+ num_rcv_total += num_rcv;
+
+ /* we need to continue to pull data until we either receive
+ * a packet < endpoint size or == 0 */
+ } while (num_rcv == 8 && num_rcv_total < len);
+
+ DEBUGE("ep0_rcv_returning(%u total) ", num_rcv_total);
+
+ return num_rcv_total;
+}
+
+/* Send zero length packet through the control endpoint */
+static void __dfufunc udp_ep0_send_zlp(void)
+{
+ AT91PS_UDP pUdp = AT91C_BASE_UDP;
+ pUdp->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
+ while (!(pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP)) ;
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_TXCOMP);
+ while (pUdp->UDP_CSR[0] & AT91C_UDP_TXCOMP) ;
+}
+
+/* Stall the control endpoint */
+static void __dfufunc udp_ep0_send_stall(void)
+{
+ AT91PS_UDP pUdp = AT91C_BASE_UDP;
+ pUdp->UDP_CSR[0] |= AT91C_UDP_FORCESTALL;
+ while (!(pUdp->UDP_CSR[0] & AT91C_UDP_ISOERROR)) ;
+ pUdp->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);
+ while (pUdp->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR)) ;
+}
+
+
+static u_int8_t *ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
+static __dfudata u_int8_t dfu_status;
+__dfudata u_int32_t dfu_state = DFU_STATE_appIDLE;
+static u_int32_t pagebuf32[AT91C_IFLASH_PAGE_SIZE/4];
+
+static int __dfufunc handle_dnload(u_int16_t val, u_int16_t len)
+{
+ volatile u_int32_t *p = (volatile u_int32_t *)ptr;
+ u_int8_t *pagebuf = (u_int8_t *) pagebuf32;
+ int i;
+
+ DEBUGE("download ");
+
+ if (len > AT91C_IFLASH_PAGE_SIZE) {
+ /* Too big. Not that we'd really care, but it's a
+ * DFU protocol violation */
+ DEBUGP("length exceeds flash page size ");
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+ if (len & 0x3) {
+ /* reject non-four-byte-aligned writes */
+ DEBUGP("not four-byte-aligned length ");
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+ if (len == 0) {
+ DEBUGP("zero-size write -> MANIFEST_SYNC ");
+ flash_page(p);
+ dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+ return RET_ZLP;
+ }
+ if (ptr + len >= (u_int8_t *) AT91C_IFLASH + AT91C_IFLASH_SIZE - ENVIRONMENT_SIZE ) {
+ DEBUGP("end of write exceeds flash end ");
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ return RET_STALL;
+ }
+
+ DEBUGP("try_to_recv=%u ", len);
+ udp_ep0_recv_data(pagebuf, len);
+
+ DEBUGR(hexdump(pagebuf, len));
+
+ /* we can only access the write buffer with correctly aligned
+ * 32bit writes ! */
+#ifndef DEBUG_DFU_NOFLASH
+ DEBUGP("copying ");
+ for (i = 0; i < len/4; i++) {
+ *p++ = pagebuf32[i];
+ /* If we have filled a page buffer, flash it */
+ if (((unsigned long)p % AT91C_IFLASH_PAGE_SIZE) == 0) {
+ DEBUGP("page_full ");
+ flash_page(p-1);
+ }
+ }
+ ptr = (u_int8_t *) p;
+#endif
+
+ return RET_ZLP;
+}
+
+#define AT91C_IFLASH_END ((u_int8_t *)AT91C_IFLASH + AT91C_IFLASH_SIZE)
+static __dfufunc int handle_upload(u_int16_t val, u_int16_t len)
+{
+ DEBUGE("upload ");
+ if (len > AT91C_IFLASH_PAGE_SIZE) {
+ /* Too big */
+ dfu_state = DFU_STATE_dfuERROR;
+ dfu_status = DFU_STATUS_errADDRESS;
+ udp_ep0_send_stall();
+ return -EINVAL;
+ }
+
+ if (ptr + len > AT91C_IFLASH_END)
+ len = AT91C_IFLASH_END - (u_int8_t *)ptr;
+
+ udp_ep0_send_data((char *)ptr, len);
+ ptr+= len;
+
+ return len;
+}
+
+static __dfufunc void handle_getstatus(void)
+{
+ struct dfu_status dstat;
+ u_int32_t fsr = AT91F_MC_EFC_GetStatus(AT91C_BASE_MC);
+
+ DEBUGE("getstatus(fsr=0x%08x) ", fsr);
+
+ switch (dfu_state) {
+ case DFU_STATE_dfuDNLOAD_SYNC:
+ case DFU_STATE_dfuDNBUSY:
+ if (fsr & AT91C_MC_PROGE) {
+ DEBUGE("errPROG ");
+ dfu_status = DFU_STATUS_errPROG;
+ dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_LOCKE) {
+ DEBUGE("errWRITE ");
+ dfu_status = DFU_STATUS_errWRITE;
+ dfu_state = DFU_STATE_dfuERROR;
+ } else if (fsr & AT91C_MC_FRDY) {
+ DEBUGE("DNLOAD_IDLE ");
+ dfu_state = DFU_STATE_dfuDNLOAD_IDLE;
+ } else {
+ DEBUGE("DNBUSY ");
+ dfu_state = DFU_STATE_dfuDNBUSY;
+ }
+ break;
+ case DFU_STATE_dfuMANIFEST_SYNC:
+ dfu_state = DFU_STATE_dfuMANIFEST;
+ break;
+ }
+
+ /* send status response */
+ dstat.bStatus = dfu_status;
+ dstat.bState = dfu_state;
+ dstat.iString = 0;
+ /* FIXME: set dstat.bwPollTimeout */
+
+ udp_ep0_send_data((char *)&dstat, sizeof(dstat));
+}
+
+static void __dfufunc handle_getstate(void)
+{
+ u_int8_t u8 = dfu_state;
+ DEBUGE("getstate ");
+
+ udp_ep0_send_data((char *)&u8, sizeof(u8));
+}
+
+/* callback function for DFU requests */
+int __dfufunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
+ u_int16_t val, u_int16_t len)
+{
+ int rc, ret = RET_NOTHING;
+
+ DEBUGE("old_state = %u ", dfu_state);
+
+ switch (dfu_state) {
+ case DFU_STATE_appIDLE:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ case USB_REQ_DFU_DETACH:
+ dfu_state = DFU_STATE_appDETACH;
+ ret = RET_ZLP;
+ goto out;
+ break;
+ default:
+ ret = RET_STALL;
+ }
+ break;
+ case DFU_STATE_appDETACH:
+ switch (req) {
+ 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;
+ goto out;
+ break;
+ }
+ /* FIXME: implement timer to return to appIDLE */
+ break;
+ case DFU_STATE_dfuIDLE:
+ switch (req) {
+ case USB_REQ_DFU_DNLOAD:
+ if (len == 0) {
+ dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ }
+ dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
+ ret = handle_dnload(val, len);
+ break;
+ case USB_REQ_DFU_UPLOAD:
+ ptr = (u_int8_t *) AT91C_IFLASH + SAM7DFU_SIZE;
+ dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
+ handle_upload(val, len);
+ break;
+ case USB_REQ_DFU_ABORT:
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ goto out;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuDNLOAD_SYNC:
+ switch (req) {
+ 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;
+ goto out;
+ }
+ break;
+ case DFU_STATE_dfuDNBUSY:
+ switch (req) {
+ 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;
+ goto out;
+ }
+ break;
+ case DFU_STATE_dfuDNLOAD_IDLE:
+ switch (req) {
+ case USB_REQ_DFU_DNLOAD:
+ dfu_state = DFU_STATE_dfuDNLOAD_SYNC;
+ ret = handle_dnload(val, len);
+ break;
+ case USB_REQ_DFU_ABORT:
+ dfu_state = DFU_STATE_dfuIDLE;
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuMANIFEST_SYNC:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ 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) {
+ case USB_REQ_DFU_UPLOAD:
+ /* state transition if less data then requested */
+ rc = handle_upload(val, len);
+ if (rc >= 0 && rc < len)
+ dfu_state = DFU_STATE_dfuIDLE;
+ break;
+ case USB_REQ_DFU_ABORT:
+ dfu_state = DFU_STATE_dfuIDLE;
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuERROR:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ case USB_REQ_DFU_CLRSTATUS:
+ dfu_state = DFU_STATE_dfuIDLE;
+ dfu_status = DFU_STATUS_OK;
+ /* no zlp? */
+ ret = RET_ZLP;
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ ret = RET_STALL;
+ break;
+ }
+ break;
+ }
+
+out:
+ DEBUGE("new_state = %u\r\n", dfu_state);
+
+ switch (ret) {
+ case RET_NOTHING:
+ break;
+ case RET_ZLP:
+ udp_ep0_send_zlp();
+ break;
+ case RET_STALL:
+ udp_ep0_send_stall();
+ break;
+ }
+ return 0;
+}
+
+static u_int8_t cur_config;
+
+/* USB DFU Device descriptor in DFU mode */
+__dfustruct const struct usb_device_descriptor dfu_dev_descriptor = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0100,
+ .bDeviceClass = 0x00,
+ .bDeviceSubClass = 0x00,
+ .bDeviceProtocol = 0x00,
+ .bMaxPacketSize0 = 8,
+ .idVendor = USB_VENDOR_ID,
+ .idProduct = USB_PRODUCT_ID,
+ .bcdDevice = 0x0000,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 0x00,
+ .bNumConfigurations = 0x01,
+};
+
+/* USB DFU Config descriptor in DFU mode */
+__dfustruct const struct _dfu_desc dfu_cfg_descriptor = {
+ .ucfg = {
+ .bLength = USB_DT_CONFIG_SIZE,
+ .bDescriptorType = USB_DT_CONFIG,
+ .wTotalLength = USB_DT_CONFIG_SIZE +
+ 2* USB_DT_INTERFACE_SIZE +
+ USB_DT_DFU_SIZE,
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+#ifdef CONFIG_USB_STRING
+ .iConfiguration = 3,
+#else
+ .iConfiguration = 0,
+#endif
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = 100,
+ },
+ .uif[0] = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x00,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x02,
+#ifdef CONFIG_USB_STRING
+ .iInterface = 4,
+#else
+ .iInterface = 0,
+#endif
+ },
+ .uif[1] = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x01,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x02,
+#ifdef CONFIG_USB_STRING
+ .iInterface = 5,
+#else
+ .iInterface = 0,
+#endif
+ },
+
+ .func_dfu = DFU_FUNC_DESC,
+};
+
+
+/* minimal USB EP0 handler in DFU mode */
+static __dfufunc void dfu_udp_ep0_handler(void)
+{
+ AT91PS_UDP pUDP = AT91C_BASE_UDP;
+ u_int8_t bmRequestType, bRequest;
+ u_int16_t wValue, wIndex, wLength, wStatus;
+ u_int32_t csr = pUDP->UDP_CSR[0];
+
+ DEBUGE("CSR=0x%04x ", csr);
+
+ if (csr & AT91C_UDP_STALLSENT) {
+ DEBUGE("ACK_STALLSENT ");
+ pUDP->UDP_CSR[0] = ~AT91C_UDP_STALLSENT;
+ }
+
+ if (csr & AT91C_UDP_RX_DATA_BK0) {
+ DEBUGE("ACK_BANK0 ");
+ pUDP->UDP_CSR[0] &= ~AT91C_UDP_RX_DATA_BK0;
+ }
+
+ if (!(csr & AT91C_UDP_RXSETUP)) {
+ DEBUGE("no setup packet\r\n");
+ return;
+ }
+
+ DEBUGE("len=%d ", csr >> 16);
+ if (csr >> 16 == 0) {
+ DEBUGE("empty packet\r\n");
+ return;
+ }
+
+ bmRequestType = pUDP->UDP_FDR[0];
+ bRequest = pUDP->UDP_FDR[0];
+ wValue = (pUDP->UDP_FDR[0] & 0xFF);
+ wValue |= (pUDP->UDP_FDR[0] << 8);
+ wIndex = (pUDP->UDP_FDR[0] & 0xFF);
+ wIndex |= (pUDP->UDP_FDR[0] << 8);
+ wLength = (pUDP->UDP_FDR[0] & 0xFF);
+ wLength |= (pUDP->UDP_FDR[0] << 8);
+
+ DEBUGE("bmRequestType=0x%2x ", bmRequestType);
+
+ if (bmRequestType & 0x80) {
+ DEBUGE("DATA_IN=1 ");
+ pUDP->UDP_CSR[0] |= AT91C_UDP_DIR;
+ while (!(pUDP->UDP_CSR[0] & AT91C_UDP_DIR)) ;
+ }
+ pUDP->UDP_CSR[0] &= ~AT91C_UDP_RXSETUP;
+ while ((pUDP->UDP_CSR[0] & AT91C_UDP_RXSETUP)) ;
+
+ /* Handle supported standard device request Cf Table 9-3 in USB
+ * speciication Rev 1.1 */
+ switch ((bRequest << 8) | bmRequestType) {
+ u_int8_t desc_type, desc_index;
+ case STD_GET_DESCRIPTOR:
+ DEBUGE("GET_DESCRIPTOR ");
+ desc_type = wValue >> 8;
+ desc_index = wValue & 0xff;
+ switch (desc_type) {
+ case USB_DT_DEVICE:
+ /* Return Device Descriptor */
+ udp_ep0_send_data((const char *)
+ &dfu_dev_descriptor,
+ MIN(sizeof(dfu_dev_descriptor),
+ wLength));
+ break;
+ case USB_DT_CONFIG:
+ /* Return Configuration Descriptor */
+ udp_ep0_send_data((const char *)
+ &dfu_cfg_descriptor,
+ MIN(sizeof(dfu_cfg_descriptor),
+ wLength));
+ break;
+ case USB_DT_STRING:
+ /* Return String Descriptor */
+ if (desc_index > ARRAY_SIZE(usb_strings)) {
+ udp_ep0_send_stall();
+ break;
+ }
+ DEBUGE("bLength=%u, wLength=%u ",
+ usb_strings[desc_index]->bLength, wLength);
+ udp_ep0_send_data((const char *) usb_strings[desc_index],
+ MIN(usb_strings[desc_index]->bLength,
+ wLength));
+ break;
+ case USB_DT_CS_DEVICE:
+ /* Return Function descriptor */
+ udp_ep0_send_data((const char *) &dfu_cfg_descriptor.func_dfu,
+ MIN(sizeof(dfu_cfg_descriptor.func_dfu),
+ wLength));
+ break;
+ default:
+ udp_ep0_send_stall();
+ break;
+ }
+ break;
+ case STD_SET_ADDRESS:
+ DEBUGE("SET_ADDRESS ");
+ udp_ep0_send_zlp();
+ pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue);
+ pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;
+ break;
+ case STD_SET_CONFIGURATION:
+ DEBUGE("SET_CONFIG ");
+ if (wValue)
+ DEBUGE("VALUE!=0 ");
+ cur_config = wValue;
+ udp_ep0_send_zlp();
+ pUDP->UDP_GLBSTATE =
+ (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
+ pUDP->UDP_CSR[1] =
+ (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) :
+ 0;
+ pUDP->UDP_CSR[2] =
+ (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;
+ pUDP->UDP_CSR[3] =
+ (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;
+ pUDP->UDP_IER = (AT91C_UDP_EPINT0|AT91C_UDP_EPINT1|
+ AT91C_UDP_EPINT2|AT91C_UDP_EPINT3);
+ break;
+ case STD_GET_CONFIGURATION:
+ DEBUGE("GET_CONFIG ");
+ udp_ep0_send_data((char *)&(cur_config),
+ sizeof(cur_config));
+ break;
+ case STD_GET_STATUS_ZERO:
+ DEBUGE("GET_STATUS_ZERO ");
+ wStatus = 0;
+ udp_ep0_send_data((char *)&wStatus, sizeof(wStatus));
+ break;
+ case STD_GET_STATUS_INTERFACE:
+ DEBUGE("GET_STATUS_INTERFACE ");
+ wStatus = 0;
+ udp_ep0_send_data((char *)&wStatus, sizeof(wStatus));
+ break;
+ case STD_GET_STATUS_ENDPOINT:
+ DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f);
+ wStatus = 0;
+ wIndex &= 0x0F;
+ if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex == 0)) {
+ wStatus =
+ (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
+ udp_ep0_send_data((char *)&wStatus,
+ sizeof(wStatus));
+ } else if ((pUDP->UDP_GLBSTATE & AT91C_UDP_FADDEN)
+ && (wIndex == 0)) {
+ wStatus =
+ (pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
+ udp_ep0_send_data((char *)&wStatus,
+ sizeof(wStatus));
+ } else
+ udp_ep0_send_stall();
+ break;
+ case STD_SET_FEATURE_ZERO:
+ DEBUGE("SET_FEATURE_ZERO ");
+ udp_ep0_send_stall();
+ break;
+ case STD_SET_FEATURE_INTERFACE:
+ DEBUGE("SET_FEATURE_INTERFACE ");
+ udp_ep0_send_zlp();
+ break;
+ case STD_SET_FEATURE_ENDPOINT:
+ DEBUGE("SET_FEATURE_ENDPOINT ");
+ udp_ep0_send_stall();
+ break;
+ case STD_CLEAR_FEATURE_ZERO:
+ DEBUGE("CLEAR_FEATURE_ZERO ");
+ udp_ep0_send_stall();
+ break;
+ case STD_CLEAR_FEATURE_INTERFACE:
+ DEBUGE("CLEAR_FEATURE_INTERFACE ");
+ udp_ep0_send_zlp();
+ break;
+ case STD_CLEAR_FEATURE_ENDPOINT:
+ DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f);
+ udp_ep0_send_stall();
+ break;
+ case STD_SET_INTERFACE:
+ DEBUGE("SET INTERFACE ");
+ /* FIXME: store the interface number somewhere, once
+ * we need to support DFU flashing DFU */
+ udp_ep0_send_zlp();
+ break;
+ default:
+ DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ",
+ bRequest, bmRequestType);
+ if ((bmRequestType & 0x3f) == USB_TYPE_DFU) {
+ dfu_ep0_handler(bmRequestType, bRequest,
+ wValue, wLength);
+ } else
+ udp_ep0_send_stall();
+ break;
+ }
+ DEBUGE("\r\n");
+}
+
+/* minimal USB IRQ handler in DFU mode */
+static __dfufunc void dfu_udp_irq(void)
+{
+ AT91PS_UDP pUDP = AT91C_BASE_UDP;
+ AT91_REG isr = pUDP->UDP_ISR;
+ led1on();
+
+ if (isr & AT91C_UDP_ENDBUSRES) {
+ led2on();
+ pUDP->UDP_IER = AT91C_UDP_EPINT0;
+ /* reset all endpoints */
+ pUDP->UDP_RSTEP = (unsigned int)-1;
+ pUDP->UDP_RSTEP = 0;
+ /* Enable the function */
+ pUDP->UDP_FADDR = AT91C_UDP_FEN;
+ /* Configure endpoint 0 */
+ pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
+ cur_config = 0;
+
+ if (dfu_state == DFU_STATE_dfuMANIFEST_WAIT_RST ||
+ dfu_state == DFU_STATE_dfuMANIFEST) {
+ AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
+ AT91C_RSTC_PERRST|
+ AT91C_RSTC_EXTRST);
+ }
+
+ }
+
+ if (isr & AT91C_UDP_EPINT0)
+ dfu_udp_ep0_handler();
+
+ /* clear all interrupts */
+ pUDP->UDP_ICR = isr;
+
+ AT91F_AIC_ClearIt(AT91C_ID_UDP);
+
+ led1off();
+}
+
+/* this is only called once before DFU mode, no __dfufunc required */
+static void dfu_switch(void)
+{
+ AT91PS_AIC pAic = AT91C_BASE_AIC;
+
+ DEBUGE("\r\nsam7dfu: switching to DFU mode\r\n");
+
+ dfu_state = DFU_STATE_appDETACH;
+ AT91F_RSTSoftReset(AT91C_BASE_RSTC, AT91C_RSTC_PROCRST|
+ AT91C_RSTC_PERRST|AT91C_RSTC_EXTRST);
+
+ /* We should never reach here, but anyway avoid returning to the
+ * caller since he doesn't expect us to do so */
+ while (1) ;
+}
+
+void __dfufunc dfu_main(void)
+{
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED1);
+ AT91F_PIO_CfgOutput(AT91C_BASE_PIOA, OPENPCD_PIO_LED2);
+ led1off();
+ led2off();
+
+ AT91F_DBGU_Init();
+ AT91F_DBGU_Printk("\n\r\n\rsam7dfu - AT91SAM7 USB DFU bootloader\n\r"
+ "(C) 2006 by Harald Welte <hwelte@hmw-consulting.de>\n\r"
+ "This software is FREE SOFTWARE licensed under GNU GPL\n\r");
+ AT91F_DBGU_Printk("Version " COMPILE_SVNREV
+ " compiled " COMPILE_DATE
+ " by " COMPILE_BY "\n\r\n\r");
+
+ udp_init();
+
+ dfu_state = DFU_STATE_dfuIDLE;
+
+ /* This implements
+ AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP,
+ OPENPCD_IRQ_PRIO_UDP,
+ AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, dfu_udp_irq);
+ */
+ AT91PS_AIC pAic = AT91C_BASE_AIC;
+ pAic->AIC_IDCR = 1 << AT91C_ID_UDP;
+ pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq;
+ pAic->AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL |
+ OPENPCD_IRQ_PRIO_UDP;
+ pAic->AIC_ICCR = 1 << AT91C_ID_UDP;
+
+ AT91F_AIC_EnableIt(AT91C_ID_UDP);
+
+ /* End-of-Bus-Reset is always enabled */
+
+ /* Clear for set the Pull up resistor */
+#if defined(PCD)
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
+#endif
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUPv4);
+
+ flash_init();
+
+ AT91F_DBGU_Printk("You may now start the DFU up/download process\r\n");
+ /* do nothing, since all of DFU is interrupt driven */
+ int i = 0;
+ while (1) {
+ /* Occasionally reset watchdog */
+ i = (i+1) % 10000;
+ if( i== 0) {
+ AT91F_WDTRestart(AT91C_BASE_WDTC);
+ }
+ }
+}
+
+const struct dfuapi __dfufunctab dfu_api = {
+ .udp_init = &udp_init,
+ .ep0_send_data = &udp_ep0_send_data,
+ .ep0_send_zlp = &udp_ep0_send_zlp,
+ .ep0_send_stall = &udp_ep0_send_stall,
+ .dfu_ep0_handler = &dfu_ep0_handler,
+ .dfu_switch = &dfu_switch,
+ .dfu_state = &dfu_state,
+ .dfu_dev_descriptor = &dfu_dev_descriptor,
+ .dfu_cfg_descriptor = &dfu_cfg_descriptor,
+};
+
+/* just for testing */
+int foo = 12345;
diff --git a/openpicc/dfu/dfu.h b/openpicc/dfu/dfu.h
new file mode 100644
index 0000000..77f80a1
--- /dev/null
+++ b/openpicc/dfu/dfu.h
@@ -0,0 +1,143 @@
+#ifndef _DFU_H
+#define _DFU_H
+
+/* USB Device Firmware Update Implementation for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+#include <sys/types.h>
+#include <usb_ch9.h>
+#include <usb_dfu.h>
+
+/* USB DFU functional descriptor */
+#define DFU_FUNC_DESC { \
+ .bLength = USB_DT_DFU_SIZE, \
+ .bDescriptorType = USB_DT_DFU, \
+ .bmAttributes = USB_DFU_CAN_UPLOAD | USB_DFU_CAN_DOWNLOAD, \
+ .wDetachTimeOut = 0xff00, \
+ .wTransferSize = AT91C_IFLASH_PAGE_SIZE, \
+ .bcdDFUVersion = 0x0100, \
+}
+
+/* USB Interface descriptor in Runtime mode */
+#ifdef CONFIG_USB_STRING
+#define DFU_RT_IF_DESC { \
+ { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x01, \
+ .bAlternateSetting = 0x00, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 1, \
+ }, { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x02, \
+ .bAlternateSetting = 0x00, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 2, \
+ }, \
+}
+#else
+#define DFU_RT_IF_DESC { \
+ { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x01, \
+ .bAlternateSetting = 0x00, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 0, \
+ }, { \
+ .bLength = USB_DT_INTERFACE_SIZE, \
+ .bDescriptorType = USB_DT_INTERFACE, \
+ .bInterfaceNumber = 0x02, \
+ .bAlternateSetting = 0x00, \
+ .bNumEndpoints = 0x00, \
+ .bInterfaceClass = 0xfe, \
+ .bInterfaceSubClass = 0x01, \
+ .bInterfaceProtocol = 0x01, \
+ .iInterface = 0, \
+ }, \
+}
+#endif
+
+#define __dfufunctab __attribute__ ((section (".dfu.functab")))
+#define __dfudata __attribute__ ((section (".data.shared")))
+#define __dfufunc
+#define __dfustruct const
+
+#define DFU_API_LOCATION ((const struct dfuapi *) 0x00103fd0)
+
+struct _dfu_desc {
+ struct usb_config_descriptor ucfg;
+ struct usb_interface_descriptor uif[2];
+ struct usb_dfu_func_descriptor func_dfu;
+};
+
+struct dfuapi {
+ void (*udp_init)(void);
+ void (*ep0_send_data)(const char *data, u_int32_t len);
+ void (*ep0_send_zlp)(void);
+ void (*ep0_send_stall)(void);
+ int (*dfu_ep0_handler)(u_int8_t req_type, u_int8_t req,
+ u_int16_t val, u_int16_t len);
+ void (*dfu_switch)(void);
+ u_int32_t *dfu_state;
+ const struct usb_device_descriptor *dfu_dev_descriptor;
+ const struct _dfu_desc *dfu_cfg_descriptor;
+};
+
+/* From openpcd/firmware/src/os/pcd_enumerate.h */
+/* USB standard request code */
+
+#define STD_GET_STATUS_ZERO 0x0080
+#define STD_GET_STATUS_INTERFACE 0x0081
+#define STD_GET_STATUS_ENDPOINT 0x0082
+
+#define STD_CLEAR_FEATURE_ZERO 0x0100
+#define STD_CLEAR_FEATURE_INTERFACE 0x0101
+#define STD_CLEAR_FEATURE_ENDPOINT 0x0102
+
+#define STD_SET_FEATURE_ZERO 0x0300
+#define STD_SET_FEATURE_INTERFACE 0x0301
+#define STD_SET_FEATURE_ENDPOINT 0x0302
+
+#define STD_SET_ADDRESS 0x0500
+#define STD_GET_DESCRIPTOR 0x0680
+#define STD_SET_DESCRIPTOR 0x0700
+#define STD_GET_CONFIGURATION 0x0880
+#define STD_SET_CONFIGURATION 0x0900
+#define STD_GET_INTERFACE 0x0A81
+#define STD_SET_INTERFACE 0x0B01
+#define STD_SYNCH_FRAME 0x0C82
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#endif /* _DFU_H */
diff --git a/openpicc/dfu/usb_strings_dfu.h b/openpicc/dfu/usb_strings_dfu.h
new file mode 100644
index 0000000..24fde2f
--- /dev/null
+++ b/openpicc/dfu/usb_strings_dfu.h
@@ -0,0 +1,120 @@
+#ifndef _USB_STRINGS_H
+#define _USB_STRINGS_H
+
+/* THIS FILE IS AUTOGENERATED, DO NOT MODIFY MANUALLY */
+
+#include <usb_ch9.h>
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string0 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 1 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = {0x0409 /* English */ },
+};
+
+/* String 1 "bitmanufaktur.de IT Solutions and hmw-consulting.de" */
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string1 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 51 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = { 0x0062, 0x0069, 0x0074, 0x006d, 0x0061, 0x006e,
+ 0x0075, 0x0066, 0x0061, 0x006b, 0x0074, 0x0075,
+ 0x0072, 0x002e, 0x0064, 0x0065, 0x0020, 0x0049,
+ 0x0054, 0x0020, 0x0053, 0x006f, 0x006c, 0x0075,
+ 0x0074, 0x0069, 0x006f, 0x006e, 0x0073, 0x0020,
+ 0x0061, 0x006e, 0x0064, 0x0020, 0x0068, 0x006d,
+ 0x0077, 0x002d, 0x0063, 0x006f, 0x006e, 0x0073,
+ 0x0075, 0x006c, 0x0074, 0x0069, 0x006e, 0x0067,
+ 0x002e, 0x0064, 0x0065, },
+};
+
+/* String 2 "OpenPICC RFID Simulator - DFU Mode" */
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string2 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 34 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049,
+ 0x0043, 0x0043, 0x0020, 0x0052, 0x0046, 0x0049,
+ 0x0044, 0x0020, 0x0053, 0x0069, 0x006d, 0x0075,
+ 0x006c, 0x0061, 0x0074, 0x006f, 0x0072, 0x0020,
+ 0x002d, 0x0020, 0x0044, 0x0046, 0x0055, 0x0020,
+ 0x004d, 0x006f, 0x0064, 0x0065, },
+};
+
+/* String 3 "OpenPIIC DFU Configuration" */
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string3 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 26 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049,
+ 0x0049, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055,
+ 0x0020, 0x0043, 0x006f, 0x006e, 0x0066, 0x0069,
+ 0x0067, 0x0075, 0x0072, 0x0061, 0x0074, 0x0069,
+ 0x006f, 0x006e, },
+};
+
+/* String 4 "OpenPICC DFU Interface - Application Partition" */
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string4 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 46 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049,
+ 0x0043, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055,
+ 0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072,
+ 0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d,
+ 0x0020, 0x0041, 0x0070, 0x0070, 0x006c, 0x0069,
+ 0x0063, 0x0061, 0x0074, 0x0069, 0x006f, 0x006e,
+ 0x0020, 0x0050, 0x0061, 0x0072, 0x0074, 0x0069,
+ 0x0074, 0x0069, 0x006f, 0x006e, },
+};
+
+/* String 5 "OpenPICC DFU Interface - Bootloader Partition" */
+static const struct {
+ struct usb_descriptor_header hdr;
+ u_int16_t wData[];
+} __attribute__((packed)) string5 = {
+ .hdr = {
+ .bLength = sizeof(struct usb_descriptor_header) + 45 * sizeof(u_int16_t),
+ .bDescriptorType = USB_DT_STRING,
+ },
+ .wData = { 0x004f, 0x0070, 0x0065, 0x006e, 0x0050, 0x0049,
+ 0x0043, 0x0043, 0x0020, 0x0044, 0x0046, 0x0055,
+ 0x0020, 0x0049, 0x006e, 0x0074, 0x0065, 0x0072,
+ 0x0066, 0x0061, 0x0063, 0x0065, 0x0020, 0x002d,
+ 0x0020, 0x0042, 0x006f, 0x006f, 0x0074, 0x006c,
+ 0x006f, 0x0061, 0x0064, 0x0065, 0x0072, 0x0020,
+ 0x0050, 0x0061, 0x0072, 0x0074, 0x0069, 0x0074,
+ 0x0069, 0x006f, 0x006e, },
+};
+
+static const struct usb_descriptor_header *usb_strings[] = {
+ (struct usb_descriptor_header *) &string0,
+ (struct usb_descriptor_header *) &string1,
+ (struct usb_descriptor_header *) &string2,
+ (struct usb_descriptor_header *) &string3,
+ (struct usb_descriptor_header *) &string4,
+ (struct usb_descriptor_header *) &string5,
+};
+
+#endif /* _USB_STRINGS_H */
diff --git a/openpicc/dfu/usb_strings_dfu.txt b/openpicc/dfu/usb_strings_dfu.txt
new file mode 100644
index 0000000..681c30a
--- /dev/null
+++ b/openpicc/dfu/usb_strings_dfu.txt
@@ -0,0 +1,5 @@
+bitmanufaktur.de IT Solutions and hmw-consulting.de
+OpenPICC RFID Simulator - DFU Mode
+OpenPIIC DFU Configuration
+OpenPICC DFU Interface - Application Partition
+OpenPICC DFU Interface - Bootloader Partition
personal git repositories of Harald Welte. Your mileage may vary