solo/efm8/lib/efm8_usb/src/efm8_usbdch9.c
2018-07-04 12:48:18 -04:00

881 lines
30 KiB
C

/**************************************************************************//**
* Copyright (c) 2015 by Silicon Laboratories Inc. All rights reserved.
*
* http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt
*****************************************************************************/
#include "si_toolchain.h"
#include "efm8_usb.h"
#include <stdint.h>
#include <endian.h>
// -----------------------------------------------------------------------------
// Function Prototypes
static USB_Status_TypeDef ClearFeature(void);
static USB_Status_TypeDef GetConfiguration(void);
static USB_Status_TypeDef GetDescriptor(void);
static USB_Status_TypeDef GetInterface(void);
static USB_Status_TypeDef GetStatus(void);
static USB_Status_TypeDef SetAddress(void);
static USB_Status_TypeDef SetConfiguration(void);
static USB_Status_TypeDef SetFeature(void);
static USB_Status_TypeDef SetInterface(void);
static void USBD_ActivateAllEps(bool forceIdle);
static void EP0_Write(uint8_t *dat, uint16_t numBytes);
void SendEp0Stall(void);
// -----------------------------------------------------------------------------
// Global Variables
extern SI_SEGMENT_VARIABLE(myUsbDevice, USBD_Device_TypeDef, MEM_MODEL_SEG);
SI_SEGMENT_VARIABLE(txZero[2], uint8_t, SI_SEG_CODE);
// -----------------------------------------------------------------------------
// Static Global Variables
static uint16_t pStatus;
// -----------------------------------------------------------------------------
// Chapter 9 Functions
/***************************************************************************//**
* @brief Processes Standard Request (Chapter 9 Command)
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
USB_Status_TypeDef USBDCH9_SetupCmd(void)
{
USB_Status_TypeDef status = USB_STATUS_OK;
switch (myUsbDevice.setup.bRequest)
{
case GET_STATUS:
status = GetStatus();
break;
case CLEAR_FEATURE:
status = ClearFeature();
break;
case SET_FEATURE:
status = SetFeature();
break;
case SET_ADDRESS:
status = SetAddress();
break;
case GET_DESCRIPTOR:
status = GetDescriptor();
break;
case GET_CONFIGURATION:
status = GetConfiguration();
break;
case SET_CONFIGURATION:
status = SetConfiguration();
break;
case GET_INTERFACE:
status = GetInterface();
break;
case SET_INTERFACE:
status = SetInterface();
break;
default:
status = USB_STATUS_REQ_ERR;
break;
}
// Reset index to 0 in case one of the above commands modified it
USB_SetIndex(0);
// If the command resulted in an error, send a procedural stall
if (status == USB_STATUS_REQ_ERR)
{
SendEp0Stall();
}
return status;
}
/***************************************************************************//**
* @brief Clears the requested feature
* @details Supports CLEAR_FEATURE for Remote Wakeup and Endpoint Halt
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef ClearFeature(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if (myUsbDevice.setup.wLength == 0)
{
switch (myUsbDevice.setup.bmRequestType.Recipient)
{
#if SLAB_USB_REMOTE_WAKEUP_ENABLED
case USB_SETUP_RECIPIENT_DEVICE:
if ((myUsbDevice.setup.wIndex == 0)
&& (myUsbDevice.setup.wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP)
&& (myUsbDevice.state >= USBD_STATE_ADDRESSED))
{
// Remote wakeup feature clear
myUsbDevice.remoteWakeupEnabled = false;
retVal = USB_STATUS_OK;
}
break;
#endif // SLAB_USB_REMOTE_WAKEUP_ENABLED
case USB_SETUP_RECIPIENT_ENDPOINT:
if (myUsbDevice.setup.wValue == USB_FEATURE_ENDPOINT_HALT)
{
// Device does not support halting endpoint 0, but do not return
// an error as this is a valid request
if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0)
&& (myUsbDevice.state >= USBD_STATE_ADDRESSED))
{
retVal = USB_STATUS_OK;
}
else if (((myUsbDevice.setup.wIndex & ~USB_SETUP_DIR_D2H) < SLAB_USB_NUM_EPS_USED)
&& (myUsbDevice.state == USBD_STATE_CONFIGURED))
{
retVal = USB_STATUS_OK;
USB_SetIndex((myUsbDevice.setup.wIndex & 0xFF) & ~USB_SETUP_DIR_D2H);
#if (SLAB_USB_EP1IN_USED || SLAB_USB_EP2IN_USED || SLAB_USB_EP3IN_USED)
if ((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN)
{
USB_EpnInEndStallAndClearDataToggle();
}
#endif
#if (SLAB_USB_EP1OUT_USED || SLAB_USB_EP2OUT_USED || SLAB_USB_EP3OUT_USED)
if (((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) == 0)
{
USB_EpnOutEndStallAndClearDataToggle();
}
#endif
switch (myUsbDevice.setup.wIndex & 0xFF)
{
#if SLAB_USB_EP1OUT_USED
case (USB_EP_DIR_OUT | 1):
if (myUsbDevice.ep1out.state != D_EP_RECEIVING)
{
myUsbDevice.ep1out.state = D_EP_IDLE;
}
break;
#endif
#if SLAB_USB_EP2OUT_USED
case (USB_EP_DIR_OUT | 2):
if (myUsbDevice.ep2out.state != D_EP_RECEIVING)
{
myUsbDevice.ep2out.state = D_EP_IDLE;
}
break;
#endif
#if SLAB_USB_EP3OUT_USED
case (USB_EP_DIR_OUT | 3):
if (myUsbDevice.ep3out.state != D_EP_RECEIVING)
{
myUsbDevice.ep3out.state = D_EP_IDLE;
}
break;
#endif
#if SLAB_USB_EP1IN_USED
case (USB_EP_DIR_IN | 1):
if (myUsbDevice.ep1in.state != D_EP_TRANSMITTING)
{
myUsbDevice.ep1in.state = D_EP_IDLE;
}
break;
#endif
#if SLAB_USB_EP2IN_USED
case (USB_EP_DIR_IN | 2):
if (myUsbDevice.ep2in.state != D_EP_TRANSMITTING)
{
myUsbDevice.ep2in.state = D_EP_IDLE;
}
break;
#endif
#if SLAB_USB_EP3IN_USED
case (USB_EP_DIR_IN | 3):
if (myUsbDevice.ep3in.state != D_EP_TRANSMITTING)
{
myUsbDevice.ep3in.state = D_EP_IDLE;
}
break;
#endif
}
}
}
}
}
return retVal;
}
/***************************************************************************//**
* @brief Gets the current configuration value
* @details Zero means the device is not configured, a non-zero value
* is the configuration value of the configured device.
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef GetConfiguration(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ((myUsbDevice.setup.wIndex == 0)
&& (myUsbDevice.setup.wValue == 0)
&& (myUsbDevice.setup.wLength == 1)
&& (myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_IN)
&& (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE))
{
if (myUsbDevice.state == USBD_STATE_ADDRESSED)
{
EP0_Write(txZero, 1);
retVal = USB_STATUS_OK;
}
else if (myUsbDevice.state == USBD_STATE_CONFIGURED)
{
EP0_Write(&myUsbDevice.configurationValue, 1);
retVal = USB_STATUS_OK;
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sends the requested USB Descriptor
* @details Supports single or multiple languages (configured by
* @ref SLAB_USB_NUM_LANGUAGES).
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef GetDescriptor(void)
{
#if (SLAB_USB_NUM_LANGUAGES > 1)
bool langSupported;
uint8_t lang;
#endif
uint8_t index;
uint16_t length = 0;
uint8_t *dat;
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if (*((uint8_t *)&myUsbDevice.setup.bmRequestType) ==
(USB_SETUP_DIR_D2H | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_DEVICE))
{
index = myUsbDevice.setup.wValue & 0xFF;
switch (myUsbDevice.setup.wValue >> 8)
{
case USB_DEVICE_DESCRIPTOR:
if (index != 0)
{
break;
}
dat = (uint8_t *)myUsbDevice.deviceDescriptor;
length = myUsbDevice.deviceDescriptor->bLength;
break;
case USB_CONFIG_DESCRIPTOR:
if (index != 0)
{
break;
}
dat = (uint8_t *)myUsbDevice.configDescriptor;
length = le16toh(myUsbDevice.configDescriptor->wTotalLength);
break;
case USB_STRING_DESCRIPTOR:
#if (SLAB_USB_NUM_LANGUAGES == 1)
dat = (uint8_t *)myUsbDevice.stringDescriptors[index];
// Index 0 is the language string. If SLAB_USB_NUM_LANGUAGES == 1, we
// know the length will be 4 and the format will be UTF16LE.
if (index == 0)
{
length = 4;
myUsbDevice.ep0String.encoding.type = USB_STRING_DESCRIPTOR_UTF16LE;
}
// Otherwise, verify the language is correct (either the value set as
// SLAB_USB_LANGUAGE in usbconfig.h, or 0).
else if ((myUsbDevice.setup.wIndex == 0) || (myUsbDevice.setup.wIndex == SLAB_USB_LANGUAGE))
{
// Verify the index is valid
if (index < myUsbDevice.numberOfStrings)
{
length = *(dat + USB_STRING_DESCRIPTOR_LENGTH);
myUsbDevice.ep0String.encoding.type = *(dat + USB_STRING_DESCRIPTOR_ENCODING);
dat += USB_STRING_DESCRIPTOR_LENGTH;
myUsbDevice.ep0String.encoding.init = true;
}
}
#elif (SLAB_USB_NUM_LANGUAGES > 1)
langSupported = false;
// Index 0 is the language.
if (index == 0)
{
dat = ((uint8_t *)myUsbDevice.stringDescriptors->languageArray[0][index]);
length = *((uint8_t *)dat);
myUsbDevice.ep0String.encoding.type = USB_STRING_DESCRIPTOR_UTF16LE;
}
else
{
// Otherwise, verify the language is one of the supported languages or 0.
for (lang = 0; lang < SLAB_USB_NUM_LANGUAGES; lang++)
{
if ((myUsbDevice.stringDescriptors->languageIDs[lang] == myUsbDevice.setup.wIndex)
|| (myUsbDevice.stringDescriptors->languageIDs[lang] == 0))
{
langSupported = true;
break;
}
}
if ((langSupported == true) && (index < myUsbDevice.numberOfStrings))
{
dat = ((uint8_t *)myUsbDevice.stringDescriptors->languageArray[lang][index]);
length = *(dat + USB_STRING_DESCRIPTOR_LENGTH);
myUsbDevice.ep0String.encoding.type = *(dat + USB_STRING_DESCRIPTOR_ENCODING);
dat += USB_STRING_DESCRIPTOR_LENGTH;
if (myUsbDevice.ep0String.encoding.type == USB_STRING_DESCRIPTOR_UTF16LE_PACKED)
{
myUsbDevice.ep0String.encoding.init = true;
}
else
{
myUsbDevice.ep0String.encoding.init = false;
}
}
}
#endif // ( SLAB_USB_NUM_LANGUAGES == 1 )
}
// If there is a descriptor to send, get the proper length, then call
// EP0_Write() to send.
if (length)
{
if (length > myUsbDevice.setup.wLength)
{
length = myUsbDevice.setup.wLength;
}
EP0_Write(dat, length);
retVal = USB_STATUS_OK;
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sends the current interface alternate setting
* @details Sends 0x0000 if alternate interfaces are not supported.
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef GetInterface(void)
{
uint16_t interface = myUsbDevice.setup.wIndex;
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ((interface < SLAB_USB_NUM_INTERFACES)
&& (myUsbDevice.setup.wLength == 1)
&& (myUsbDevice.setup.wValue == 0)
&& (*((uint8_t *)&myUsbDevice.setup.bmRequestType) ==
(USB_SETUP_DIR_D2H | USB_SETUP_TYPE_STANDARD | USB_SETUP_RECIPIENT_INTERFACE)))
{
if (myUsbDevice.state == USBD_STATE_CONFIGURED)
{
#if (SLAB_USB_SUPPORT_ALT_INTERFACES)
// Return the alternate setting for the specified interface
EP0_Write(&myUsbDevice.interfaceAltSetting[interface], 1);
#else
// Alternate interfaces are not supported, so return 0x0000.
EP0_Write(&txZero, 1);
#endif
retVal = USB_STATUS_OK;
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sends the requested Remote Wakeup, Self-Powered, or
* Endpoint Status
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef GetStatus(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ((myUsbDevice.setup.wLength == 2)
&& (myUsbDevice.setup.wValue == 0)
&& (myUsbDevice.setup.bmRequestType.Direction == USB_SETUP_DIR_IN)
&& (myUsbDevice.state >= USBD_STATE_ADDRESSED))
{
pStatus = htole16(0); // Default return value is 0x0000
switch (myUsbDevice.setup.bmRequestType.Recipient)
{
case USB_SETUP_RECIPIENT_DEVICE:
if (myUsbDevice.setup.wIndex == 0)
{
#if SLAB_USB_REMOTE_WAKEUP_ENABLED
// Remote wakeup feature status
if (myUsbDevice.remoteWakeupEnabled)
{
pStatus |= htole16(REMOTE_WAKEUP_ENABLED);
}
#endif // SLAB_USB_REMOTE_WAKEUP_ENABLED
#if SLAB_USB_IS_SELF_POWERED_CB
// Current self/bus power status
if (USBD_IsSelfPoweredCb())
{
pStatus |= htole16(DEVICE_IS_SELFPOWERED);
}
#elif (SLAB_USB_BUS_POWERED == 0)
pStatus |= htole16(DEVICE_IS_SELFPOWERED);
#endif // SLAB_USB_IS_SELF_POWERED_CB
retVal = USB_STATUS_OK;
}
break;
case USB_SETUP_RECIPIENT_INTERFACE:
if (myUsbDevice.setup.wIndex < SLAB_USB_NUM_INTERFACES)
{
retVal = USB_STATUS_OK;
}
break;
case USB_SETUP_RECIPIENT_ENDPOINT:
// Device does not support halting endpoint 0, but do not give
// an error as this is a valid request
if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0)
&& (myUsbDevice.state == USBD_STATE_ADDRESSED))
{
retVal = USB_STATUS_OK;
}
else if (myUsbDevice.state == USBD_STATE_CONFIGURED)
{
switch (myUsbDevice.setup.wIndex & 0xFF)
{
#if SLAB_USB_EP1OUT_USED
case (USB_EP_DIR_OUT | 1):
if (myUsbDevice.ep1out.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
#if SLAB_USB_EP2OUT_USED
case (USB_EP_DIR_OUT | 2):
if (myUsbDevice.ep2out.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
#if SLAB_USB_EP3OUT_USED
case (USB_EP_DIR_OUT | 3):
if (myUsbDevice.ep3out.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
#if SLAB_USB_EP1IN_USED
case (USB_EP_DIR_IN | 1):
if (myUsbDevice.ep1in.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
#if SLAB_USB_EP2IN_USED
case (USB_EP_DIR_IN | 2):
if (myUsbDevice.ep2in.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
#if SLAB_USB_EP3IN_USED
case (USB_EP_DIR_IN | 3):
if (myUsbDevice.ep3in.state == D_EP_HALT)
{
pStatus = htole16(1);
}
retVal = USB_STATUS_OK;
break;
#endif
}
}
break;
}
// If the command was valid, send the requested status.
if (retVal == USB_STATUS_OK)
{
EP0_Write((uint8_t *)&pStatus, 2);
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sets the Address
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef SetAddress(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if ((myUsbDevice.setup.wValue < 128)
&& (myUsbDevice.setup.wLength == 0)
&& (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE)
&& (myUsbDevice.setup.wIndex == 0))
{
// If the device is in the Default state and the address is non-zero, put
// the device in the Addressed state.
if (myUsbDevice.state == USBD_STATE_DEFAULT)
{
if (myUsbDevice.setup.wValue != 0)
{
USBD_SetUsbState(USBD_STATE_ADDRESSED);
}
retVal = USB_STATUS_OK;
}
// If the device is already addressed and the address is zero, put the
// device in the Default state.
else if (myUsbDevice.state == USBD_STATE_ADDRESSED)
{
if (myUsbDevice.setup.wValue == 0)
{
USBD_SetUsbState(USBD_STATE_DEFAULT);
}
retVal = USB_STATUS_OK;
}
// Set the new address if the request was valid.
if (retVal == USB_STATUS_OK)
{
USB_SetAddress(myUsbDevice.setup.wValue);
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sets the Configuration
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef SetConfiguration(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if (((myUsbDevice.setup.wValue >> 8) == 0)
&& (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_DEVICE)
&& (myUsbDevice.setup.wLength == 0)
&& (myUsbDevice.setup.wIndex == 0))
{
// If the device is in the Addressed state and a valid Configuration value
// was sent, enter the Configured state.
if (myUsbDevice.state == USBD_STATE_ADDRESSED)
{
if ((myUsbDevice.setup.wValue == 0)
|| (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue))
{
myUsbDevice.configurationValue = myUsbDevice.setup.wValue;
if (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue)
{
USBD_ActivateAllEps(true);
USBD_SetUsbState(USBD_STATE_CONFIGURED);
}
retVal = USB_STATUS_OK;
}
}
// If the device is in the Configured state and Configuration zero is sent,
// abort all transfer and enter the Addressed state.
else if (myUsbDevice.state == USBD_STATE_CONFIGURED)
{
if ((myUsbDevice.setup.wValue == 0)
|| (myUsbDevice.setup.wValue == myUsbDevice.configDescriptor->bConfigurationValue))
{
myUsbDevice.configurationValue = myUsbDevice.setup.wValue;
if (myUsbDevice.setup.wValue == 0)
{
USBD_SetUsbState(USBD_STATE_ADDRESSED);
USBD_AbortAllTransfers();
}
else
{
// Reenable device endpoints, will reset data toggles
USBD_ActivateAllEps(false);
}
retVal = USB_STATUS_OK;
}
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sets the Remote Wakeup or Endpoint Halt Feature
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef SetFeature(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
if (myUsbDevice.setup.wLength == 0)
{
switch (myUsbDevice.setup.bmRequestType.Recipient)
{
#if SLAB_USB_REMOTE_WAKEUP_ENABLED
case USB_SETUP_RECIPIENT_DEVICE:
if ((myUsbDevice.setup.wIndex == 0) // ITF no. 0
&& (myUsbDevice.setup.wValue == USB_FEATURE_DEVICE_REMOTE_WAKEUP)
&& (myUsbDevice.state == USBD_STATE_CONFIGURED))
{
myUsbDevice.remoteWakeupEnabled = true;
retVal = USB_STATUS_OK;
}
break;
#endif // SLAB_USB_REMOTE_WAKEUP_ENABLED
case USB_SETUP_RECIPIENT_ENDPOINT:
// Device does not support halting endpoint 0, but do not return
// an error as this is a valid request
if (((myUsbDevice.setup.wIndex & ~USB_EP_DIR_IN) == 0)
&& (myUsbDevice.state >= USBD_STATE_ADDRESSED))
{
retVal = USB_STATUS_OK;
}
else if ((((myUsbDevice.setup.wIndex) & ~USB_SETUP_DIR_D2H) < SLAB_USB_NUM_EPS_USED)
&& (myUsbDevice.setup.wValue == USB_FEATURE_ENDPOINT_HALT)
&& (myUsbDevice.state == USBD_STATE_CONFIGURED))
{
retVal = USB_STATUS_OK;
USB_SetIndex((myUsbDevice.setup.wIndex & 0xFF) & ~USB_SETUP_DIR_D2H);
// Enable Stalls on the specified endpoint.
#if (SLAB_USB_EP1IN_USED || SLAB_USB_EP2IN_USED || SLAB_USB_EP3IN_USED)
if ((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN)
{
USB_EpnInStall();
}
#endif
#if (SLAB_USB_EP1OUT_USED || SLAB_USB_EP2OUT_USED || SLAB_USB_EP3OUT_USED)
if (((myUsbDevice.setup.wIndex & 0xFF) & USB_EP_DIR_IN) == 0)
{
USB_EpnOutStall();
}
#endif
// Put the specified endpoint in the Halted state.
switch (myUsbDevice.setup.wIndex & 0xFF)
{
#if SLAB_USB_EP1OUT_USED
case (USB_EP_DIR_OUT | 1):
myUsbDevice.ep1out.state = D_EP_HALT;
break;
#endif
#if SLAB_USB_EP2OUT_USED
case (USB_EP_DIR_OUT | 2):
myUsbDevice.ep2out.state = D_EP_HALT;
break;
#endif
#if SLAB_USB_EP3OUT_USED
case (USB_EP_DIR_OUT | 3):
myUsbDevice.ep3out.state = D_EP_HALT;
break;
#endif
#if SLAB_USB_EP1IN_USED
case (USB_EP_DIR_IN | 1):
myUsbDevice.ep1in.state = D_EP_HALT;
break;
#endif
#if SLAB_USB_EP2IN_USED
case (USB_EP_DIR_IN | 2):
myUsbDevice.ep2in.state = D_EP_HALT;
break;
#endif
#if SLAB_USB_EP3IN_USED
case (USB_EP_DIR_IN | 3):
myUsbDevice.ep3in.state = D_EP_HALT;
break;
#endif
}
}
}
}
return retVal;
}
/***************************************************************************//**
* @brief Sets the Interface and Alternate Interface (if supported)
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static USB_Status_TypeDef SetInterface(void)
{
USB_Status_TypeDef retVal = USB_STATUS_REQ_ERR;
uint8_t interface = (uint8_t)myUsbDevice.setup.wIndex;
uint8_t altSetting = (uint8_t)myUsbDevice.setup.wValue;
if ((interface < SLAB_USB_NUM_INTERFACES)
&& (myUsbDevice.state == USBD_STATE_CONFIGURED)
&& (myUsbDevice.setup.wLength == 0)
#if (SLAB_USB_SUPPORT_ALT_INTERFACES == 0)
&& (altSetting == 0)
#endif
&& (myUsbDevice.setup.bmRequestType.Recipient == USB_SETUP_RECIPIENT_INTERFACE))
{
#if (SLAB_USB_SUPPORT_ALT_INTERFACES)
if (USBD_SetInterfaceCb(interface, altSetting) == USB_STATUS_OK)
{
myUsbDevice.interfaceAltSetting[interface] = altSetting;
retVal = USB_STATUS_OK;
}
#else
#if (SLAB_USB_NUM_INTERFACES == 1)
// Reset data toggles on EP's
USBD_ActivateAllEps(false);
#endif // ( SLAB_USB_NUM_INTERFACES == 1 )
retVal = USB_STATUS_OK;
#endif // ( SLAB_USB_SUPPORT_ALT_INTERFACES )
}
return retVal;
}
// -----------------------------------------------------------------------------
// Utility Functions
/***************************************************************************//**
* @brief Enables all endpoints for data transfers
* @return Status of request (type @ref USB_Status_TypeDef)
* @note This function takes no parameters, but it uses the setup command
* stored in @ref myUsbDevice.setup.
******************************************************************************/
static void USBD_ActivateAllEps(bool forceIdle)
{
if (forceIdle == true)
{
#if SLAB_USB_EP1IN_USED
myUsbDevice.ep1in.state = D_EP_IDLE;
#endif
#if SLAB_USB_EP2IN_USED
myUsbDevice.ep2in.state = D_EP_IDLE;
#endif
#if SLAB_USB_EP3IN_USED
myUsbDevice.ep3in.state = D_EP_IDLE;
#endif
#if SLAB_USB_EP1OUT_USED
myUsbDevice.ep1out.state = D_EP_IDLE;
#endif
#if SLAB_USB_EP2OUT_USED
myUsbDevice.ep2out.state = D_EP_IDLE;
#endif
#if SLAB_USB_EP3OUT_USED
myUsbDevice.ep3out.state = D_EP_IDLE;
#endif
}
#if SLAB_USB_EP1IN_USED
USB_ActivateEp(1, // ep
SLAB_USB_EP1IN_MAX_PACKET_SIZE, // packetSize
1, // inDir
SLAB_USB_EP1OUT_USED, // splitMode
0); // isoMod
#endif // SLAB_USB_EP1IN_USED
#if SLAB_USB_EP2IN_USED
USB_ActivateEp(2, // ep
SLAB_USB_EP2IN_MAX_PACKET_SIZE, // packetSize
1, // inDir
SLAB_USB_EP2OUT_USED, // splitMode
0); // isoMod
#endif // SLAB_USB_EP2IN_USED
#if SLAB_USB_EP3IN_USED
USB_ActivateEp(3, // ep
SLAB_USB_EP3IN_MAX_PACKET_SIZE, // packetSize
1, // inDir
SLAB_USB_EP3OUT_USED, // splitMode
(SLAB_USB_EP3IN_TRANSFER_TYPE == USB_EPTYPE_ISOC)); // isoMod
#endif // SLAB_USB_EP3IN_USED
#if SLAB_USB_EP1OUT_USED
USB_ActivateEp(1, // ep
SLAB_USB_EP1OUT_MAX_PACKET_SIZE, // packetSize
0, // inDir
SLAB_USB_EP1IN_USED, // splitMode
0); // isoMod
#endif // SLAB_USB_EP1OUT_USED
#if SLAB_USB_EP2OUT_USED
USB_ActivateEp(2, // ep
SLAB_USB_EP2OUT_MAX_PACKET_SIZE, // packetSize
0, // inDir
SLAB_USB_EP2IN_USED, // splitMode
0); // isoMod
#endif // SLAB_USB_EP2OUT_USED
#if SLAB_USB_EP3OUT_USED
USB_ActivateEp(3, // ep
SLAB_USB_EP3OUT_MAX_PACKET_SIZE, // packetSize
0, // inDir
SLAB_USB_EP3IN_USED, // splitMode
(SLAB_USB_EP3OUT_TRANSFER_TYPE == USB_EPTYPE_ISOC)); // isoMod
#endif // SLAB_USB_EP1OUT_USED
}
/***************************************************************************//**
* @brief Sets up an Endpoint 0 Write
* @param dat
* Data to transmit on Endpoint 0
* @param numBytes
* Number of bytes to transmit on Endpoint 0
******************************************************************************/
static void EP0_Write(uint8_t *dat, uint16_t numBytes)
{
if (myUsbDevice.ep0.state == D_EP_IDLE)
{
myUsbDevice.ep0.buf = (uint8_t *)dat;
myUsbDevice.ep0.remaining = numBytes;
myUsbDevice.ep0.state = D_EP_TRANSMITTING;
myUsbDevice.ep0.misc.c = 0;
}
}