summaryrefslogtreecommitdiff
path: root/usb/device/core
diff options
context:
space:
mode:
Diffstat (limited to 'usb/device/core')
-rw-r--r--usb/device/core/USBD.h276
-rw-r--r--usb/device/core/USBDCallbacks.h65
-rw-r--r--usb/device/core/USBDCallbacks_Initialized.c67
-rw-r--r--usb/device/core/USBDCallbacks_RequestReceived.c49
-rw-r--r--usb/device/core/USBDCallbacks_Reset.c47
-rw-r--r--usb/device/core/USBDCallbacks_Resumed.c54
-rw-r--r--usb/device/core/USBDCallbacks_Suspended.c51
-rw-r--r--usb/device/core/USBDDriver.c753
-rw-r--r--usb/device/core/USBDDriver.h101
-rw-r--r--usb/device/core/USBDDriverCallbacks.h61
-rw-r--r--usb/device/core/USBDDriverCb_CfgChanged.c49
-rw-r--r--usb/device/core/USBDDriverCb_IfSettingChanged.c52
-rw-r--r--usb/device/core/USBDDriverDescriptors.h86
-rw-r--r--usb/device/core/USBD_OTGHS.c1697
-rw-r--r--usb/device/core/USBD_UDP.c1692
-rw-r--r--usb/device/core/USBD_UDPHS.c2384
-rw-r--r--usb/device/core/core.dir41
17 files changed, 7525 insertions, 0 deletions
diff --git a/usb/device/core/USBD.h b/usb/device/core/USBD.h
new file mode 100644
index 0000000..e6c2e9b
--- /dev/null
+++ b/usb/device/core/USBD.h
@@ -0,0 +1,276 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// Collection of methods for using the USB device controller on AT91
+/// microcontrollers.
+///
+/// !!!Usage
+///
+/// Please refer to the corresponding application note.
+/// - "AT91 USB device framework"
+/// - "USBD API" . "USBD API Methods"
+//------------------------------------------------------------------------------
+
+#ifndef USBD_H
+#define USBD_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <memories/Media.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBGenericRequest.h>
+
+//------------------------------------------------------------------------------
+// Compile Options
+//------------------------------------------------------------------------------
+
+/// Compile option for HS or OTG, use DMA. Remove this define for not use DMA.
+#if defined(CHIP_USB_OTGHS) || defined(CHIP_USB_UDPHS)
+#define DMA
+#endif
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "USB device API return values"
+///
+/// This page lists the return values of the USB %device driver API
+///
+/// !Return codes
+/// - USBD_STATUS_SUCCESS
+/// - USBD_STATUS_LOCKED
+/// - USBD_STATUS_ABORTED
+/// - USBD_STATUS_RESET
+
+/// Indicates the operation was successful.
+#define USBD_STATUS_SUCCESS 0
+/// Endpoint/device is already busy.
+#define USBD_STATUS_LOCKED 1
+/// Operation has been aborted.
+#define USBD_STATUS_ABORTED 2
+/// Operation has been aborted because the device has been reset.
+#define USBD_STATUS_RESET 3
+/// Part ot operation successfully done.
+#define USBD_STATUS_PARTIAL_DONE 4
+/// Operation failed because parameter error
+#define USBD_STATUS_INVALID_PARAMETER 5
+/// Operation failed because in unexpected state
+#define USBD_STATUS_WRONG_STATE 6
+/// Operation failed because HW not supported
+#define USBD_STATUS_HW_NOT_SUPPORTED 0xFE
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "USB device states"
+///
+/// This page lists the %device states of the USB %device driver.
+///
+/// !States
+/// - USBD_STATE_SUSPENDED
+/// - USBD_STATE_ATTACHED
+/// - USBD_STATE_POWERED
+/// - USBD_STATE_DEFAULT
+/// - USBD_STATE_ADDRESS
+/// - USBD_STATE_CONFIGURED
+
+/// The device is currently suspended.
+#define USBD_STATE_SUSPENDED 0
+/// USB cable is plugged into the device.
+#define USBD_STATE_ATTACHED 1
+/// Host is providing +5V through the USB cable.
+#define USBD_STATE_POWERED 2
+/// Device has been reset.
+#define USBD_STATE_DEFAULT 3
+/// The device has been given an address on the bus.
+#define USBD_STATE_ADDRESS 4
+/// A valid configuration has been selected.
+#define USBD_STATE_CONFIGURED 5
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "USB device LEDs"
+///
+/// This page lists the LEDs used in the USB %device driver.
+///
+/// !LEDs
+/// - USBD_LEDPOWER
+/// - USBD_LEDUSB
+/// - USBD_LEDOTHER
+
+/// LED for indicating that the device is powered.
+#define USBD_LEDPOWER 0
+/// LED for indicating USB activity.
+#define USBD_LEDUSB 1
+/// LED for custom usage.
+#define USBD_LEDOTHER 2
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Buffer struct used for multi-buffer-listed transfer.
+/// The driver can process 255 bytes of buffers or buffer list window.
+//------------------------------------------------------------------------------
+typedef struct _USBDTransferBuffer {
+ /// Pointer to frame buffer
+ unsigned char * pBuffer;
+ /// Size of the frame (up to 64K-1)
+ unsigned short size;
+ /// Bytes transferred
+ unsigned short transferred;
+ /// Bytes in FIFO
+ unsigned short buffered;
+ /// Bytes remaining
+ unsigned short remaining;
+} USBDTransferBuffer;
+
+#ifdef __ICCARM__ // IAR
+#define __attribute__(...) // IAR
+#endif // IAR
+
+//------------------------------------------------------------------------------
+/// Struct used for USBD DMA Link List Transfer Descriptor, must be 16-bytes
+/// aligned.
+/// (For USB, DMA transfer is linked to EPs and FIFO address is EP defined)
+//------------------------------------------------------------------------------
+typedef struct _USBDDmaDescriptor {
+ /// Pointer to Next Descriptor
+ void* pNxtDesc;
+ /// Pointer to data buffer address
+ void* pDataAddr;
+ /// DMA Control setting register value
+ unsigned int ctrlSettings:8, /// Control settings
+ reserved:8, /// Not used
+ bufferLength:16; /// Length of buffer
+ /// Loaded to DMA register, OK to modify
+ unsigned int used;
+} __attribute__((aligned(16))) USBDDmaDescriptor;
+
+#ifdef __ICCARM__ // IAR
+#pragma pack() // IAR
+#endif // IAR
+
+//------------------------------------------------------------------------------
+/// Callback used by transfer functions (USBD_Read & USBD_Write) to notify
+/// that a transaction is complete.
+//------------------------------------------------------------------------------
+typedef void (*TransferCallback)(void *pArg,
+ unsigned char status,
+ unsigned int transferred,
+ unsigned int remaining);
+
+//------------------------------------------------------------------------------
+/// Callback used by MBL transfer functions (USBD_Read & USBD_Write) to notify
+/// that a transaction is complete.
+/// \param pArg Pointer to callback arguments.
+/// \param status USBD status.
+/// \param nbFreed Number of buffers that is freed since last callback.
+//------------------------------------------------------------------------------
+typedef void (*MblTransferCallback)(void *pArg,
+ unsigned char status,
+ unsigned int nbFreed);
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void USBD_IrqHandler(void);
+
+extern void USBD_Init(void);
+
+extern void USBD_ConfigureSpeed(unsigned char forceFS);
+
+extern void USBD_Connect(void);
+
+extern void USBD_Disconnect(void);
+
+extern char USBD_Write(
+ unsigned char bEndpoint,
+ const void *pData,
+ unsigned int size,
+ TransferCallback callback,
+ void *pArg);
+
+extern char USBD_MblWrite(
+ unsigned char bEndpoint,
+ void * pMbl,
+ unsigned short wListSize,
+ unsigned char bCircList,
+ unsigned short wStartNdx,
+ MblTransferCallback fCallback,
+ void * pArgument);
+
+extern char USBD_MblReuse(
+ unsigned char bEndpoint,
+ unsigned char * pNewBuffer,
+ unsigned short wNewSize);
+
+extern char USBD_Read(
+ unsigned char bEndpoint,
+ void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArg);
+
+extern unsigned char USBD_Stall(unsigned char bEndpoint);
+
+extern void USBD_Halt(unsigned char bEndpoint);
+
+extern void USBD_Unhalt(unsigned char bEndpoint);
+
+extern void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor);
+
+extern unsigned char USBD_IsHalted(unsigned char bEndpoint);
+
+extern void USBD_RemoteWakeUp(void);
+
+extern void USBD_SetAddress(unsigned char address);
+
+extern void USBD_SetConfiguration(unsigned char cfgnum);
+
+extern unsigned char USBD_GetState(void);
+
+extern unsigned char USBD_IsHighSpeed(void);
+
+extern void USBD_Test(unsigned char bIndex);
+
+#endif //#ifndef USBD_H
+
diff --git a/usb/device/core/USBDCallbacks.h b/usb/device/core/USBDCallbacks.h
new file mode 100644
index 0000000..d4d5c7e
--- /dev/null
+++ b/usb/device/core/USBDCallbacks.h
@@ -0,0 +1,65 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ \unit
+
+ !!!Purpose
+
+ Definitions of callbacks used by the USBD API to notify the user
+ application of incoming events. These functions are declared as 'weak',
+ so they can be re-implemented elsewhere in the application in a
+ transparent way.
+*/
+
+#ifndef USBDCALLBACKS_H
+#define USBDCALLBACKS_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <usb/common/core/USBGenericRequest.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void USBDCallbacks_Initialized(void);
+
+extern void USBDCallbacks_Reset(void);
+
+extern void USBDCallbacks_Suspended(void);
+
+extern void USBDCallbacks_Resumed(void);
+
+extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request);
+
+#endif //#ifndef USBDCALLBACKS_H
+
diff --git a/usb/device/core/USBDCallbacks_Initialized.c b/usb/device/core/USBDCallbacks_Initialized.c
new file mode 100644
index 0000000..0ac4ffe
--- /dev/null
+++ b/usb/device/core/USBDCallbacks_Initialized.c
@@ -0,0 +1,67 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDCallbacks.h"
+#include "USBD.h"
+#include <board.h>
+#include <irq/irq.h>
+
+//------------------------------------------------------------------------------
+// Exported function
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Invoked after the USB driver has been initialized. By default, configures
+/// the UDP/UDPHS interrupt.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Initialized(void)
+{
+#if defined(CHIP_USB_UDP)
+ // Configure and enable the UDP interrupt
+ IRQ_ConfigureIT(AT91C_ID_UDP, 0, USBD_IrqHandler);
+ IRQ_EnableIT(AT91C_ID_UDP);
+
+#elif defined(CHIP_USB_UDPHS)
+ // Configure and enable the UDPHS interrupt
+ IRQ_ConfigureIT(AT91C_ID_UDPHS, 0, USBD_IrqHandler);
+ IRQ_EnableIT(AT91C_ID_UDPHS);
+
+#elif defined(CHIP_USB_OTGHS)
+ IRQ_ConfigureIT(AT91C_ID_OTGHS, 1, (void*) 0);
+ IRQ_EnableIT(AT91C_ID_OTGHS);
+
+#else
+ #error Unsupported controller.
+#endif
+}
+
diff --git a/usb/device/core/USBDCallbacks_RequestReceived.c b/usb/device/core/USBDCallbacks_RequestReceived.c
new file mode 100644
index 0000000..29468ff
--- /dev/null
+++ b/usb/device/core/USBDCallbacks_RequestReceived.c
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDCallbacks.h"
+
+//------------------------------------------------------------------------------
+// Exported function
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// USBDCallbacks_RequestReceived - Invoked when a new SETUP request is
+/// received. Does nothing by default.
+/// \param pRequest Pointer to the request to handle.
+//------------------------------------------------------------------------------
+void USBDCallbacks_RequestReceived(const USBGenericRequest *pRequest)
+{
+ // Does nothing
+}
+
diff --git a/usb/device/core/USBDCallbacks_Reset.c b/usb/device/core/USBDCallbacks_Reset.c
new file mode 100644
index 0000000..64d9aaa
--- /dev/null
+++ b/usb/device/core/USBDCallbacks_Reset.c
@@ -0,0 +1,47 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDCallbacks.h"
+
+//------------------------------------------------------------------------------
+// Exported function
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Invoked when the USB driver is reset. Does nothing by default.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Reset(void)
+{
+ // Does nothing
+}
+
diff --git a/usb/device/core/USBDCallbacks_Resumed.c b/usb/device/core/USBDCallbacks_Resumed.c
new file mode 100644
index 0000000..3d58646
--- /dev/null
+++ b/usb/device/core/USBDCallbacks_Resumed.c
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDCallbacks.h"
+#include "USBD.h"
+#include <utility/led.h>
+
+//------------------------------------------------------------------------------
+// Exported function
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Invoked when the USB device leaves the Suspended state. By default,
+/// configures the LEDs.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Resumed(void)
+{
+ // Initialize LEDs
+ LED_Configure(USBD_LEDPOWER);
+ LED_Set(USBD_LEDPOWER);
+ LED_Configure(USBD_LEDUSB);
+ LED_Clear(USBD_LEDUSB);
+}
+
diff --git a/usb/device/core/USBDCallbacks_Suspended.c b/usb/device/core/USBDCallbacks_Suspended.c
new file mode 100644
index 0000000..dbc10b9
--- /dev/null
+++ b/usb/device/core/USBDCallbacks_Suspended.c
@@ -0,0 +1,51 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDCallbacks.h"
+#include "USBD.h"
+#include <utility/led.h>
+
+//------------------------------------------------------------------------------
+// Exported function
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Invoked when the USB device gets suspended. By default, turns off all LEDs.
+//------------------------------------------------------------------------------
+void USBDCallbacks_Suspended(void)
+{
+ // Turn off LEDs
+ LED_Clear(USBD_LEDPOWER);
+ LED_Clear(USBD_LEDUSB);
+}
+
diff --git a/usb/device/core/USBDDriver.c b/usb/device/core/USBDDriver.c
new file mode 100644
index 0000000..6a7c000
--- /dev/null
+++ b/usb/device/core/USBDDriver.c
@@ -0,0 +1,753 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDDriver.h"
+#include "USBDDriverCallbacks.h"
+#include "USBD.h"
+#include <board.h>
+#include <utility/trace.h>
+#include <usb/common/core/USBGenericDescriptor.h>
+#include <usb/common/core/USBDeviceDescriptor.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/common/core/USBDeviceQualifierDescriptor.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#include <usb/common/core/USBSetAddressRequest.h>
+#include <usb/common/core/USBGetDescriptorRequest.h>
+#include <usb/common/core/USBSetConfigurationRequest.h>
+#include <usb/common/core/USBInterfaceRequest.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+#if defined(CHIP_USB_OTGHS)
+static unsigned char otg_features_supported = 0;
+#endif
+
+//------------------------------------------------------------------------------
+/// Send a NULL packet
+//------------------------------------------------------------------------------
+static void TerminateCtrlInWithNull(void *pArg,
+ unsigned char status,
+ unsigned int transferred,
+ unsigned int remaining)
+{
+ USBD_Write(0, // Endpoint #0
+ 0, // No data buffer
+ 0, // No data buffer
+ (TransferCallback) 0,
+ (void *) 0);
+}
+
+//------------------------------------------------------------------------------
+/// Configures the device by setting it into the Configured state and
+/// initializing all endpoints.
+/// \param pDriver Pointer to a USBDDriver instance.
+/// \param cfgnum Configuration number to set.
+//------------------------------------------------------------------------------
+static void SetConfiguration(USBDDriver *pDriver, unsigned char cfgnum)
+{
+ USBEndpointDescriptor *pEndpoints[CHIP_USB_NUMENDPOINTS+1];
+ const USBConfigurationDescriptor *pConfiguration;
+
+ // Use different descriptor depending on device speed
+ if (USBD_IsHighSpeed()) {
+
+ pConfiguration = pDriver->pDescriptors->pHsConfiguration;
+ }
+ else {
+
+ pConfiguration = pDriver->pDescriptors->pFsConfiguration;
+ }
+
+ // Set & save the desired configuration
+ USBD_SetConfiguration(cfgnum);
+ pDriver->cfgnum = cfgnum;
+
+ // If the configuration is not 0, configure endpoints
+ if (cfgnum != 0) {
+
+ // Parse configuration to get endpoint descriptors
+ USBConfigurationDescriptor_Parse(pConfiguration, 0, pEndpoints, 0);
+
+ // Configure endpoints
+ int i = 0;
+ while (pEndpoints[i] != 0) {
+
+ USBD_ConfigureEndpoint(pEndpoints[i]);
+ i++;
+ }
+ }
+ // Should be done before send the ZLP
+ USBDDriverCallbacks_ConfigurationChanged(cfgnum);
+
+ // Acknowledge the request
+ USBD_Write(0, // Endpoint #0
+ 0, // No data buffer
+ 0, // No data buffer
+ (TransferCallback) 0,
+ (void *) 0);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the current configuration number to the host.
+/// \param pDriver Pointer to a USBDDriver instance.
+//------------------------------------------------------------------------------
+static void GetConfiguration(const USBDDriver *pDriver)
+{
+ USBD_Write(0, &(pDriver->cfgnum), 1, 0, 0);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the current status of the device to the host.
+/// \param pDriver Pointer to a USBDDriver instance.
+//------------------------------------------------------------------------------
+static void GetDeviceStatus(const USBDDriver *pDriver)
+{
+ static unsigned short data;
+ const USBConfigurationDescriptor *pConfiguration;
+
+ data = 0;
+ // Use different configuration depending on device speed
+ if (USBD_IsHighSpeed()) {
+
+ pConfiguration = pDriver->pDescriptors->pHsConfiguration;
+ }
+ else {
+
+ pConfiguration = pDriver->pDescriptors->pFsConfiguration;
+ }
+
+ // Check current configuration for power mode (if device is configured)
+ if (pDriver->cfgnum != 0) {
+
+ if (USBConfigurationDescriptor_IsSelfPowered(pConfiguration)) {
+
+ data |= 1;
+ }
+ }
+
+ // Check if remote wake-up is enabled
+ if (pDriver->isRemoteWakeUpEnabled) {
+
+ data |= 2;
+ }
+
+ // Send the device status
+ USBD_Write(0, &data, 2, 0, 0);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the current status of an endpoints to the USB host.
+/// \param bEndpoint Endpoint number.
+//------------------------------------------------------------------------------
+static void GetEndpointStatus(unsigned char bEndpoint)
+{
+ static unsigned short data;
+
+ data = 0;
+ // Check if the endpoint exists
+ if (bEndpoint > CHIP_USB_NUMENDPOINTS) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ // Check if the endpoint if currently halted
+ if (USBD_IsHalted(bEndpoint)) {
+
+ data = 1;
+ }
+
+ // Send the endpoint status
+ USBD_Write(0, &data, 2, 0, 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sends the requested USB descriptor to the host if available, or STALLs the
+/// request.
+/// \param pDriver Pointer to a USBDDriver instance.
+/// \param type Type of the requested descriptor
+/// \param index Index of the requested descriptor.
+/// \param length Maximum number of bytes to return.
+//------------------------------------------------------------------------------
+static void GetDescriptor(
+ const USBDDriver *pDriver,
+ unsigned char type,
+ unsigned char indexRDesc,
+ unsigned int length)
+{
+ const USBDeviceDescriptor *pDevice;
+ const USBConfigurationDescriptor *pConfiguration;
+ const USBDeviceQualifierDescriptor *pQualifier;
+ const USBConfigurationDescriptor *pOtherSpeed;
+ const USBGenericDescriptor **pStrings =
+ (const USBGenericDescriptor **) pDriver->pDescriptors->pStrings;
+ const USBGenericDescriptor *pString;
+ unsigned char numStrings = pDriver->pDescriptors->numStrings;
+ unsigned char terminateWithNull = 0;
+
+ // Use different set of descriptors depending on device speed
+ if (USBD_IsHighSpeed()) {
+
+ TRACE_DEBUG("HS ");
+ pDevice = pDriver->pDescriptors->pHsDevice;
+ pConfiguration = pDriver->pDescriptors->pHsConfiguration;
+ pQualifier = pDriver->pDescriptors->pHsQualifier;
+ pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed;
+ }
+ else {
+
+ TRACE_DEBUG("FS ");
+ pDevice = pDriver->pDescriptors->pFsDevice;
+ pConfiguration = pDriver->pDescriptors->pFsConfiguration;
+ pQualifier = pDriver->pDescriptors->pFsQualifier;
+ pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed;
+ }
+
+ // Check the descriptor type
+ switch (type) {
+
+ case USBGenericDescriptor_DEVICE:
+ TRACE_INFO_WP("Dev ");
+
+ // Adjust length and send descriptor
+ if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) {
+
+ length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice);
+ }
+ USBD_Write(0, pDevice, length, 0, 0);
+ break;
+
+ case USBGenericDescriptor_CONFIGURATION:
+ TRACE_INFO_WP("Cfg ");
+
+ // Adjust length and send descriptor
+ if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) {
+
+ length = USBConfigurationDescriptor_GetTotalLength(pConfiguration);
+ terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
+ }
+ USBD_Write(0,
+ pConfiguration,
+ length,
+ terminateWithNull ? TerminateCtrlInWithNull : 0,
+ 0);
+ break;
+
+ case USBGenericDescriptor_DEVICEQUALIFIER:
+ TRACE_INFO_WP("Qua ");
+
+ // Check if descriptor exists
+ if (!pQualifier) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ // Adjust length and send descriptor
+ if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) {
+
+ length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier);
+ }
+ USBD_Write(0, pQualifier, length, 0, 0);
+ }
+ break;
+
+ case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
+ TRACE_INFO_WP("OSC ");
+
+ // Check if descriptor exists
+ if (!pOtherSpeed) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ // Adjust length and send descriptor
+ if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) {
+
+ length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed);
+ terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
+ }
+ USBD_Write(0,
+ pOtherSpeed,
+ length,
+ terminateWithNull ? TerminateCtrlInWithNull : 0,
+ 0);
+ }
+ break;
+
+ case USBGenericDescriptor_STRING:
+ TRACE_INFO_WP("Str%d ", indexRDesc);
+
+ // Check if descriptor exists
+ if (indexRDesc >= numStrings) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ pString = pStrings[indexRDesc];
+
+ // Adjust length and send descriptor
+ if (length > USBGenericDescriptor_GetLength(pString)) {
+
+ length = USBGenericDescriptor_GetLength(pString);
+ terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
+ }
+ USBD_Write(0,
+ pString,
+ length,
+ terminateWithNull ? TerminateCtrlInWithNull : 0,
+ 0);
+ }
+ break;
+
+ default:
+ TRACE_WARNING(
+ "USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r",
+ type);
+ USBD_Stall(0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the active setting of the given interface if the configuration supports
+/// it; otherwise, the control pipe is STALLed. If the setting of an interface
+/// changes.
+/// \parma pDriver Pointer to a USBDDriver instance.
+/// \parma infnum Interface number.
+/// \parma setting New active setting for the interface.
+//------------------------------------------------------------------------------
+static void SetInterface(
+ USBDDriver *pDriver,
+ unsigned char infnum,
+ unsigned char setting)
+{
+ // Make sure alternate settings are supported
+ if (!pDriver->pInterfaces) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ // Change the current setting of the interface and trigger the callback
+ // if necessary
+ if (pDriver->pInterfaces[infnum] != setting) {
+
+ pDriver->pInterfaces[infnum] = setting;
+ USBDDriverCallbacks_InterfaceSettingChanged(infnum, setting);
+ }
+
+ // Acknowledge the request
+ USBD_Write(0, 0, 0, 0, 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sends the currently active setting of the given interface to the USB
+/// host. If alternate settings are not supported, this function STALLs the
+/// control pipe.
+/// \param pDriver Pointer to a USBDDriver instance.
+/// \param infnum Interface number.
+//------------------------------------------------------------------------------
+static void GetInterface(
+ const USBDDriver *pDriver,
+ unsigned char infnum)
+{
+ // Make sure alternate settings are supported, or STALL the control pipe
+ if (!pDriver->pInterfaces) {
+
+ USBD_Stall(0);
+ }
+ else {
+
+ // Sends the current interface setting to the host
+ USBD_Write(0, &(pDriver->pInterfaces[infnum]), 1, 0, 0);
+ }
+}
+
+#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)
+//------------------------------------------------------------------------------
+// Performs the selected test on the USB device (high-speed only).
+// \param test Test selector value.
+//------------------------------------------------------------------------------
+static void USBDDriver_Test(unsigned char test)
+{
+ TRACE_DEBUG("UDPHS_Test\n\r");
+
+ // the lower byte of wIndex must be zero
+ // the most significant byte of wIndex is used to specify the specific test mode
+ switch (test) {
+ case USBFeatureRequest_TESTPACKET:
+ //Test mode Test_Packet:
+ //Upon command, a port must repetitively transmit the following test packet until
+ //the exit action is taken. This enables the testing of rise and fall times, eye
+ //patterns, jitter, and any other dynamic waveform specifications.
+ //The test packet is made up by concatenating the following strings.
+ //(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one
+ //transmitted. “S” indicates that a bit stuff occurs, which inserts an “extra” NRZI data bit.
+ //“* N” is used to indicate N occurrences of a string of bits or symbols.)
+ //A port in Test_Packet mode must send this packet repetitively. The inter-packet timing
+ //must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and
+ //no greater than 125 us.
+ // Send ZLP
+ USBD_Test(USBFeatureRequest_TESTSENDZLP);
+ // Tst PACKET
+ USBD_Test(USBFeatureRequest_TESTPACKET);
+ while (1);
+ //break; not reached
+
+ case USBFeatureRequest_TESTJ:
+ //Test mode Test_J:
+ //Upon command, a port’s transceiver must enter the high-speed J state and remain in that
+ //state until the exit action is taken. This enables the testing of the high output drive
+ //level on the D+ line.
+ // Send ZLP
+ USBD_Test(USBFeatureRequest_TESTSENDZLP);
+ // Tst J
+ USBD_Test(USBFeatureRequest_TESTJ);
+ while (1);
+ //break; not reached
+
+ case USBFeatureRequest_TESTK:
+ //Test mode Test_K:
+ //Upon command, a port’s transceiver must enter the high-speed K state and remain in
+ //that state until the exit action is taken. This enables the testing of the high output drive
+ //level on the D- line.
+ // Send a ZLP
+ USBD_Test(USBFeatureRequest_TESTSENDZLP);
+ USBD_Test(USBFeatureRequest_TESTK);
+ while (1);
+ //break; not reached
+
+ case USBFeatureRequest_TESTSE0NAK:
+ //Test mode Test_SE0_NAK:
+ //Upon command, a port’s transceiver must enter the high-speed receive mode
+ //and remain in that mode until the exit action is taken. This enables the testing
+ //of output impedance, low level output voltage, and loading characteristics.
+ //In addition, while in this mode, upstream facing ports (and only upstream facing ports)
+ //must respond to any IN token packet with a NAK handshake (only if the packet CRC is
+ //determined to be correct) within the normal allowed device response time. This enables testing of
+ //the device squelch level circuitry and, additionally, provides a general purpose stimulus/response
+ //test for basic functional testing.
+ // Send a ZLP
+ USBD_Test(USBFeatureRequest_TESTSENDZLP);
+ // Test SE0_NAK
+ USBD_Test(USBFeatureRequest_TESTSE0NAK);
+ while (1);
+ //break; not reached
+
+ default:
+ USBD_Stall(0);
+ break;
+
+ }
+ // The exit action is to power cycle the device.
+ // The device must be disconnected from the host
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a USBDDriver instance with a list of descriptors. If
+/// interfaces can have multiple alternate settings, an array to store the
+/// current setting for each interface must be provided.
+/// \param pDriver Pointer to a USBDDriver instance.
+/// \param pDescriptors Pointer to a USBDDriverDescriptors instance.
+/// \param pInterfaces Pointer to an array for storing the current alternate
+/// setting of each interface (optional).
+//------------------------------------------------------------------------------
+void USBDDriver_Initialize(
+ USBDDriver *pDriver,
+ const USBDDriverDescriptors *pDescriptors,
+ unsigned char *pInterfaces)
+{
+
+ pDriver->cfgnum = 0;
+#if (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_SELFPOWERED_RWAKEUP) \
+ || (BOARD_USB_BMATTRIBUTES == USBConfigurationDescriptor_BUSPOWERED_RWAKEUP)
+ pDriver->isRemoteWakeUpEnabled = 1;
+#else
+ pDriver->isRemoteWakeUpEnabled = 0;
+#endif
+
+ pDriver->pDescriptors = pDescriptors;
+ pDriver->pInterfaces = pInterfaces;
+
+ // Initialize interfaces array if not null
+ if (pInterfaces != 0) {
+
+ memset(pInterfaces, sizeof(pInterfaces), 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Handles the given request if it is standard, otherwise STALLs it.
+/// \param pDriver Pointer to a USBDDriver instance.
+/// \param pRequest Pointer to a USBGenericRequest instance.
+//------------------------------------------------------------------------------
+void USBDDriver_RequestHandler(
+ USBDDriver *pDriver,
+ const USBGenericRequest *pRequest)
+{
+ unsigned char cfgnum;
+ unsigned char infnum;
+ unsigned char eptnum;
+ unsigned char setting;
+ unsigned char type;
+ unsigned char indexDesc;
+ unsigned int length;
+ unsigned int address;
+
+ TRACE_INFO_WP("Std ");
+
+ // Check request code
+ switch (USBGenericRequest_GetRequest(pRequest)) {
+
+ case USBGenericRequest_GETDESCRIPTOR:
+ TRACE_INFO_WP("gDesc ");
+
+ // Send the requested descriptor
+ type = USBGetDescriptorRequest_GetDescriptorType(pRequest);
+ indexDesc = USBGetDescriptorRequest_GetDescriptorIndex(pRequest);
+ length = USBGenericRequest_GetLength(pRequest);
+ GetDescriptor(pDriver, type, indexDesc, length);
+ break;
+
+ case USBGenericRequest_SETADDRESS:
+ TRACE_INFO_WP("sAddr ");
+
+ // Sends a zero-length packet and then set the device address
+ address = USBSetAddressRequest_GetAddress(pRequest);
+ USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address);
+ break;
+
+ case USBGenericRequest_SETCONFIGURATION:
+ TRACE_INFO_WP("sCfg ");
+
+ // Set the requested configuration
+ cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest);
+ SetConfiguration(pDriver, cfgnum);
+ break;
+
+ case USBGenericRequest_GETCONFIGURATION:
+ TRACE_INFO_WP("gCfg ");
+
+ // Send the current configuration number
+ GetConfiguration(pDriver);
+ break;
+
+ case USBGenericRequest_GETSTATUS:
+ TRACE_INFO_WP("gSta ");
+
+ // Check who is the recipient
+ switch (USBGenericRequest_GetRecipient(pRequest)) {
+
+ case USBGenericRequest_DEVICE:
+ TRACE_INFO_WP("Dev ");
+
+ // Send the device status
+ GetDeviceStatus(pDriver);
+ break;
+
+ case USBGenericRequest_ENDPOINT:
+ TRACE_INFO_WP("Ept ");
+
+ // Send the endpoint status
+ eptnum = USBGenericRequest_GetEndpointNumber(pRequest);
+ GetEndpointStatus(eptnum);
+ break;
+
+ default:
+ TRACE_WARNING(
+ "USBDDriver_RequestHandler: Unknown recipient (%d)\n\r",
+ USBGenericRequest_GetRecipient(pRequest));
+ USBD_Stall(0);
+ }
+ break;
+
+ case USBGenericRequest_CLEARFEATURE:
+ TRACE_INFO_WP("cFeat ");
+
+ // Check which is the requested feature
+ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
+
+ case USBFeatureRequest_ENDPOINTHALT:
+ TRACE_INFO_WP("Hlt ");
+
+ // Unhalt endpoint and send a zero-length packet
+ USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest));
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+
+ case USBFeatureRequest_DEVICEREMOTEWAKEUP:
+ TRACE_INFO_WP("RmWU ");
+
+ // Disable remote wake-up and send a zero-length packet
+ pDriver->isRemoteWakeUpEnabled = 0;
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+
+ default:
+ TRACE_WARNING(
+ "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r",
+ USBFeatureRequest_GetFeatureSelector(pRequest));
+ USBD_Stall(0);
+ }
+ break;
+
+ case USBGenericRequest_SETFEATURE:
+ TRACE_INFO_WP("sFeat ");
+
+ // Check which is the selected feature
+ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
+
+ case USBFeatureRequest_DEVICEREMOTEWAKEUP:
+ TRACE_INFO_WP("RmWU ");
+
+ // Enable remote wake-up and send a ZLP
+ pDriver->isRemoteWakeUpEnabled = 1;
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+
+ case USBFeatureRequest_ENDPOINTHALT:
+ TRACE_INFO_WP("Halt ");
+ // Halt endpoint
+ USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest));
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+
+#if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS)
+
+ case USBFeatureRequest_TESTMODE:
+ // 7.1.20 Test Mode Support, 9.4.9 SetFeature
+ if ((USBGenericRequest_GetRecipient(pRequest) == USBGenericRequest_DEVICE)
+ && ((USBGenericRequest_GetIndex(pRequest) & 0x000F) == 0)) {
+
+ // Handle test request
+ USBDDriver_Test(USBFeatureRequest_GetTestSelector(pRequest));
+ }
+ else {
+
+ USBD_Stall(0);
+ }
+ break;
+#endif
+#if defined(CHIP_USB_OTGHS)
+ case USBFeatureRequest_OTG_B_HNP_ENABLE:
+ TRACE_INFO_WP("OTG_B_HNP_ENABLE ");
+ otg_features_supported |= 1<<USBFeatureRequest_OTG_B_HNP_ENABLE;
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+ case USBFeatureRequest_OTG_A_HNP_SUPPORT:
+ TRACE_INFO_WP("OTG_A_HNP_SUPPORT ");
+ otg_features_supported |= 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT;
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+ case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT:
+ TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT ");
+ otg_features_supported |= 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT;
+ USBD_Write(0, 0, 0, 0, 0);
+ break;
+#endif
+ default:
+ TRACE_WARNING(
+ "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r",
+ USBFeatureRequest_GetFeatureSelector(pRequest));
+ USBD_Stall(0);
+ }
+ break;
+
+ case USBGenericRequest_SETINTERFACE:
+ TRACE_INFO_WP("sInterface ");
+
+ infnum = USBInterfaceRequest_GetInterface(pRequest);
+ setting = USBInterfaceRequest_GetAlternateSetting(pRequest);
+ SetInterface(pDriver, infnum, setting);
+ break;
+
+ case USBGenericRequest_GETINTERFACE:
+ TRACE_INFO_WP("gInterface ");
+
+ infnum = USBInterfaceRequest_GetInterface(pRequest);
+ GetInterface(pDriver, infnum);
+ break;
+
+ default:
+ TRACE_WARNING(
+ "USBDDriver_RequestHandler: Unknown request code (%d)\n\r",
+ USBGenericRequest_GetRequest(pRequest));
+ USBD_Stall(0);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Test if RemoteWakeUP feature is enabled
+/// \param pDriver Pointer to an USBDDriver instance.
+/// \return 1 if remote wake up has been enabled by the host; otherwise, returns
+/// 0
+//------------------------------------------------------------------------------
+unsigned char USBDDriver_IsRemoteWakeUpEnabled(const USBDDriver *pDriver)
+{
+ return pDriver->isRemoteWakeUpEnabled;
+}
+
+#if defined(CHIP_USB_OTGHS)
+//------------------------------------------------------------------------------
+/// Return OTG features supported
+/// \return the OTG features
+//------------------------------------------------------------------------------
+unsigned char USBDDriver_returnOTGFeatures(void)
+{
+ return otg_features_supported;
+}
+
+//------------------------------------------------------------------------------
+/// Clear OTG features supported
+/// \return none
+//------------------------------------------------------------------------------
+void USBDDriver_clearOTGFeatures(void)
+{
+ otg_features_supported = 0;
+}
+#endif
+
diff --git a/usb/device/core/USBDDriver.h b/usb/device/core/USBDDriver.h
new file mode 100644
index 0000000..40ca6d7
--- /dev/null
+++ b/usb/device/core/USBDDriver.h
@@ -0,0 +1,101 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ \unit
+
+ !!!Purpose
+
+ USB Device Driver class definition.
+
+ !!!Usage
+
+ -# Instanciate a USBDDriver object and initialize it using
+ USBDDriver_Initialize.
+ -# When a USB SETUP request is received, forward it to the standard
+ driver using USBDDriver_RequestHandler.
+ -# Check the Remote Wakeup setting via USBDDriver_IsRemoteWakeUpEnabled.
+*/
+
+#ifndef USBDDRIVER_H
+#define USBDDRIVER_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDDriverDescriptors.h"
+#include <usb/common/core/USBGenericRequest.h>
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// USB device driver structure, holding a list of descriptors identifying
+/// the device as well as the driver current state.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// List of descriptors used by the device.
+ const USBDDriverDescriptors *pDescriptors;
+ /// Current setting for each interface.
+ unsigned char *pInterfaces;
+ /// Current configuration number (0 -> device is not configured).
+ unsigned char cfgnum;
+ /// Indicates if remote wake up has been enabled by the host.
+ unsigned char isRemoteWakeUpEnabled;
+#if defined(CHIP_USB_OTGHS)
+ /// Features supported by OTG
+ unsigned char otg_features_supported;
+#endif
+} USBDDriver;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void USBDDriver_Initialize(
+ USBDDriver *pDriver,
+ const USBDDriverDescriptors *pDescriptors,
+ unsigned char *pInterfaces);
+
+extern void USBDDriver_RequestHandler(
+ USBDDriver *pDriver,
+ const USBGenericRequest *pRequest);
+
+extern unsigned char USBDDriver_IsRemoteWakeUpEnabled(const USBDDriver *pDriver);
+
+#if defined(CHIP_USB_OTGHS)
+extern unsigned char USBDDriver_returnOTGFeatures(void);
+extern void USBDDriver_clearOTGFeatures(void);
+#endif
+
+#endif //#ifndef USBDDRIVER_H
+
diff --git a/usb/device/core/USBDDriverCallbacks.h b/usb/device/core/USBDDriverCallbacks.h
new file mode 100644
index 0000000..053e8ac
--- /dev/null
+++ b/usb/device/core/USBDDriverCallbacks.h
@@ -0,0 +1,61 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ \unit
+
+ !!!Purpose
+
+ Definition of several callbacks which are triggered by the USB software
+ driver after receiving specific requests.
+
+ !!!Usage
+
+ -# Re-implement the USBDDriverCallbacks_ConfigurationChanged
+ callback to know when the hosts changes the active configuration of
+ the device.
+ -# Re-implement the USBDDriverCallbacks_InterfaceSettingChanged
+ callback to get notified whenever the active setting of an interface
+ is changed by the host.
+*/
+
+#ifndef USBDDRIVERCALLBACKS_H
+#define USBDDRIVERCALLBACKS_H
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum);
+
+extern void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface,
+ unsigned char setting);
+
+#endif //#ifndef USBDDRIVERCALLBACKS_H
+
diff --git a/usb/device/core/USBDDriverCb_CfgChanged.c b/usb/device/core/USBDDriverCb_CfgChanged.c
new file mode 100644
index 0000000..08e2b2f
--- /dev/null
+++ b/usb/device/core/USBDDriverCb_CfgChanged.c
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDDriverCallbacks.h"
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Indicates that the current configuration of the device has changed.
+/// \param cfgnum New device configuration index.
+//------------------------------------------------------------------------------
+void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum)
+{
+ TRACE_INFO_WP("ConfigurationChanged ");
+}
+
diff --git a/usb/device/core/USBDDriverCb_IfSettingChanged.c b/usb/device/core/USBDDriverCb_IfSettingChanged.c
new file mode 100644
index 0000000..c9049e6
--- /dev/null
+++ b/usb/device/core/USBDDriverCb_IfSettingChanged.c
@@ -0,0 +1,52 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBDDriverCallbacks.h"
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Notifies of a change in the currently active setting of an interface.
+/// \param interface Number of the interface whose setting has changed.
+/// \param setting New interface setting.
+//------------------------------------------------------------------------------
+void USBDDriverCallbacks_InterfaceSettingChanged(
+ unsigned char interface,
+ unsigned char setting)
+{
+ TRACE_INFO_WP("InterfaceSettingChanged ");
+}
+
diff --git a/usb/device/core/USBDDriverDescriptors.h b/usb/device/core/USBDDriverDescriptors.h
new file mode 100644
index 0000000..f1064e4
--- /dev/null
+++ b/usb/device/core/USBDDriverDescriptors.h
@@ -0,0 +1,86 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ \unit
+
+ !!!Purpose
+
+ Definition of a class for declaring USB descriptors required by the
+ device driver.
+*/
+
+#ifndef USBDDRIVERDESCRIPTORS_H
+#define USBDDRIVERDESCRIPTORS_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <usb/common/core/USBDeviceDescriptor.h>
+#include <usb/common/core/USBConfigurationDescriptor.h>
+#include <usb/common/core/USBDeviceQualifierDescriptor.h>
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// List of all descriptors used by a USB device driver. Each descriptor can
+/// be provided in two versions: full-speed and high-speed. Devices which are
+/// not high-speed capable do not need to provided high-speed descriptors and
+/// the full-speed qualifier & other speed descriptors.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to the full-speed device descriptor.
+ const USBDeviceDescriptor *pFsDevice;
+ /// Pointer to the full-speed configuration descriptor.
+ const USBConfigurationDescriptor *pFsConfiguration;
+ /// Pointer to the full-speed qualifier descriptor.
+ const USBDeviceQualifierDescriptor *pFsQualifier;
+ /// Pointer to the full-speed other speed configuration descriptor.
+ const USBConfigurationDescriptor *pFsOtherSpeed;
+ /// Pointer to the high-speed device descriptor.
+ const USBDeviceDescriptor *pHsDevice;
+ /// Pointer to the high-speed configuration descriptor.
+ const USBConfigurationDescriptor *pHsConfiguration;
+ /// Pointer to the high-speed qualifier descriptor.
+ const USBDeviceQualifierDescriptor *pHsQualifier;
+ /// Pointer to the high-speed other speed configuration descriptor.
+ const USBConfigurationDescriptor *pHsOtherSpeed;
+ /// Pointer to the list of string descriptors.
+ const unsigned char **pStrings;
+ /// Number of string descriptors in list.
+ unsigned char numStrings;
+
+} USBDDriverDescriptors;
+
+#endif //#ifndef USBDDRIVERDESCRIPTORS_H
+
diff --git a/usb/device/core/USBD_OTGHS.c b/usb/device/core/USBD_OTGHS.c
new file mode 100644
index 0000000..1795aaf
--- /dev/null
+++ b/usb/device/core/USBD_OTGHS.c
@@ -0,0 +1,1697 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBD.h"
+#include "USBDCallbacks.h"
+#include "USBDDriver.h"
+#include <board.h>
+#include <pio/pio.h>
+#include <utility/trace.h>
+#include <utility/led.h>
+#include <usb/common/core/USBConfigurationOTG.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBGenericRequest.h>
+#include <usb/common/core/USBFeatureRequest.h>
+#include <pmc/pmc.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Maximum number of endpoints interrupts.
+#define NUM_IT_MAX \
+ (AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_EPT_NBR_MAX)
+/// Maximum number of endpoint DMA interrupts
+#define NUM_IT_MAX_DMA \
+ ((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4)
+/// Bits that should be shifted to access DMA control bits.
+#define SHIFT_DMA 24
+/// Bits that should be shifted to access interrupt bits.
+#define SHIFT_INTERUPT 12
+
+/// Max size of the FMA FIFO
+#define DMA_MAX_FIFO_SIZE 32768
+
+#define EPT_VIRTUAL_SIZE 8192
+
+//------------------------------------------------------------------------------
+/// \page "Endpoint states"
+/// This page lists the endpoint states.
+/// !States
+// - UDP_ENDPOINT_DISABLED
+// - UDP_ENDPOINT_HALTED
+// - UDP_ENDPOINT_IDLE
+// - UDP_ENDPOINT_SENDING
+// - UDP_ENDPOINT_RECEIVING
+
+/// Endpoint states: Endpoint is disabled
+#define UDP_ENDPOINT_DISABLED 0
+/// Endpoint states: Endpoint is halted (i.e. STALLs every request)
+#define UDP_ENDPOINT_HALTED 1
+/// Endpoint states: Endpoint is idle (i.e. ready for transmission)
+#define UDP_ENDPOINT_IDLE 2
+/// Endpoint states: Endpoint is sending data
+#define UDP_ENDPOINT_SENDING 3
+/// Endpoint states: Endpoint is receiving data
+#define UDP_ENDPOINT_RECEIVING 4
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+
+/// Describes an ongoing transfer on a UDP endpoint.
+typedef struct
+{
+ /// Pointer to a data buffer used for emission/reception.
+ char *pData;
+ /// Number of bytes which have been written into the UDP internal FIFO
+ /// buffers.
+ volatile int buffered;
+ /// Number of bytes which have been sent/received.
+ volatile int transferred;
+ /// Number of bytes which have not been buffered/transferred yet.
+ volatile int remaining;
+ /// Optional callback to invoke when the transfer completes.
+ volatile TransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} Transfer;
+
+//------------------------------------------------------------------------------
+/// Describes the state of an endpoint of the UDP controller.
+//------------------------------------------------------------------------------
+typedef struct
+{
+ /// Current endpoint state.
+ volatile unsigned char state;
+ /// Current reception bank (0 or 1).
+ unsigned char bank;
+ /// Maximum packet size for the endpoint.
+ unsigned short size;
+ /// Describes an ongoing transfer (if current state is either
+ /// <UDP_ENDPOINT_SENDING> or <UDP_ENDPOINT_RECEIVING>)
+ Transfer transfer;
+ /// Special case for send a ZLP
+ unsigned char sendZLP;
+} Endpoint;
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+/// Holds the internal state for each endpoint of the UDP.
+static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
+/// Device current state.
+static unsigned char deviceState;
+/// Indicates the previous device state
+static unsigned char previousDeviceState;
+
+/// 7.1.20 Test Mode Support
+/// Test codes for the USB HS test mode.
+static const char test_packet_buffer[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9
+ 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8
+ 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8
+ 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8
+ 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8
+ 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK
+};
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Enable UDPHS clock
+//------------------------------------------------------------------------------
+static inline void OTGHS_EnableUsbClock( void )
+{
+
+}
+
+//------------------------------------------------------------------------------
+/// Disable UDPHS clock
+//------------------------------------------------------------------------------
+static inline void OTGHS_DisableUsbClock( void )
+{
+
+}
+
+//------------------------------------------------------------------------------
+/// Enables the transceiver of the USB controller
+//------------------------------------------------------------------------------
+static void OTGHS_EnableTransceiver(void)
+{
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the transceiver of the USB controller associated with the specified
+/// USB driver
+//------------------------------------------------------------------------------
+static void OTGHS_DisableTransceiver(void)
+{
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE;
+}
+
+//------------------------------------------------------------------------------
+/// Handles a completed transfer on the given endpoint, invoking the
+/// configured callback if any.
+/// \param bEndpoint Number of the endpoint for which the transfer has completed.
+/// \param bStatus Status code returned by the transfer operation
+//------------------------------------------------------------------------------
+static void OTGHS_EndOfTransfer( unsigned char bEndpoint, char bStatus )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+
+ // Check that endpoint was sending or receiving data
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) {
+
+ TRACE_DEBUG_WP("Eo");
+ if(pEndpoint->state == UDP_ENDPOINT_SENDING) {
+ pEndpoint->sendZLP = 0;
+ }
+ // Endpoint returns in Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Invoke callback is present
+ if (pTransfer->fCallback != 0) {
+
+ ((TransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus,
+ pTransfer->transferred,
+ pTransfer->remaining + pTransfer->buffered);
+ }
+ else {
+ TRACE_DEBUG_WP("No callBack\n\r");
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from the current tranfer buffer to the endpoint
+/// FIFO
+/// \param bEndpoint Number of the endpoint which is sending data.
+//------------------------------------------------------------------------------
+static void OTGHS_WritePayload( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+ char *pFifo;
+ signed int size;
+ unsigned int dCtr;
+
+ pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint));
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pTransfer->remaining) {
+
+ size = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->buffered += size;
+ pTransfer->remaining -= size;
+
+ // Write packet in the FIFO buffer
+ dCtr = 0;
+ while (size > 0) {
+
+ pFifo[dCtr] = *(pTransfer->pData);
+ pTransfer->pData++;
+ size--;
+ dCtr++;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from an endpoint FIFO to the current transfer buffer
+/// \param bEndpoint Endpoint number.
+/// \param wPacketSize Size of received data packet
+//------------------------------------------------------------------------------
+static void OTGHS_ReadPayload( unsigned char bEndpoint, int wPacketSize )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+ char *pFifo;
+ unsigned char dBytes=0;
+
+ pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint));
+
+ // Check that the requested size is not bigger than the remaining transfer
+ if (wPacketSize > pTransfer->remaining) {
+
+ pTransfer->buffered += wPacketSize - pTransfer->remaining;
+ wPacketSize = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->remaining -= wPacketSize;
+ pTransfer->transferred += wPacketSize;
+
+ // Retrieve packet
+ while (wPacketSize > 0) {
+
+ *(pTransfer->pData) = pFifo[dBytes];
+ pTransfer->pData++;
+ wPacketSize--;
+ dBytes++;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Received SETUP packet from endpoint 0 FIFO
+/// \param pRequest Generic USB SETUP request sent over Control endpoints
+//------------------------------------------------------------------------------
+static void OTGHS_ReadRequest( USBGenericRequest *pRequest )
+{
+ unsigned int *pData = (unsigned int *)pRequest;
+ unsigned int fifo;
+
+ fifo = (AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]);
+ *pData = fifo;
+ fifo = (AT91C_BASE_OTGHS_EPTFIFO->OTGHS_READEPT0[0]);
+ pData++;
+ *pData = fifo;
+ //TRACE_ERROR("SETUP: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n\r", pData[0],pData[1],pData[2],pData[3],pData[4],pData[5],pData[6],pData[7]);
+}
+
+//------------------------------------------------------------------------------
+/// Reset all endpoint transfer descriptors
+//------------------------------------------------------------------------------
+static void OTGHS_ResetEndpoints( void )
+{
+ Endpoint *pEndpoint;
+ Transfer *pTransfer;
+
+ unsigned char bEndpoint;
+
+ // Reset the transfer descriptor of every endpoint
+ for( bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) {
+
+ pEndpoint = &(endpoints[bEndpoint]);
+ pTransfer = &(pEndpoint->transfer);
+
+ // Reset endpoint transfer descriptor
+ pTransfer->pData = 0;
+ pTransfer->transferred = -1;
+ pTransfer->buffered = -1;
+ pTransfer->remaining = -1;
+ pTransfer->fCallback = 0;
+ pTransfer->pArgument = 0;
+
+ // Reset endpoint state
+ pEndpoint->bank = 0;
+ pEndpoint->state = UDP_ENDPOINT_DISABLED;
+ // Reset ZLP
+ pEndpoint->sendZLP = 0;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Disable all endpoints (except control endpoint 0), aborting current
+/// transfers if necessary
+//------------------------------------------------------------------------------
+static void OTGHS_DisableEndpoints( void )
+{
+ unsigned char bEndpoint;
+
+ // Disable each endpoint, terminating any pending transfer
+
+
+ // Control endpoint 0 is not disabled
+ for( bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) {
+
+ OTGHS_EndOfTransfer( bEndpoint, USBD_STATUS_ABORTED );
+ endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Endpoint interrupt handler.
+/// Handle IN/OUT transfers, received SETUP packets and STALLing
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+static void OTGHS_EndpointHandler( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+ unsigned int status = AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint];
+ unsigned short wPacketSize;
+ USBGenericRequest request;
+
+ TRACE_DEBUG_WP("E%d ", bEndpoint);
+ TRACE_DEBUG_WP("st:0x%X ", status);
+
+ // Handle interrupts
+ // IN packet sent
+ if((AT91C_BASE_OTGHS->OTGHS_DEVEPTIMR[bEndpoint] & AT91C_OTGHS_TXINI)
+ && (status & AT91C_OTGHS_TXINI )) {
+
+ TRACE_DEBUG_WP("Wr ");
+
+ // Check that endpoint was in Sending state
+ if( pEndpoint->state == UDP_ENDPOINT_SENDING ) {
+
+ if (pTransfer->buffered > 0) {
+ pTransfer->transferred += pTransfer->buffered;
+ pTransfer->buffered = 0;
+ }
+
+ if( ((pTransfer->buffered)==0)
+ &&((pTransfer->transferred)==0)
+ &&((pTransfer->remaining)==0)
+ &&(pEndpoint->sendZLP == 0)) {
+ pEndpoint->sendZLP = 1;
+ }
+
+ // End of transfer ?
+ if( (pTransfer->remaining > 0)
+ ||(pEndpoint->sendZLP == 1)) {
+
+ pEndpoint->sendZLP = 2;
+ // Transfer remaining data
+ TRACE_DEBUG_WP(" %d ", pEndpoint->size);
+ // Send next packet
+ OTGHS_WritePayload(bEndpoint);
+
+ // Send Token IN
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_TXINI;
+ // For a non-control endpoint, the FIFOCON bit must be cleared
+ // to start the transfer
+ if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+ // Send IN
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
+ }
+ }
+ else {
+
+ TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining);
+
+ TRACE_DEBUG_WP(" %d ", pTransfer->transferred);
+
+ // Disable interrupt if this is not a control endpoint
+ if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+
+ }
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI;
+ OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ pEndpoint->sendZLP = 0;
+ }
+ }
+ else {
+ TRACE_DEBUG("Error Wr %d", pEndpoint->sendZLP);
+ }
+ }
+
+ // OUT packet received
+ if( AT91C_OTGHS_RXOUT == (status & AT91C_OTGHS_RXOUT) ) {
+
+ // Check that the endpoint is in Receiving state
+ if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
+
+ // Check if an ACK has been received on a Control endpoint
+ if( ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ == AT91C_OTGHS_EPT_TYPE_CTL_EPT)
+ && (0 == (status & AT91C_OTGHS_BYCT)) ) {
+
+ // Control endpoint, 0 bytes received
+ // Acknowledge the data and finish the current transfer
+ TRACE_DEBUG_WP("Ack ");
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ //OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Check if the data has been STALLed
+ else if( AT91C_OTGHS_STALL == (status & AT91C_OTGHS_STALL)) {
+
+ // Discard STALLed data
+ TRACE_DEBUG_WP("Discard ");
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ }
+ else {
+ // NAK the data
+ TRACE_DEBUG_WP("Nak ");
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+ }
+ }
+ else {
+
+ // Endpoint is in Read state
+ // Retrieve data and store it into the current transfer buffer
+ wPacketSize = (unsigned short) ((status >> 20) & 0x7FF);
+
+ //TRACE_ERROR_WP("out:%d ", wPacketSize);
+ OTGHS_ReadPayload(bEndpoint, wPacketSize);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXOUT;
+ if((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
+ }
+
+ // Check if the transfer is finished
+ if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_RXOUT;
+
+ // Disable interrupt if this is not a control endpoint
+ if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = 1<<SHIFT_INTERUPT<<bEndpoint;
+ }
+ //TRACE_ERROR_WP("Y ");
+ OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ }
+ }
+
+ // STALL sent
+ if( AT91C_OTGHS_STALL == (status & AT91C_OTGHS_STALL) ) {
+
+ TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint);
+
+ // Acknowledge the stall flag
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_STALL;
+
+ // If the endpoint is not halted, clear the STALL condition
+ if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
+
+ TRACE_WARNING("_ " );
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ }
+ }
+
+ // SETUP packet received
+ if( AT91C_OTGHS_RXSTP == (status & AT91C_OTGHS_RXSTP) ) {
+
+ TRACE_DEBUG_WP("Stp ");
+
+ // If a transfer was pending, complete it
+ // Handles the case where during the status phase of a control write
+ // transfer, the host receives the device ZLP and ack it, but the ack
+ // is not received by the device
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+
+ // Copy the setup packet
+ OTGHS_ReadRequest(&request);
+
+ // Acknowledge setup packet
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_RXSTP;
+
+ // Forward the request to the upper layer
+ USBDCallbacks_RequestReceived(&request);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Interrupt service routine
+//------------------------------------------------------------------------------
+#ifdef DMA
+//----------------------------------------------------------------------------
+/// Endpoint DMA interrupt handler.
+/// This function (ISR) handles dma interrupts
+/// \param bEndpoint Index of endpoint
+//----------------------------------------------------------------------------
+static void OTGHS_DmaHandler( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+ int justTransferred;
+ unsigned int status;
+ unsigned char result = USBD_STATUS_SUCCESS;
+
+ status = AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS;
+ TRACE_DEBUG_WP("Dma Ept%d ", bEndpoint);
+
+ // Disable DMA interrupt to avoid receiving 2 interrupts (B_EN and TR_EN)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL &=
+ ~(unsigned int)(AT91C_OTGHS_END_TR_EN | AT91C_OTGHS_END_B_EN);
+
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = (1<<SHIFT_DMA<<bEndpoint);
+
+ if( AT91C_OTGHS_END_BF_ST == (status & AT91C_OTGHS_END_BF_ST) ) {
+
+ TRACE_DEBUG_WP("EndBuffer ");
+
+ // BUFF_COUNT holds the number of untransmitted bytes.
+ // BUFF_COUNT is equal to zero in case of good transfer
+ justTransferred = pTransfer->buffered
+ - ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16);
+ pTransfer->transferred += justTransferred;
+
+ pTransfer->buffered = ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16);
+
+ pTransfer->remaining -= justTransferred;
+
+ TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining);
+
+ if( (pTransfer->remaining + pTransfer->buffered) > 0 ) {
+
+ // Prepare an other transfer
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS =
+ (unsigned int)((pTransfer->pData) + (pTransfer->transferred));
+
+ // Clear unwanted interrupts
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS;
+
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1 << SHIFT_DMA << bEndpoint);
+ // DMA config for receive the good size of buffer, or an error buffer
+
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL =
+ ( ((pTransfer->buffered << 16) & AT91C_OTGHS_BUFF_COUNT)
+ | AT91C_OTGHS_END_TR_EN
+ | AT91C_OTGHS_END_TR_IT
+ | AT91C_OTGHS_END_B_EN
+ | AT91C_OTGHS_END_BUFFIT
+ | AT91C_OTGHS_CHANN_ENB );
+ }
+ }
+ else if( AT91C_OTGHS_END_TR_ST == (status & AT91C_OTGHS_END_TR_ST) ) {
+
+ TRACE_DEBUG_WP("EndTransf ");
+
+ pTransfer->transferred = pTransfer->buffered
+ - ((status & (unsigned int)AT91C_OTGHS_BUFF_COUNT) >> 16);
+ pTransfer->remaining = 0;
+ TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining);
+ }
+ else {
+
+ TRACE_ERROR("OTGHS_DmaHandler: Error (0x%08X)\n\r", status);
+ result = USBD_STATUS_ABORTED;
+ }
+
+ // Invoke callback
+ if( pTransfer->remaining == 0 ) {
+
+ TRACE_DEBUG_WP("EOT ");
+ OTGHS_EndOfTransfer(bEndpoint, result);
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// USB device interrupt handler
+/// Manages device resume, suspend, end of bus reset.
+/// Forwards endpoint interrupts to the appropriate handler.
+//------------------------------------------------------------------------------
+void USBD_IrqHandler(void)
+{
+ unsigned int status;
+ unsigned char numIT;
+
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Set(USBD_LEDUSB);
+ }
+
+#ifndef OTG_PROJECT
+ // Get interrupts status
+ status = AT91C_BASE_OTGHS->OTGHS_SR & AT91C_BASE_OTGHS->OTGHS_CTRL & 0xFF;
+ while (status != 0) {
+ //TRACE_ERROR_WP("~");
+ if((status&AT91C_OTGHS_VBUSTI)==AT91C_OTGHS_VBUSTI) {
+ TRACE_DEBUG_WP("__VBus\n\r");
+
+ USBD_Connect();
+
+ // Acknowledge the interrupt
+ AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_VBUSTI;
+ }
+
+ // Don't treat others interrupt for this time
+ AT91C_BASE_OTGHS->OTGHS_SCR = AT91C_OTGHS_IDT | AT91C_OTGHS_SRP
+ | AT91C_OTGHS_VBERR | AT91C_OTGHS_BCERR
+ | AT91C_OTGHS_ROLEEX | AT91C_OTGHS_HNPERR
+ | AT91C_OTGHS_STO;
+
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_IDT;
+
+ status = AT91C_BASE_OTGHS->OTGHS_SR & AT91C_BASE_OTGHS->OTGHS_CTRL & 0xFF;
+ }
+#endif
+
+ // Get OTG Device interrupts status
+ status = AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_BASE_OTGHS->OTGHS_DEVIMR;
+ //TRACE_ERROR_WP("S=0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVISR );
+ //TRACE_ERROR_WP("M=0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVIMR );
+ while (status != 0) {
+ //TRACE_ERROR_WP("=");
+ // Start Of Frame (SOF)
+ if((status&AT91C_OTGHS_SOF)==AT91C_OTGHS_SOF) {
+ TRACE_DEBUG_WP("SOF ");
+
+ // Invoke the SOF callback
+ //USB_StartOfFrameCallback();
+
+ // Acknowledge interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SOF;
+ status &= ~(unsigned int)AT91C_OTGHS_SOF;
+ }
+
+ // Suspend
+ // This interrupt is always treated last (hence the '==')
+ else if (status == AT91C_OTGHS_SUSP) {
+
+ TRACE_DEBUG_WP("S");
+
+ // The device enters the Suspended state
+ // MCK + UDPCK must be off
+ // Pull-Up must be connected
+ // Transceiver must be disabled
+
+ LED_Clear(USBD_LEDUSB);
+
+ // Enable wakeup
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_EORST | AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM;
+
+ // Acknowledge interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_SUSP;
+ previousDeviceState = deviceState;
+ deviceState = USBD_STATE_SUSPENDED;
+ OTGHS_DisableTransceiver();
+ OTGHS_DisableUsbClock();
+ // Invoke the Suspend callback
+ USBDCallbacks_Suspended();
+ }
+
+ // Resume
+ else if( ((status & AT91C_OTGHS_WAKEUP) != 0) // line activity
+ || ((status & AT91C_OTGHS_EORSM) != 0)) { // pc wakeup
+
+ // Invoke the Resume callback
+ USBDCallbacks_Resumed();
+
+ TRACE_DEBUG_WP("R");
+
+ OTGHS_EnableUsbClock();
+ OTGHS_EnableTransceiver();
+
+ // The device enters Configured state
+ // MCK + UDPCK must be on
+ // Pull-Up must be connected
+ // Transceiver must be enabled
+
+ deviceState = previousDeviceState;
+
+ AT91C_BASE_OTGHS->OTGHS_DEVICR =
+ (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM | AT91C_OTGHS_SUSP);
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (AT91C_OTGHS_EORST | AT91C_OTGHS_SUSP);
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = (AT91C_OTGHS_WAKEUP | AT91C_OTGHS_EORSM);
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = AT91C_OTGHS_WAKEUP;
+
+ }
+
+ // End of bus reset
+ else if ((status & AT91C_OTGHS_EORST) == AT91C_OTGHS_EORST) {
+
+ TRACE_DEBUG_WP("EoB ");
+
+ // The device enters the Default state
+ deviceState = USBD_STATE_DEFAULT;
+ // MCK + UDPCK are already enabled
+ // Pull-Up is already connected
+ // Transceiver must be enabled
+ // Endpoint 0 must be enabled
+
+ OTGHS_EnableTransceiver();
+ USBDDriver_clearOTGFeatures();
+
+ // The device leaves the Address & Configured states
+ OTGHS_ResetEndpoints();
+ OTGHS_DisableEndpoints();
+ USBD_ConfigureEndpoint(0);
+
+ // Flush and enable the Suspend interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_WAKEUP | AT91C_OTGHS_SUSP;
+
+ //// Enable the Start Of Frame (SOF) interrupt if needed
+ //if (pCallbacks->startOfFrame != 0)
+ //{
+ // AT91C_BASE_OTGHS->OTGHS_DEVIER |= AT91C_OTGHS_SOF;
+ //}
+
+ // Invoke the Reset callback
+ USBDCallbacks_Reset();
+
+ // Acknowledge end of bus reset interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_EORST;
+ }
+
+ // Handle upstream resume interrupt
+ else if (status & AT91C_OTGHS_UPRSM) {
+
+ TRACE_DEBUG_WP("ExtRes ");
+
+ // - Acknowledge the IT
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = AT91C_OTGHS_UPRSM;
+ }
+
+ // Endpoint interrupts
+ else {
+#ifndef DMA
+
+ // Handle endpoint interrupts
+ for (numIT = 0; numIT < NUM_IT_MAX; numIT++) {
+
+ if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) {
+
+ OTGHS_EndpointHandler(numIT);
+ }
+ }
+#else
+ // Handle endpoint control interrupt
+ if ((status & (1 << SHIFT_INTERUPT << 0)) != 0) {
+
+ OTGHS_EndpointHandler( 0 );
+ }
+ else {
+
+ numIT = 1;
+ while((status&(0x7E<<SHIFT_DMA)) != 0) {
+
+ // Check if endpoint has a pending interrupt
+ if ((status & (1 << SHIFT_DMA << numIT)) != 0) {
+
+ OTGHS_DmaHandler(numIT);
+ status &= ~(1 << SHIFT_DMA << numIT);
+ if (status != 0) {
+
+ TRACE_INFO_WP("\n\r - ");
+ }
+ }
+ numIT++;
+ }
+ }
+#endif
+ }
+
+ // Retrieve new interrupt status
+ status = AT91C_BASE_OTGHS->OTGHS_DEVISR & AT91C_BASE_OTGHS->OTGHS_DEVIMR;
+
+ TRACE_DEBUG_WP("\n\r");
+
+ if (status != 0) {
+
+ TRACE_DEBUG_WP(" - ");
+ }
+ }
+
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Clear(USBD_LEDUSB);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configure an endpoint with the provided endpoint descriptor
+/// \param pDdescriptor Pointer to the endpoint descriptor
+//------------------------------------------------------------------------------
+void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
+
+{
+ Endpoint *pEndpoint;
+ unsigned char bEndpoint;
+ unsigned char bType;
+ unsigned char bEndpointDir;
+ unsigned char bSizeEpt = 0;
+
+ // NULL descriptor -> Control endpoint 0
+ if (pDescriptor == 0) {
+
+ bEndpoint = 0;
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType = USBEndpointDescriptor_CONTROL;
+ bEndpointDir = 0;
+ pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
+ pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
+ }
+ else {
+
+ // The endpoint number
+ bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
+ pEndpoint = &(endpoints[bEndpoint]);
+ // Transfer type: Control, Isochronous, Bulk, Interrupt
+ bType = USBEndpointDescriptor_GetType(pDescriptor);
+ // Direction, ignored for control endpoints
+ bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
+ pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
+ pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
+ }
+
+ // Abort the current transfer is the endpoint was configured and in
+ // Write or Read state
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) {
+
+ OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
+ }
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Disable endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI
+ | AT91C_OTGHS_RXOUT
+ | AT91C_OTGHS_RXSTP
+ | AT91C_OTGHS_NAKOUT
+ | AT91C_OTGHS_NAKIN
+ | AT91C_OTGHS_OVERFL
+ | AT91C_OTGHS_STALL
+ | AT91C_OTGHS_SHRTPACK
+ | AT91C_OTGHS_MADATA
+ | AT91C_OTGHS_DATAX
+ | AT91C_OTGHS_ERRTRANS
+ | AT91C_OTGHS_NBUSYBK
+ | AT91C_OTGHS_FIFOCON
+ | AT91C_OTGHS_EPDISHDMA
+ | AT91C_OTGHS_NYETDIS
+ | AT91C_OTGHS_STALLRQ;
+
+ // Reset Endpoint Fifos
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<<bEndpoint<<16);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(1<<bEndpoint<<16);
+
+ // Configure endpoint
+ if( pEndpoint->size <= 8 ) {
+ bSizeEpt = 0;
+ }
+ else if ( pEndpoint->size <= 16 ) {
+ bSizeEpt = 1;
+ }
+ else if ( pEndpoint->size <= 32 ) {
+ bSizeEpt = 2;
+ }
+ else if ( pEndpoint->size <= 64 ) {
+ bSizeEpt = 3;
+ }
+ else if ( pEndpoint->size <= 128 ) {
+ bSizeEpt = 4;
+ }
+ else if ( pEndpoint->size <= 256 ) {
+ bSizeEpt = 5;
+ }
+ else if ( pEndpoint->size <= 512 ) {
+ bSizeEpt = 6;
+ }
+ else if ( pEndpoint->size <= 1024 ) {
+ bSizeEpt = 7;
+ } //else {
+ // sizeEpt = 0; // control endpoint
+ //}
+
+ // Enable endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<<bEndpoint);
+
+ // Configure endpoint
+ if (bType == USBEndpointDescriptor_CONTROL) {
+
+ // Enable endpoint IT for control endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = 1<<SHIFT_INTERUPT<<bEndpoint;
+ }
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] = (bSizeEpt << 4)
+ | (bEndpointDir << 8)
+ | (bType << 11)
+ | (((pEndpoint->bank)-1) << 2);
+
+ if (bType == USBEndpointDescriptor_CONTROL) {
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RXSTP;
+ }
+#ifdef DMA
+ else {
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] |= AT91C_OTGHS_AUTOSW;
+ }
+#endif
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_NYETDIS;// with nyet
+ //AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_NYETDIS; // without nyet
+
+ // Check if the configuration is ok
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] |= AT91C_OTGHS_ALLOC;
+ if((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint]&AT91C_OTGHS_CFGOK)==0) {
+
+ TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint);
+ TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt);
+ TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir);
+ TRACE_ERROR("PB bType: 0x%X\n\r", bType);
+ TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank);
+ TRACE_ERROR("PB OTGHS_EPTCFG: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint]);
+ for(;;);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sends data through an USB endpoint (IN)
+/// Sets up the transfer descriptor, write one or two data payloads
+/// (depending on the number of FIFO banks for the endpoint) and then
+/// starts the actual transfer. The operation is complete when all
+/// the data has been sent.
+/// \param bEndpoint Index of endpoint
+/// \param *pData Data to be written
+/// \param dLength Data length to be send
+/// \param fCallback Callback to be call after the success command
+/// \param *pArgument Callback argument
+/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+char USBD_Write( unsigned char bEndpoint,
+ const void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+//unsigned char i;
+//unsigned char * data;
+
+ // Return if the endpoint is not in IDLE state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength);
+ pEndpoint->sendZLP = 0;
+ // Setup the transfer descriptor
+ pTransfer->pData = (void *) pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+ // Send one packet
+ pEndpoint->state = UDP_ENDPOINT_SENDING;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])) {
+#endif
+ // Enable endpoint IT
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_TXINI;
+
+#ifdef DMA
+ }
+ else {
+ if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) {
+ TRACE_FATAL("Endpoint has no DMA\n\r");
+ }
+ if( pTransfer->remaining == 0 ) {
+
+ // DMA not handle ZLP
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_TXINI;
+ // For a non-control endpoint, the FIFOCON bit must be cleared
+ // to start the transfer
+ if ((AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])
+ != AT91C_OTGHS_EPT_TYPE_CTL_EPT) {
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_FIFOCON;
+ }
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_TXINI;
+
+ // Enable endpoint IT
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+ else {
+ // Others endpoints (not control)
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ // Transfer the max
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ // Transfer the good size
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ TRACE_DEBUG_WP("\n\r_WR:%d ", pTransfer->remaining );
+ TRACE_DEBUG_WP("B:%d ", pTransfer->buffered );
+ TRACE_DEBUG_WP("T:%d ", pTransfer->transferred );
+
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int)(pTransfer->pData);
+
+ // Clear unwanted interrupts
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS;
+
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
+ // DMA config
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL =
+ (((pTransfer->buffered<<16)&AT91C_OTGHS_BUFF_LENGTH)
+ | AT91C_OTGHS_END_B_EN
+ | AT91C_OTGHS_END_BUFFIT
+ | AT91C_OTGHS_CHANN_ENB);
+ }
+ }
+#endif
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Reads incoming data on an USB endpoint (OUT)
+/// \param bEndpoint Index of endpoint
+/// \param *pData Data to be readen
+/// \param dLength Data length to be receive
+/// \param fCallback Callback to be call after the success command
+/// \param *pArgument Callback argument
+/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+char USBD_Read( unsigned char bEndpoint,
+ void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = &(pEndpoint->transfer);
+
+ // Return if the endpoint is not in IDLE state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength);
+ //TRACE_ERROR_WP("Read%d(%d) ", bEndpoint, dLength);
+
+ // Endpoint enters Receiving state
+ pEndpoint->state = UDP_ENDPOINT_RECEIVING;
+
+ // Set the transfer descriptor
+ pTransfer->pData = pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if (AT91C_OTGHS_EPT_TYPE_CTL_EPT == (AT91C_OTGHS_EPT_TYPE & AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint])) {
+#endif
+ // Control endpoint
+ // Enable endpoint IT
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<<SHIFT_INTERUPT<<bEndpoint);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RXOUT;
+#ifdef DMA
+ }
+ else {
+ if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) {
+ TRACE_FATAL("Endpoint has no DMA\n\r");
+ }
+ TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength);
+
+ // Others endpoints (not control)
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ // Transfer the max
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ // Transfer the good size
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMAADDRESS = (unsigned int)(pTransfer->pData);
+
+ // Clear unwanted interrupts
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMASTATUS;
+
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = (1<<SHIFT_DMA<<bEndpoint);
+
+ TRACE_DEBUG_WP("\n\r_RR:%d ", pTransfer->remaining );
+ TRACE_DEBUG_WP("B:%d ", pTransfer->buffered );
+ TRACE_DEBUG_WP("T:%d ", pTransfer->transferred );
+
+ // DMA config
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL = 0; // raz
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[bEndpoint].OTGHS_DEVDMACONTROL =
+ (((pTransfer->buffered<<16)&AT91C_OTGHS_BUFF_LENGTH)
+ | AT91C_OTGHS_END_TR_EN
+ | AT91C_OTGHS_END_TR_IT
+ | AT91C_OTGHS_END_B_EN
+ | AT91C_OTGHS_END_BUFFIT
+ | AT91C_OTGHS_CHANN_ENB);
+ }
+#endif
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Put endpoint into Halt state
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+void USBD_Halt( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ TRACE_INFO("usbd_Halt%d ", bEndpoint);
+ //TRACE_ERROR("usbd_Halt%d ", bEndpoint);
+
+ // Check that endpoint is enabled and not already in Halt state
+ if( (pEndpoint->state != UDP_ENDPOINT_DISABLED)
+ && (pEndpoint->state != UDP_ENDPOINT_HALTED) ) {
+
+ TRACE_INFO("Halt%d ", bEndpoint);
+
+ // Abort the current transfer if necessary
+ OTGHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+
+ pEndpoint->state = UDP_ENDPOINT_HALTED;
+ // Put endpoint into Halt state
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALL;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the Halt feature on the given endpoint.
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+void USBD_Unhalt( unsigned char bEndpoint )
+{
+ unsigned int cfgSav;
+
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check if the endpoint is enabled
+ //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+
+ TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
+ //TRACE_ERROR("Unhalt%d ", bEndpoint);
+
+ // Return endpoint to Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ cfgSav = AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint];
+
+ // Reset Endpoint Fifos
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (1<<bEndpoint<<16);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(1<<bEndpoint<<16);
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[bEndpoint] = cfgSav;
+
+ if((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[bEndpoint]&AT91C_OTGHS_CFGOK)==0) {
+
+ TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint);
+ for(;;);
+ }
+
+ // Reset data-toggle
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_RSTDT;
+
+ // Clear FORCESTALL flag
+ // Disable stall on endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[bEndpoint] = AT91C_OTGHS_STALLRQ;
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[bEndpoint] = AT91C_OTGHS_STALL;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current Halt status of an endpoint.
+/// \param bEndpoint Index of endpoint
+/// \return 1 if the endpoint is currently halted; otherwise 0
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHalted( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ unsigned char status = 0;
+
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+ status = 1;
+ }
+ return( status );
+}
+
+//------------------------------------------------------------------------------
+/// IS High Speed device working in High Speed ?
+/// \return 1 if the device is in High Speed; otherwise 0 (Full Speed)
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHighSpeed( void )
+{
+ unsigned char status = 0;
+
+ if(AT91C_OTGHS_SPEED_SR_HS == (AT91C_BASE_OTGHS->OTGHS_SR & (0x03<<12))) {
+ // High Speed
+ TRACE_DEBUG_WP("High Speed\n\r");
+ status = 1;
+ }
+ else {
+ TRACE_DEBUG_WP("Full Speed\n\r");
+ }
+ return( status );
+}
+
+//------------------------------------------------------------------------------
+/// Causes the endpoint to acknowledge the next received packet with a STALL
+/// handshake.
+/// Further packets are then handled normally.
+/// \param bEndpoint Index of endpoint
+/// \return Operation result code: USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+unsigned char USBD_Stall( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint);
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Stall%d ", bEndpoint);
+
+ // Sends a STALL handshake for the next host request.
+ // A STALL handshake will be sent for each following request until a SETUP
+ // or a Clear Halt Feature occurs for this endpoint.
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIER[bEndpoint] = AT91C_OTGHS_STALLRQ|AT91C_OTGHS_RXSTP;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Activates a remote wakeup procedure
+//------------------------------------------------------------------------------
+void USBD_RemoteWakeUp(void)
+{
+ TRACE_DEBUG_WP("Remote WakeUp\n\r");
+
+ // Device is currently suspended
+ if (deviceState == USBD_STATE_SUSPENDED) {
+
+ TRACE_DEBUG_WP("RW\n\r");
+ OTGHS_EnableUsbClock();
+ OTGHS_EnableTransceiver();
+
+ // Activates a remote wakeup
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_RMWKUP;
+ }
+ // Device is NOT suspended
+ else {
+
+ TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the device address
+/// \param address Adress to be set
+//------------------------------------------------------------------------------
+void USBD_SetAddress( unsigned char address )
+{
+ TRACE_DEBUG_WP("SetAddr(%d) ", address);
+
+ // Set address
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_UADD;
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= address & AT91C_OTGHS_UADD;
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_ADDEN;
+
+ // If the address is 0, the device returns to the Default state
+ if (address == 0) {
+ deviceState = USBD_STATE_DEFAULT;
+ }
+ // If the address is non-zero, the device enters the Address state
+ else {
+ deviceState = USBD_STATE_ADDRESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Changes the device state from Address to Configured, or from Configured
+/// to Address.
+/// This method directly access the last received SETUP packet to decide on
+/// what to do.
+/// \param cfgnum configuration number
+//------------------------------------------------------------------------------
+void USBD_SetConfiguration( unsigned char cfgnum )
+{
+ TRACE_DEBUG_WP("SetCfg(%d) ", cfgnum);
+
+ // Check the request
+ if( cfgnum != 0 ) {
+
+ // Enter Configured state
+ deviceState = USBD_STATE_CONFIGURED;
+ }
+ // If the configuration number is zero, the device goes back to the Address
+ // state
+ else {
+
+ // Go back to Address state
+ deviceState = USBD_STATE_ADDRESS;
+
+ // Abort all transfers
+ OTGHS_DisableEndpoints();
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Enables the pull-up on the D+ line to connect the device to the USB.
+//------------------------------------------------------------------------------
+void USBD_Connect( void )
+{
+ TRACE_DEBUG_WP("Conn ");
+#if defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_DETACH;
+#else
+ #error "not defined"
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disables the pull-up on the D+ line to disconnect the device from the bus.
+//------------------------------------------------------------------------------
+void USBD_Disconnect( void )
+{
+ TRACE_DEBUG_WP("Disc ");
+#if defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_DETACH;
+
+#else
+ #error "not defined"
+#endif
+ // Device returns to the Powered state
+ if (deviceState > USBD_STATE_POWERED) {
+
+ deviceState = USBD_STATE_POWERED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Certification test for High Speed device.
+/// \param bIndex Test to be done
+//------------------------------------------------------------------------------
+void USBD_Test( unsigned char bIndex )
+{
+ char *pFifo;
+ unsigned char i;
+
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR &= ~(unsigned int)AT91C_OTGHS_SUSP;
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_SPDCONF_HS; // remove suspend ?
+
+ switch( bIndex ) {
+ case USBFeatureRequest_TESTPACKET:
+ TRACE_DEBUG_WP("TEST_PACKET ");
+
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[1].OTGHS_DEVDMACONTROL = 0; // raz
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[2].OTGHS_DEVDMACONTROL = 0; // raz
+
+ // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[2] = AT91C_OTGHS_EPT_SIZE_64
+ | AT91C_OTGHS_EPT_DIR_IN
+ | AT91C_OTGHS_EPT_TYPE_BUL_EPT
+ | AT91C_OTGHS_BK_NUMBER_1;
+ // Check if the configuration is ok
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[2] |= AT91C_OTGHS_ALLOC;
+ while((AT91C_BASE_OTGHS->OTGHS_DEVEPTISR[2]&AT91C_OTGHS_CFGOK)==0) {
+ }
+
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT |= AT91C_OTGHS_EPEN2;
+
+ // Write FIFO
+ pFifo = (char*)((unsigned int *)AT91C_BASE_OTGHS_EPTFIFO + (EPT_VIRTUAL_SIZE * 2));
+ for( i=0; i<sizeof(test_packet_buffer); i++) {
+ pFifo[i] = test_packet_buffer[i];
+ }
+ // Tst PACKET
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTPCKT;
+ // Send packet
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[2] = AT91C_OTGHS_TXINI;
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[2] = AT91C_OTGHS_FIFOCON;
+ break;
+
+ case USBFeatureRequest_TESTJ:
+ TRACE_DEBUG_WP("TEST_J ");
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTJ;
+ break;
+
+ case USBFeatureRequest_TESTK:
+ TRACE_DEBUG_WP("TEST_K ");
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL |= AT91C_OTGHS_TSTK;
+ break;
+
+ case USBFeatureRequest_TESTSE0NAK:
+ TRACE_DEBUG_WP("TEST_SEO_NAK ");
+ AT91C_BASE_OTGHS->OTGHS_DEVIDR = 0xFFFFFFFF;
+ break;
+
+ case USBFeatureRequest_TESTSENDZLP:
+ //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {}
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTICR[0] = AT91C_OTGHS_TXINI;
+ //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {}
+ TRACE_DEBUG_WP("SEND_ZLP ");
+ break;
+ }
+ TRACE_DEBUG_WP("\n\r");
+}
+
+//------------------------------------------------------------------------------
+/// Initializes the specified USB driver
+/// This function initializes the current FIFO bank of endpoints,
+/// configures the pull-up and VBus lines, disconnects the pull-up and
+/// then trigger the Init callback.
+//------------------------------------------------------------------------------
+void USBD_Init(void)
+{
+ // forceFS must not be used !
+ unsigned int i;
+
+ TRACE_DEBUG_WP("USBD Init()\n\r");
+
+ // Enable USB macro
+ *AT91C_OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;
+
+ // Automatic mode speed for device
+ *AT91C_OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_FS; // Normal mode
+
+ *AT91C_OTGHS_DEVCTRL &= ~(unsigned int)( AT91C_OTGHS_LS | AT91C_OTGHS_TSTJ
+ | AT91C_OTGHS_TSTK | AT91C_OTGHS_TSTPCKT
+ | AT91C_OTGHS_OPMODE2 ); // Normal mode
+
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL = 0;
+ AT91C_BASE_OTGHS->OTGHS_HSTCTRL = 0;
+
+ // Enable OTG pad
+ *AT91C_OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;
+
+ // Enable clock OTG pad
+ *AT91C_OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;
+
+ //Usb_disable();
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_USBECTRL;
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_OTGPADE;
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_FRZCLKCTRL;
+ //Usb_enable();
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;
+ //Usb_select_device();
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_UIDE;
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIMOD;
+
+ // Device is in the Attached state
+ deviceState = USBD_STATE_SUSPENDED;
+ previousDeviceState = USBD_STATE_POWERED;
+
+
+ PMC_EnablePeripheral(AT91C_ID_OTGHS);
+
+ // Reset endpoint structures
+ OTGHS_ResetEndpoints();
+
+ // Enables the USB Clock
+ OTGHS_EnableUsbClock();
+
+ //926C
+ // Enable USB macro and clear all other bit
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;
+ AT91C_BASE_OTGHS->OTGHS_CTRL = AT91C_OTGHS_USBECTRL;
+
+ // Configure the pull-up on D+ and disconnect it
+ USBD_Disconnect();
+
+ // Enable clock OTG pad
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;
+ TRACE_DEBUG("AT91C_OTGHS_CTRL: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_CTRL );
+
+ // Clear General IT
+ AT91C_BASE_OTGHS->OTGHS_SCR = 0x01FF;
+
+ // Clear OTG Device IT
+ AT91C_BASE_OTGHS->OTGHS_DEVICR = 0xFF;
+
+ // Clear OTG Host IT
+ AT91C_BASE_OTGHS->OTGHS_HSTICR = 0x7F;
+
+ // Reset all Endpoints Fifos
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT |= (0x7F<<16);
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(unsigned int)(0x7F<<16);
+
+ // Disable all endpoints
+ AT91C_BASE_OTGHS->OTGHS_DEVEPT &= ~(unsigned int)0x7F;
+
+ AT91C_BASE_OTGHS->OTGHS_TSTA2 = 0;
+
+ // Device is in the Attached state
+ deviceState = USBD_STATE_SUSPENDED;
+ previousDeviceState = USBD_STATE_POWERED;
+
+ // Automatic mode speed for device
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_FS;
+ // Force Full Speed mode for device
+ //*AT91C_OTGHS_DEVCTRL = AT91C_OTGHS_SPDCONF_FS;
+ // Force High Speed mode for device
+ //*AT91C_OTGHS_DEVCTRL = AT91C_OTGHS_SPDCONF_HS;
+
+ AT91C_BASE_OTGHS->OTGHS_DEVCTRL &= ~(unsigned int)( AT91C_OTGHS_LS
+ | AT91C_OTGHS_TSTJ
+ | AT91C_OTGHS_TSTK
+ | AT91C_OTGHS_TSTPCKT
+ | AT91C_OTGHS_OPMODE2 );
+
+
+ // Automatic mode speed for host
+ AT91C_BASE_OTGHS->OTGHS_HSTCTRL &= ~(unsigned int)AT91C_OTGHS_SPDCONF_HST_FS;
+ // Force Full Speed mode for host
+ //AT91C_BASE_OTGHS->OTGHS_HSTCTRL = AT91C_OTGHS_SPDCONF_HST_FS;
+ // Force High Speed mode for host
+ //*AT91C_BASE_OTGHS->OTGHS_HSTCTRL = AT91C_OTGHS_SPDCONF_HST_HS;
+
+ // Enable USB macro
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_USBECTRL;
+
+ // Enable the UID pin select
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_UIDE;
+
+ // Enable OTG pad
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_OTGPADE;
+
+ // Enable clock OTG pad
+ AT91C_BASE_OTGHS->OTGHS_CTRL &= ~(unsigned int)AT91C_OTGHS_FRZCLKCTRL;
+
+
+ // With OR without DMA !!!
+ // Initialization of DMA
+ for( i=1; i<=(unsigned int)((AT91C_BASE_OTGHS->OTGHS_IPFEATURES & AT91C_OTGHS_DMA_CHANNEL_NBR)>>4); i++ ) {
+
+ // RESET endpoint canal DMA:
+ // DMA stop channel command
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
+
+ // Disable endpoint
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTIDR[i] = 0XFFFFFFFF;
+
+ // Reset endpoint config
+ AT91C_BASE_OTGHS->OTGHS_DEVEPTCFG[i] = 0;
+
+ // Reset DMA channel (Buff count and Control field)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0x02; // NON STOP command
+
+ // Reset DMA channel 0 (STOP)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMACONTROL = 0; // STOP command
+
+ // Clear DMA channel status (read the register for clear it)
+ AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS = AT91C_BASE_OTGHS->OTGHS_DEVDMA[i].OTGHS_DEVDMASTATUS;
+
+ }
+
+
+ // Configure interrupts
+ USBDCallbacks_Initialized();
+
+ AT91C_BASE_OTGHS->OTGHS_CTRL |= AT91C_OTGHS_VBUSTI;
+
+ TRACE_DEBUG("AT91C_OTGHS_CTRL: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_CTRL );
+ TRACE_DEBUG("AT91C_OTGHS_SR: 0x%X\n\r", AT91C_BASE_OTGHS->OTGHS_SR );
+
+ AT91C_BASE_OTGHS->OTGHS_DEVIER = AT91C_OTGHS_WAKEUP;
+
+ TRACE_DEBUG("NUM_IT_MAX_DMA: 0x%X\n\r", NUM_IT_MAX_DMA );
+ TRACE_DEBUG("NUM_IT_MAX: 0x%X\n\r", NUM_IT_MAX );
+
+}
+
+
+//------------------------------------------------------------------------------
+/// Returns the current state of the USB device.
+/// \return Device current state.
+//------------------------------------------------------------------------------
+unsigned char USBD_GetState( void )
+{
+ return deviceState;
+}
+
diff --git a/usb/device/core/USBD_UDP.c b/usb/device/core/USBD_UDP.c
new file mode 100644
index 0000000..437d185
--- /dev/null
+++ b/usb/device/core/USBD_UDP.c
@@ -0,0 +1,1692 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+/**
+ \unit
+
+ !!!Purpose
+
+ Implementation of USB device functions on a UDP controller.
+
+ See "USBD API Methods".
+*/
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBD.h"
+#include "USBDCallbacks.h"
+#include <board.h>
+#include <pio/pio.h>
+#include <utility/trace.h>
+#include <utility/led.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBGenericRequest.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "UDP register field values"
+///
+/// This page lists the initialize values of UDP registers.
+///
+/// !Values
+/// - UDP_RXDATA
+
+/// Bit mask for both banks of the UDP_CSR register.
+#define UDP_RXDATA (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "Endpoint states"
+///
+/// This page lists the endpoint states.
+///
+/// !States
+// - UDP_ENDPOINT_DISABLED
+// - UDP_ENDPOINT_HALTED
+// - UDP_ENDPOINT_IDLE
+// - UDP_ENDPOINT_SENDING
+// - UDP_ENDPOINT_RECEIVING
+// - UDP_ENDPOINT_SENDINGM
+// - UDP_ENDPOINT_RECEIVINGM
+
+/// Endpoint states: Endpoint is disabled
+#define UDP_ENDPOINT_DISABLED 0
+/// Endpoint states: Endpoint is halted (i.e. STALLs every request)
+#define UDP_ENDPOINT_HALTED 1
+/// Endpoint states: Endpoint is idle (i.e. ready for transmission)
+#define UDP_ENDPOINT_IDLE 2
+/// Endpoint states: Endpoint is sending data
+#define UDP_ENDPOINT_SENDING 3
+/// Endpoint states: Endpoint is receiving data
+#define UDP_ENDPOINT_RECEIVING 4
+/// Endpoint states: Endpoint is sending MBL
+#define UDP_ENDPOINT_SENDINGM 5
+/// Endpoint states: Endpoint is receiving MBL
+#define UDP_ENDPOINT_RECEIVINGM 6
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "UDP_CSR register access"
+///
+/// This page lists the macroes to access UDP CSR register.
+///
+/// !Macros
+/// - CLEAR_CSR
+/// - SET_CSR
+
+/// Bitmap for all status bits in CSR.
+#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \
+ |AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \
+ |AT91C_UDP_TXCOMP
+
+/// Clears the specified bit(s) in the UDP_CSR register.
+/// \param endpoint The endpoint number of the CSR to process.
+/// \param flags The bitmap to set to 1.
+#define SET_CSR(endpoint, flags) \
+ { \
+ volatile unsigned int reg; \
+ int timeOut = 200; \
+ reg = AT91C_BASE_UDP->UDP_CSR[endpoint] ; \
+ reg |= REG_NO_EFFECT_1_ALL; \
+ reg |= (flags); \
+ AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \
+ while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) != (flags)) \
+ { \
+ if (-- timeOut <= 0) break; \
+ } \
+ }
+
+/// Sets the specified bit(s) in the UDP_CSR register.
+/// \param endpoint The endpoint number of the CSR to process.
+/// \param flags The bitmap to clear to 0.
+#define CLEAR_CSR(endpoint, flags) \
+ { \
+ volatile unsigned int reg; \
+ reg = AT91C_BASE_UDP->UDP_CSR[endpoint]; \
+ reg |= REG_NO_EFFECT_1_ALL; \
+ reg &= ~(flags); \
+ AT91C_BASE_UDP->UDP_CSR[endpoint] = reg; \
+ while ( (AT91C_BASE_UDP->UDP_CSR[endpoint] & (flags)) == (flags)); \
+ }
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// Describes an ongoing transfer on a UDP endpoint.
+typedef struct {
+
+ /// Pointer to a data buffer used for emission/reception.
+ char *pData;
+ /// Number of bytes which have been written into the UDP internal FIFO
+ /// buffers.
+ volatile int buffered;
+ /// Number of bytes which have been sent/received.
+ volatile int transferred;
+ /// Number of bytes which have not been buffered/transferred yet.
+ volatile int remaining;
+ /// Optional callback to invoke when the transfer completes.
+ volatile TransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} Transfer;
+
+/// Describes Multi Buffer List transfer on a UDP endpoint.
+typedef struct {
+ /// Pointer to frame list
+ USBDTransferBuffer *pMbl;
+ /// Pointer to last loaded buffer
+ USBDTransferBuffer *pLastLoaded;
+ /// List size
+ unsigned short listSize;
+ /// Current processing frame
+ unsigned short currBuffer;
+ /// First freed frame to re-use
+ unsigned short freedBuffer;
+ /// Frame setting, circle frame list
+ unsigned char circList;
+ /// All buffer listed is used
+ unsigned char allUsed;
+ /// Optional callback to invoke when the transfer completes.
+ MblTransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} MblTransfer;
+
+//------------------------------------------------------------------------------
+/// Describes the state of an endpoint of the UDP controller.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Current endpoint state.
+ volatile unsigned char state;
+ /// Current reception bank (0 or 1).
+ volatile unsigned char bank;
+ /// Maximum packet size for the endpoint.
+ volatile unsigned short size;
+ /// Describes an ongoing transfer (if current state is either
+ /// <UDP_ENDPOINT_SENDING> or <UDP_ENDPOINT_RECEIVING>)
+ union {
+ Transfer singleTransfer;
+ MblTransfer mblTransfer;
+ } transfer;
+} Endpoint;
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+/// Holds the internal state for each endpoint of the UDP.
+static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
+
+/// Device current state.
+static unsigned char deviceState;
+/// Indicates the previous device state
+static unsigned char previousDeviceState;
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Enables the clock of the UDP peripheral.
+//------------------------------------------------------------------------------
+static inline void UDP_EnablePeripheralClock(void)
+{
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_UDP;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the UDP peripheral clock.
+//------------------------------------------------------------------------------
+static inline void UDP_DisablePeripheralClock(void)
+{
+ AT91C_BASE_PMC->PMC_PCDR = 1 << AT91C_ID_UDP;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the 48MHz USB clock.
+//------------------------------------------------------------------------------
+static inline void UDP_EnableUsbClock(void)
+{
+ AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the 48MHz USB clock.
+//------------------------------------------------------------------------------
+static inline void UDP_DisableUsbClock(void)
+{
+ AT91C_BASE_PMC->PMC_SCDR = AT91C_PMC_UDP;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the UDP transceiver.
+//------------------------------------------------------------------------------
+static inline void UDP_EnableTransceiver(void)
+{
+ AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_TXVDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Disables the UDP transceiver.
+//------------------------------------------------------------------------------
+static inline void UDP_DisableTransceiver(void)
+{
+ AT91C_BASE_UDP->UDP_TXVC |= AT91C_UDP_TXVDIS;
+}
+
+//------------------------------------------------------------------------------
+/// Handles a completed transfer on the given endpoint, invoking the
+/// configured callback if any.
+/// \param bEndpoint Number of the endpoint for which the transfer has completed.
+/// \param bStatus Status code returned by the transfer operation
+//------------------------------------------------------------------------------
+static void UDP_EndOfTransfer(unsigned char bEndpoint, char bStatus)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint was sending or receiving data
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ Transfer *pTransfer = (Transfer *)&(pEndpoint->transfer);
+
+ TRACE_DEBUG_WP("EoT ");
+
+ // Endpoint returns in Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Invoke callback is present
+ if (pTransfer->fCallback != 0) {
+
+ ((TransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus,
+ pTransfer->transferred,
+ pTransfer->remaining + pTransfer->buffered);
+ }
+ else {
+ TRACE_DEBUG_WP("NoCB ");
+ }
+ }
+ else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
+
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+
+ TRACE_DEBUG_WP("EoMT ");
+
+ // Endpoint returns in Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+ // Invoke callback
+ if (pTransfer->fCallback != 0) {
+
+ ((MblTransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus,
+ 0);
+ }
+ else {
+ TRACE_DEBUG_WP("NoCB ");
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the correct reception flag (bank 0 or bank 1) of an endpoint
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+static void UDP_ClearRxFlag(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Clear flag and change banks
+ if (pEndpoint->bank == 0) {
+
+ CLEAR_CSR(bEndpoint, AT91C_UDP_RX_DATA_BK0);
+ // Swap bank if in dual-fifo mode
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) {
+
+ pEndpoint->bank = 1;
+ }
+ }
+ else {
+
+ CLEAR_CSR(bEndpoint, AT91C_UDP_RX_DATA_BK1);
+ pEndpoint->bank = 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Update multi-buffer-transfer descriptors.
+/// \param pTransfer Pointer to instance MblTransfer.
+/// \param size Size of bytes that processed.
+/// \param forceEnd Force the buffer END.
+/// \return 1 if current buffer ended.
+//------------------------------------------------------------------------------
+static char UDP_MblUpdate(MblTransfer *pTransfer,
+ USBDTransferBuffer * pBi,
+ unsigned short size,
+ unsigned char forceEnd)
+{
+ // Update transfer descriptor
+ pBi->remaining -= size;
+ // Check if current buffer ended
+ if (pBi->remaining == 0 || forceEnd) {
+
+ // Process to next buffer
+ if ((++ pTransfer->currBuffer) == pTransfer->listSize) {
+ if (pTransfer->circList) {
+ pTransfer->currBuffer = 0;
+ }
+ else {
+ pTransfer->allUsed = 1;
+ }
+ }
+ // All buffer in the list is processed
+ if (pTransfer->currBuffer == pTransfer->freedBuffer) {
+ pTransfer->allUsed = 1;
+ }
+ // Continue transfer, prepare for next operation
+ if (pTransfer->allUsed == 0) {
+ pBi = &pTransfer->pMbl[pTransfer->currBuffer];
+ pBi->buffered = 0;
+ pBi->transferred = 0;
+ pBi->remaining = pBi->size;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from the current tranfer buffer to the endpoint
+/// FIFO
+/// \param bEndpoint Number of the endpoint which is sending data.
+//------------------------------------------------------------------------------
+static char UDP_MblWriteFifo(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]);
+ signed int size;
+
+ volatile unsigned char * pBytes;
+ volatile char bufferEnd = 1;
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pBi->remaining) {
+
+ size = pBi->remaining;
+ }
+
+ TRACE_DEBUG_WP("w%d.%d ", pTransfer->currBuffer, size);
+ if (size == 0) {
+
+ return 1;
+ }
+
+ pTransfer->pLastLoaded = pBi;
+ pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
+ pBi->buffered += size;
+ bufferEnd = UDP_MblUpdate(pTransfer, pBi, size, 0);
+
+ // Write packet in the FIFO buffer
+ if (size) {
+ signed int c8 = size >> 3;
+ signed int c1 = size & 0x7;
+ //printf("%d[%x] ", pBi->transferred, pBytes);
+ for (; c8; c8 --) {
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ }
+ for (; c1; c1 --) {
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pBytes ++);
+ }
+ }
+ return bufferEnd;
+}
+/*
+//------------------------------------------------------------------------------
+/// Transfers a data payload from an endpoint FIFO to the current transfer
+/// buffer, if NULL packet received, the current buffer is ENDed.
+/// \param bEndpoint Endpoint number.
+/// \param wPacketSize Size of received data packet
+/// \return 1 if the buffer ENDed.
+//------------------------------------------------------------------------------
+static char UDP_MblReadFifo(unsigned char bEndpoint, unsigned short wPacketSize)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]);
+ char bufferEnd;
+
+ // Check that the requested size is not bigger than the remaining transfer
+ if (wPacketSize > pTransfer->remaining) {
+
+ pTransfer->buffered += wPacketSize - pTransfer->remaining;
+ wPacketSize = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pBi->transferred += wPacketSize;
+ bufferEnd = UDP_MblUpdate(pTransfer,
+ wPacketSize,
+ (wPacketSize < pEndpoint->size));
+
+ // Retrieve packet
+ if (wPacketSize) {
+ unsigned char * pBytes = &pBi->pBuffer[pBi->transferred];
+ signed int c8 = wPacketSize >> 3;
+ signed int c1 = wPacketSize & 0x7;
+ for (; c8; c8 --) {
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ }
+ for (; c1; c1 --) {
+ *(pBytes ++) = AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ }
+ }
+ return bufferEnd;
+}
+*/
+//------------------------------------------------------------------------------
+/// Transfers a data payload from the current tranfer buffer to the endpoint
+/// FIFO
+/// \param bEndpoint Number of the endpoint which is sending data.
+//------------------------------------------------------------------------------
+static void UDP_WritePayload(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ signed int size;
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pTransfer->remaining) {
+
+ size = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->buffered += size;
+ pTransfer->remaining -= size;
+
+ // Write packet in the FIFO buffer
+ while (size > 0) {
+
+ AT91C_BASE_UDP->UDP_FDR[bEndpoint] = *(pTransfer->pData);
+ pTransfer->pData++;
+ size--;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from an endpoint FIFO to the current transfer buffer
+/// \param bEndpoint Endpoint number.
+/// \param wPacketSize Size of received data packet
+//------------------------------------------------------------------------------
+static void UDP_ReadPayload(unsigned char bEndpoint, int wPacketSize)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check that the requested size is not bigger than the remaining transfer
+ if (wPacketSize > pTransfer->remaining) {
+
+ pTransfer->buffered += wPacketSize - pTransfer->remaining;
+ wPacketSize = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->remaining -= wPacketSize;
+ pTransfer->transferred += wPacketSize;
+
+ // Retrieve packet
+ while (wPacketSize > 0) {
+
+ *(pTransfer->pData) = (char) AT91C_BASE_UDP->UDP_FDR[bEndpoint];
+ pTransfer->pData++;
+ wPacketSize--;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Received SETUP packet from endpoint 0 FIFO
+/// \param pRequest Generic USB SETUP request sent over Control endpoints
+//------------------------------------------------------------------------------
+static void UDP_ReadRequest(USBGenericRequest *pRequest)
+{
+ unsigned char *pData = (unsigned char *)pRequest;
+ unsigned int i;
+
+ // Copy packet
+ for (i = 0; i < 8; i++) {
+
+ *pData = (unsigned char) AT91C_BASE_UDP->UDP_FDR[0];
+ pData++;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reset all endpoint transfer descriptors
+//------------------------------------------------------------------------------
+static void UDP_ResetEndpoints( void )
+{
+ Endpoint *pEndpoint;
+ Transfer *pTransfer;
+ unsigned char bEndpoint;
+
+ // Reset the transfer descriptor of every endpoint
+ for (bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++) {
+
+ pEndpoint = &(endpoints[bEndpoint]);
+ pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Reset endpoint transfer descriptor
+ pTransfer->pData = 0;
+ pTransfer->transferred = -1;
+ pTransfer->buffered = -1;
+ pTransfer->remaining = -1;
+ pTransfer->fCallback = 0;
+ pTransfer->pArgument = 0;
+
+ // Reset endpoint state
+ pEndpoint->bank = 0;
+ pEndpoint->state = UDP_ENDPOINT_DISABLED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Disable all endpoints (except control endpoint 0), aborting current
+/// transfers if necessary
+//------------------------------------------------------------------------------
+static void UDP_DisableEndpoints( void )
+
+{
+ unsigned char bEndpoint;
+
+ // Disable each endpoint, terminating any pending transfer
+ // Control endpoint 0 is not disabled
+ for (bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++) {
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+ endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Checks if an ongoing transfer on an endpoint has been completed.
+/// \param bEndpoint Endpoint number.
+/// \return 1 if the current transfer on the given endpoint is complete;
+/// otherwise 0.
+//------------------------------------------------------------------------------
+static unsigned char UDP_IsTransferFinished(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check if it is a Control endpoint
+ // -> Control endpoint must always finish their transfer with a zero-length
+ // packet
+ if ((AT91C_BASE_UDP->UDP_CSR[bEndpoint] & AT91C_UDP_EPTYPE)
+ == AT91C_UDP_EPTYPE_CTRL) {
+
+ return (pTransfer->buffered < pEndpoint->size);
+ }
+ // Other endpoints only need to transfer all the data
+ else {
+
+ return (pTransfer->buffered <= pEndpoint->size)
+ && (pTransfer->remaining == 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Endpoint interrupt handler.
+/// Handle IN/OUT transfers, received SETUP packets and STALLing
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+static void UDP_EndpointHandler(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
+ unsigned int status = AT91C_BASE_UDP->UDP_CSR[bEndpoint];
+ unsigned short wPacketSize;
+ USBGenericRequest request;
+
+ TRACE_DEBUG_WP("E%d ", bEndpoint);
+ TRACE_DEBUG_WP("st:0x%X ", status);
+
+ // Handle interrupts
+ // IN packet sent
+ if ((status & AT91C_UDP_TXCOMP) != 0) {
+
+ TRACE_DEBUG_WP("Wr ");
+
+ // Check that endpoint was in MBL Sending state
+ if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) {
+
+ USBDTransferBuffer * pMbli = pMblt->pLastLoaded;
+ unsigned char bufferEnd = 0;
+
+ TRACE_DEBUG_WP("TxM%d.%d ", pMblt->allUsed, pMbli->buffered);
+
+ // End of transfer ?
+ if (pMblt->allUsed && pMbli->buffered == 0) {
+
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+
+ // Disable interrupt
+ AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ }
+ else {
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP("%d ", pEndpoint->size);
+
+ if (pMbli->buffered > pEndpoint->size) {
+ pMbli->transferred += pEndpoint->size;
+ pMbli->buffered -= pEndpoint->size;
+ }
+ else {
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+ }
+
+ // Send next packet
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
+
+ // No double buffering
+ bufferEnd = UDP_MblWriteFifo(bEndpoint);
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ }
+ else {
+ // Double buffering
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ bufferEnd = UDP_MblWriteFifo(bEndpoint);
+ }
+
+ if (bufferEnd && pMblt->fCallback) {
+ ((MblTransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ USBD_STATUS_PARTIAL_DONE,
+ 1);
+ }
+ }
+ }
+ // Check that endpoint was in Sending state
+ else if (pEndpoint->state == UDP_ENDPOINT_SENDING) {
+
+ // End of transfer ?
+ if (UDP_IsTransferFinished(bEndpoint)) {
+
+ pTransfer->transferred += pTransfer->buffered;
+ pTransfer->buffered = 0;
+
+ // Disable interrupt if this is not a control endpoint
+ if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
+
+ AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
+ }
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ }
+ else {
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP(" %d ", pEndpoint->size);
+
+ pTransfer->transferred += pEndpoint->size;
+ pTransfer->buffered -= pEndpoint->size;
+
+ // Send next packet
+ if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) == 1) {
+
+ // No double buffering
+ UDP_WritePayload(bEndpoint);
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ }
+ else {
+ // Double buffering
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ UDP_WritePayload(bEndpoint);
+ }
+ }
+ }
+ else {
+ // Acknowledge interrupt
+ TRACE_ERROR("Error Wr%d, %x\n\r", bEndpoint, pEndpoint->state);
+ CLEAR_CSR(bEndpoint, AT91C_UDP_TXCOMP);
+ }
+ }
+
+ // OUT packet received
+ if ((status & UDP_RXDATA) != 0) {
+
+ TRACE_DEBUG_WP("Rd ");
+
+ // Check that the endpoint is in Receiving state
+ if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
+
+ // Check if an ACK has been received on a Control endpoint
+ if (((status & AT91C_UDP_EPTYPE) == AT91C_UDP_EPTYPE_CTRL)
+ && ((status & AT91C_UDP_RXBYTECNT) == 0)) {
+
+ // Acknowledge the data and finish the current transfer
+ UDP_ClearRxFlag(bEndpoint);
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Check if the data has been STALLed
+ else if ((status & AT91C_UDP_FORCESTALL) != 0) {
+
+ // Discard STALLed data
+ TRACE_DEBUG_WP("Discard ");
+ UDP_ClearRxFlag(bEndpoint);
+ }
+ // NAK the data
+ else {
+
+ TRACE_DEBUG_WP("Nak ");
+ AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
+ }
+ }
+ // Endpoint is in Read state
+ else {
+
+ // Retrieve data and store it into the current transfer buffer
+ wPacketSize = (unsigned short) (status >> 16);
+ TRACE_DEBUG_WP("%d ", wPacketSize);
+ UDP_ReadPayload(bEndpoint, wPacketSize);
+ UDP_ClearRxFlag(bEndpoint);
+
+ // Check if the transfer is finished
+ if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
+
+ // Disable interrupt if this is not a control endpoint
+ if ((status & AT91C_UDP_EPTYPE) != AT91C_UDP_EPTYPE_CTRL) {
+
+ AT91C_BASE_UDP->UDP_IDR = 1 << bEndpoint;
+ }
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ }
+ }
+
+ // STALL sent
+ if ((status & AT91C_UDP_STALLSENT) != 0) {
+
+ TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint);
+
+ // If the endpoint is not halted, clear the STALL condition
+ CLEAR_CSR(bEndpoint, AT91C_UDP_STALLSENT);
+ if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
+
+ TRACE_WARNING( "_ " );
+ CLEAR_CSR(bEndpoint, AT91C_UDP_FORCESTALL);
+ }
+ }
+
+ // SETUP packet received
+ if ((status & AT91C_UDP_RXSETUP) != 0) {
+
+ TRACE_DEBUG_WP("Stp ");
+
+ // If a transfer was pending, complete it
+ // Handles the case where during the status phase of a control write
+ // transfer, the host receives the device ZLP and ack it, but the ack
+ // is not received by the device
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Copy the setup packet
+ UDP_ReadRequest(&request);
+
+ // Set the DIR bit before clearing RXSETUP in Control IN sequence
+ if (USBGenericRequest_GetDirection(&request) == USBGenericRequest_IN) {
+
+ SET_CSR(bEndpoint, AT91C_UDP_DIR);
+ }
+ // Acknowledge setup packet
+ CLEAR_CSR(bEndpoint, AT91C_UDP_RXSETUP);
+
+ // Forward the request to the upper layer
+ USBDCallbacks_RequestReceived(&request);
+ }
+
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// USB device interrupt handler
+/// Manages device resume, suspend, end of bus reset.
+/// Forwards endpoint interrupts to the appropriate handler.
+//------------------------------------------------------------------------------
+void USBD_IrqHandler(void)
+{
+ unsigned int status;
+ int eptnum = 0;
+
+ // Get interrupt status
+ // Some interrupts may get masked depending on the device state
+ status = AT91C_BASE_UDP->UDP_ISR;
+ status &= AT91C_BASE_UDP->UDP_IMR;
+
+ if (deviceState < USBD_STATE_POWERED) {
+
+ status &= AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
+ AT91C_BASE_UDP->UDP_ICR = ~status;
+ }
+
+ // Return immediately if there is no interrupt to service
+ if (status == 0) {
+
+ TRACE_DEBUG_WP(".\n\r");
+ return;
+ }
+
+ // Toggle USB LED if the device is active
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Set(USBD_LEDUSB);
+ }
+
+ // Service interrupts
+
+ //// Start Of Frame (SOF)
+ //if (ISSET(dStatus, AT91C_UDP_SOFINT)) {
+ //
+ // TRACE_DEBUG("SOF");
+ //
+ // // Invoke the SOF callback
+ // USB_StartOfFrameCallback(pUsb);
+ //
+ // // Acknowledge interrupt
+ // AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_SOFINT;
+ // dStatus &= ~AT91C_UDP_SOFINT;
+ //}
+
+ // Resume
+ if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) {
+
+ TRACE_INFO_WP("Res ");
+
+ // Don't do anything if the device was not suspended
+ if (deviceState == USBD_STATE_SUSPENDED) {
+
+ // The device enters its previous state
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+
+ // Enable the transceiver if the device was past the Default
+ // state
+ deviceState = previousDeviceState;
+ if (deviceState >= USBD_STATE_DEFAULT) {
+
+ UDP_EnableTransceiver();
+
+ // Invoke the Resume callback
+ USBDCallbacks_Resumed();
+ }
+ }
+
+ // Clear and disable resume interrupts
+ AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
+ | AT91C_UDP_RXRSM
+ | AT91C_UDP_RXSUSP;
+ AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
+ }
+
+ // Suspend
+ // This interrupt is always treated last (hence the '==')
+ if (status == AT91C_UDP_RXSUSP) {
+
+ TRACE_INFO_WP("Susp ");
+
+ // Don't do anything if the device is already suspended
+ if (deviceState != USBD_STATE_SUSPENDED) {
+
+ // The device enters the Suspended state
+ // Enable wakeup
+ AT91C_BASE_UDP->UDP_IER = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
+
+ // Acknowledge interrupt
+ AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_RXSUSP;
+
+ // Switch to the Suspended state
+ previousDeviceState = deviceState;
+ deviceState = USBD_STATE_SUSPENDED;
+ // Invoke the Suspended callback
+ USBDCallbacks_Suspended();
+ UDP_DisableTransceiver();
+ UDP_DisablePeripheralClock();
+ UDP_DisableUsbClock();
+ }
+ }
+ #if 0
+ // Resume
+ else if ((status & (AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM)) != 0) {
+
+ TRACE_INFO_WP("Res ");
+
+ // Don't do anything if the device was not suspended
+ if (deviceState == USBD_STATE_SUSPENDED) {
+
+ // The device enters its previous state
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+
+ // Enable the transceiver if the device was past the Default
+ // state
+ deviceState = previousDeviceState;
+ if (deviceState >= USBD_STATE_DEFAULT) {
+
+ UDP_EnableTransceiver();
+
+ // Invoke the Resume callback
+ USBDCallbacks_Resumed();
+ }
+ }
+
+ // Clear and disable resume interrupts
+ AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
+ | AT91C_UDP_RXRSM
+ | AT91C_UDP_RXSUSP;
+ AT91C_BASE_UDP->UDP_IDR = AT91C_UDP_WAKEUP | AT91C_UDP_RXRSM;
+ }
+ #endif
+ // End of bus reset
+ else if ((status & AT91C_UDP_ENDBUSRES) != 0) {
+
+ TRACE_INFO_WP("EoBRes ");
+
+ // The device enters the Default state
+ deviceState = USBD_STATE_DEFAULT;
+ UDP_EnableTransceiver();
+ UDP_ResetEndpoints();
+ UDP_DisableEndpoints();
+ USBD_ConfigureEndpoint(0);
+
+ // Flush and enable the Suspend interrupt
+ AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_WAKEUP
+ | AT91C_UDP_RXRSM
+ | AT91C_UDP_RXSUSP;
+ AT91C_BASE_UDP->UDP_IER = AT91C_UDP_RXSUSP;
+
+ //// Enable the Start Of Frame (SOF) interrupt if needed
+ //if (pUsb->pCallbacks->startOfFrame != 0) {
+ //
+ // AT91C_BASE_UDP->UDP_IER = AT91C_UDP_SOFINT;
+ //}
+
+ // Invoke the Reset callback
+ USBDCallbacks_Reset();
+
+ // Acknowledge end of bus reset interrupt
+ AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES;
+ }
+ // Endpoint interrupts
+ else {
+
+ status &= ((1 << CHIP_USB_NUMENDPOINTS) - 1);
+ while (status != 0) {
+
+ // Check if endpoint has a pending interrupt
+ if ((status & (1 << eptnum)) != 0) {
+
+ UDP_EndpointHandler(eptnum);
+ status &= ~(1 << eptnum);
+
+ if (status != 0) {
+
+ TRACE_INFO_WP("\n\r - ");
+ }
+ }
+ eptnum++;
+ }
+ }
+
+ // Toggle LED back to its previous state
+ TRACE_DEBUG_WP("!");
+ TRACE_INFO_WP("\n\r");
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Clear(USBD_LEDUSB);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configures an endpoint according to its Endpoint Descriptor.
+/// \param pDescriptor Pointer to an Endpoint descriptor.
+//------------------------------------------------------------------------------
+void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
+{
+ Endpoint *pEndpoint;
+ unsigned char bEndpoint;
+ unsigned char bType;
+ unsigned char bEndpointDir;
+
+ // NULL descriptor -> Control endpoint 0
+ if (pDescriptor == 0) {
+
+ bEndpoint = 0;
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType= USBEndpointDescriptor_CONTROL;
+ bEndpointDir = 0;
+ pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
+ }
+ else {
+
+ bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType = USBEndpointDescriptor_GetType(pDescriptor);
+ bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
+ pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
+ }
+
+ // Abort the current transfer is the endpoint was configured and in
+ // Write or Read state
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)
+ || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM)) {
+
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
+ }
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Reset Endpoint Fifos
+ AT91C_BASE_UDP->UDP_RSTEP |= (1 << bEndpoint);
+ AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << bEndpoint);
+
+ // Configure endpoint
+ SET_CSR(bEndpoint, (unsigned int)AT91C_UDP_EPEDS
+ | (bType << 8) | (bEndpointDir << 10));
+ if (bType != USBEndpointDescriptor_CONTROL) {
+
+ }
+ else {
+
+ AT91C_BASE_UDP->UDP_IER = (1 << bEndpoint);
+ }
+
+ TRACE_INFO_WP("CfgEpt%d ", bEndpoint);
+}
+
+//------------------------------------------------------------------------------
+/// Sends data through a USB endpoint. Sets up the transfer descriptor,
+/// writes one or two data payloads (depending on the number of FIFO bank
+/// for the endpoint) and then starts the actual transfer. The operation is
+/// complete when all the data has been sent.
+///
+/// *If the size of the buffer is greater than the size of the endpoint
+/// (or twice the size if the endpoint has two FIFO banks), then the buffer
+/// must be kept allocated until the transfer is finished*. This means that
+/// it is not possible to declare it on the stack (i.e. as a local variable
+/// of a function which returns after starting a transfer).
+///
+/// \param bEndpoint Endpoint number.
+/// \param pData Pointer to a buffer with the data to send.
+/// \param dLength Size of the data buffer.
+/// \param fCallback Optional callback function to invoke when the transfer is
+/// complete.
+/// \param pArgument Optional argument to the callback function.
+/// \return USBD_STATUS_SUCCESS if the transfer has been started;
+/// otherwise, the corresponding error status code.
+//------------------------------------------------------------------------------
+char USBD_Write( unsigned char bEndpoint,
+ const void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check that the endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+ TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength);
+
+ // Setup the transfer descriptor
+ pTransfer->pData = (void *) pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+ // Send the first packet
+ pEndpoint->state = UDP_ENDPOINT_SENDING;
+ while((AT91C_BASE_UDP->UDP_CSR[bEndpoint]&AT91C_UDP_TXPKTRDY)==AT91C_UDP_TXPKTRDY);
+ UDP_WritePayload(bEndpoint);
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+
+ // If double buffering is enabled and there is data remaining,
+ // prepare another packet
+ if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) && (pTransfer->remaining > 0)) {
+
+ UDP_WritePayload(bEndpoint);
+ }
+
+ // Enable interrupt on endpoint
+ AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Sends data frames through a USB endpoint. Sets up the transfer descriptor
+/// list, writes one or two data payloads (depending on the number of FIFO bank
+/// for the endpoint) and then starts the actual transfer. The operation is
+/// complete when all the data has been sent.
+///
+/// *If the size of the frame is greater than the size of the endpoint
+/// (or twice the size if the endpoint has two FIFO banks), then the buffer
+/// must be kept allocated until the frame is finished*. This means that
+/// it is not possible to declare it on the stack (i.e. as a local variable
+/// of a function which returns after starting a transfer).
+///
+/// \param bEndpoint Endpoint number.
+/// \param pMbl Pointer to a frame (USBDTransferBuffer) list that describes
+/// the buffer list to send.
+/// \param wListSize Size of the frame list.
+/// \param bCircList Circle the list.
+/// \param wStartNdx For circled list only, the first buffer index to transfer.
+/// \param fCallback Optional callback function to invoke when the transfer is
+/// complete.
+/// \param pArgument Optional argument to the callback function.
+/// \return USBD_STATUS_SUCCESS if the transfer has been started;
+/// otherwise, the corresponding error status code.
+/// \see USBDTransferBuffer, MblTransferCallback, USBD_MblReuse
+//------------------------------------------------------------------------------
+char USBD_MblWrite( unsigned char bEndpoint,
+ void *pMbl,
+ unsigned short wListSize,
+ unsigned char bCircList,
+ unsigned short wStartNdx,
+ MblTransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ unsigned short i;
+
+ // EP0 is not suitable for Mbl
+ if (bEndpoint == 0) {
+
+ return USBD_STATUS_INVALID_PARAMETER;
+ }
+
+ // Check that the endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+ pEndpoint->state = UDP_ENDPOINT_SENDINGM;
+
+ TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);
+
+ // Start from first if not circled list
+ if (!bCircList) wStartNdx = 0;
+
+ // Setup the transfer descriptor
+ pTransfer->pMbl = (USBDTransferBuffer*)pMbl;
+ pTransfer->listSize = wListSize;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+ pTransfer->currBuffer = wStartNdx;
+ pTransfer->freedBuffer = 0;
+ pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
+ pTransfer->circList = bCircList;
+ pTransfer->allUsed = 0;
+
+ // Clear all buffer
+ for (i = 0; i < wListSize; i ++) {
+
+ pTransfer->pMbl[i].transferred = 0;
+ pTransfer->pMbl[i].buffered = 0;
+ pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size;
+ }
+
+ // Send the first packet
+ while((AT91C_BASE_UDP->UDP_CSR[bEndpoint]&AT91C_UDP_TXPKTRDY)
+ ==AT91C_UDP_TXPKTRDY);
+ UDP_MblWriteFifo(bEndpoint);
+ SET_CSR(bEndpoint, AT91C_UDP_TXPKTRDY);
+
+ // If double buffering is enabled and there is data remaining,
+ // prepare another packet
+ if ((CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1)
+ && (pTransfer->pMbl[pTransfer->currBuffer].remaining > 0)) {
+
+ UDP_MblWriteFifo(bEndpoint);
+ }
+
+ // Enable interrupt on endpoint
+ AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Reads incoming data on an USB endpoint This methods sets the transfer
+/// descriptor and activate the endpoint interrupt. The actual transfer is
+/// then carried out by the endpoint interrupt handler. The Read operation
+/// finishes either when the buffer is full, or a short packet (inferior to
+/// endpoint maximum size) is received.
+///
+/// *The buffer must be kept allocated until the transfer is finished*.
+/// \param bEndpoint Endpoint number.
+/// \param pData Pointer to a data buffer.
+/// \param dLength Size of the data buffer in bytes.
+/// \param fCallback Optional end-of-transfer callback function.
+/// \param pArgument Optional argument to the callback function.
+/// \return USBD_STATUS_SUCCESS if the read operation has been started;
+/// otherwise, the corresponding error code.
+//------------------------------------------------------------------------------
+char USBD_Read(unsigned char bEndpoint,
+ void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Return if the endpoint is not in IDLE state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ // Endpoint enters Receiving state
+ pEndpoint->state = UDP_ENDPOINT_RECEIVING;
+ TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength);
+
+ // Set the transfer descriptor
+ pTransfer->pData = pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+ // Enable interrupt on endpoint
+ AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Reuse first used/released buffer with new buffer address and size to be used
+/// in transfer again. Only valid when frame list is ringed. Can be used for
+/// both read & write.
+/// \param bEndpoint Endpoint number.
+/// \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).
+/// \param wNewSize Size of the data buffer
+//------------------------------------------------------------------------------
+char USBD_MblReuse( unsigned char bEndpoint,
+ unsigned char *pNewBuffer,
+ unsigned short wNewSize )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);
+
+ TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",
+ bEndpoint, pEndpoint->state, pTransfer->circList);
+
+ // Only for Multi-buffer-circle list
+ if (bEndpoint != 0
+ && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM
+ || pEndpoint->state == UDP_ENDPOINT_SENDINGM)
+ && pTransfer->circList) {
+ }
+ else {
+
+ return USBD_STATUS_WRONG_STATE;
+ }
+
+ // Check if there is freed buffer
+ if (pTransfer->freedBuffer == pTransfer->currBuffer
+ && !pTransfer->allUsed) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ // Update transfer information
+ if ((++ pTransfer->freedBuffer) == pTransfer->listSize)
+ pTransfer->freedBuffer = 0;
+ if (pNewBuffer) {
+ pBi->pBuffer = pNewBuffer;
+ pBi->size = wNewSize;
+ }
+ pBi->buffered = 0;
+ pBi->transferred = 0;
+ pBi->remaining = pBi->size;
+
+ // At least one buffer is not processed
+ pTransfer->allUsed = 0;
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the HALT feature on the given endpoint (if not already in this state).
+/// \param bEndpoint Endpoint number.
+//------------------------------------------------------------------------------
+void USBD_Halt(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint is enabled and not already in Halt state
+ if ((pEndpoint->state != UDP_ENDPOINT_DISABLED)
+ && (pEndpoint->state != UDP_ENDPOINT_HALTED)) {
+
+ TRACE_DEBUG_WP("Halt%d ", bEndpoint);
+
+ // Abort the current transfer if necessary
+ UDP_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+
+ // Put endpoint into Halt state
+ SET_CSR(bEndpoint, AT91C_UDP_FORCESTALL);
+ pEndpoint->state = UDP_ENDPOINT_HALTED;
+
+ // Enable the endpoint interrupt
+ AT91C_BASE_UDP->UDP_IER = 1 << bEndpoint;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the Halt feature on the given endpoint.
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+void USBD_Unhalt(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check if the endpoint is enabled
+ //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+
+ TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
+
+ // Return endpoint to Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Clear FORCESTALL flag
+ CLEAR_CSR(bEndpoint, AT91C_UDP_FORCESTALL);
+
+ // Reset Endpoint Fifos, beware this is a 2 steps operation
+ AT91C_BASE_UDP->UDP_RSTEP |= 1 << bEndpoint;
+ AT91C_BASE_UDP->UDP_RSTEP &= ~(1 << bEndpoint);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current Halt status of an endpoint.
+/// \param bEndpoint Index of endpoint
+/// \return 1 if the endpoint is currently halted; otherwise 0
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHalted(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ unsigned char status = 0;
+
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+
+ status = 1;
+ }
+ return( status );
+}
+
+//------------------------------------------------------------------------------
+/// Indicates if the device is running in high or full-speed. Always returns 0
+/// since UDP does not support high-speed mode.
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHighSpeed(void)
+{
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Causes the given endpoint to acknowledge the next packet it receives
+/// with a STALL handshake.
+/// \param bEndpoint Endpoint number.
+/// \return USBD_STATUS_SUCCESS or USBD_STATUS_LOCKED.
+//------------------------------------------------------------------------------
+unsigned char USBD_Stall(unsigned char bEndpoint)
+
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint);
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Stall%d ", bEndpoint);
+ SET_CSR(bEndpoint, AT91C_UDP_FORCESTALL);
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Starts a remote wake-up procedure.
+//------------------------------------------------------------------------------
+void USBD_RemoteWakeUp(void)
+{
+ // Device is NOT suspended
+ if (deviceState != USBD_STATE_SUSPENDED) {
+
+ TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r");
+ return;
+ }
+
+
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+ UDP_EnableTransceiver();
+
+ TRACE_INFO_WP("RWUp ");
+
+ // Activates a remote wakeup (edge on ESR), then clear ESR
+ AT91C_BASE_UDP->UDP_GLBSTATE |= AT91C_UDP_ESR;
+ AT91C_BASE_UDP->UDP_GLBSTATE &= ~AT91C_UDP_ESR;
+}
+
+//------------------------------------------------------------------------------
+/// Sets the device address to the given value.
+/// \param address New device address.
+//------------------------------------------------------------------------------
+void USBD_SetAddress(unsigned char address)
+{
+ TRACE_INFO_WP("SetAddr(%d) ", address);
+
+ // Set address
+ AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN | address;
+
+ // If the address is 0, the device returns to the Default state
+ if (address == 0) {
+
+ AT91C_BASE_UDP->UDP_GLBSTATE = 0;
+ deviceState = USBD_STATE_DEFAULT;
+ }
+ // If the address is non-zero, the device enters the Address state
+ else {
+
+ AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
+ deviceState = USBD_STATE_ADDRESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the current device configuration.
+/// \param cfgnum - Configuration number to set.
+//------------------------------------------------------------------------------
+void USBD_SetConfiguration(unsigned char cfgnum)
+{
+ TRACE_INFO_WP("SetCfg(%d) ", cfgnum);
+
+ // If the configuration number if non-zero, the device enters the
+ // Configured state
+ if (cfgnum != 0) {
+
+ // Enter Configured state
+ deviceState = USBD_STATE_CONFIGURED;
+ AT91C_BASE_UDP->UDP_GLBSTATE |= AT91C_UDP_CONFG;
+ }
+ // If the configuration number is zero, the device goes back to the Address
+ // state
+ else {
+
+ deviceState = USBD_STATE_ADDRESS;
+ AT91C_BASE_UDP->UDP_GLBSTATE = AT91C_UDP_FADDEN;
+
+ // Abort all transfers
+ UDP_DisableEndpoints();
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Connects the pull-up on the D+ line of the USB.
+//------------------------------------------------------------------------------
+void USBD_Connect(void)
+{
+ TRACE_DEBUG("Conn ");
+
+#if defined(CHIP_USB_PULLUP_EXTERNAL)
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ if (pinPullUp.type == PIO_OUTPUT_0) {
+
+ PIO_Set(&pinPullUp);
+ }
+ else {
+
+ PIO_Clear(&pinPullUp);
+ }
+#elif defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDP->UDP_TXVC |= AT91C_UDP_PUON;
+#elif defined(CHIP_USB_PULLUP_MATRIX)
+ AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON;
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Unsupported pull-up type.
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disconnects the pull-up from the D+ line of the USB.
+//------------------------------------------------------------------------------
+void USBD_Disconnect(void)
+{
+ TRACE_DEBUG("Disc ");
+
+#if defined(CHIP_USB_PULLUP_EXTERNAL)
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ if (pinPullUp.type == PIO_OUTPUT_0) {
+
+ PIO_Clear(&pinPullUp);
+ }
+ else {
+
+ PIO_Set(&pinPullUp);
+ }
+#elif defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_PUON;
+#elif defined(CHIP_USB_PULLUP_MATRIX)
+ AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Unsupported pull-up type.
+#endif
+
+ // Device returns to the Powered state
+ if (deviceState > USBD_STATE_POWERED) {
+
+ deviceState = USBD_STATE_POWERED;
+ }
+
+ if (previousDeviceState > USBD_STATE_POWERED) {
+
+ previousDeviceState = USBD_STATE_POWERED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Initializes the USB driver.
+//------------------------------------------------------------------------------
+void USBD_Init(void)
+{
+ TRACE_INFO_WP("USBD_Init\n\r");
+
+ // Reset endpoint structures
+ UDP_ResetEndpoints();
+
+ // Configure the pull-up on D+ and disconnect it
+#if defined(CHIP_USB_PULLUP_EXTERNAL)
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ PIO_Configure(&pinPullUp, 1);
+#elif defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDP->UDP_TXVC &= ~AT91C_UDP_PUON;
+#elif defined(CHIP_USB_PULLUP_MATRIX)
+ AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Missing pull-up definition.
+#endif
+
+ // Device is in the Attached state
+ deviceState = USBD_STATE_SUSPENDED;
+ previousDeviceState = USBD_STATE_POWERED;
+ UDP_EnablePeripheralClock();
+ UDP_EnableUsbClock();
+
+ AT91C_BASE_UDP->UDP_IDR = 0xFE;
+
+ AT91C_BASE_UDP->UDP_IER = AT91C_UDP_WAKEUP;
+
+ // Configure interrupts
+ USBDCallbacks_Initialized();
+}
+
+//------------------------------------------------------------------------------
+/// Configure USB Speed, should be invoked before USB attachment.
+/// \param forceFS Force to use FS mode.
+//------------------------------------------------------------------------------
+void USBD_ConfigureSpeed(unsigned char forceFS)
+{
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current state of the USB device.
+/// \return Device current state.
+//------------------------------------------------------------------------------
+unsigned char USBD_GetState(void)
+{
+ return deviceState;
+}
+
diff --git a/usb/device/core/USBD_UDPHS.c b/usb/device/core/USBD_UDPHS.c
new file mode 100644
index 0000000..f02fa55
--- /dev/null
+++ b/usb/device/core/USBD_UDPHS.c
@@ -0,0 +1,2384 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "USBD.h"
+#include "USBDCallbacks.h"
+#include "USBDDriver.h"
+#include <board.h>
+#include <pio/pio.h>
+#include <utility/trace.h>
+#include <utility/led.h>
+#include <usb/common/core/USBEndpointDescriptor.h>
+#include <usb/common/core/USBGenericRequest.h>
+#include <usb/common/core/USBFeatureRequest.h>
+
+#include <stdio.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Maximum number of endpoints interrupts.
+#define NUM_IT_MAX \
+ (AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_EPT_NBR_MAX)
+/// Maximum number of endpoint DMA interrupts
+#define NUM_IT_MAX_DMA \
+ ((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4)
+/// Bits that should be shifted to access DMA control bits.
+#define SHIFT_DMA 24
+/// Bits that should be shifted to access interrupt bits.
+#define SHIFT_INTERUPT 8
+
+/// Max size of the FMA FIFO
+#define DMA_MAX_FIFO_SIZE 65536
+
+#define EPT_VIRTUAL_SIZE 16384
+
+//------------------------------------------------------------------------------
+/// \page "Endpoint states"
+/// This page lists the endpoint states.
+/// !States
+// - UDP_ENDPOINT_DISABLED
+// - UDP_ENDPOINT_HALTED
+// - UDP_ENDPOINT_IDLE
+// - UDP_ENDPOINT_SENDING
+// - UDP_ENDPOINT_RECEIVING
+
+/// Endpoint states: Endpoint is disabled
+#define UDP_ENDPOINT_DISABLED 0
+/// Endpoint states: Endpoint is halted (i.e. STALLs every request)
+#define UDP_ENDPOINT_HALTED 1
+/// Endpoint states: Endpoint is idle (i.e. ready for transmission)
+#define UDP_ENDPOINT_IDLE 2
+/// Endpoint states: Endpoint is sending data
+#define UDP_ENDPOINT_SENDING 3
+/// Endpoint states: Endpoint is receiving data
+#define UDP_ENDPOINT_RECEIVING 4
+/// Endpoint states: Endpoint is sending MBL
+#define UDP_ENDPOINT_SENDINGM 5
+/// Endpoint states: Endpoint is receiving MBL
+#define UDP_ENDPOINT_RECEIVINGM 6
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Check if DMA is used to transfer data
+#define UDP_IsDmaUsed(ep) (CHIP_USB_ENDPOINTS_DMA(ep))
+
+//------------------------------------------------------------------------------
+// Structures
+//------------------------------------------------------------------------------
+
+/// Describes an ongoing transfer on a UDP endpoint.
+typedef struct
+{
+ /// Pointer to a data buffer used for emission/reception.
+ char *pData;
+ /// Number of bytes which have been written into the UDP internal FIFO
+ /// buffers.
+ int buffered;
+ /// Number of bytes which have been sent/received.
+ int transferred;
+ /// Number of bytes which have not been buffered/transferred yet.
+ int remaining;
+ /// Optional callback to invoke when the transfer completes.
+ TransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} Transfer;
+
+/// Describes Multi Buffer List transfer on a UDP endpoint.
+typedef struct {
+ /// Pointer to frame list
+ USBDTransferBuffer *pMbl;
+ /// Pointer to last loaded buffer
+ USBDTransferBuffer *pLastLoaded;
+ /// List size
+ unsigned short listSize;
+ /// Current processing frame
+ unsigned short currBuffer;
+ /// First freed frame to re-use
+ unsigned short freedBuffer;
+ /// Frame setting, circle frame list
+ unsigned char circList;
+ /// All buffer listed is used
+ unsigned char allUsed;
+ /// Optional callback to invoke when the transfer completes.
+ MblTransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} MblTransfer;
+
+/// Describes DMA Link List transfer on a UDPHS endpoint.
+typedef struct {
+ /// Pointer to frame list
+ USBDDmaDescriptor *pMbl;
+ /// Pointer to current buffer
+ USBDDmaDescriptor *pCurrBuffer;
+ /// Pointer to freed buffer
+ USBDDmaDescriptor *pFreedBuffer;
+ /// List size
+ unsigned short listSize;
+ /// Frame setting, circle frame list
+ unsigned char circList;
+ /// All buffer listed is used
+ unsigned char allUsed;
+ /// Optional callback to invoke when the transfer completes.
+ MblTransferCallback fCallback;
+ /// Optional argument to the callback function.
+ void *pArgument;
+} DmaLlTransfer;
+
+//------------------------------------------------------------------------------
+/// Describes the state of an endpoint of the UDP controller.
+//------------------------------------------------------------------------------
+typedef struct
+{
+ /// Current endpoint state.
+ volatile unsigned char state;
+ /// Current reception bank (0 or 1).
+ unsigned char bank;
+ /// Maximum packet size for the endpoint.
+ unsigned short size;
+ /// Describes an ongoing transfer (if current state is either
+ /// <UDP_ENDPOINT_SENDING> or <UDP_ENDPOINT_RECEIVING>)
+ union {
+ Transfer singleTransfer;
+ MblTransfer mblTransfer;
+ DmaLlTransfer dmaTransfer;
+ } transfer;
+ /// Special case for send a ZLP
+ unsigned char sendZLP;
+} Endpoint;
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+/// Holds the internal state for each endpoint of the UDP.
+static Endpoint endpoints[CHIP_USB_NUMENDPOINTS];
+/// Device current state.
+static unsigned char deviceState;
+/// Indicates the previous device state
+static unsigned char previousDeviceState;
+
+/// 7.1.20 Test Mode Support
+/// Test codes for the USB HS test mode.
+static const char test_packet_buffer[] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // JKJKJKJK * 9
+ 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA, // JJKKJJKK * 8
+ 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE, // JJJJKKKK * 8
+ 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, // JJJJJJJKKKKKKK * 8
+ 0x7F,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD, // JJJJJJJK * 8
+ 0xFC,0x7E,0xBF,0xDF,0xEF,0xF7,0xFB,0xFD,0x7E // {JKKKKKKK * 10}, JK
+};
+
+// Force HS
+static const unsigned char forceUsbFS = 0;
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Disables the BIAS of the USB controller
+//------------------------------------------------------------------------------
+static inline void UDPHS_DisableBIAS( void )
+{
+ AT91C_BASE_PMC->PMC_UCKR &= ~(unsigned int)AT91C_CKGR_BIASEN_ENABLED;
+}
+
+//------------------------------------------------------------------------------
+/// Enables the BIAS of the USB controller
+//------------------------------------------------------------------------------
+static inline void UDPHS_EnableBIAS( void )
+{
+ UDPHS_DisableBIAS();
+ AT91C_BASE_PMC->PMC_UCKR |= AT91C_CKGR_BIASEN_ENABLED;
+}
+
+//------------------------------------------------------------------------------
+/// Enable UDPHS Peripheral
+//------------------------------------------------------------------------------
+static inline void UDPHS_EnablePeripheral( void )
+{
+#if !defined (PMC_BY_HARD)
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDPHS);
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Enable UDPHS clock
+//------------------------------------------------------------------------------
+static inline void UDPHS_EnableUsbClock( void )
+{
+#if !defined (PMC_BY_HARD)
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDPHS);
+ // Enable 480MHZ
+ //AT91C_BASE_CKGR->CKGR_UCKR |= (AT91C_CKGR_PLLCOUNT & (3 << 20)) | AT91C_CKGR_UPLLEN;
+ AT91C_BASE_CKGR->CKGR_UCKR |= ((0xf << 20) & (3 << 20)) | AT91C_CKGR_UPLLEN;
+ // Wait until UTMI PLL is locked
+ while ((AT91C_BASE_PMC->PMC_SR & AT91C_PMC_LOCKU) == 0);
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disable UDPHS clock
+//------------------------------------------------------------------------------
+static inline void UDPHS_DisableUsbClock( void )
+{
+#if !defined (PMC_BY_HARD)
+ AT91C_BASE_PMC->PMC_PCDR = (1 << AT91C_ID_UDPHS);
+ // 480MHZ
+ AT91C_BASE_CKGR->CKGR_UCKR &= ~(unsigned int)AT91C_CKGR_UPLLEN;
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Handles a completed transfer on the given endpoint, invoking the
+/// configured callback if any.
+/// \param bEndpoint Number of the endpoint for which the transfer has completed.
+/// \param bStatus Status code returned by the transfer operation
+//------------------------------------------------------------------------------
+static void UDPHS_EndOfTransfer( unsigned char bEndpoint, char bStatus )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Check that endpoint was sending or receiving data
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING) ) {
+
+ TRACE_DEBUG_WP("Eo");
+ if(pEndpoint->state == UDP_ENDPOINT_SENDING) {
+ pEndpoint->sendZLP = 0;
+ }
+ // Endpoint returns in Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Invoke callback is present
+ if (pTransfer->fCallback != 0) {
+
+ ((TransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ bStatus,
+ pTransfer->transferred,
+ pTransfer->remaining + pTransfer->buffered);
+ }
+ else {
+ TRACE_DEBUG_WP("No callBack\n\r");
+ }
+ }
+ else if ( (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
+
+ MblTransfer* pMblt = (MblTransfer*)&(pEndpoint->transfer);
+ MblTransferCallback fCallback;
+ void* pArg;
+
+ TRACE_DEBUG_WP("EoMT ");
+
+ #ifdef DMA
+ { DmaLlTransfer *pDmat = (DmaLlTransfer*)&(pEndpoint->transfer);
+ fCallback = UDP_IsDmaUsed(bEndpoint) ?
+ pDmat->fCallback : pMblt->fCallback;
+ pArg = UDP_IsDmaUsed(bEndpoint) ?
+ pDmat->pArgument : pMblt->pArgument;
+ }
+ #else
+ fCallback = pMblt->fCallback;
+ pArg = pMblt->pArgument;
+ #endif
+
+ // Endpoint returns in Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+ // Invoke callback
+ if (fCallback != 0) {
+
+ (fCallback)(pArg, bStatus, 0);
+ }
+ else {
+ TRACE_DEBUG_WP("NoCB ");
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the correct RX flag in endpoint status register
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+static void UDPHS_ClearRxFlag( unsigned char bEndpoint )
+{
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_BK_RDY;
+}
+
+//------------------------------------------------------------------------------
+/// Update multi-buffer-transfer descriptors.
+/// \param pTransfer Pointer to instance MblTransfer.
+/// \param size Size of bytes that processed.
+/// \param forceEnd Force the buffer END.
+/// \return 1 if current buffer ended.
+//------------------------------------------------------------------------------
+static char UDPHS_MblUpdate(MblTransfer *pTransfer,
+ USBDTransferBuffer * pBi,
+ unsigned short size,
+ unsigned char forceEnd)
+{
+ // Update transfer descriptor
+ pBi->remaining -= size;
+ // Check if current buffer ended
+ if (pBi->remaining == 0 || forceEnd) {
+
+ // Process to next buffer
+ if ((++ pTransfer->currBuffer) == pTransfer->listSize) {
+ if (pTransfer->circList) {
+ pTransfer->currBuffer = 0;
+ }
+ else {
+ pTransfer->allUsed = 1;
+ }
+ }
+ // All buffer in the list is processed
+ if (pTransfer->currBuffer == pTransfer->freedBuffer) {
+ pTransfer->allUsed = 1;
+ }
+ // Continue transfer, prepare for next operation
+ if (pTransfer->allUsed == 0) {
+ pBi = &pTransfer->pMbl[pTransfer->currBuffer];
+ pBi->buffered = 0;
+ pBi->transferred = 0;
+ pBi->remaining = pBi->size;
+ }
+ return 1;
+ }
+ return 0;
+}
+/*
+void UDPHS_WriteFifo(volatile char* pFifo,
+ unsigned char* pBuffer,
+ unsigned int size)
+{
+ register unsigned int c8 = size >> 3;
+ register unsigned int c1 = size & 0x7;
+ for (; c8; c8 --) {
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+ *pFifo = *(pBuffer ++);
+ }
+ for (; c1; c1 --) {
+ *pFifo = *(pBuffer ++);
+ }
+}
+*/
+//------------------------------------------------------------------------------
+/// Transfers a data payload from the current tranfer buffer to the endpoint
+/// FIFO
+/// \param bEndpoint Number of the endpoint which is sending data.
+//------------------------------------------------------------------------------
+static char UDPHS_MblWriteFifo(unsigned char bEndpoint)
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->currBuffer]);
+ volatile char *pFifo;
+ signed int size;
+
+ volatile unsigned char * pBytes;
+ volatile char bufferEnd = 1;
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pBi->remaining) {
+
+ size = pBi->remaining;
+ }
+
+ TRACE_DEBUG_WP("w%d.%d ", pTransfer->currBuffer, size);
+ if (size == 0) {
+
+ return 1;
+ }
+
+ pTransfer->pLastLoaded = pBi;
+ pBytes = &(pBi->pBuffer[pBi->transferred + pBi->buffered]);
+ pBi->buffered += size;
+ bufferEnd = UDPHS_MblUpdate(pTransfer, pBi, size, 0);
+
+ // Write packet in the FIFO buffer
+ pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO
+ + (EPT_VIRTUAL_SIZE * bEndpoint));
+ if (size) {
+ signed int c8 = size >> 3;
+ signed int c1 = size & 0x7;
+ //printf("%d[%x] ", pBi->transferred, pBytes);
+ for (; c8; c8 --) {
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+ *(pFifo++) = *(pBytes ++);
+ }
+ for (; c1; c1 --) {
+ *(pFifo++) = *(pBytes ++);
+ }
+ }
+ return bufferEnd;
+}
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from the current tranfer buffer to the endpoint
+/// FIFO
+/// \param bEndpoint Number of the endpoint which is sending data.
+//------------------------------------------------------------------------------
+static void UDPHS_WritePayload( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ char *pFifo;
+ signed int size;
+ unsigned int dCtr;
+
+ pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint));
+
+ // Get the number of bytes to send
+ size = pEndpoint->size;
+ if (size > pTransfer->remaining) {
+
+ size = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->buffered += size;
+ pTransfer->remaining -= size;
+
+ // Write packet in the FIFO buffer
+ dCtr = 0;
+ while (size > 0) {
+
+ pFifo[dCtr] = *(pTransfer->pData);
+ pTransfer->pData++;
+ size--;
+ dCtr++;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Transfers a data payload from an endpoint FIFO to the current transfer buffer
+/// \param bEndpoint Endpoint number.
+/// \param wPacketSize Size of received data packet
+//------------------------------------------------------------------------------
+static void UDPHS_ReadPayload( unsigned char bEndpoint, int wPacketSize )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ char *pFifo;
+ unsigned char dBytes=0;
+
+ pFifo = (char*)((unsigned int *)AT91C_BASE_UDPHS_EPTFIFO + (EPT_VIRTUAL_SIZE * bEndpoint));
+
+ // Check that the requested size is not bigger than the remaining transfer
+ if (wPacketSize > pTransfer->remaining) {
+
+ pTransfer->buffered += wPacketSize - pTransfer->remaining;
+ wPacketSize = pTransfer->remaining;
+ }
+
+ // Update transfer descriptor information
+ pTransfer->remaining -= wPacketSize;
+ pTransfer->transferred += wPacketSize;
+
+ // Retrieve packet
+ while (wPacketSize > 0) {
+
+ *(pTransfer->pData) = pFifo[dBytes];
+ pTransfer->pData++;
+ wPacketSize--;
+ dBytes++;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Received SETUP packet from endpoint 0 FIFO
+/// \param pRequest Generic USB SETUP request sent over Control endpoints
+//------------------------------------------------------------------------------
+static void UDPHS_ReadRequest( USBGenericRequest *pRequest )
+{
+ unsigned int *pData = (unsigned int *)pRequest;
+ unsigned int fifo;
+
+ fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]);
+ *pData = fifo;
+ fifo = (AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0[0]);
+ pData++;
+ *pData = fifo;
+ //TRACE_ERROR("SETUP: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n\r", pData[0],pData[1],pData[2],pData[3],pData[4],pData[5],pData[6],pData[7]);
+}
+
+//------------------------------------------------------------------------------
+/// Reset all endpoint transfer descriptors
+//------------------------------------------------------------------------------
+static void UDPHS_ResetEndpoints( void )
+{
+ Endpoint *pEndpoint;
+ Transfer *pTransfer;
+ unsigned char bEndpoint;
+
+ // Reset the transfer descriptor of every endpoint
+ for( bEndpoint = 0; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) {
+
+ pEndpoint = &(endpoints[bEndpoint]);
+ pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Reset endpoint transfer descriptor
+ pTransfer->pData = 0;
+ pTransfer->transferred = -1;
+ pTransfer->buffered = -1;
+ pTransfer->remaining = -1;
+ pTransfer->fCallback = 0;
+ pTransfer->pArgument = 0;
+
+ // Reset endpoint state
+ pEndpoint->bank = 0;
+ pEndpoint->state = UDP_ENDPOINT_DISABLED;
+ // Reset ZLP
+ pEndpoint->sendZLP = 0;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Disable all endpoints (except control endpoint 0), aborting current
+/// transfers if necessary
+//------------------------------------------------------------------------------
+static void UDPHS_DisableEndpoints( void )
+{
+ unsigned char bEndpoint;
+
+ // Disable each endpoint, terminating any pending transfer
+ // Control endpoint 0 is not disabled
+ for( bEndpoint = 1; bEndpoint < CHIP_USB_NUMENDPOINTS; bEndpoint++ ) {
+
+ UDPHS_EndOfTransfer( bEndpoint, USBD_STATUS_ABORTED );
+ endpoints[bEndpoint].state = UDP_ENDPOINT_DISABLED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Endpoint interrupt handler.
+/// Handle IN/OUT transfers, received SETUP packets and STALLing
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+static void UDPHS_EndpointHandler( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ MblTransfer *pMblt = (MblTransfer*)&(pEndpoint->transfer);
+ unsigned int status = AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSTA;
+ unsigned short wPacketSize;
+ USBGenericRequest request;
+
+ TRACE_DEBUG_WP("E%d ", bEndpoint);
+ TRACE_DEBUG_WP("st:0x%X ", status);
+
+ // Handle interrupts
+ // IN packet sent
+ if( (AT91C_UDPHS_TX_PK_RDY == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTL & AT91C_UDPHS_TX_PK_RDY))
+ && (0 == (status & AT91C_UDPHS_TX_PK_RDY )) ) {
+
+ TRACE_DEBUG_WP("Wr ");
+
+ // Check that endpoint was sending multi-buffer-list
+ if( pEndpoint->state == UDP_ENDPOINT_SENDINGM ) {
+
+ USBDTransferBuffer * pMbli = pMblt->pLastLoaded;
+
+ TRACE_DEBUG_WP("TxM%d.%d,%d ",
+ pMblt->allUsed, pMbli->buffered, pMbli->remaining);
+
+ // End of transfer ?
+ if (pMblt->allUsed && pMbli->remaining == 0) {
+
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+
+ // Disable interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS =
+ AT91C_UDPHS_TX_PK_RDY;
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ else {
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP("%d ", pEndpoint->size);
+
+ if (pMbli->buffered > pEndpoint->size) {
+ pMbli->transferred += pEndpoint->size;
+ pMbli->buffered -= pEndpoint->size;
+ }
+ else {
+ pMbli->transferred += pMbli->buffered;
+ pMbli->buffered = 0;
+ }
+
+ // Send next packet
+ UDPHS_MblWriteFifo(bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA =
+ AT91C_UDPHS_TX_PK_RDY;
+
+ if (pMbli->remaining == 0 && pMbli->buffered == 0) {
+
+ if (pMblt->fCallback) {
+ ((MblTransferCallback) pTransfer->fCallback)
+ (pTransfer->pArgument,
+ USBD_STATUS_PARTIAL_DONE,
+ 1);
+ }
+ }
+ }
+ }
+
+ // Check that endpoint was in Sending state
+ if( pEndpoint->state == UDP_ENDPOINT_SENDING ) {
+
+ if (pTransfer->buffered > 0) {
+ pTransfer->transferred += pTransfer->buffered;
+ pTransfer->buffered = 0;
+ }
+
+ if( ((pTransfer->buffered)==0)
+ &&((pTransfer->transferred)==0)
+ &&((pTransfer->remaining)==0)
+ &&(pEndpoint->sendZLP == 0)) {
+ pEndpoint->sendZLP = 1;
+ }
+
+ // End of transfer ?
+ if( (pTransfer->remaining > 0)
+ ||(pEndpoint->sendZLP == 1)) {
+
+ pEndpoint->sendZLP = 2;
+ TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining);
+
+ // Transfer remaining data
+ TRACE_DEBUG_WP(" %d ", pEndpoint->size);
+
+ // Send next packet
+ UDPHS_WritePayload(bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY;
+ }
+ else {
+ TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining);
+
+ TRACE_DEBUG_WP(" %d ", pTransfer->transferred);
+
+ // Disable interrupt if this is not a control endpoint
+ if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) {
+
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_TX_PK_RDY;
+
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ pEndpoint->sendZLP = 0;
+ }
+ }
+ else {
+
+ TRACE_DEBUG("Error Wr %d", pEndpoint->sendZLP);
+ }
+ }
+
+ // OUT packet received
+ if( AT91C_UDPHS_RX_BK_RDY == (status & AT91C_UDPHS_RX_BK_RDY) ) {
+
+ TRACE_DEBUG_WP("Rd ");
+
+ // Check that the endpoint is in Receiving state
+ if (pEndpoint->state != UDP_ENDPOINT_RECEIVING) {
+
+ // Check if an ACK has been received on a Control endpoint
+ if( (0 == (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG & AT91C_UDPHS_EPT_TYPE))
+ && (0 == (status & AT91C_UDPHS_BYTE_COUNT)) ) {
+
+ // Control endpoint, 0 bytes received
+ // Acknowledge the data and finish the current transfer
+ TRACE_DEBUG_WP("Ack ");
+ UDPHS_ClearRxFlag(bEndpoint);
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ //todo remove endoftranfer and test
+ }
+ // Check if the data has been STALLed
+ else if( AT91C_UDPHS_FRCESTALL == (status & AT91C_UDPHS_FRCESTALL)) {
+
+ // Discard STALLed data
+ TRACE_DEBUG_WP("Discard ");
+ UDPHS_ClearRxFlag(bEndpoint);
+ }
+ // NAK the data
+ else {
+
+ TRACE_DEBUG_WP("Nak ");
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+ }
+ else {
+
+ // Endpoint is in Read state
+ // Retrieve data and store it into the current transfer buffer
+ wPacketSize = (unsigned short)((status & AT91C_UDPHS_BYTE_COUNT)>>20);
+
+ TRACE_DEBUG_WP("%d ", wPacketSize);
+ UDPHS_ReadPayload(bEndpoint, wPacketSize);
+ UDPHS_ClearRxFlag(bEndpoint);
+
+ // Check if the transfer is finished
+ if ((pTransfer->remaining == 0) || (wPacketSize < pEndpoint->size)) {
+
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = AT91C_UDPHS_RX_BK_RDY;
+
+ // Disable interrupt if this is not a control endpoint
+ if( AT91C_UDPHS_EPT_TYPE_CTL_EPT != (AT91C_UDPHS_EPT_TYPE & (AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG)) ) {
+
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ }
+ }
+
+
+ // STALL sent
+ if( AT91C_UDPHS_STALL_SNT == (status & AT91C_UDPHS_STALL_SNT) ) {
+
+ TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint);
+
+ // Acknowledge the stall flag
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_STALL_SNT;
+
+ // If the endpoint is not halted, clear the STALL condition
+ if (pEndpoint->state != UDP_ENDPOINT_HALTED) {
+
+ TRACE_WARNING( "_ " );
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_FRCESTALL;
+ }
+ }
+
+ // SETUP packet received
+ if( AT91C_UDPHS_RX_SETUP == (status & AT91C_UDPHS_RX_SETUP) ) {
+
+ TRACE_DEBUG_WP("Stp ");
+
+ // If a transfer was pending, complete it
+ // Handles the case where during the status phase of a control write
+ // transfer, the host receives the device ZLP and ack it, but the ack
+ // is not received by the device
+ if ((pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)) {
+
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS);
+ }
+ // Copy the setup packet
+ UDPHS_ReadRequest(&request);
+
+ // Acknowledge setup packet
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_RX_SETUP;
+
+ // Forward the request to the upper layer
+ USBDCallbacks_RequestReceived(&request);
+ }
+
+}
+
+//------------------------------------------------------------------------------
+// Interrupt service routine
+//------------------------------------------------------------------------------
+#ifdef DMA
+//----------------------------------------------------------------------------
+/// Endpoint DMA interrupt handler.
+/// This function (ISR) handles dma interrupts
+/// \param bEndpoint Index of endpoint
+//----------------------------------------------------------------------------
+static void UDPHS_DmaHandler( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+ int justTransferred;
+ unsigned int status;
+ unsigned char result = USBD_STATUS_SUCCESS;
+
+ status = AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
+ TRACE_DEBUG_WP("DmaE%d,%x ", bEndpoint, status);
+
+ if (pEndpoint->state == UDP_ENDPOINT_SENDINGM) {
+
+ DmaLlTransfer *pDmat = (DmaLlTransfer*)&(pEndpoint->transfer);
+ USBDDmaDescriptor *pDi = pDmat->pCurrBuffer;
+ USBDDmaDescriptor *pNi = (USBDDmaDescriptor*)AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC;
+ unsigned char bufCnt = 0;
+
+ if (AT91C_UDPHS_END_BF_ST == (status & AT91C_UDPHS_END_BF_ST)) {
+
+ // Stop loading descriptors
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &=
+ ~((unsigned int)AT91C_UDPHS_LDNXT_DSC);
+
+ //printf("%x,%x|",
+ // (char)status,
+ // (short)AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC);
+
+ while( pDi->pNxtDesc != pNi ) {
+
+ // All descriptor processed
+ if (pDi == 0) break;
+ if (pDi->used) break;
+
+ // Current descriptor processed
+ /*
+ pDi->ctrlSettings = 0
+ //|AT91C_UDPHS_CHANN_ENB
+ //| AT91C_UDPHS_LDNXT_DSC
+ //| AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ //| AT91C_UDPHS_END_B_EN
+ //| AT91C_UDPHS_END_BUFFIT
+ //| AT91C_UDPHS_DESC_LD_IT
+ ; */
+ pDi->used = 1; // Flag as used
+ bufCnt ++;
+ pDi = pDi->pNxtDesc;
+ }
+ pDmat->pCurrBuffer = pDi;
+
+ if (bufCnt) {
+
+ if (pDmat->fCallback) {
+
+ pDmat->fCallback(pDmat->pArgument,
+ ((result == USBD_STATUS_SUCCESS) ?
+ USBD_STATUS_PARTIAL_DONE : result),
+ bufCnt);
+ }
+ }
+
+ if ( (pNi == 0)
+ || (pNi->used && pNi) ) {
+
+ // Disable DMA endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0;
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint);
+
+ TRACE_DEBUG_WP("EoMDT ");
+ //printf("E:N%x,C%d ", (short)pNi, bufCnt);
+
+ UDPHS_EndOfTransfer(bEndpoint, result);
+ }
+ else {
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL |=
+ (AT91C_UDPHS_LDNXT_DSC);
+ }
+ }
+ else {
+
+ TRACE_ERROR("UDPHS: Dma(0x%X)\n\r", status);
+ result = USBD_STATUS_ABORTED;
+ UDPHS_EndOfTransfer(bEndpoint, result);
+ }
+ return;
+ }
+ else if (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM) {
+ return;
+ }
+
+ // Disable DMA interrupt to avoid receiving 2 interrupts (B_EN and TR_EN)
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL &=
+ ~(unsigned int)(AT91C_UDPHS_END_TR_EN | AT91C_UDPHS_END_B_EN);
+
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint);
+
+ if( AT91C_UDPHS_END_BF_ST == (status & AT91C_UDPHS_END_BF_ST) ) {
+
+ TRACE_DEBUG_WP("EndBuffer ");
+
+ // BUFF_COUNT holds the number of untransmitted bytes.
+ // BUFF_COUNT is equal to zero in case of good transfer
+ justTransferred = pTransfer->buffered
+ - ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16);
+ pTransfer->transferred += justTransferred;
+
+ pTransfer->buffered =
+ ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16);
+
+ pTransfer->remaining -= justTransferred;
+
+ TRACE_DEBUG_WP("\n\r1pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("1pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("1pTransfer->remaining %d \n\r", pTransfer->remaining);
+
+ if( (pTransfer->remaining + pTransfer->buffered) > 0 ) {
+
+ // Prepare an other transfer
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS =
+ (unsigned int)((pTransfer->pData) + (pTransfer->transferred));
+
+ // Clear unwanted interrupts
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
+
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
+ // DMA config for receive the good size of buffer, or an error buffer
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL =
+ ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT)
+ | AT91C_UDPHS_END_TR_EN
+ | AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ | AT91C_UDPHS_CHANN_ENB );
+ }
+ }
+ else if( AT91C_UDPHS_END_TR_ST == (status & AT91C_UDPHS_END_TR_ST) ) {
+
+ TRACE_DEBUG_WP("EndTransf ");
+
+ pTransfer->transferred = pTransfer->buffered
+ - ((status & (unsigned int)AT91C_UDPHS_BUFF_COUNT) >> 16);
+ pTransfer->remaining = 0;
+ TRACE_DEBUG_WP("\n\r0pTransfer->buffered %d \n\r", pTransfer->buffered);
+ TRACE_DEBUG_WP("0pTransfer->transferred %d \n\r", pTransfer->transferred);
+ TRACE_DEBUG_WP("0pTransfer->remaining %d \n\r", pTransfer->remaining);
+ }
+ else {
+
+ TRACE_ERROR("UDPHS_DmaHandler: Error (0x%08X)\n\r", status);
+ result = USBD_STATUS_ABORTED;
+ }
+
+ // Invoke callback
+ if( pTransfer->remaining == 0 ) {
+
+ TRACE_DEBUG_WP("EOT ");
+ UDPHS_EndOfTransfer(bEndpoint, result);
+ }
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// USB device interrupt handler
+/// Manages device resume, suspend, end of bus reset.
+/// Forwards endpoint interrupts to the appropriate handler.
+//------------------------------------------------------------------------------
+void USBD_IrqHandler(void)
+{
+ unsigned int status;
+ unsigned char numIT;
+
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Set(USBD_LEDUSB);
+ }
+
+ // Get interrupts status
+ status = AT91C_BASE_UDPHS->UDPHS_INTSTA;
+ status &= AT91C_BASE_UDPHS->UDPHS_IEN;
+
+ // Handle all UDPHS interrupts
+ TRACE_DEBUG_WP("H");
+ while (status != 0) {
+
+ // Start Of Frame (SOF)
+ if ((status & AT91C_UDPHS_IEN_SOF) != 0) {
+
+ TRACE_DEBUG_WP("SOF ");
+
+ // Invoke the SOF callback
+ //USB_StartOfFrameCallback(pUsb);
+
+ // Acknowledge interrupt
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_IEN_SOF;
+ status &= ~(unsigned int)AT91C_UDPHS_IEN_SOF;
+ }
+ // Suspend
+ // This interrupt is always treated last (hence the '==')
+ else if (status == AT91C_UDPHS_DET_SUSPD) {
+
+ TRACE_DEBUG_WP("S");
+
+ // The device enters the Suspended state
+ // MCK + UDPCK must be off
+ // Pull-Up must be connected
+ // Transceiver must be disabled
+
+ LED_Clear(USBD_LEDUSB);
+
+ UDPHS_DisableBIAS();
+
+ // Enable wakeup
+ AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM;
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_DET_SUSPD;
+
+ // Acknowledge interrupt
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_DET_SUSPD | AT91C_UDPHS_WAKE_UP;
+ previousDeviceState = deviceState;
+ deviceState = USBD_STATE_SUSPENDED;
+ UDPHS_DisableUsbClock();
+
+ // Invoke the Suspend callback
+ USBDCallbacks_Suspended();
+ }
+ // Resume
+ else if( ((status & AT91C_UDPHS_WAKE_UP) != 0) // line activity
+ || ((status & AT91C_UDPHS_ENDOFRSM) != 0)) { // pc wakeup
+ {
+ // Invoke the Resume callback
+ USBDCallbacks_Resumed();
+
+ TRACE_DEBUG_WP("R");
+
+ UDPHS_EnableUsbClock();
+ UDPHS_EnableBIAS();
+
+ // The device enters Configured state
+ // MCK + UDPCK must be on
+ // Pull-Up must be connected
+ // Transceiver must be enabled
+
+ deviceState = previousDeviceState;
+
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD;
+
+ AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_ENDOFRSM | AT91C_UDPHS_DET_SUSPD;
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_ENDOFRSM;
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_WAKE_UP;
+ }
+ }
+ // End of bus reset
+ else if ((status & AT91C_UDPHS_ENDRESET) == AT91C_UDPHS_ENDRESET) {
+
+// TRACE_DEBUG_WP("EoB ");
+
+ // The device enters the Default state
+ deviceState = USBD_STATE_DEFAULT;
+ // MCK + UDPCK are already enabled
+ // Pull-Up is already connected
+ // Transceiver must be enabled
+ // Endpoint 0 must be enabled
+
+ UDPHS_ResetEndpoints();
+ UDPHS_DisableEndpoints();
+ USBD_ConfigureEndpoint(0);
+
+ // Flush and enable the Suspend interrupt
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_WAKE_UP | AT91C_UDPHS_DET_SUSPD;
+
+ //// Enable the Start Of Frame (SOF) interrupt if needed
+ //if (pCallbacks->startOfFrame != 0)
+ //{
+ // AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_IEN_SOF;
+ //}
+
+ // Invoke the Reset callback
+ USBDCallbacks_Reset();
+
+ // Acknowledge end of bus reset interrupt
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_ENDRESET;
+
+ AT91C_BASE_UDPHS->UDPHS_IEN |= AT91C_UDPHS_DET_SUSPD;
+ }
+ // Handle upstream resume interrupt
+ else if (status & AT91C_UDPHS_UPSTR_RES) {
+
+ TRACE_DEBUG_WP("ExtRes ");
+
+ // - Acknowledge the IT
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES;
+ }
+ // Endpoint interrupts
+ else {
+#ifndef DMA
+ // Handle endpoint interrupts
+ for (numIT = 0; numIT < NUM_IT_MAX; numIT++) {
+
+ if ((status & (1 << SHIFT_INTERUPT << numIT)) != 0) {
+
+ UDPHS_EndpointHandler(numIT);
+ }
+ }
+#else
+ // Handle endpoint control interrupt
+ if ((status & (1 << SHIFT_INTERUPT << 0)) != 0) {
+
+ UDPHS_EndpointHandler( 0 );
+ }
+ else {
+
+ numIT = 1;
+ while((status&(0x7E<<SHIFT_DMA)) != 0) {
+
+ // Check if endpoint has a pending interrupt
+ if ((status & (1 << SHIFT_DMA << numIT)) != 0) {
+
+ UDPHS_DmaHandler(numIT);
+ status &= ~(1 << SHIFT_DMA << numIT);
+ if (status != 0) {
+
+ TRACE_INFO_WP("\n\r - ");
+ }
+ }
+ numIT++;
+ }
+ }
+#endif
+ }
+
+ // Retrieve new interrupt status
+ status = AT91C_BASE_UDPHS->UDPHS_INTSTA;
+ status &= AT91C_BASE_UDPHS->UDPHS_IEN;
+
+ TRACE_DEBUG_WP("\n\r");
+ if (status != 0) {
+
+ TRACE_DEBUG_WP(" - ");
+ }
+ }
+
+ if (deviceState >= USBD_STATE_POWERED) {
+
+ LED_Clear(USBD_LEDUSB);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Configure an endpoint with the provided endpoint descriptor
+/// \param pDdescriptor Pointer to the endpoint descriptor
+//------------------------------------------------------------------------------
+void USBD_ConfigureEndpoint(const USBEndpointDescriptor *pDescriptor)
+{
+ Endpoint *pEndpoint;
+ unsigned char bEndpoint;
+ unsigned char bType;
+ unsigned char bEndpointDir;
+ //unsigned char bInterval = 0;
+ unsigned char bNbTrans = 1;
+ unsigned char bSizeEpt = 0;
+ unsigned char bHs = ((AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_UDPHS_SPEED)
+ > 0);
+
+ // NULL descriptor -> Control endpoint 0
+ if (pDescriptor == 0) {
+
+ bEndpoint = 0;
+ pEndpoint = &(endpoints[bEndpoint]);
+ bType = USBEndpointDescriptor_CONTROL;
+ bEndpointDir = 0;
+ pEndpoint->size = CHIP_USB_ENDPOINTS_MAXPACKETSIZE(0);
+ pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(0);
+ }
+ else {
+
+ // The endpoint number
+ bEndpoint = USBEndpointDescriptor_GetNumber(pDescriptor);
+ pEndpoint = &(endpoints[bEndpoint]);
+ // Transfer type: Control, Isochronous, Bulk, Interrupt
+ bType = USBEndpointDescriptor_GetType(pDescriptor);
+ // interval
+ //bInterval = USBEndpointDescriptor_GetInterval(pDescriptor);
+ // Direction, ignored for control endpoints
+ bEndpointDir = USBEndpointDescriptor_GetDirection(pDescriptor);
+ pEndpoint->size = USBEndpointDescriptor_GetMaxPacketSize(pDescriptor);
+ pEndpoint->bank = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
+
+ // Convert descriptor value to EP configuration
+ if (bHs) { // HS Interval, *125us
+
+ // MPS: Bit12,11 specify NB_TRANS
+ bNbTrans = ((pEndpoint->size >> 11) & 0x3);
+ if (bNbTrans == 3)
+ bNbTrans = 1;
+ else
+ bNbTrans ++;
+
+ // Mask, bit 10..0 is the size
+ pEndpoint->size &= 0x3FF;
+ }
+ }
+
+ // Abort the current transfer is the endpoint was configured and in
+ // Write or Read state
+ if( (pEndpoint->state == UDP_ENDPOINT_RECEIVING)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDING)
+ || (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM)
+ || (pEndpoint->state == UDP_ENDPOINT_SENDINGM) ) {
+
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_RESET);
+ }
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Disable endpoint
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLDIS = (unsigned int)AT91C_UDPHS_SHRT_PCKT
+ | AT91C_UDPHS_BUSY_BANK
+ | AT91C_UDPHS_NAK_OUT
+ | AT91C_UDPHS_NAK_IN
+ | AT91C_UDPHS_STALL_SNT
+ | AT91C_UDPHS_RX_SETUP
+ | AT91C_UDPHS_TX_PK_RDY
+ | AT91C_UDPHS_TX_COMPLT
+ | AT91C_UDPHS_RX_BK_RDY
+ | AT91C_UDPHS_ERR_OVFLW
+ | AT91C_UDPHS_MDATA_RX
+ | AT91C_UDPHS_DATAX_RX
+ | AT91C_UDPHS_NYET_DIS
+ | AT91C_UDPHS_INTDIS_DMA
+ | AT91C_UDPHS_AUTO_VALID
+ | AT91C_UDPHS_EPT_DISABL;
+
+ // Reset Endpoint Fifos
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL;
+ AT91C_BASE_UDPHS->UDPHS_EPTRST = 1<<bEndpoint;
+
+ // Configure endpoint
+ if( pEndpoint->size <= 8 ) {
+ bSizeEpt = 0;
+ }
+ else if ( pEndpoint->size <= 16 ) {
+ bSizeEpt = 1;
+ }
+ else if ( pEndpoint->size <= 32 ) {
+ bSizeEpt = 2;
+ }
+ else if ( pEndpoint->size <= 64 ) {
+ bSizeEpt = 3;
+ }
+ else if ( pEndpoint->size <= 128 ) {
+ bSizeEpt = 4;
+ }
+ else if ( pEndpoint->size <= 256 ) {
+ bSizeEpt = 5;
+ }
+ else if ( pEndpoint->size <= 512 ) {
+ bSizeEpt = 6;
+ }
+ else if ( pEndpoint->size <= 1024 ) {
+ bSizeEpt = 7;
+ } //else {
+ // sizeEpt = 0; // control endpoint
+ //}
+
+ // Configure endpoint
+ if (bType == USBEndpointDescriptor_CONTROL) {
+
+ // Enable endpoint IT for control endpoint
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1<<SHIFT_INTERUPT<<bEndpoint);
+ }
+
+
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG = bSizeEpt
+ | ( bEndpointDir << 3)
+ | ( bType << 4)
+ | ((pEndpoint->bank) << 6)
+ | ( bNbTrans << 8)
+ ;
+
+ while( (signed int)AT91C_UDPHS_EPT_MAPD != (signed int)((AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG) & (unsigned int)AT91C_UDPHS_EPT_MAPD) ) {
+
+ // resolved by clearing the reset IT in good place
+ TRACE_ERROR("PB bEndpoint: 0x%X\n\r", bEndpoint);
+ TRACE_ERROR("PB bSizeEpt: 0x%X\n\r", bSizeEpt);
+ TRACE_ERROR("PB bEndpointDir: 0x%X\n\r", bEndpointDir);
+ TRACE_ERROR("PB bType: 0x%X\n\r", bType);
+ TRACE_ERROR("PB pEndpoint->bank: 0x%X\n\r", pEndpoint->bank);
+ TRACE_ERROR("PB UDPHS_EPTCFG: 0x%X\n\r", AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG);
+ for(;;);
+ }
+
+ if (bType == USBEndpointDescriptor_CONTROL) {
+
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY
+ | AT91C_UDPHS_RX_SETUP
+ | AT91C_UDPHS_EPT_ENABL;
+ }
+ else {
+#ifndef DMA
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL;
+#else
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_AUTO_VALID
+ | AT91C_UDPHS_EPT_ENABL;
+#endif
+ }
+
+}
+
+//------------------------------------------------------------------------------
+/// Sends data through an USB endpoint (IN)
+/// Sets up the transfer descriptor, write one or two data payloads
+/// (depending on the number of FIFO banks for the endpoint) and then
+/// starts the actual transfer. The operation is complete when all
+/// the data has been sent.
+/// \param bEndpoint Index of endpoint
+/// \param *pData Data to be written
+/// \param dLength Data length to be send
+/// \param fCallback Callback to be call after the success command
+/// \param *pArgument Callback argument
+/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+char USBD_Write( unsigned char bEndpoint,
+ const void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Return if the endpoint is not in IDLE state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Write%d(%d) ", bEndpoint, dLength);
+ pEndpoint->sendZLP = 0;
+ // Setup the transfer descriptor
+ pTransfer->pData = (void *) pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+ // Send one packet
+ pEndpoint->state = UDP_ENDPOINT_SENDING;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) {
+#endif
+ // Enable endpoint IT
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY;
+
+#ifdef DMA
+ }
+ else {
+ if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) {
+ TRACE_FATAL("Endpoint has no DMA\n\r");
+ }
+ if( pTransfer->remaining == 0 ) {
+ // DMA not handle ZLP
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY;
+ // Enable endpoint IT
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_TX_PK_RDY;
+ }
+ else {
+ // Others endpoints (not control)
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ // Transfer the max
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ // Transfer the good size
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ TRACE_DEBUG_WP("\n\r_WR[%x]:%d ", pTransfer->pData, pTransfer->remaining );
+ TRACE_DEBUG_WP("B:%d ", pTransfer->buffered );
+ TRACE_DEBUG_WP("T:%d ", pTransfer->transferred );
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData);
+
+ // Clear unwanted interrupts
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
+ // DMA config
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL =
+ ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT)
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ | AT91C_UDPHS_CHANN_ENB );
+ }
+ }
+#endif
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Sends data frames through a USB endpoint. Sets up the transfer descriptor
+/// list, writes one or two data payloads (depending on the number of FIFO bank
+/// for the endpoint) and then starts the actual transfer. The operation invoke
+/// a callback with RC USBD_STATUS_PARTIAL_DONE each time when a buffer is
+/// transferred and is complete when all the data has been sent.
+///
+/// *If the size of the frame is greater than the size of the endpoint
+/// (or twice the size if the endpoint has two FIFO banks), then the buffer
+/// must be kept allocated until the frame is finished*. This means that
+/// it is not possible to declare it on the stack (i.e. as a local variable
+/// of a function which returns after starting a transfer).
+///
+/// \param bEndpoint Endpoint number.
+/// \param pMbl Pointer to a frame list with the data to send.
+/// Two different list is supported, for EPs that support DMA,
+/// the frame is described by USBDDmaDescriptor link list,
+/// for EPs that uses FIFO the frame is described by
+/// USBDTransferBuffer array.
+/// For DMA transfer, the size of each frame is limited by the
+/// max size of one DMA transfer. When using DMA, the frame list
+/// size and size of each frame should be larger so that more
+/// efficiency is achieved and CPU could have more time on
+/// handler of each buffer end event.
+/// \param wListSize Size of the frame list.
+/// \param bCircList Circle the list.
+/// \param wStartNdx Starting buffer index in the list.
+/// \param fCallback Optional callback function to invoke when the transfer is
+/// complete.
+/// \param pArgument Optional argument to the callback function.
+/// \return USBD_STATUS_SUCCESS if the transfer has been started;
+/// otherwise, the corresponding error status code.
+/// \see USBDDmaDescriptor, USBDTransferBuffer
+//------------------------------------------------------------------------------
+char USBD_MblWrite( unsigned char bEndpoint,
+ void *pMbl,
+ unsigned short wListSize,
+ unsigned char bCircList,
+ unsigned short wStartNdx,
+ MblTransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ unsigned short i;
+
+ // EP0 is not suitable for Mbl
+ if (bEndpoint == 0) {
+
+ return USBD_STATUS_INVALID_PARAMETER;
+ }
+
+ // Check that the endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ //return USBD_STATUS_LOCKED;
+ }
+ // Setup state
+ pEndpoint->state = UDP_ENDPOINT_SENDINGM;
+
+ TRACE_DEBUG_WP("WriteM%d(0x%x,%d) ", bEndpoint, pMbl, wListSize);
+
+ // Start from first if not circled list
+ if (!bCircList) wStartNdx = 0;
+
+#ifdef DMA
+ if (UDP_IsDmaUsed(bEndpoint)) {
+
+ DmaLlTransfer *pDmallt = (DmaLlTransfer*)&(pEndpoint->transfer);
+ USBDDmaDescriptor * pDi = (USBDDmaDescriptor*)pMbl;
+
+ // DMA config
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0;
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(1 << SHIFT_DMA << bEndpoint);
+
+ // Setup the transfer descriptor
+ pDmallt->pMbl = (USBDDmaDescriptor*)pMbl;
+ pDmallt->listSize = wListSize;
+ pDmallt->fCallback = fCallback;
+ pDmallt->pArgument = pArgument;
+ pDmallt->circList = bCircList;
+ pDmallt->allUsed = 0;
+
+ // Check all buffers, fill settings
+ for (i = 0; i < wListSize - 1; i ++) {
+
+ if (pDi->bufferLength > DMA_MAX_FIFO_SIZE) {
+
+ TRACE_ERROR("DMA buffer size %d exceeds max %d\n\r",
+ pDi->bufferLength, DMA_MAX_FIFO_SIZE);
+ return USBD_STATUS_INVALID_PARAMETER;
+ }
+
+ // Channel control value
+ pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
+ | AT91C_UDPHS_LDNXT_DSC
+ | AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ | AT91C_UDPHS_DESC_LD_IT
+ ;
+ pDi->used = 0;
+ pDi = pDi->pNxtDesc;
+ }
+
+ // Circled list check
+ pDi->used = 0;
+ if (bCircList) {
+
+ pDi->pNxtDesc = pDmallt->pMbl;
+ pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
+ | AT91C_UDPHS_LDNXT_DSC
+ | AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ //| AT91C_UDPHS_DESC_LD_IT
+ ;
+ }
+ else {
+
+ pDi->pNxtDesc = 0;
+ pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
+ //| AT91C_UDPHS_LDNXT_DSC
+ | AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ //| AT91C_UDPHS_DESC_LD_IT
+ ;
+ }
+
+ // Start from 'wStartNdx'th descriptor
+ pDi = (USBDDmaDescriptor*)pMbl;
+ for (;wStartNdx; wStartNdx --) {
+ pDi = pDi->pNxtDesc;
+ }
+ pDmallt->pCurrBuffer = (USBDDmaDescriptor*)pDi;
+ pDmallt->pFreedBuffer = (USBDDmaDescriptor*)pDi;
+
+ // Disable DMA when interrupt happenned
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_INTDIS_DMA;
+
+ // Clear unwanted interrupts
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMANXTDSC = (unsigned int)pMbl;
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC
+ //| AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ //| AT91C_UDPHS_END_B_EN
+ //| AT91C_UDPHS_END_BUFFIT
+ //| AT91C_UDPHS_DESC_LD_IT
+ ;
+
+ return USBD_STATUS_SUCCESS;
+ }
+#endif
+
+ // DMA is not used
+ {
+ unsigned char nbBanks = CHIP_USB_ENDPOINTS_BANKS(bEndpoint);
+
+ // Setup the transfer descriptor
+ pTransfer->pMbl = (USBDTransferBuffer*)pMbl;
+ pTransfer->listSize = wListSize;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+ pTransfer->currBuffer = wStartNdx;
+ pTransfer->freedBuffer = 0;
+ pTransfer->pLastLoaded = &(((USBDTransferBuffer*)pMbl)[wStartNdx]);
+ pTransfer->circList = bCircList;
+ pTransfer->allUsed = 0;
+
+ // Clear all buffer
+ for (i = 0; i < wListSize; i ++) {
+
+ pTransfer->pMbl[i].transferred = 0;
+ pTransfer->pMbl[i].buffered = 0;
+ pTransfer->pMbl[i].remaining = pTransfer->pMbl[i].size;
+ }
+
+ // Fill data into FIFO
+ for (;
+ nbBanks && pTransfer->pMbl[pTransfer->currBuffer].remaining;
+ nbBanks --) {
+
+ UDPHS_MblWriteFifo(bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA =
+ AT91C_UDPHS_TX_PK_RDY;
+ }
+
+ // Enable interrup
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = 0
+ //| AT91C_UDPHS_TX_COMPLT
+ | AT91C_UDPHS_TX_PK_RDY
+ ;
+ return USBD_STATUS_SUCCESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reads incoming data on an USB endpoint (OUT)
+/// \param bEndpoint Index of endpoint
+/// \param *pData Data to be readen
+/// \param dLength Data length to be receive
+/// \param fCallback Callback to be call after the success command
+/// \param *pArgument Callback argument
+/// \return USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+char USBD_Read( unsigned char bEndpoint,
+ void *pData,
+ unsigned int dLength,
+ TransferCallback fCallback,
+ void *pArgument )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ Transfer *pTransfer = (Transfer*)&(pEndpoint->transfer);
+
+ // Return if the endpoint is not in IDLE state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength);
+
+ // Endpoint enters Receiving state
+ pEndpoint->state = UDP_ENDPOINT_RECEIVING;
+
+ // Set the transfer descriptor
+ pTransfer->pData = pData;
+ pTransfer->remaining = dLength;
+ pTransfer->buffered = 0;
+ pTransfer->transferred = 0;
+ pTransfer->fCallback = fCallback;
+ pTransfer->pArgument = pArgument;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) {
+#endif
+ // Control endpoint
+ // Enable endpoint IT
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_INTERUPT << bEndpoint);
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCTLENB = AT91C_UDPHS_RX_BK_RDY;
+#ifdef DMA
+ }
+ else {
+ if( CHIP_USB_ENDPOINTS_DMA(bEndpoint) == 0 ) {
+ TRACE_FATAL("Endpoint has no DMA\n\r");
+ }
+ TRACE_DEBUG_WP("Read%d(%d) ", bEndpoint, dLength);
+
+ // Others endpoints (not control)
+ if( pTransfer->remaining > DMA_MAX_FIFO_SIZE ) {
+
+ // Transfer the max
+ pTransfer->buffered = DMA_MAX_FIFO_SIZE;
+ }
+ else {
+ // Transfer the good size
+ pTransfer->buffered = pTransfer->remaining;
+ }
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMAADDRESS = (unsigned int)(pTransfer->pData);
+
+ // Clear unwanted interrupts
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMASTATUS;
+
+ // Enable DMA endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1 << SHIFT_DMA << bEndpoint);
+
+ TRACE_DEBUG_WP("\n\r_RR:%d ", pTransfer->remaining );
+ TRACE_DEBUG_WP("B:%d ", pTransfer->buffered );
+ TRACE_DEBUG_WP("T:%d ", pTransfer->transferred );
+
+ // DMA config
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL = 0; // raz
+ AT91C_BASE_UDPHS->UDPHS_DMA[bEndpoint].UDPHS_DMACONTROL =
+ ( ((pTransfer->buffered << 16) & AT91C_UDPHS_BUFF_COUNT)
+ | AT91C_UDPHS_END_TR_EN
+ | AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ | AT91C_UDPHS_CHANN_ENB );
+ }
+#endif
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Reuse first used/released buffer with new buffer address and size to be used
+/// in transfer again. Only valid when frame list is ringed. Can be used for
+/// both read & write.
+/// \param bEndpoint Endpoint number.
+/// \param pNewBuffer Pointer to new buffer with data to send (0 to keep last).
+/// \param wNewSize Size of the data buffer
+//------------------------------------------------------------------------------
+char USBD_MblReuse( unsigned char bEndpoint,
+ unsigned char *pNewBuffer,
+ unsigned short wNewSize )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ MblTransfer *pTransfer = (MblTransfer*)&(pEndpoint->transfer);
+ USBDTransferBuffer *pBi = &(pTransfer->pMbl[pTransfer->freedBuffer]);
+
+ // Only for Multi-buffer-circle list
+ if (bEndpoint != 0
+ && (pEndpoint->state == UDP_ENDPOINT_RECEIVINGM
+ || pEndpoint->state == UDP_ENDPOINT_SENDINGM)) {
+ }
+ else {
+
+ return USBD_STATUS_WRONG_STATE;
+ }
+
+ TRACE_DEBUG_WP("MblReuse(%d), st%x, circ%d\n\r",
+ bEndpoint, pEndpoint->state, pTransfer->circList);
+
+#ifdef DMA
+ if (UDP_IsDmaUsed(bEndpoint)) {
+
+ DmaLlTransfer *pDmallt = (DmaLlTransfer*)&(pEndpoint->transfer);
+ USBDDmaDescriptor *pDi = pDmallt->pFreedBuffer;
+
+ // ONLY for circled list
+ if (!pDmallt->circList) {
+
+ return USBD_STATUS_WRONG_STATE;
+ }
+
+ // Check if there is freed buffer
+ if ((pDi == 0) || (pDi && !pDi->used) ) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ // Update transfer information
+ pDmallt->pFreedBuffer = pDi->pNxtDesc;
+ if (pNewBuffer) {
+
+ pDi->pDataAddr = pNewBuffer;
+ pDi->bufferLength = wNewSize;
+ }
+ /*
+ pDi->ctrlSettings = AT91C_UDPHS_CHANN_ENB
+ | AT91C_UDPHS_LDNXT_DSC
+ | AT91C_UDPHS_END_TR_EN
+ //| AT91C_UDPHS_END_TR_IT
+ | AT91C_UDPHS_END_B_EN
+ | AT91C_UDPHS_END_BUFFIT
+ | AT91C_UDPHS_DESC_LD_IT
+ ; */
+ pDi->used = 0;
+
+ pDmallt->allUsed = 0;
+
+ return USBD_STATUS_SUCCESS;
+ }
+#endif
+
+ // DMA is not used
+ {
+
+ // ONLY for circled list
+ if (!pTransfer->circList) {
+
+ return USBD_STATUS_WRONG_STATE;
+ }
+
+ // Check if there is freed buffer
+ if (pTransfer->freedBuffer == pTransfer->currBuffer
+ && !pTransfer->allUsed) {
+
+ return USBD_STATUS_LOCKED;
+ }
+
+ // Update transfer information
+ if ((++ pTransfer->freedBuffer) == pTransfer->listSize)
+ pTransfer->freedBuffer = 0;
+ if (pNewBuffer) {
+
+ pBi->pBuffer = pNewBuffer;
+ pBi->size = wNewSize;
+ }
+ pBi->buffered = 0;
+ pBi->transferred = 0;
+ pBi->remaining = pBi->size;
+
+ // At least one buffer is not processed
+ pTransfer->allUsed = 0;
+ }
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Put endpoint into Halt state
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+void USBD_Halt( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ TRACE_INFO("usbd_Halt%d ", bEndpoint);
+ // Check that endpoint is enabled and not already in Halt state
+ if( (pEndpoint->state != UDP_ENDPOINT_DISABLED)
+ && (pEndpoint->state != UDP_ENDPOINT_HALTED) ) {
+
+ TRACE_INFO("Halt%d ", bEndpoint);
+
+ // Abort the current transfer if necessary
+ UDPHS_EndOfTransfer(bEndpoint, USBD_STATUS_ABORTED);
+
+ // Put endpoint into Halt state
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL;
+ pEndpoint->state = UDP_ENDPOINT_HALTED;
+
+#ifdef DMA
+ // Test if endpoint type control
+ if(AT91C_UDPHS_EPT_TYPE_CTL_EPT == (AT91C_UDPHS_EPT_TYPE&(AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCFG))) {
+#endif
+ // Enable the endpoint interrupt
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1<<SHIFT_INTERUPT<<bEndpoint);
+#ifdef DMA
+ }
+ else {
+ // Enable IT DMA
+ AT91C_BASE_UDPHS->UDPHS_IEN |= (1<<SHIFT_DMA<<bEndpoint);
+ }
+#endif
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the Halt feature on the given endpoint.
+/// \param bEndpoint Index of endpoint
+//------------------------------------------------------------------------------
+void USBD_Unhalt( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check if the endpoint is enabled
+ //if (pEndpoint->state != UDP_ENDPOINT_DISABLED) {
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+
+ TRACE_DEBUG_WP("Unhalt%d ", bEndpoint);
+
+ // Return endpoint to Idle state
+ pEndpoint->state = UDP_ENDPOINT_IDLE;
+
+ // Clear FORCESTALL flag
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ | AT91C_UDPHS_FRCESTALL;
+
+ // Reset Endpoint Fifos
+ AT91C_BASE_UDPHS->UDPHS_EPTRST = (1<<bEndpoint);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns the current Halt status of an endpoint.
+/// \param bEndpoint Index of endpoint
+/// \return 1 if the endpoint is currently halted; otherwise 0
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHalted( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+ unsigned char status = 0;
+
+ if (pEndpoint->state == UDP_ENDPOINT_HALTED) {
+ status = 1;
+ }
+ return( status );
+}
+
+//------------------------------------------------------------------------------
+/// IS High Speed device working in High Speed ?
+/// \return 1 if the device is in High Speed; otherwise 0 (Full Speed)
+//------------------------------------------------------------------------------
+unsigned char USBD_IsHighSpeed( void )
+{
+ unsigned char status = 0;
+
+ if( AT91C_UDPHS_SPEED == (AT91C_BASE_UDPHS->UDPHS_INTSTA & AT91C_UDPHS_SPEED) )
+ {
+ // High Speed
+ TRACE_DEBUG_WP("High Speed\n\r");
+ status = 1;
+ }
+ else {
+ TRACE_DEBUG_WP("Full Speed\n\r");
+ }
+ return( status );
+}
+
+
+//------------------------------------------------------------------------------
+/// Causes the endpoint to acknowledge the next received packet with a STALL
+/// handshake.
+/// Further packets are then handled normally.
+/// \param bEndpoint Index of endpoint
+/// \return Operation result code: USBD_STATUS_LOCKED or USBD_STATUS_SUCCESS
+//------------------------------------------------------------------------------
+unsigned char USBD_Stall( unsigned char bEndpoint )
+{
+ Endpoint *pEndpoint = &(endpoints[bEndpoint]);
+
+ // Check that endpoint is in Idle state
+ if (pEndpoint->state != UDP_ENDPOINT_IDLE) {
+
+ TRACE_WARNING("UDP_Stall: Endpoint%d locked\n\r", bEndpoint);
+ return USBD_STATUS_LOCKED;
+ }
+
+ TRACE_DEBUG_WP("Stall%d ", bEndpoint);
+
+ AT91C_BASE_UDPHS->UDPHS_EPT[bEndpoint].UDPHS_EPTSETSTA = AT91C_UDPHS_FRCESTALL;
+
+ return USBD_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Activates a remote wakeup procedure
+//------------------------------------------------------------------------------
+void USBD_RemoteWakeUp(void)
+{
+ TRACE_DEBUG_WP("Remote WakeUp\n\r");
+
+ // Device is currently suspended
+ if (deviceState == USBD_STATE_SUSPENDED) {
+
+ TRACE_DEBUG_WP("RW\n\r");
+ UDPHS_EnableUsbClock();
+
+ // Activates a remote wakeup
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_REWAKEUP;
+
+ while ((AT91C_BASE_UDPHS->UDPHS_CTRL&AT91C_UDPHS_REWAKEUP) == AT91C_UDPHS_REWAKEUP) {
+
+ TRACE_DEBUG_WP("W");
+ }
+ UDPHS_EnableBIAS();
+ }
+ // Device is NOT suspended
+ else {
+
+ TRACE_WARNING("USBD_RemoteWakeUp: Device is not suspended\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the device address
+/// \param address Adress to be set
+//------------------------------------------------------------------------------
+void USBD_SetAddress( unsigned char address )
+{
+ TRACE_DEBUG_WP("SetAddr(%d) ", address);
+
+ // Set address
+ AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_DEV_ADDR; // RAZ Address
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= address | AT91C_UDPHS_FADDR_EN;
+
+ // If the address is 0, the device returns to the Default state
+ if (address == 0) {
+ deviceState = USBD_STATE_DEFAULT;
+ }
+ // If the address is non-zero, the device enters the Address state
+ else {
+ deviceState = USBD_STATE_ADDRESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Changes the device state from Address to Configured, or from Configured
+/// to Address.
+/// This method directly access the last received SETUP packet to decide on
+/// what to do.
+/// \param cfgnum configuration number
+//------------------------------------------------------------------------------
+void USBD_SetConfiguration( unsigned char cfgnum )
+{
+ TRACE_DEBUG_WP("SetCfg(%d) ", cfgnum);
+
+ // Check the request
+ if( cfgnum != 0 ) {
+
+ // Enter Configured state
+ deviceState = USBD_STATE_CONFIGURED;
+ }
+ // If the configuration number is zero, the device goes back to the Address
+ // state
+ else {
+
+ // Go back to Address state
+ deviceState = USBD_STATE_ADDRESS;
+
+ // Abort all transfers
+ UDPHS_DisableEndpoints();
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Enables the pull-up on the D+ line to connect the device to the USB.
+//------------------------------------------------------------------------------
+void USBD_Connect( void )
+{
+ TRACE_DEBUG_WP("Conn ");
+#if defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_DETACH; // Pull Up on DP
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down
+
+#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX)
+ TRACE_DEBUG_WP("PUON 1\n\r");
+ AT91C_BASE_MATRIX->MATRIX_USBPCR |= AT91C_MATRIX_USBPCR_PUON;
+
+#elif defined(CHIP_USB_PULLUP_EXTERNAL)
+
+#ifdef PIN_USB_PULLUP
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ if( pinPullUp.type == PIO_OUTPUT_0 ) {
+
+ PIO_Set(&pinPullUp);
+ }
+ else {
+
+ PIO_Clear(&pinPullUp);
+ }
+#else
+ #error unsupported now
+#endif
+
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Unsupported pull-up type.
+
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Disables the pull-up on the D+ line to disconnect the device from the bus.
+//------------------------------------------------------------------------------
+void USBD_Disconnect( void )
+{
+ TRACE_DEBUG_WP("Disc ");
+
+#if defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach
+ AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_PULLD_DIS; // Enable Pull Down
+
+#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX)
+ AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
+
+#elif defined(CHIP_USB_PULLUP_EXTERNAL)
+
+#ifdef PIN_USB_PULLUP
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ if (pinPullUp.type == PIO_OUTPUT_0) {
+
+ PIO_Clear(&pinPullUp);
+ }
+ else {
+
+ PIO_Set(&pinPullUp);
+ }
+#else
+ #error unsupported now
+#endif
+
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Unsupported pull-up type.
+
+#endif
+
+ // Device returns to the Powered state
+ if (deviceState > USBD_STATE_POWERED) {
+
+ deviceState = USBD_STATE_POWERED;
+ }
+ if (previousDeviceState > USBD_STATE_POWERED) {
+
+ previousDeviceState = USBD_STATE_POWERED;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Certification test for High Speed device.
+/// \param bIndex Test to be done
+//------------------------------------------------------------------------------
+void USBD_Test( unsigned char bIndex )
+{
+ char *pFifo;
+ unsigned char i;
+
+ AT91C_BASE_UDPHS->UDPHS_IEN &= ~(unsigned int)AT91C_UDPHS_DET_SUSPD; // remove suspend for TEST
+ AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_SPEED_CFG_HS; // force High Speed (remove suspend)
+
+ switch( bIndex ) {
+
+ case USBFeatureRequest_TESTPACKET:
+ TRACE_DEBUG_WP("TEST_PACKET ");
+
+ AT91C_BASE_UDPHS->UDPHS_DMA[1].UDPHS_DMACONTROL = 0;
+ AT91C_BASE_UDPHS->UDPHS_DMA[2].UDPHS_DMACONTROL = 0;
+
+ // Configure endpoint 2, 64 bytes, direction IN, type BULK, 1 bank
+ AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG = AT91C_UDPHS_EPT_SIZE_64 | AT91C_UDPHS_EPT_DIR_IN | AT91C_UDPHS_EPT_TYPE_BUL_EPT | AT91C_UDPHS_BK_NUMBER_1;
+ while( (signed int)(AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCFG & (unsigned int)AT91C_UDPHS_EPT_MAPD) != (signed int)AT91C_UDPHS_EPT_MAPD ) {}
+
+ AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTCTLENB = AT91C_UDPHS_EPT_ENABL;
+
+ // Write FIFO
+ pFifo = (char*)((unsigned int *)(AT91C_BASE_UDPHS_EPTFIFO->UDPHS_READEPT0) + (EPT_VIRTUAL_SIZE * 2));
+ for( i=0; i<sizeof(test_packet_buffer); i++) {
+ pFifo[i] = test_packet_buffer[i];
+ }
+ // Tst PACKET
+ AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_TST_PKT;
+ // Send packet
+ AT91C_BASE_UDPHS->UDPHS_EPT[2].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY;
+ break;
+
+ case USBFeatureRequest_TESTJ:
+ TRACE_DEBUG_WP("TEST_J ");
+ AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_J;
+ break;
+
+ case USBFeatureRequest_TESTK:
+ TRACE_DEBUG_WP("TEST_K ");
+ AT91C_BASE_UDPHS->UDPHS_TST = AT91C_UDPHS_TST_K;
+ break;
+
+ case USBFeatureRequest_TESTSE0NAK:
+ TRACE_DEBUG_WP("TEST_SEO_NAK ");
+ AT91C_BASE_UDPHS->UDPHS_IEN = 0; // for test
+ break;
+
+ case USBFeatureRequest_TESTSENDZLP:
+ //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {}
+ AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSETSTA = AT91C_UDPHS_TX_PK_RDY;
+ //while( 0 != (AT91C_BASE_UDPHS->UDPHS_EPT[0].UDPHS_EPTSTA & AT91C_UDPHS_TX_PK_RDY ) ) {}
+ TRACE_DEBUG_WP("SEND_ZLP ");
+ break;
+ }
+ TRACE_DEBUG_WP("\n\r");
+}
+
+
+//------------------------------------------------------------------------------
+/// Initializes the specified USB driver
+/// This function initializes the current FIFO bank of endpoints,
+/// configures the pull-up and VBus lines, disconnects the pull-up and
+/// then trigger the Init callback.
+//------------------------------------------------------------------------------
+void USBD_Init(void)
+{
+ unsigned char i;
+
+ TRACE_DEBUG_WP("USBD Init()\n\r");
+
+ // Reset endpoint structures
+ UDPHS_ResetEndpoints();
+
+ // Enables the UDPHS peripheral
+ UDPHS_EnablePeripheral();
+
+ // XCHQ[2010.1.21]: From IP recomendation, the order for init is:
+ // - reset IP (EN_UDPHS), - enable PLL 480M, - enable USB Clock
+
+ // Enables the USB Clock
+ // UDPHS_EnableUsbClock();
+
+ // Configure the pull-up on D+ and disconnect it
+#if defined(CHIP_USB_PULLUP_INTERNAL)
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_DETACH; // detach
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_PULLD_DIS; // Disable Pull Down
+
+#elif defined(CHIP_USB_PULLUP_INTERNAL_BY_MATRIX)
+ TRACE_DEBUG_WP("PUON 0\n\r");
+ AT91C_BASE_MATRIX->MATRIX_USBPCR &= ~AT91C_MATRIX_USBPCR_PUON;
+
+#elif defined(CHIP_USB_PULLUP_EXTERNAL)
+#ifdef PIN_USB_PULLUP
+ const Pin pinPullUp = PIN_USB_PULLUP;
+ PIO_Configure(&pinPullUp, 1);
+ if (pinPullUp.type == PIO_OUTPUT_0) {
+
+ PIO_Clear(&pinPullUp);
+ }
+ else {
+
+ PIO_Set(&pinPullUp);
+ }
+#else
+ #error unsupported now
+#endif
+#elif !defined(CHIP_USB_PULLUP_ALWAYSON)
+ #error Unsupported pull-up type.
+
+#endif
+
+ // Reset and enable IP UDPHS
+ AT91C_BASE_UDPHS->UDPHS_CTRL &= ~(unsigned int)AT91C_UDPHS_EN_UDPHS;
+ AT91C_BASE_UDPHS->UDPHS_CTRL |= AT91C_UDPHS_EN_UDPHS;
+ // Enable and disable of the transceiver is automaticaly done by the IP.
+
+ // Enables the USB Clock
+ // (XCHQ[2010.1.21], IP recomendation, setup clock after reset IP)
+ UDPHS_EnableUsbClock();
+
+ // With OR without DMA !!!
+ // Initialization of DMA
+ for( i=1; i<=((AT91C_BASE_UDPHS->UDPHS_IPFEATURES & AT91C_UDPHS_DMA_CHANNEL_NBR)>>4); i++ ) {
+
+ // RESET endpoint canal DMA:
+ // DMA stop channel command
+ AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command
+
+ // Disable endpoint
+ AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLDIS = (unsigned int)AT91C_UDPHS_SHRT_PCKT
+ | AT91C_UDPHS_BUSY_BANK
+ | AT91C_UDPHS_NAK_OUT
+ | AT91C_UDPHS_NAK_IN
+ | AT91C_UDPHS_STALL_SNT
+ | AT91C_UDPHS_RX_SETUP
+ | AT91C_UDPHS_TX_PK_RDY
+ | AT91C_UDPHS_TX_COMPLT
+ | AT91C_UDPHS_RX_BK_RDY
+ | AT91C_UDPHS_ERR_OVFLW
+ | AT91C_UDPHS_MDATA_RX
+ | AT91C_UDPHS_DATAX_RX
+ | AT91C_UDPHS_NYET_DIS
+ | AT91C_UDPHS_INTDIS_DMA
+ | AT91C_UDPHS_AUTO_VALID
+ | AT91C_UDPHS_EPT_DISABL;
+
+ // Clear status endpoint
+ AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCLRSTA = AT91C_UDPHS_TOGGLESQ
+ | AT91C_UDPHS_FRCESTALL
+ | AT91C_UDPHS_RX_BK_RDY
+ | AT91C_UDPHS_TX_COMPLT
+ | AT91C_UDPHS_RX_SETUP
+ | AT91C_UDPHS_STALL_SNT
+ | AT91C_UDPHS_NAK_IN
+ | AT91C_UDPHS_NAK_OUT;
+
+ // Reset endpoint config
+ AT91C_BASE_UDPHS->UDPHS_EPT[i].UDPHS_EPTCTLENB = 0;
+
+ // Reset DMA channel (Buff count and Control field)
+ AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = AT91C_UDPHS_LDNXT_DSC; // NON STOP command
+
+ // Reset DMA channel 0 (STOP)
+ AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMACONTROL = 0; // STOP command
+
+ // Clear DMA channel status (read the register for clear it)
+ AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS = AT91C_BASE_UDPHS->UDPHS_DMA[i].UDPHS_DMASTATUS;
+
+ }
+
+ AT91C_BASE_UDPHS->UDPHS_TST = forceUsbFS ? AT91C_UDPHS_SPEED_CFG_FS : 0;
+ AT91C_BASE_UDPHS->UDPHS_IEN = 0;
+ AT91C_BASE_UDPHS->UDPHS_CLRINT = AT91C_UDPHS_UPSTR_RES
+ | AT91C_UDPHS_ENDOFRSM
+ | AT91C_UDPHS_WAKE_UP
+ | AT91C_UDPHS_ENDRESET
+ | AT91C_UDPHS_IEN_SOF
+ | AT91C_UDPHS_MICRO_SOF
+ | AT91C_UDPHS_DET_SUSPD;
+
+ // Device is in the Attached state
+ deviceState = USBD_STATE_SUSPENDED;
+ previousDeviceState = USBD_STATE_POWERED;
+
+ // Enable interrupts
+ AT91C_BASE_UDPHS->UDPHS_IEN = AT91C_UDPHS_ENDOFRSM
+ | AT91C_UDPHS_WAKE_UP
+ | AT91C_UDPHS_DET_SUSPD;
+
+ // Disable USB clocks
+ UDPHS_DisableUsbClock();
+
+ // Configure interrupts
+ USBDCallbacks_Initialized();
+}
+
+//------------------------------------------------------------------------------
+/// Configure USB Speed, should be invoked before USB attachment.
+/// \param forceFS Force to use FS mode.
+//------------------------------------------------------------------------------
+void USBD_ConfigureSpeed(unsigned char forceFS)
+{
+ if (forceFS) {
+ AT91C_BASE_UDPHS->UDPHS_TST |= AT91C_UDPHS_SPEED_CFG_FS;
+ }
+ else {
+ AT91C_BASE_UDPHS->UDPHS_TST &= ~(unsigned int)AT91C_UDPHS_SPEED_CFG_FS;
+ }
+}
+
+
+//------------------------------------------------------------------------------
+/// Returns the current state of the USB device.
+/// \return Device current state.
+//------------------------------------------------------------------------------
+unsigned char USBD_GetState( void )
+{
+ return deviceState;
+}
+
+
diff --git a/usb/device/core/core.dir b/usb/device/core/core.dir
new file mode 100644
index 0000000..fcf0dc0
--- /dev/null
+++ b/usb/device/core/core.dir
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2008, Atmel Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the disclaimer below.
+ *
+ * Atmel's name may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !Purpose
+///
+/// This directory contains structures, definitions and functions for AT91 UDP.
+/// They can be divided into two groups:
+/// - Hardware layer: low-level operations on the USB UDP controller
+/// - USBD_OTGHS.c USBD_UDP.c USBD_UDPHS.c
+/// - USB Device API: other files in the directory, offers hardware-independent
+/// methods and structures
+//------------------------------------------------------------------------------
+
personal git repositories of Harald Welte. Your mileage may vary