diff --git a/radio/src/targets/sky9x/usb/device/core/USBD.h b/radio/src/targets/sky9x/usb/device/core/USBD.h index a2fa898a8..76ce7a028 100644 --- a/radio/src/targets/sky9x/usb/device/core/USBD.h +++ b/radio/src/targets/sky9x/usb/device/core/USBD.h @@ -1,290 +1,290 @@ -/* ---------------------------------------------------------------------------- - * 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 -#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); - -/* USBD Callbacks */ - -#define USBDCallbacks_Reset() - -#define USBDCallbacks_Suspended() - -#define USBDCallbacks_Resumed() - -extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request); - -extern void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum); - -extern void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, - unsigned char setting); - -#endif //#ifndef USBD_H - +/* ---------------------------------------------------------------------------- + * 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 +#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); + +/* USBD Callbacks */ + +#define USBDCallbacks_Reset() + +#define USBDCallbacks_Suspended() + +#define USBDCallbacks_Resumed() + +extern void USBDCallbacks_RequestReceived(const USBGenericRequest *request); + +extern void USBDDriverCallbacks_ConfigurationChanged(unsigned char cfgnum); + +extern void USBDDriverCallbacks_InterfaceSettingChanged(unsigned char interface, + unsigned char setting); + +#endif //#ifndef USBD_H + diff --git a/radio/src/targets/sky9x/usb/device/core/USBDDriver.c b/radio/src/targets/sky9x/usb/device/core/USBDDriver.c index 6043e3449..36f3591f0 100644 --- a/radio/src/targets/sky9x/usb/device/core/USBDDriver.c +++ b/radio/src/targets/sky9x/usb/device/core/USBDDriver.c @@ -1,752 +1,752 @@ -/* ---------------------------------------------------------------------------- - * 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 "../../../usb/device/core/USBDDriver.h" - -#include "debug.h" -#include - -#include "../../../usb/common/core/USBFeatureRequest.h" -#include "../../../usb/common/core/USBGetDescriptorRequest.h" -#include "../../../usb/common/core/USBInterfaceRequest.h" -#include "../../../usb/common/core/USBSetAddressRequest.h" -#include "../../../usb/common/core/USBSetConfigurationRequest.h" -#include "../../../usb/device/core/USBD.h" -#include "board_lowlevel.h" -#include "../../../usb/common/core/USBConfigurationDescriptor.h" -#include "../../../usb/common/core/USBDeviceDescriptor.h" -#include "../../../usb/common/core/USBDeviceQualifierDescriptor.h" -#include "../../../usb/common/core/USBEndpointDescriptor.h" -#include "../../../usb/common/core/USBGenericDescriptor.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, 0, sizeof(pInterfaces)); - } -} - -//------------------------------------------------------------------------------ -/// 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 - if ((USBGenericRequest_GetType(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<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 - +/* ---------------------------------------------------------------------------- + * 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 "../../../usb/device/core/USBDDriver.h" + +#include "debug.h" +#include + +#include "../../../usb/common/core/USBFeatureRequest.h" +#include "../../../usb/common/core/USBGetDescriptorRequest.h" +#include "../../../usb/common/core/USBInterfaceRequest.h" +#include "../../../usb/common/core/USBSetAddressRequest.h" +#include "../../../usb/common/core/USBSetConfigurationRequest.h" +#include "../../../usb/device/core/USBD.h" +#include "board_lowlevel.h" +#include "../../../usb/common/core/USBConfigurationDescriptor.h" +#include "../../../usb/common/core/USBDeviceDescriptor.h" +#include "../../../usb/common/core/USBDeviceQualifierDescriptor.h" +#include "../../../usb/common/core/USBEndpointDescriptor.h" +#include "../../../usb/common/core/USBGenericDescriptor.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, 0, sizeof(pInterfaces)); + } +} + +//------------------------------------------------------------------------------ +/// 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 + if ((USBGenericRequest_GetType(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<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/radio/src/targets/sky9x/usb/device/core/USBDDriver.h b/radio/src/targets/sky9x/usb/device/core/USBDDriver.h index c16364cbb..e0c05a573 100644 --- a/radio/src/targets/sky9x/usb/device/core/USBDDriver.h +++ b/radio/src/targets/sky9x/usb/device/core/USBDDriver.h @@ -1,101 +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 "../../../usb/common/core/USBGenericRequest.h" -#include "../../../usb/device/core/USBDDriverDescriptors.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 - +/* ---------------------------------------------------------------------------- + * 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 "../../../usb/common/core/USBGenericRequest.h" +#include "../../../usb/device/core/USBDDriverDescriptors.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/radio/src/targets/sky9x/usb/device/core/USBDDriverDescriptors.h b/radio/src/targets/sky9x/usb/device/core/USBDDriverDescriptors.h index aca698216..0a66c5177 100644 --- a/radio/src/targets/sky9x/usb/device/core/USBDDriverDescriptors.h +++ b/radio/src/targets/sky9x/usb/device/core/USBDDriverDescriptors.h @@ -1,86 +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/USBConfigurationDescriptor.h" -#include "../../../usb/common/core/USBDeviceDescriptor.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 - +/* ---------------------------------------------------------------------------- + * 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/USBConfigurationDescriptor.h" +#include "../../../usb/common/core/USBDeviceDescriptor.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/radio/src/targets/sky9x/usb/device/core/USBD_UDP.c b/radio/src/targets/sky9x/usb/device/core/USBD_UDP.c index c827c977a..3ea259437 100644 --- a/radio/src/targets/sky9x/usb/device/core/USBD_UDP.c +++ b/radio/src/targets/sky9x/usb/device/core/USBD_UDP.c @@ -1,1730 +1,1730 @@ -/* ---------------------------------------------------------------------------- - * 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 "board_lowlevel.h" -#include "../../../usb/common/core/USBEndpointDescriptor.h" -#include "../../../usb/common/core/USBGenericRequest.h" -#include "../../../usb/device/core/USBD.h" -#include "debug.h" - -//------------------------------------------------------------------------------ -// Local definitions -//------------------------------------------------------------------------------ -#define MASK_STATUS0 0xFFFFFFFC -#define MASK_STATUS1 0xFFFFFFFF - - -/*---------------------------------------------------------------------------- - * Exported functions - *----------------------------------------------------------------------------*/ - -/** - * \brief Enables the clock of a peripheral. The peripheral ID is used - * to identify which peripheral is targetted. - * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). - * \param id Peripheral ID (ID_xxx). - */ -void PMC_EnablePeripheral(unsigned int id) -{ - // SANITY_CHECK(id < 35); - - if (id < 32) { - if ((PMC->PMC_PCSR0 & (1 << id)) == (1 << id)) { - - TRACE_DEBUG("PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", id); - } - else { - PMC->PMC_PCER0 = 1 << id; - } - } - else { - id -= 32; - if ((PMC->PMC_PCSR1 & (1 << id)) == (1 << id)) { - - TRACE_DEBUG("PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", id + 32); - } - else { - PMC->PMC_PCER1 = 1 << id; - } - } -} - -/** - * \brief Disables the clock of a peripheral. The peripheral ID is used - * to identify which peripheral is targetted. - * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). - * \param id Peripheral ID (ID_xxx). - */ -void PMC_DisablePeripheral(unsigned int id) -{ - // SANITY_CHECK(id < 35); - if (id < 32) { - if ((PMC->PMC_PCSR0 & (1 << id)) != (1 << id)) { - TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", id); - } - else { - PMC->PMC_PCDR0 = 1 << id; - } - } - else { - id -= 32; - if ((PMC->PMC_PCSR1 & (1 << id)) != (1 << id)) { - TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", id + 32); - } - else { - PMC->PMC_PCDR1 = 1 << id; - } - } -} - -/** - * \brief Enable all the periph clock via PMC - */ -void PMC_EnableAllPeripherals(void) -{ - PMC->PMC_PCER0 = MASK_STATUS0; - while( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0); - PMC->PMC_PCER1 = MASK_STATUS1; - while( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1); - TRACE_DEBUG("Enable all periph clocks\n\r"); -} -/** - * \brief Disable all the periph clock via PMC - */ -void PMC_DisableAllPeripherals(void) -{ - PMC->PMC_PCDR0 = MASK_STATUS0; - while((PMC->PMC_PCSR0 & MASK_STATUS0) != 0); - PMC->PMC_PCDR1 = MASK_STATUS1; - while((PMC->PMC_PCSR1 & MASK_STATUS1) != 0); - TRACE_DEBUG("Disable all periph clocks\n\r"); -} - -/** - * \brief Get Periph Status for the given peripheral ID. - * \param id Peripheral ID (ID_xxx). - */ -unsigned int PMC_IsPeriphEnabled(unsigned int id) -{ - // SANITY_CHECK(id < 35); - - if (id < 32) { - return (PMC->PMC_PCSR0 & (1 << id)); - } - else { - return (PMC->PMC_PCSR1 & (1 << (id - 32))); - } -} - -//------------------------------------------------------------------------------ -// 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_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_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 UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \ - |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \ - |UDP_CSR_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 = UDP->UDP_CSR[endpoint] ; \ - reg |= REG_NO_EFFECT_1_ALL; \ - reg |= (flags); \ - UDP->UDP_CSR[endpoint] = reg; \ - while ( (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 = UDP->UDP_CSR[endpoint]; \ - reg |= REG_NO_EFFECT_1_ALL; \ - reg &= ~(flags); \ - UDP->UDP_CSR[endpoint] = reg; \ - while ( (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 - /// or ) - 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. -/// \return 1 if peripheral status changed. -//------------------------------------------------------------------------------ -static unsigned char UDP_EnablePeripheralClock(void) -{ - if (!PMC_IsPeriphEnabled(ID_UDP)) { - PMC_EnablePeripheral(ID_UDP); - return 1; - } - return 0; -} - -//------------------------------------------------------------------------------ -/// Disables the UDP peripheral clock. -//------------------------------------------------------------------------------ -static inline void UDP_DisablePeripheralClock(void) -{ - PMC_DisablePeripheral(ID_UDP); -} - -//------------------------------------------------------------------------------ -/// Enables the 48MHz USB clock. -//------------------------------------------------------------------------------ -static inline void UDP_EnableUsbClock(void) -{ - REG_PMC_SCER = PMC_SCER_UDP; -} - -//------------------------------------------------------------------------------ -/// Disables the 48MHz USB clock. -//------------------------------------------------------------------------------ -static inline void UDP_DisableUsbClock(void) -{ - REG_PMC_SCDR = PMC_SCER_UDP; -} - -//------------------------------------------------------------------------------ -/// Enables the UDP transceiver. -//------------------------------------------------------------------------------ -static inline void UDP_EnableTransceiver(void) -{ - UDP->UDP_TXVC &= ~UDP_TXVC_TXVDIS; -} - -//------------------------------------------------------------------------------ -/// Disables the UDP transceiver. -//------------------------------------------------------------------------------ -static inline void UDP_DisableTransceiver(void) -{ - UDP->UDP_TXVC |= UDP_TXVC_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, UDP_CSR_RX_DATA_BK0); - // Swap bank if in dual-fifo mode - if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) { - - pEndpoint->bank = 1; - } - } - else { - - CLEAR_CSR(bEndpoint, UDP_CSR_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 --) { - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - UDP->UDP_FDR[bEndpoint] = *(pBytes ++); - } - for (; c1; c1 --) { - 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 ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; - } - for (; c1; c1 --) { - *(pBytes ++) = 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) { - - 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) 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) 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 ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) - == UDP_CSR_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 = 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 & UDP_CSR_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 - UDP->UDP_IDR = 1 << bEndpoint; - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - CLEAR_CSR(bEndpoint, UDP_CSR_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, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - // Double buffering - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_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 & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { - - UDP->UDP_IDR = 1 << bEndpoint; - } - - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - CLEAR_CSR(bEndpoint, UDP_CSR_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, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - else { - // Double buffering - SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - UDP_WritePayload(bEndpoint); - } - } - } - else { - // Acknowledge interrupt - TRACE_ERROR("Error Wr"); - CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); - } - } - - // OUT packet received - if ((status & UDP_CSR_RXDATA_BK) != 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 & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) - && ((status & UDP_CSR_RXBYTECNT_Msk) == 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 & UDP_CSR_FORCESTALL) != 0) { - - // Discard STALLed data - TRACE_DEBUG_WP("Discard "); - UDP_ClearRxFlag(bEndpoint); - } - // NAK the data - else { - - TRACE_DEBUG_WP("Nak "); - 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 & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { - - UDP->UDP_IDR = 1 << bEndpoint; - } - UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); - } - } - } - - // STALL sent - if ((status & UDP_CSR_STALLSENTISOERROR) != 0) { - - TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint); - - // If the endpoint is not halted, clear the STALL condition - CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR); - if (pEndpoint->state != UDP_ENDPOINT_HALTED) { - - TRACE_WARNING( "_ " ); - CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); - } - } - - // SETUP packet received - if ((status & UDP_CSR_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, UDP_CSR_DIR); - } - // Acknowledge setup packet - CLEAR_CSR(bEndpoint, UDP_CSR_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 = UDP->UDP_ISR; - status &= UDP->UDP_IMR; - - if (deviceState < USBD_STATE_POWERED) { - - status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM; - 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, UDP_ISR_SOFINT)) { - // - // TRACE_DEBUG("SOF"); - // - // // Invoke the SOF callback - // USB_StartOfFrameCallback(pUsb); - // - // // Acknowledge interrupt - // UDP->UDP_ICR = UDP_ICR_SOFINT; - // dStatus &= ~UDP_ISR_SOFINT; - //} - - // Suspend - // This interrupt is always treated last (hence the '==') - if (status == UDP_ISR_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 - UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM; - - // Acknowledge interrupt - UDP->UDP_ICR = UDP_ICR_RXSUSP; - - // Switch to the Suspended state - previousDeviceState = deviceState; - deviceState = USBD_STATE_SUSPENDED; - // Invoke the Suspended callback - USBDCallbacks_Suspended(); - UDP_DisableTransceiver(); - UDP_DisablePeripheralClock(); - UDP_DisableUsbClock(); - } - } - // Resume - else if ((status & (UDP_ISR_WAKEUP | UDP_ISR_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 - UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; - UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM; - } - // End of bus reset - else if ((status & UDP_ISR_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 - UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; - UDP->UDP_IER = UDP_IER_RXSUSP; - - //// Enable the Start Of Frame (SOF) interrupt if needed - //if (pUsb->pCallbacks->startOfFrame != 0) { - // - // UDP->UDP_IER = UDP_IER_SOFINT; - //} - - // Invoke the Reset callback - USBDCallbacks_Reset(); - - // Acknowledge end of bus reset interrupt - UDP->UDP_ICR = UDP_ICR_ENDBUSRES; - } - // Endpoint interrupts - else { - - 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 - UDP->UDP_RST_EP |= (1 << bEndpoint); - UDP->UDP_RST_EP &= ~(1 << bEndpoint); - - // Configure endpoint - SET_CSR(bEndpoint, (unsigned int)UDP_CSR_EPEDS - | (bType << 8) | (bEndpointDir << 10)); - if (bType != USBEndpointDescriptor_CONTROL) { - - } - else { - - 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((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); - UDP_WritePayload(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_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 - 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((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); - UDP_MblWriteFifo(bEndpoint); - SET_CSR(bEndpoint, UDP_CSR_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 - 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 - 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, UDP_CSR_FORCESTALL); - pEndpoint->state = UDP_ENDPOINT_HALTED; - - // Enable the endpoint interrupt - 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) { - - TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); - - // Return endpoint to Idle state - pEndpoint->state = UDP_ENDPOINT_IDLE; - - // Clear FORCESTALL flag - CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); - - // Reset Endpoint Fifos, beware this is a 2 steps operation - UDP->UDP_RST_EP |= 1 << bEndpoint; - UDP->UDP_RST_EP &= ~(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, UDP_CSR_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 - UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR; - UDP->UDP_GLB_STAT &= ~UDP_GLB_STAT_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 - UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk); - - // If the address is 0, the device returns to the Default state - if (address == 0) { - - UDP->UDP_GLB_STAT = 0; - deviceState = USBD_STATE_DEFAULT; - } - // If the address is non-zero, the device enters the Address state - else { - - UDP->UDP_GLB_STAT = UDP_GLB_STAT_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; - UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG; - } - // If the configuration number is zero, the device goes back to the Address - // state - else { - - deviceState = USBD_STATE_ADDRESS; - UDP->UDP_GLB_STAT = UDP_FADDR_FEN; - - // Abort all transfers - UDP_DisableEndpoints(); - } -} - -//------------------------------------------------------------------------------ -/// Connects the pull-up on the D+ line of the USB. -//------------------------------------------------------------------------------ -void USBD_Connect(void) -{ - unsigned char dis = UDP_EnablePeripheralClock(); - - TRACE_DEBUG("Conn "); - UDP->UDP_TXVC |= UDP_TXVC_PUON; - - if (dis) UDP_DisablePeripheralClock(); -} - -//------------------------------------------------------------------------------ -/// Disconnects the pull-up from the D+ line of the USB. -//------------------------------------------------------------------------------ -void USBD_Disconnect(void) -{ - unsigned char dis = UDP_EnablePeripheralClock(); - - TRACE_DEBUG("Disc "); - UDP->UDP_TXVC &= ~UDP_TXVC_PUON; - - if (dis) UDP_DisablePeripheralClock(); - - // 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(); - - // Must before TXVC access! - UDP_EnablePeripheralClock(); - - // Configure the pull-up on D+ and disconnect it - UDP->UDP_TXVC &= ~UDP_TXVC_PUON; - - // Device is in the Attached state - deviceState = USBD_STATE_SUSPENDED; - previousDeviceState = USBD_STATE_POWERED; - UDP_EnableUsbClock(); - - UDP->UDP_IDR = 0xFE; - - UDP->UDP_IER = UDP_IER_WAKEUP; - - // Configure interrupts - NVIC_EnableIRQ(UDP_IRQn); -} - -//------------------------------------------------------------------------------ -/// 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; -} - +/* ---------------------------------------------------------------------------- + * 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 "board_lowlevel.h" +#include "../../../usb/common/core/USBEndpointDescriptor.h" +#include "../../../usb/common/core/USBGenericRequest.h" +#include "../../../usb/device/core/USBD.h" +#include "debug.h" + +//------------------------------------------------------------------------------ +// Local definitions +//------------------------------------------------------------------------------ +#define MASK_STATUS0 0xFFFFFFFC +#define MASK_STATUS1 0xFFFFFFFF + + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Enables the clock of a peripheral. The peripheral ID is used + * to identify which peripheral is targetted. + * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). + * \param id Peripheral ID (ID_xxx). + */ +void PMC_EnablePeripheral(unsigned int id) +{ + // SANITY_CHECK(id < 35); + + if (id < 32) { + if ((PMC->PMC_PCSR0 & (1 << id)) == (1 << id)) { + + TRACE_DEBUG("PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", id); + } + else { + PMC->PMC_PCER0 = 1 << id; + } + } + else { + id -= 32; + if ((PMC->PMC_PCSR1 & (1 << id)) == (1 << id)) { + + TRACE_DEBUG("PMC_EnablePeripheral: clock of peripheral" " %u is already enabled\n\r", id + 32); + } + else { + PMC->PMC_PCER1 = 1 << id; + } + } +} + +/** + * \brief Disables the clock of a peripheral. The peripheral ID is used + * to identify which peripheral is targetted. + * \note The ID must NOT be shifted (i.e. 1 << ID_xxx). + * \param id Peripheral ID (ID_xxx). + */ +void PMC_DisablePeripheral(unsigned int id) +{ + // SANITY_CHECK(id < 35); + if (id < 32) { + if ((PMC->PMC_PCSR0 & (1 << id)) != (1 << id)) { + TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", id); + } + else { + PMC->PMC_PCDR0 = 1 << id; + } + } + else { + id -= 32; + if ((PMC->PMC_PCSR1 & (1 << id)) != (1 << id)) { + TRACE_DEBUG("PMC_DisablePeripheral: clock of peripheral" " %u is not enabled\n\r", id + 32); + } + else { + PMC->PMC_PCDR1 = 1 << id; + } + } +} + +/** + * \brief Enable all the periph clock via PMC + */ +void PMC_EnableAllPeripherals(void) +{ + PMC->PMC_PCER0 = MASK_STATUS0; + while( (PMC->PMC_PCSR0 & MASK_STATUS0) != MASK_STATUS0); + PMC->PMC_PCER1 = MASK_STATUS1; + while( (PMC->PMC_PCSR1 & MASK_STATUS1) != MASK_STATUS1); + TRACE_DEBUG("Enable all periph clocks\n\r"); +} +/** + * \brief Disable all the periph clock via PMC + */ +void PMC_DisableAllPeripherals(void) +{ + PMC->PMC_PCDR0 = MASK_STATUS0; + while((PMC->PMC_PCSR0 & MASK_STATUS0) != 0); + PMC->PMC_PCDR1 = MASK_STATUS1; + while((PMC->PMC_PCSR1 & MASK_STATUS1) != 0); + TRACE_DEBUG("Disable all periph clocks\n\r"); +} + +/** + * \brief Get Periph Status for the given peripheral ID. + * \param id Peripheral ID (ID_xxx). + */ +unsigned int PMC_IsPeriphEnabled(unsigned int id) +{ + // SANITY_CHECK(id < 35); + + if (id < 32) { + return (PMC->PMC_PCSR0 & (1 << id)); + } + else { + return (PMC->PMC_PCSR1 & (1 << (id - 32))); + } +} + +//------------------------------------------------------------------------------ +// 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_CSR_RXDATA_BK (UDP_CSR_RX_DATA_BK0 | UDP_CSR_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 UDP_CSR_RX_DATA_BK0 | UDP_CSR_RX_DATA_BK1 \ + |UDP_CSR_STALLSENTISOERROR | UDP_CSR_RXSETUP \ + |UDP_CSR_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 = UDP->UDP_CSR[endpoint] ; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg |= (flags); \ + UDP->UDP_CSR[endpoint] = reg; \ + while ( (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 = UDP->UDP_CSR[endpoint]; \ + reg |= REG_NO_EFFECT_1_ALL; \ + reg &= ~(flags); \ + UDP->UDP_CSR[endpoint] = reg; \ + while ( (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 + /// or ) + 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. +/// \return 1 if peripheral status changed. +//------------------------------------------------------------------------------ +static unsigned char UDP_EnablePeripheralClock(void) +{ + if (!PMC_IsPeriphEnabled(ID_UDP)) { + PMC_EnablePeripheral(ID_UDP); + return 1; + } + return 0; +} + +//------------------------------------------------------------------------------ +/// Disables the UDP peripheral clock. +//------------------------------------------------------------------------------ +static inline void UDP_DisablePeripheralClock(void) +{ + PMC_DisablePeripheral(ID_UDP); +} + +//------------------------------------------------------------------------------ +/// Enables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UDP_EnableUsbClock(void) +{ + REG_PMC_SCER = PMC_SCER_UDP; +} + +//------------------------------------------------------------------------------ +/// Disables the 48MHz USB clock. +//------------------------------------------------------------------------------ +static inline void UDP_DisableUsbClock(void) +{ + REG_PMC_SCDR = PMC_SCER_UDP; +} + +//------------------------------------------------------------------------------ +/// Enables the UDP transceiver. +//------------------------------------------------------------------------------ +static inline void UDP_EnableTransceiver(void) +{ + UDP->UDP_TXVC &= ~UDP_TXVC_TXVDIS; +} + +//------------------------------------------------------------------------------ +/// Disables the UDP transceiver. +//------------------------------------------------------------------------------ +static inline void UDP_DisableTransceiver(void) +{ + UDP->UDP_TXVC |= UDP_TXVC_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, UDP_CSR_RX_DATA_BK0); + // Swap bank if in dual-fifo mode + if (CHIP_USB_ENDPOINTS_BANKS(bEndpoint) > 1) { + + pEndpoint->bank = 1; + } + } + else { + + CLEAR_CSR(bEndpoint, UDP_CSR_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 --) { + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + UDP->UDP_FDR[bEndpoint] = *(pBytes ++); + } + for (; c1; c1 --) { + 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 ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + *(pBytes ++) = UDP->UDP_FDR[bEndpoint]; + } + for (; c1; c1 --) { + *(pBytes ++) = 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) { + + 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) 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) 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 ((UDP->UDP_CSR[bEndpoint] & UDP_CSR_EPTYPE_Msk) + == UDP_CSR_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 = 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 & UDP_CSR_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 + UDP->UDP_IDR = 1 << bEndpoint; + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, UDP_CSR_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, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_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 & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { + + UDP->UDP_IDR = 1 << bEndpoint; + } + + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + CLEAR_CSR(bEndpoint, UDP_CSR_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, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + else { + // Double buffering + SET_CSR(bEndpoint, UDP_CSR_TXPKTRDY); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + UDP_WritePayload(bEndpoint); + } + } + } + else { + // Acknowledge interrupt + TRACE_ERROR("Error Wr"); + CLEAR_CSR(bEndpoint, UDP_CSR_TXCOMP); + } + } + + // OUT packet received + if ((status & UDP_CSR_RXDATA_BK) != 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 & UDP_CSR_EPTYPE_Msk) == UDP_CSR_EPTYPE_CTRL) + && ((status & UDP_CSR_RXBYTECNT_Msk) == 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 & UDP_CSR_FORCESTALL) != 0) { + + // Discard STALLed data + TRACE_DEBUG_WP("Discard "); + UDP_ClearRxFlag(bEndpoint); + } + // NAK the data + else { + + TRACE_DEBUG_WP("Nak "); + 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 & UDP_CSR_EPTYPE_Msk) != UDP_CSR_EPTYPE_CTRL) { + + UDP->UDP_IDR = 1 << bEndpoint; + } + UDP_EndOfTransfer(bEndpoint, USBD_STATUS_SUCCESS); + } + } + } + + // STALL sent + if ((status & UDP_CSR_STALLSENTISOERROR) != 0) { + + TRACE_WARNING( "Sta 0x%X [%d] ", status, bEndpoint); + + // If the endpoint is not halted, clear the STALL condition + CLEAR_CSR(bEndpoint, UDP_CSR_STALLSENTISOERROR); + if (pEndpoint->state != UDP_ENDPOINT_HALTED) { + + TRACE_WARNING( "_ " ); + CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); + } + } + + // SETUP packet received + if ((status & UDP_CSR_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, UDP_CSR_DIR); + } + // Acknowledge setup packet + CLEAR_CSR(bEndpoint, UDP_CSR_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 = UDP->UDP_ISR; + status &= UDP->UDP_IMR; + + if (deviceState < USBD_STATE_POWERED) { + + status &= UDP_ICR_WAKEUP | UDP_ICR_RXRSM; + 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, UDP_ISR_SOFINT)) { + // + // TRACE_DEBUG("SOF"); + // + // // Invoke the SOF callback + // USB_StartOfFrameCallback(pUsb); + // + // // Acknowledge interrupt + // UDP->UDP_ICR = UDP_ICR_SOFINT; + // dStatus &= ~UDP_ISR_SOFINT; + //} + + // Suspend + // This interrupt is always treated last (hence the '==') + if (status == UDP_ISR_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 + UDP->UDP_IER = UDP_IER_WAKEUP | UDP_IER_RXRSM; + + // Acknowledge interrupt + UDP->UDP_ICR = UDP_ICR_RXSUSP; + + // Switch to the Suspended state + previousDeviceState = deviceState; + deviceState = USBD_STATE_SUSPENDED; + // Invoke the Suspended callback + USBDCallbacks_Suspended(); + UDP_DisableTransceiver(); + UDP_DisablePeripheralClock(); + UDP_DisableUsbClock(); + } + } + // Resume + else if ((status & (UDP_ISR_WAKEUP | UDP_ISR_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 + UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; + UDP->UDP_IDR = UDP_IDR_WAKEUP | UDP_IDR_RXRSM; + } + // End of bus reset + else if ((status & UDP_ISR_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 + UDP->UDP_ICR = UDP_ICR_WAKEUP | UDP_ICR_RXRSM | UDP_ICR_RXSUSP; + UDP->UDP_IER = UDP_IER_RXSUSP; + + //// Enable the Start Of Frame (SOF) interrupt if needed + //if (pUsb->pCallbacks->startOfFrame != 0) { + // + // UDP->UDP_IER = UDP_IER_SOFINT; + //} + + // Invoke the Reset callback + USBDCallbacks_Reset(); + + // Acknowledge end of bus reset interrupt + UDP->UDP_ICR = UDP_ICR_ENDBUSRES; + } + // Endpoint interrupts + else { + + 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 + UDP->UDP_RST_EP |= (1 << bEndpoint); + UDP->UDP_RST_EP &= ~(1 << bEndpoint); + + // Configure endpoint + SET_CSR(bEndpoint, (unsigned int)UDP_CSR_EPEDS + | (bType << 8) | (bEndpointDir << 10)); + if (bType != USBEndpointDescriptor_CONTROL) { + + } + else { + + 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((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); + UDP_WritePayload(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_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 + 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((UDP->UDP_CSR[bEndpoint]&UDP_CSR_TXPKTRDY)==UDP_CSR_TXPKTRDY); + UDP_MblWriteFifo(bEndpoint); + SET_CSR(bEndpoint, UDP_CSR_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 + 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 + 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, UDP_CSR_FORCESTALL); + pEndpoint->state = UDP_ENDPOINT_HALTED; + + // Enable the endpoint interrupt + 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) { + + TRACE_DEBUG_WP("Unhalt%d ", bEndpoint); + + // Return endpoint to Idle state + pEndpoint->state = UDP_ENDPOINT_IDLE; + + // Clear FORCESTALL flag + CLEAR_CSR(bEndpoint, UDP_CSR_FORCESTALL); + + // Reset Endpoint Fifos, beware this is a 2 steps operation + UDP->UDP_RST_EP |= 1 << bEndpoint; + UDP->UDP_RST_EP &= ~(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, UDP_CSR_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 + UDP->UDP_GLB_STAT |= UDP_GLB_STAT_ESR; + UDP->UDP_GLB_STAT &= ~UDP_GLB_STAT_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 + UDP->UDP_FADDR = UDP_FADDR_FEN | (address & UDP_FADDR_FADD_Msk); + + // If the address is 0, the device returns to the Default state + if (address == 0) { + + UDP->UDP_GLB_STAT = 0; + deviceState = USBD_STATE_DEFAULT; + } + // If the address is non-zero, the device enters the Address state + else { + + UDP->UDP_GLB_STAT = UDP_GLB_STAT_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; + UDP->UDP_GLB_STAT |= UDP_GLB_STAT_CONFG; + } + // If the configuration number is zero, the device goes back to the Address + // state + else { + + deviceState = USBD_STATE_ADDRESS; + UDP->UDP_GLB_STAT = UDP_FADDR_FEN; + + // Abort all transfers + UDP_DisableEndpoints(); + } +} + +//------------------------------------------------------------------------------ +/// Connects the pull-up on the D+ line of the USB. +//------------------------------------------------------------------------------ +void USBD_Connect(void) +{ + unsigned char dis = UDP_EnablePeripheralClock(); + + TRACE_DEBUG("Conn "); + UDP->UDP_TXVC |= UDP_TXVC_PUON; + + if (dis) UDP_DisablePeripheralClock(); +} + +//------------------------------------------------------------------------------ +/// Disconnects the pull-up from the D+ line of the USB. +//------------------------------------------------------------------------------ +void USBD_Disconnect(void) +{ + unsigned char dis = UDP_EnablePeripheralClock(); + + TRACE_DEBUG("Disc "); + UDP->UDP_TXVC &= ~UDP_TXVC_PUON; + + if (dis) UDP_DisablePeripheralClock(); + + // 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(); + + // Must before TXVC access! + UDP_EnablePeripheralClock(); + + // Configure the pull-up on D+ and disconnect it + UDP->UDP_TXVC &= ~UDP_TXVC_PUON; + + // Device is in the Attached state + deviceState = USBD_STATE_SUSPENDED; + previousDeviceState = USBD_STATE_POWERED; + UDP_EnableUsbClock(); + + UDP->UDP_IDR = 0xFE; + + UDP->UDP_IER = UDP_IER_WAKEUP; + + // Configure interrupts + NVIC_EnableIRQ(UDP_IRQn); +} + +//------------------------------------------------------------------------------ +/// 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; +} +