diff options
author | henryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2007-11-07 16:28:57 +0000 |
---|---|---|
committer | henryk <henryk@6dc7ffe9-61d6-0310-9af1-9938baff3ed1> | 2007-11-07 16:28:57 +0000 |
commit | 39cb47ed0951074afb24687fcb6e66947b4f8ef8 (patch) | |
tree | 53c25e96487b86ac64113180d3731e73d75c13c5 /openpicc/dfu | |
parent | 2306bcac783751b073babef1bf60dd196cfef73d (diff) |
Start working at dfu by copying from main openpcd repository (with modifications), doesn't boot application yet
git-svn-id: https://svn.openpcd.org:2342/trunk@315 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpicc/dfu')
-rw-r--r-- | openpicc/dfu/dbgu.c | 140 | ||||
-rw-r--r-- | openpicc/dfu/dbgu.h | 25 | ||||
-rw-r--r-- | openpicc/dfu/dfu.c | 938 | ||||
-rw-r--r-- | openpicc/dfu/dfu.h | 143 | ||||
-rw-r--r-- | openpicc/dfu/usb_strings_dfu.h | 120 | ||||
-rw-r--r-- | openpicc/dfu/usb_strings_dfu.txt | 5 |
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 |