summaryrefslogtreecommitdiff
path: root/openpicc/dfu/dfu.c
diff options
context:
space:
mode:
Diffstat (limited to 'openpicc/dfu/dfu.c')
-rw-r--r--openpicc/dfu/dfu.c938
1 files changed, 0 insertions, 938 deletions
diff --git a/openpicc/dfu/dfu.c b/openpicc/dfu/dfu.c
deleted file mode 100644
index af09a62..0000000
--- a/openpicc/dfu/dfu.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/* 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;
personal git repositories of Harald Welte. Your mileage may vary