summaryrefslogtreecommitdiff
path: root/openpcd
diff options
context:
space:
mode:
author(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-25 20:28:51 +0000
committer(no author) <(no author)@6dc7ffe9-61d6-0310-9af1-9938baff3ed1>2006-08-25 20:28:51 +0000
commit43d61cf07955679d364ed5805dab29bc37e6477a (patch)
tree373b98c8ce2bd5226ffb1599397976fb794544a1 /openpcd
parent7ed1726e91620cd058590d4efbc2794041f748c6 (diff)
- add unfinished support for DFU (up to now state machine switching works, including change of interrupt handlers, etc)
git-svn-id: https://svn.openpcd.org:2342/trunk@136 6dc7ffe9-61d6-0310-9af1-9938baff3ed1
Diffstat (limited to 'openpcd')
-rw-r--r--openpcd/firmware/Makefile2
-rw-r--r--openpcd/firmware/include/usb_dfu.h81
-rw-r--r--openpcd/firmware/src/dfu.c585
-rw-r--r--openpcd/firmware/src/dfu.h90
-rw-r--r--openpcd/firmware/src/pcd_enumerate.c249
-rw-r--r--openpcd/firmware/src/pcd_enumerate.h50
6 files changed, 854 insertions, 203 deletions
diff --git a/openpcd/firmware/Makefile b/openpcd/firmware/Makefile
index 4312257..edbf63c 100644
--- a/openpcd/firmware/Makefile
+++ b/openpcd/firmware/Makefile
@@ -76,7 +76,7 @@ SRCARM = lib/lib_AT91SAM7.c
SRCARM += src/pcd_enumerate.c src/fifo.c src/dbgu.c \
src/led.c src/rc632.c src/rc632_highlevel.c src/req_ctx.c \
src/trigger.c src/main.c src/syscalls.c src/pwm.c src/tc.c \
- src/usb_handler.c src/ssc.c src/usb_benchmark.c \
+ src/usb_handler.c src/ssc.c src/usb_benchmark.c src/dfu.c \
src/$(TARGET).c src/start/Cstartup_SAM7.c
ifdef DEBUG
SRCARM += lib/vsprintf.c lib/ctype.c lib/string.c
diff --git a/openpcd/firmware/include/usb_dfu.h b/openpcd/firmware/include/usb_dfu.h
new file mode 100644
index 0000000..5000edc
--- /dev/null
+++ b/openpcd/firmware/include/usb_dfu.h
@@ -0,0 +1,81 @@
+#ifndef _USB_DFU_H
+#define _USB_DFU_H
+/* USB Device Firmware Update Implementation for OpenPCD
+ * (C) 2006 by Harald Welte <hwelte@hmw-consulting.de>
+ *
+ * Protocol definitions for USB DFU
+ *
+ * This ought to be compliant to the USB DFU Spec 1.0 as available from
+ * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf
+ *
+ */
+
+#include <sys/types.h>
+
+#define USB_DT_DFU 0x21
+
+struct usb_dfu_func_descriptor {
+ u_int8_t bLength;
+ u_int8_t bDescriptorType;
+ u_int8_t bmAttributes;
+#define USB_DFU_CAN_DOWNLOAD (1 << 0)
+#define USB_DFU_CAN_UPLOAD (1 << 1)
+#define USB_DFU_MANIFEST_TOL (1 << 2)
+#define USB_DFU_WILL_DETACH (1 << 3)
+ u_int16_t wDetachTimeOut;
+ u_int16_t wTransferSize;
+ u_int16_t bcdDFUVersion;
+} __attribute__ ((packed));
+
+#define USB_DT_DFU_SIZE 9
+
+#define USB_TYPE_DFU (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+
+/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
+#define USB_REQ_DFU_DETACH 0x00
+#define USB_REQ_DFU_DNLOAD 0x01
+#define USB_REQ_DFU_UPLOAD 0x02
+#define USB_REQ_DFU_GETSTATUS 0x03
+#define USB_REQ_DFU_CLRSTATUS 0x04
+#define USB_REQ_DFU_GETSTATE 0x05
+#define USB_REQ_DFU_ABORT 0x06
+
+struct dfu_status {
+ u_int8_t bStatus;
+ u_int8_t bwPollTimeout[3];
+ u_int8_t bState;
+ u_int8_t iString;
+} __attribute__((packed));
+
+#define DFU_STATUS_OK 0x00
+#define DFU_STATUS_errTARGET 0x01
+#define DFU_STATUS_errFILE 0x02
+#define DFU_STATUS_errWRITE 0x03
+#define DFU_STATUS_errERASE 0x04
+#define DFU_STATUS_errCHECK_ERASED 0x05
+#define DFU_STATUS_errPROG 0x06
+#define DFU_STATUS_errVERIFY 0x07
+#define DFU_STATUS_errADDRESS 0x08
+#define DFU_STATUS_errNOTDONE 0x09
+#define DFU_STATUS_errFIRMWARE 0x0a
+#define DFU_STATUS_errVENDOR 0x0b
+#define DFU_STATUS_errUSBR 0x0c
+#define DFU_STATUS_errPOR 0x0d
+#define DFU_STATUS_errUNKNOWN 0x0e
+#define DFU_STATUS_errSTALLEDPKT 0x0f
+
+enum dfu_state {
+ DFU_STATE_appIDLE = 0,
+ DFU_STATE_appDETACH = 1,
+ DFU_STATE_dfuIDLE = 2,
+ DFU_STATE_dfuDNLOAD_SYNC = 3,
+ DFU_STATE_dfuDNBUSY = 4,
+ DFU_STATE_dfuDNLOAD_IDLE = 5,
+ DFU_STATE_dfuMANIFEST_SYNC = 6,
+ DFU_STATE_dfuMANIFEST = 7,
+ DFU_STATE_dfuMANIFEST_WAIT_RST = 8,
+ DFU_STATE_dfuUPLOAD_IDLE = 9,
+ DFU_STATE_dfuERROR = 10,
+};
+
+#endif /* _USB_DFU_H */
diff --git a/openpcd/firmware/src/dfu.c b/openpcd/firmware/src/dfu.c
index 85f85ee..a1624e9 100644
--- a/openpcd/firmware/src/dfu.c
+++ b/openpcd/firmware/src/dfu.c
@@ -1,19 +1,296 @@
+/* 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
+ *
+ */
-/* USB Interface descriptor in Runtime mode */
-struct usb_interface_descriptor desc_if_rt = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0x01,
- .bAlternateSetting = 0x00,
- .bNumEndpoints = 0x00,
- .bInterfaceClass = 0xfe,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x01,
- .iInterface = FIXME,
-};
+#include <errno.h>
+#include <usb_ch9.h>
+#include <usb_dfu.h>
+#include <lib_AT91SAM7.h>
+
+#include "dfu.h"
+#include "pcd_enumerate.h"
+#include "openpcd.h"
+
+/* If debug is enabled, we need to access debug functions from flash
+ * and therefore have to omit flashing */
+#define DEBUG_DFU
+
+#ifdef DEBUG_DFU
+#define DEBUGE DEBUGP
+#define DEBUGI DEBUGP
+#else
+#define DEBUGE(x, args ...)
+#define DEBUGI(x, args ...)
+#endif
+
+static u_int8_t status;
+static u_int8_t *ptr;
+enum dfu_state dfu_state;
+
+static int __ramfunc handle_dnload(u_int16_t val, u_int16_t len)
+{
+ volatile u_int32_t *p = (volatile u_int32_t *)ptr;
+
+ DEBUGE("download ");
+
+ if (len > AT91C_IFLASH_PAGE_SIZE) {
+ /* Too big */
+ dfu_state = DFU_STATE_dfuERROR;
+ status = DFU_STATUS_errADDRESS;
+ udp_ep0_send_stall();
+ return -EINVAL;
+ }
+ if (len & 0x3) {
+ dfu_state = DFU_STATE_dfuERROR;
+ status = DFU_STATUS_errADDRESS;
+ udp_ep0_send_stall();
+ return -EINVAL;
+ }
+ if (len == 0) {
+ dfu_state = DFU_STATE_dfuMANIFEST_SYNC;
+ return 0;
+ }
+#if 0
+ for (i = 0; i < len/4; i++)
+ p[i] =
+#endif
+
+ /* FIXME: get data packet from FIFO, (erase+)write flash */
+#ifndef DEBUG_DFU
+
+#endif
+
+ return 0;
+}
+
+static __ramfunc int handle_upload(u_int16_t val, u_int16_t len)
+{
+ DEBUGE("upload ");
+ if (len > AT91C_IFLASH_PAGE_SIZE
+ || ptr > AT91C_IFLASH_SIZE) {
+ /* Too big */
+ dfu_state = DFU_STATE_dfuERROR;
+ status = DFU_STATUS_errADDRESS;
+ udp_ep0_send_stall();
+ return -EINVAL;
+ }
+
+ if (ptr + len > AT91C_IFLASH_SIZE)
+ len = AT91C_IFLASH_SIZE - (u_int32_t) ptr;
+
+ udp_ep0_send_data(ptr, len);
+ ptr+= len;
+
+ return len;
+}
+
+static __ramfunc void handle_getstatus(void)
+{
+ struct dfu_status dstat;
+
+ DEBUGE("getstatus ");
+
+ /* send status response */
+ dstat.bStatus = status;
+ dstat.bState = dfu_state;
+ dstat.iString = 0;
+ udp_ep0_send_data(&dstat, sizeof(dstat));
+}
+
+static void __ramfunc 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 __ramfunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
+ u_int16_t val, u_int16_t len)
+{
+ int rc;
+
+ DEBUGE("old_state = %u ", dfu_state);
+
+ switch (dfu_state) {
+ case DFU_STATE_appIDLE:
+ if (req != USB_REQ_DFU_DETACH)
+ goto send_stall;
+ dfu_state = DFU_STATE_appDETACH;
+ goto send_zlp;
+ 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;
+ goto send_stall;
+ 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;
+ goto send_stall;
+ }
+ handle_dnload(val, len);
+ break;
+ case USB_REQ_DFU_UPLOAD:
+ ptr = 0;
+ dfu_state = DFU_STATE_dfuUPLOAD_IDLE;
+ handle_upload(val, len);
+ break;
+ case USB_REQ_DFU_ABORT:
+ /* no zlp? */
+ goto send_zlp;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_stall;
+ 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;
+ goto send_stall;
+ }
+ break;
+ case DFU_STATE_dfuDNBUSY:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_stall;
+ break;
+ case DFU_STATE_dfuDNLOAD_IDLE:
+ switch (req) {
+ case USB_REQ_DFU_DNLOAD:
+ if (handle_dnload(val, len))
+ /* FIXME: state transition */
+ break;
+ case USB_REQ_DFU_ABORT:
+ dfu_state = DFU_STATE_dfuIDLE;
+ goto send_zlp;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_stall;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuMANIFEST_SYNC:
+ switch (req) {
+ case USB_REQ_DFU_GETSTATUS:
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_stall;
+ break;
+ }
+ break;
+ case DFU_STATE_dfuMANIFEST:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_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? */
+ goto send_zlp;
+ break;
+ case USB_REQ_DFU_GETSTATUS:
+ handle_getstatus();
+ break;
+ case USB_REQ_DFU_GETSTATE:
+ handle_getstate();
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_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;
+ /* no zlp? */
+ goto send_zlp;
+ break;
+ default:
+ dfu_state = DFU_STATE_dfuERROR;
+ goto send_stall;
+ break;
+ }
+ break;
+ }
+
+ DEBUGE("OK new_state = %u\r\n", dfu_state);
+ return 0;
+
+send_stall:
+ udp_ep0_send_stall();
+ DEBUGE("STALL new_state = %u\r\n", dfu_state);
+ return -EINVAL;
+
+send_zlp:
+ udp_ep0_send_zlp();
+ DEBUGE("ZLP new_state = %u\r\n", dfu_state);
+ return 0;
+}
+static u_int8_t cur_config;
/* USB DFU Device descriptor in DFU mode */
-struct usb_device_descriptor desc_dev_dfu = {
+struct usb_device_descriptor dfu_dev_descriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0100,
@@ -21,44 +298,264 @@ struct usb_device_descriptor desc_dev_dfu = {
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = 8,
- .idVendor = USB_VENDOR,
- .idProtuct = USB_PRODUCT,
+ .idVendor = OPENPCD_VENDOR_ID,
+ .idProduct = OPENPCD_PRODUCT_ID,
.bcdDevice = 0x0000,
- .iManufacturer = FIXME,
- .iProduct = FIXME,
- .iSerialNumber = FIXME,
+ .iManufacturer = 0x00,
+ .iProduct = 0x00,
+ .iSerialNumber = 0x00,
.bNumConfigurations = 0x01,
};
-/* USB DFU Interface descriptor in DFU mode */
-struct usb_interface_descriptor desc_if_dfu = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0x00,
- .bAlternateSetting = 0x00,
- .bNumEndpoints = 0x00,
- .bInterfaceClass = 0xfe,
- .bInterfaceSubClass = 0x01,
- .bInterfaceProtocol = 0x02,
- .iInterface = FIXME,
+/* USB DFU Config descriptor in DFU mode */
+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,
+ .iConfiguration = 0,
+ .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,
+ .iInterface = 0,
+ },
+ .uif[1] = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0x00,
+ .bAlternateSetting = 0x01,
+ .bNumEndpoints = 0x00,
+ .bInterfaceClass = 0xfe,
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x02,
+ .iInterface = 0,
+ },
+
+ .func_dfu = DFU_FUNC_DESC,
};
+/* minimal USB EP0 handler in DFU mode */
+static __ramfunc void dfu_udp_ep0_handler(void)
{
- switch () {
- case USB_REQ_DFU_DETACH:
- break;
- case USB_REQ_DFU_DNLOAD:
- break;
- case USB_REQ_DFU_GETSTATUS:
- break;
- case USB_REQ_DFU_CLRSTATUS:
- break;
- case USB_REQ_DFU_ABORT:
- break;
- case USB_REQ_GETSTATE:
- break;
- case USB_REQ_DFU_UPLOAD:
- break;
+ 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 ");
+ return;
+ }
+
+ DEBUGE("len=%d ", csr >> 16);
+ if (csr >> 16 == 0) {
+ DEBUGE("empty packet ");
+ 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) {
+ case STD_GET_DESCRIPTOR:
+ DEBUGE("GET_DESCRIPTOR ");
+ if (wValue == 0x100) {
+ /* Return Device Descriptor */
+ udp_ep0_send_data((const char *)
+ &dfu_dev_descriptor,
+ MIN(sizeof(dfu_dev_descriptor),
+ wLength));
+ } else if (wValue == 0x200) {
+ /* Return Configuration Descriptor */
+ udp_ep0_send_data((const char *)
+ &dfu_cfg_descriptor,
+ MIN(sizeof(dfu_cfg_descriptor),
+ wLength));
+#if 0
+ } else if (wValue == 0x400) {
+ /* Return Interface descriptor */
+ if (wIndex != 0x01)
+ udp_ep0_send_stall();
+ udp_ep0_send_data((const char *)
+ &dfu_if_descriptor,
+ MIN(sizeof(dfu_if_descriptor),
+ wLength));
+#endif
+ } else
+ udp_ep0_send_stall();
+ 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 ");
+ udp_ep0_send_stall();
+ 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;
+ }
+}
+
+/* minimal USB IRQ handler in DFU mode */
+static __ramfunc void dfu_udp_irq(void)
+{
+ AT91PS_UDP pUDP = AT91C_BASE_UDP;
+ AT91_REG isr = pUDP->UDP_ISR;
+
+ if (isr & AT91C_UDP_ENDBUSRES) {
+ 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 (isr & AT91C_UDP_EPINT0)
+ dfu_udp_ep0_handler();
+
+ /* clear all interrupts */
+ pUDP->UDP_ICR = isr;
+
+ AT91F_AIC_ClearIt(AT91C_BASE_AIC, AT91C_ID_UDP);
+}
+
+void dfu_switch(void)
+{
+ AT91PS_AIC pAic = AT91C_BASE_AIC;
+
+ DEBUGE("Switching to DFU mode ");
+
+ pAic->AIC_SVR[AT91C_ID_UDP] = (unsigned int) &dfu_udp_irq;
+ dfu_state = DFU_STATE_dfuIDLE;
}
diff --git a/openpcd/firmware/src/dfu.h b/openpcd/firmware/src/dfu.h
index 873bc0e..4372043 100644
--- a/openpcd/firmware/src/dfu.h
+++ b/openpcd/firmware/src/dfu.h
@@ -1,31 +1,59 @@
-#ifndef _USB_DFU_H
-#define _USB_DFU_H
-
-#define USB_DT_DFU 0x21
-
-struct usb_dfu_func_descriptor {
- __u8 bLength;
- __u8 bDescriptorType;
- __u8 bmAttributs;
-#define USB_DFU_CAN_DOWNLOAD (1 << 0)
-#define USB_DFU_CAN_UPLOAD (1 << 1)
-#define USB_DFU_MANIFEST_TOL (1 << 2)
-#define USB_DFU_WILL_DETACH (1 << 3)
- __le16 wDetachTimeOut;
- __le16 wTransferSize;
- __le16 bcdDFUVersion;
-} __attribute__ ((packed));
-
-#define USB_DT_DFU_SIZE 9
-
-
-/* DFU class-specific requests (Section 3, DFU Rev 1.1) */
-#define USB_REQ_DFU_DETACH 0x00
-#define USB_REQ_DFU_DNLOAD 0x01
-#define USB_REQ_DFU_UPLOAD 0x02
-#define USB_REQ_DFU_GETSTATUS 0x03
-#define USB_REQ_DFU_CLRSTATUS 0x04
-#define USB_REQ_DFU_GETSTATE 0x05
-#define USB_REQ_DFU_ABORT 0x06
-
-#endif /* _USB_DFU_H
+#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
+ *
+ */
+
+#include <sys/types.h>
+#include <usb_ch9.h>
+#include <usb_dfu.h>
+
+#include "dbgu.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 */
+#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, \
+}
+
+struct udp_pcd;
+
+extern struct usb_device_descriptor dfu_dev_descriptor;
+
+struct _dfu_desc {
+ struct usb_config_descriptor ucfg;
+ struct usb_interface_descriptor uif[2];
+ struct usb_dfu_func_descriptor func_dfu;
+};
+
+extern struct _dfu_desc dfu_cfg_descriptor;
+
+extern void dfu_switch(void);
+extern int __ramfunc dfu_ep0_handler(u_int8_t req_type, u_int8_t req,
+ u_int16_t val, u_int16_t len);
+
+extern enum dfu_state dfu_state;
+
+#endif /* _DFU_H */
diff --git a/openpcd/firmware/src/pcd_enumerate.c b/openpcd/firmware/src/pcd_enumerate.c
index 3ac03fe..75c0279 100644
--- a/openpcd/firmware/src/pcd_enumerate.c
+++ b/openpcd/firmware/src/pcd_enumerate.c
@@ -22,11 +22,14 @@
#include <openpcd.h>
#include "pcd_enumerate.h"
+#include "dfu.h"
#include "openpcd.h"
#include "dbgu.h"
-//#define DEBUG_UDP_IRQ
-//#ifdef DEBUG_UDP_EP0
+#define DEBUG_UDP_IRQ
+#define DEBUG_UDP_EP0
+
+#define CONFIG_DFU
#define AT91C_EP_OUT 1
#define AT91C_EP_OUT_SIZE 0x40
@@ -34,24 +37,10 @@
#define AT91C_EP_IN_SIZE 0x40
#define AT91C_EP_INT 3
-struct ep_ctx {
- atomic_t pkts_in_transit;
- void *ctx;
-};
-
-struct udp_pcd {
- AT91PS_UDP pUdp;
- unsigned char cur_config;
- unsigned int cur_rcv_bank;
- struct ep_ctx ep[4];
-};
-
static struct udp_pcd upcd;
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-
-struct usb_device_descriptor dev_descriptor = {
+const struct usb_device_descriptor dev_descriptor = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
@@ -72,6 +61,10 @@ struct _desc {
struct usb_config_descriptor ucfg;
struct usb_interface_descriptor uif;
struct usb_endpoint_descriptor ep[3];
+#ifdef CONFIG_DFU
+ struct usb_interface_descriptor uif_dfu;
+ struct usb_dfu_func_descriptor func_dfu;
+#endif
};
const struct _desc cfg_descriptor = {
@@ -79,8 +72,16 @@ const struct _desc cfg_descriptor = {
.bLength = USB_DT_CONFIG_SIZE,
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength = USB_DT_CONFIG_SIZE +
- USB_DT_INTERFACE_SIZE + 3 * USB_DT_ENDPOINT_SIZE,
+#ifdef CONFIG_DFU
+ 2 * USB_DT_INTERFACE_SIZE +
+ 3 * USB_DT_ENDPOINT_SIZE +
+ USB_DT_DFU_SIZE,
+ .bNumInterfaces = 2,
+#else
+ 1 * USB_DT_INTERFACE_SIZE +
+ 3 * USB_DT_ENDPOINT_SIZE,
.bNumInterfaces = 1,
+#endif
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = USB_CONFIG_ATT_ONE,
@@ -121,30 +122,18 @@ const struct _desc cfg_descriptor = {
.bInterval = 0xff, /* FIXME */
},
},
+#ifdef CONFIG_DFU
+ .uif_dfu = DFU_RT_IF_DESC,
+ .func_dfu = DFU_FUNC_DESC,
+#endif
};
-/* 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
+static struct usb_string_descriptor string0 = {
+ .bLength = sizeof(string0),
+ .bDescriptorType = USB_DT_STRING,
+ .wData[0] = 0x0409, /* English */
+};
-#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
static void udp_ep0_handler(void);
@@ -212,6 +201,11 @@ static void udp_irq(void)
/* Configure endpoint 0 */
pUDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
upcd.cur_config = 0;
+
+ if (dfu_state == DFU_STATE_appDETACH) {
+ /* now we need to switch to DFU mode */
+ dfu_switch();
+ }
}
if (isr & AT91C_UDP_EPINT0) {
@@ -325,7 +319,7 @@ static int udp_open(AT91PS_UDP pUdp)
upcd.pUdp = pUdp;
upcd.cur_config = 0;
upcd.cur_rcv_bank = AT91C_UDP_RX_DATA_BK0;
-
+
AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_UDP,
OPENPCD_IRQ_PRIO_UDP,
AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, udp_irq);
@@ -355,67 +349,15 @@ void udp_init(void)
udp_open(AT91C_BASE_UDP);
}
-#if 0
-/* Test if the device is configured and handle enumeration */
-u_int8_t udp_is_configured(void)
-{
- return upcd.cur_config;
-}
-
-/* Send data through endpoint 2/3 */
-u_int32_t AT91F_UDP_Write(u_int8_t irq, const unsigned char *pData, u_int32_t length)
+void udp_reset(void)
{
- AT91PS_UDP pUdp = upcd.pUdp;
- u_int32_t cpt = 0;
- u_int8_t ep;
-
- DEBUGPCRF("enter(irq=%u, len=%u)", irq, length);
-
- if (irq)
- ep = 3;
- else
- ep = 2;
-
- /* Send the first packet */
- cpt = MIN(length, AT91C_EP_IN_SIZE);
- length -= cpt;
- while (cpt--)
- pUdp->UDP_FDR[ep] = *pData++;
- DEBUGPCRF("sending first packet");
- pUdp->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
-
- while (length) {
- DEBUGPCRF("sending further packet");
- /* Fill the second bank */
- cpt = MIN(length, AT91C_EP_IN_SIZE);
- length -= cpt;
- while (cpt--)
- pUdp->UDP_FDR[ep] = *pData++;
- DEBUGPCRF("waiting for end of further packet");
- /* Wait for the the first bank to be sent */
- while (!(pUdp->UDP_CSR[ep] & AT91C_UDP_TXCOMP))
- if (!udp_is_configured()) {
- DEBUGPCRF("return(!configured)");
- return length;
- }
- pUdp->UDP_CSR[ep] &= ~(AT91C_UDP_TXCOMP);
- while (pUdp->UDP_CSR[ep] & AT91C_UDP_TXCOMP) ;
- pUdp->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
- }
- /* Wait for the end of transfer */
- DEBUGPCRF("waiting for end of transfer");
- while (!(pUdp->UDP_CSR[ep] & AT91C_UDP_TXCOMP))
- if (!udp_is_configured()) {
- DEBUGPCRF("return(!configured)");
- return length;
- }
- pUdp->UDP_CSR[ep] &= ~(AT91C_UDP_TXCOMP);
- while (pUdp->UDP_CSR[ep] & AT91C_UDP_TXCOMP) ;
+ volatile int i;
- DEBUGPCRF("return(normal, len=%u)", length);
- return length;
+ AT91F_PIO_SetOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
+ for (i = 0; i < 0xffff; i++)
+ ;
+ AT91F_PIO_ClearOutput(AT91C_BASE_PIOA, OPENPCD_PIO_UDP_PUP);
}
-#endif
#ifdef DEBUG_UDP_EP0
#define DEBUGE(x, args ...) DEBUGP(x, ## args)
@@ -424,8 +366,9 @@ u_int32_t AT91F_UDP_Write(u_int8_t irq, const unsigned char *pData, u_int32_t le
#endif
/* Send Data through the control endpoint */
-static void udp_ep0_send_data(AT91PS_UDP pUdp, const char *pData, u_int32_t length)
+void __ramfunc 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;
@@ -464,8 +407,9 @@ static void udp_ep0_send_data(AT91PS_UDP pUdp, const char *pData, u_int32_t leng
}
/* Send zero length packet through the control endpoint */
-static void udp_ep0_send_zlp(AT91PS_UDP pUdp)
+void __ramfunc 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);
@@ -473,8 +417,9 @@ static void udp_ep0_send_zlp(AT91PS_UDP pUdp)
}
/* Stall the control endpoint */
-static void udp_ep0_send_stall(AT91PS_UDP pUdp)
+void __ramfunc 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);
@@ -536,18 +481,58 @@ static void udp_ep0_handler(void)
switch ((bRequest << 8) | bmRequestType) {
case STD_GET_DESCRIPTOR:
DEBUGE("GET_DESCRIPTOR ");
- if (wValue == 0x100) /* Return Device Descriptor */
- udp_ep0_send_data(pUDP, (const char *) &dev_descriptor,
+ if (wValue == 0x100) {
+ /* Return Device Descriptor */
+#ifdef CONFIG_DFU
+ if (dfu_state != DFU_STATE_appIDLE)
+ udp_ep0_send_data((const char *)
+ &dfu_dev_descriptor,
+ MIN(sizeof(dfu_dev_descriptor),
+ wLength));
+ else
+#endif
+ udp_ep0_send_data((const char *) &dev_descriptor,
MIN(sizeof(dev_descriptor), wLength));
- else if (wValue == 0x200) /* Return Configuration Descriptor */
- udp_ep0_send_data(pUDP, (const char *) &cfg_descriptor,
+ } else if (wValue == 0x200) {
+ /* Return Configuration Descriptor */
+#ifdef CONFIG_DFU
+ if (dfu_state != DFU_STATE_appIDLE)
+ udp_ep0_send_data((const char *)
+ &dfu_cfg_descriptor,
+ MIN(sizeof(dfu_cfg_descriptor),
+ wLength));
+ else
+#endif
+ udp_ep0_send_data((const char *) &cfg_descriptor,
MIN(sizeof(cfg_descriptor), wLength));
- else
- udp_ep0_send_stall(pUDP);
+ } else if (wValue == 0x300) {
+ /* Return String descriptor */
+ switch (wIndex) {
+ case 0:
+ udp_ep0_send_data((const char *) &string0,
+ MIN(sizeof(string0), wLength));
+ break;
+ default:
+ /* FIXME: implement this */
+ udp_ep0_send_stall();
+ break;
+ }
+#if 0
+ } else if (wValue == 0x400) {
+ /* Return Interface descriptor */
+ if (wIndex != 0x01)
+ udp_ep0_send_stall();
+ udp_ep0_send_data((const char *)
+ &dfu_if_descriptor,
+ MIN(sizeof(dfu_if_descriptor),
+ wLength));
+#endif
+ } else
+ udp_ep0_send_stall();
break;
case STD_SET_ADDRESS:
DEBUGE("SET_ADDRESS ");
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
pUDP->UDP_FADDR = (AT91C_UDP_FEN | wValue);
pUDP->UDP_GLBSTATE = (wValue) ? AT91C_UDP_FADDEN : 0;
break;
@@ -556,7 +541,7 @@ static void udp_ep0_handler(void)
if (wValue)
DEBUGE("VALUE!=0 ");
upcd.cur_config = wValue;
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
pUDP->UDP_GLBSTATE =
(wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
pUDP->UDP_CSR[1] =
@@ -571,18 +556,18 @@ static void udp_ep0_handler(void)
break;
case STD_GET_CONFIGURATION:
DEBUGE("GET_CONFIG ");
- udp_ep0_send_data(pUDP, (char *)&(upcd.cur_config),
+ udp_ep0_send_data((char *)&(upcd.cur_config),
sizeof(upcd.cur_config));
break;
case STD_GET_STATUS_ZERO:
DEBUGE("GET_STATUS_ZERO ");
wStatus = 0;
- udp_ep0_send_data(pUDP, (char *)&wStatus, sizeof(wStatus));
+ udp_ep0_send_data((char *)&wStatus, sizeof(wStatus));
break;
case STD_GET_STATUS_INTERFACE:
DEBUGE("GET_STATUS_INTERFACE ");
wStatus = 0;
- udp_ep0_send_data(pUDP, (char *)&wStatus, sizeof(wStatus));
+ udp_ep0_send_data((char *)&wStatus, sizeof(wStatus));
break;
case STD_GET_STATUS_ENDPOINT:
DEBUGE("GET_STATUS_ENDPOINT(EPidx=%u) ", wIndex&0x0f);
@@ -591,42 +576,42 @@ static void udp_ep0_handler(void)
if ((pUDP->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= 3)) {
wStatus =
(pUDP->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
- udp_ep0_send_data(pUDP, (char *)&wStatus,
+ 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(pUDP, (char *)&wStatus,
+ udp_ep0_send_data((char *)&wStatus,
sizeof(wStatus));
} else
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
case STD_SET_FEATURE_ZERO:
DEBUGE("SET_FEATURE_ZERO ");
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
case STD_SET_FEATURE_INTERFACE:
DEBUGE("SET_FEATURE_INTERFACE ");
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
break;
case STD_SET_FEATURE_ENDPOINT:
DEBUGE("SET_FEATURE_ENDPOINT ");
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
wIndex &= 0x0F;
if ((wValue == 0) && wIndex && (wIndex <= 3)) {
pUDP->UDP_CSR[wIndex] = 0;
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
} else
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
case STD_CLEAR_FEATURE_ZERO:
DEBUGE("CLEAR_FEATURE_ZERO ");
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
case STD_CLEAR_FEATURE_INTERFACE:
DEBUGP("CLEAR_FEATURE_INTERFACE ");
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
break;
case STD_CLEAR_FEATURE_ENDPOINT:
DEBUGE("CLEAR_FEATURE_ENDPOINT(EPidx=%u) ", wIndex & 0x0f);
@@ -664,17 +649,29 @@ static void udp_ep0_handler(void)
RCTX_STATE_FREE)) {}
atomic_set(&upcd.ep[wIndex].pkts_in_transit, 0);
}
- udp_ep0_send_zlp(pUDP);
+ udp_ep0_send_zlp();
} else
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
case STD_SET_INTERFACE:
DEBUGE("SET INTERFACE ");
- udp_ep0_send_stall(pUDP);
+ udp_ep0_send_stall();
break;
+#ifdef CONFIG_DFU
+ case USB_TYPE_DFU<<8|USB_REQ_DFU_DETACH:
+ DEBUGE("DFU_DETACH ");
+ /* if USB reset occurs within wValue milliseconds, switch to DFU */
+ break;
+#endif
default:
DEBUGE("DEFAULT(req=0x%02x, type=0x%02x) ", bRequest, bmRequestType);
- udp_ep0_send_stall(pUDP);
+#ifdef CONFIG_DFU
+ if ((bmRequestType & 0x3f) == USB_TYPE_DFU) {
+ dfu_ep0_handler(bmRequestType, bRequest, wValue, wLength);
+ } else
+#endif
+ udp_ep0_send_stall();
break;
}
}
+
diff --git a/openpcd/firmware/src/pcd_enumerate.h b/openpcd/firmware/src/pcd_enumerate.h
index aa007de..e4ad57d 100644
--- a/openpcd/firmware/src/pcd_enumerate.h
+++ b/openpcd/firmware/src/pcd_enumerate.h
@@ -1,12 +1,60 @@
#ifndef _OPCD_USB_H
#define _OPCD_USB_H
+#include <lib_AT91SAM7.h>
#include <sys/types.h>
-#include "src/openpcd.h"
+#include <asm/atomic.h>
+#include "openpcd.h"
+#include "dfu.h"
+
+struct req_ctx;
+
+extern void __ramfunc udp_ep0_send_data(const char *data, u_int32_t length);
+extern void __ramfunc udp_ep0_send_zlp(void);
+extern void __ramfunc udp_ep0_send_stall(void);
extern void udp_init(void);
extern int udp_refill_ep(int ep, struct req_ctx *rctx);
extern void udp_unthrottle(void);
+extern void udp_reset(void);
+
+struct ep_ctx {
+ atomic_t pkts_in_transit;
+ void *ctx;
+};
+
+struct udp_pcd {
+ AT91PS_UDP pUdp;
+ unsigned char cur_config;
+ unsigned int cur_rcv_bank;
+ struct ep_ctx ep[4];
+};
+
+/* 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
personal git repositories of Harald Welte. Your mileage may vary