summaryrefslogtreecommitdiff
path: root/openpcd/firmware/src/pcd_enumerate.c
diff options
context:
space:
mode:
Diffstat (limited to 'openpcd/firmware/src/pcd_enumerate.c')
-rw-r--r--openpcd/firmware/src/pcd_enumerate.c249
1 files changed, 123 insertions, 126 deletions
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;
}
}
+
personal git repositories of Harald Welte. Your mileage may vary