/**************************************************************************//** * 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 #include // ----------------------------------------------------------------------------- // 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; } }