diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.c b/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.c new file mode 100644 index 00000000..fa35a9aa --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "fsl_common.h" +// #include "fsl_debug_console.h" + +#ifndef NDEBUG +#if (defined(__CC_ARM)) || (defined(__ICCARM__)) +void __aeabi_assert(const char *failedExpr, const char *file, int line) +{ + PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" \n", failedExpr, file, line); + for (;;) + { + __BKPT(0); + } +} +#elif(defined(__REDLIB__)) + +#if SDK_DEBUGCONSOLE +void __assertion_failed(char *_Expr) +{ + PRINTF("%s\n", _Expr); + for (;;) + { + __asm("bkpt #0"); + } +} +#endif + +#elif(defined(__GNUC__)) +void __assert_func(const char *file, int line, const char *func, const char *failedExpr) +{ + PRINTF("ASSERT ERROR \" %s \": file \"%s\" Line \"%d\" function name \"%s\" \n", failedExpr, file, line, func); + for (;;) + { + __BKPT(0); + } +} +#endif /* (defined(__CC_ARM)) || (defined (__ICCARM__)) */ +#endif /* NDEBUG */ + +#ifndef __GIC_PRIO_BITS +uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler) +{ +/* Addresses for VECTOR_TABLE and VECTOR_RAM come from the linker file */ +#if defined(__CC_ARM) + extern uint32_t Image$$VECTOR_ROM$$Base[]; + extern uint32_t Image$$VECTOR_RAM$$Base[]; + extern uint32_t Image$$RW_m_data$$Base[]; + +#define __VECTOR_TABLE Image$$VECTOR_ROM$$Base +#define __VECTOR_RAM Image$$VECTOR_RAM$$Base +#define __RAM_VECTOR_TABLE_SIZE (((uint32_t)Image$$RW_m_data$$Base - (uint32_t)Image$$VECTOR_RAM$$Base)) +#elif defined(__ICCARM__) + extern uint32_t __RAM_VECTOR_TABLE_SIZE[]; + extern uint32_t __VECTOR_TABLE[]; + extern uint32_t __VECTOR_RAM[]; +#elif defined(__GNUC__) + extern uint32_t __VECTOR_TABLE[]; + extern uint32_t __VECTOR_RAM[]; + extern uint32_t __RAM_VECTOR_TABLE_SIZE_BYTES[]; + uint32_t __RAM_VECTOR_TABLE_SIZE = (uint32_t)(__RAM_VECTOR_TABLE_SIZE_BYTES); +#endif /* defined(__CC_ARM) */ + uint32_t n; + uint32_t ret; + uint32_t irqMaskValue; + + irqMaskValue = DisableGlobalIRQ(); + if (SCB->VTOR != (uint32_t)__VECTOR_RAM) + { + /* Copy the vector table from ROM to RAM */ + for (n = 0; n < ((uint32_t)__RAM_VECTOR_TABLE_SIZE) / sizeof(uint32_t); n++) + { + __VECTOR_RAM[n] = __VECTOR_TABLE[n]; + } + /* Point the VTOR to the position of vector table */ + SCB->VTOR = (uint32_t)__VECTOR_RAM; + } + + ret = __VECTOR_RAM[irq + 16]; + /* make sure the __VECTOR_RAM is noncachable */ + __VECTOR_RAM[irq + 16] = irqHandler; + + EnableGlobalIRQ(irqMaskValue); + + return ret; +} +#endif + +#ifndef CPU_QN908X +#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) + +void EnableDeepSleepIRQ(IRQn_Type interrupt) +{ + uint32_t index = 0; + uint32_t intNumber = (uint32_t)interrupt; + while (intNumber >= 32u) + { + index++; + intNumber -= 32u; + } + + SYSCON->STARTERSET[index] = 1u << intNumber; + EnableIRQ(interrupt); /* also enable interrupt at NVIC */ +} + +void DisableDeepSleepIRQ(IRQn_Type interrupt) +{ + uint32_t index = 0; + uint32_t intNumber = (uint32_t)interrupt; + while (intNumber >= 32u) + { + index++; + intNumber -= 32u; + } + + DisableIRQ(interrupt); /* also disable interrupt at NVIC */ + SYSCON->STARTERCLR[index] = 1u << intNumber; +} +#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */ +#else +void EnableDeepSleepIRQ(IRQn_Type interrupt) +{ + uint32_t index = 0; + uint32_t intNumber = (uint32_t)interrupt; + while (intNumber >= 32u) + { + index++; + intNumber -= 32u; + } + + /* SYSCON->STARTERSET[index] = 1u << intNumber; */ + EnableIRQ(interrupt); /* also enable interrupt at NVIC */ +} + +void DisableDeepSleepIRQ(IRQn_Type interrupt) +{ + uint32_t index = 0; + uint32_t intNumber = (uint32_t)interrupt; + while (intNumber >= 32u) + { + index++; + intNumber -= 32u; + } + + DisableIRQ(interrupt); /* also disable interrupt at NVIC */ + /* SYSCON->STARTERCLR[index] = 1u << intNumber; */ +} +#endif /*CPU_QN908X */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.h b/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.h new file mode 100644 index 00000000..99435660 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/fsl_common.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2015-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef _FSL_COMMON_H_ +#define _FSL_COMMON_H_ + +#include +#include +#include +#include + +#include "MK22F51212.h" + +/*! + * @addtogroup ksdk_common + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Construct a status code value from a group and code number. */ +#define MAKE_STATUS(group, code) ((((group)*100) + (code))) + +/*! @brief Construct the version number for drivers. */ +#define MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +/* Debug console type definition. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_NONE 0U /*!< No debug console. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_UART 1U /*!< Debug console base on UART. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_LPUART 2U /*!< Debug console base on LPUART. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_LPSCI 3U /*!< Debug console base on LPSCI. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_USBCDC 4U /*!< Debug console base on USBCDC. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_FLEXCOMM 5U /*!< Debug console base on USBCDC. */ +#define DEBUG_CONSOLE_DEVICE_TYPE_IUART 6U /*!< Debug console base on i.MX UART. */ + +/*! @brief Status group numbers. */ +enum _status_groups +{ + kStatusGroup_Generic = 0, /*!< Group number for generic status codes. */ + kStatusGroup_FLASH = 1, /*!< Group number for FLASH status codes. */ + kStatusGroup_LPSPI = 4, /*!< Group number for LPSPI status codes. */ + kStatusGroup_FLEXIO_SPI = 5, /*!< Group number for FLEXIO SPI status codes. */ + kStatusGroup_DSPI = 6, /*!< Group number for DSPI status codes. */ + kStatusGroup_FLEXIO_UART = 7, /*!< Group number for FLEXIO UART status codes. */ + kStatusGroup_FLEXIO_I2C = 8, /*!< Group number for FLEXIO I2C status codes. */ + kStatusGroup_LPI2C = 9, /*!< Group number for LPI2C status codes. */ + kStatusGroup_UART = 10, /*!< Group number for UART status codes. */ + kStatusGroup_I2C = 11, /*!< Group number for UART status codes. */ + kStatusGroup_LPSCI = 12, /*!< Group number for LPSCI status codes. */ + kStatusGroup_LPUART = 13, /*!< Group number for LPUART status codes. */ + kStatusGroup_SPI = 14, /*!< Group number for SPI status code.*/ + kStatusGroup_XRDC = 15, /*!< Group number for XRDC status code.*/ + kStatusGroup_SEMA42 = 16, /*!< Group number for SEMA42 status code.*/ + kStatusGroup_SDHC = 17, /*!< Group number for SDHC status code */ + kStatusGroup_SDMMC = 18, /*!< Group number for SDMMC status code */ + kStatusGroup_SAI = 19, /*!< Group number for SAI status code */ + kStatusGroup_MCG = 20, /*!< Group number for MCG status codes. */ + kStatusGroup_SCG = 21, /*!< Group number for SCG status codes. */ + kStatusGroup_SDSPI = 22, /*!< Group number for SDSPI status codes. */ + kStatusGroup_FLEXIO_I2S = 23, /*!< Group number for FLEXIO I2S status codes */ + kStatusGroup_FLEXIO_MCULCD = 24, /*!< Group number for FLEXIO LCD status codes */ + kStatusGroup_FLASHIAP = 25, /*!< Group number for FLASHIAP status codes */ + kStatusGroup_FLEXCOMM_I2C = 26, /*!< Group number for FLEXCOMM I2C status codes */ + kStatusGroup_I2S = 27, /*!< Group number for I2S status codes */ + kStatusGroup_IUART = 28, /*!< Group number for IUART status codes */ + kStatusGroup_SDRAMC = 35, /*!< Group number for SDRAMC status codes. */ + kStatusGroup_POWER = 39, /*!< Group number for POWER status codes. */ + kStatusGroup_ENET = 40, /*!< Group number for ENET status codes. */ + kStatusGroup_PHY = 41, /*!< Group number for PHY status codes. */ + kStatusGroup_TRGMUX = 42, /*!< Group number for TRGMUX status codes. */ + kStatusGroup_SMARTCARD = 43, /*!< Group number for SMARTCARD status codes. */ + kStatusGroup_LMEM = 44, /*!< Group number for LMEM status codes. */ + kStatusGroup_QSPI = 45, /*!< Group number for QSPI status codes. */ + kStatusGroup_DMA = 50, /*!< Group number for DMA status codes. */ + kStatusGroup_EDMA = 51, /*!< Group number for EDMA status codes. */ + kStatusGroup_DMAMGR = 52, /*!< Group number for DMAMGR status codes. */ + kStatusGroup_FLEXCAN = 53, /*!< Group number for FlexCAN status codes. */ + kStatusGroup_LTC = 54, /*!< Group number for LTC status codes. */ + kStatusGroup_FLEXIO_CAMERA = 55, /*!< Group number for FLEXIO CAMERA status codes. */ + kStatusGroup_LPC_SPI = 56, /*!< Group number for LPC_SPI status codes. */ + kStatusGroup_LPC_USART = 57, /*!< Group number for LPC_USART status codes. */ + kStatusGroup_DMIC = 58, /*!< Group number for DMIC status codes. */ + kStatusGroup_SDIF = 59, /*!< Group number for SDIF status codes.*/ + kStatusGroup_SPIFI = 60, /*!< Group number for SPIFI status codes. */ + kStatusGroup_OTP = 61, /*!< Group number for OTP status codes. */ + kStatusGroup_MCAN = 62, /*!< Group number for MCAN status codes. */ + kStatusGroup_CAAM = 63, /*!< Group number for CAAM status codes. */ + kStatusGroup_ECSPI = 64, /*!< Group number for ECSPI status codes. */ + kStatusGroup_USDHC = 65, /*!< Group number for USDHC status codes.*/ + kStatusGroup_ESAI = 69, /*!< Group number for ESAI status codes. */ + kStatusGroup_FLEXSPI = 70, /*!< Group number for FLEXSPI status codes. */ + kStatusGroup_NOTIFIER = 98, /*!< Group number for NOTIFIER status codes. */ + kStatusGroup_DebugConsole = 99, /*!< Group number for debug console status codes. */ + kStatusGroup_ApplicationRangeStart = 100, /*!< Starting number for application groups. */ +}; + +/*! @brief Generic status return codes. */ +enum _generic_status +{ + kStatus_Success = MAKE_STATUS(kStatusGroup_Generic, 0), + kStatus_Fail = MAKE_STATUS(kStatusGroup_Generic, 1), + kStatus_ReadOnly = MAKE_STATUS(kStatusGroup_Generic, 2), + kStatus_OutOfRange = MAKE_STATUS(kStatusGroup_Generic, 3), + kStatus_InvalidArgument = MAKE_STATUS(kStatusGroup_Generic, 4), + kStatus_Timeout = MAKE_STATUS(kStatusGroup_Generic, 5), + kStatus_NoTransferInProgress = MAKE_STATUS(kStatusGroup_Generic, 6), +}; + +/*! @brief Type used for all status and error return values. */ +typedef int32_t status_t; + +/* + * The fsl_clock.h is included here because it needs MAKE_VERSION/MAKE_STATUS/status_t + * defined in previous of this file. + */ +// #include "fsl_clock.h" + +/* + * Chip level peripheral reset API, for MCUs that implement peripheral reset control external to a peripheral + */ +#if ((defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) || \ + (defined(FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT) && (FSL_FEATURE_SOC_ASYNC_SYSCON_COUNT > 0))) +#include "fsl_reset.h" +#endif + +/*! @name Min/max macros */ +/* @{ */ +#if !defined(MIN) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if !defined(MAX) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +/* @} */ + +/*! @brief Computes the number of elements in an array. */ +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/*! @name UINT16_MAX/UINT32_MAX value */ +/* @{ */ +#if !defined(UINT16_MAX) +#define UINT16_MAX ((uint16_t)-1) +#endif + +#if !defined(UINT32_MAX) +#define UINT32_MAX ((uint32_t)-1) +#endif +/* @} */ + +/*! @name Timer utilities */ +/* @{ */ +/*! Macro to convert a microsecond period to raw count value */ +#define USEC_TO_COUNT(us, clockFreqInHz) (uint64_t)((uint64_t)us * clockFreqInHz / 1000000U) +/*! Macro to convert a raw count value to microsecond */ +#define COUNT_TO_USEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000000U / clockFreqInHz) + +/*! Macro to convert a millisecond period to raw count value */ +#define MSEC_TO_COUNT(ms, clockFreqInHz) (uint64_t)((uint64_t)ms * clockFreqInHz / 1000U) +/*! Macro to convert a raw count value to millisecond */ +#define COUNT_TO_MSEC(count, clockFreqInHz) (uint64_t)((uint64_t)count * 1000U / clockFreqInHz) +/* @} */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Enable specific interrupt. + * + * Enable the interrupt not routed from intmux. + * + * @param interrupt The IRQ number. + */ +static inline void EnableIRQ(IRQn_Type interrupt) +{ + if (NotAvail_IRQn == interrupt) + { + return; + } + +#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT > 0) + if (interrupt < FSL_FEATURE_INTMUX_IRQ_START_INDEX) +#endif + { +#if defined(__GIC_PRIO_BITS) + GIC_EnableIRQ(interrupt); +#else + NVIC_EnableIRQ(interrupt); +#endif + } +} + +/*! + * @brief Disable specific interrupt. + * + * Disable the interrupt not routed from intmux. + * + * @param interrupt The IRQ number. + */ +static inline void DisableIRQ(IRQn_Type interrupt) +{ + if (NotAvail_IRQn == interrupt) + { + return; + } + +#if defined(FSL_FEATURE_SOC_INTMUX_COUNT) && (FSL_FEATURE_SOC_INTMUX_COUNT > 0) + if (interrupt < FSL_FEATURE_INTMUX_IRQ_START_INDEX) +#endif + { +#if defined(__GIC_PRIO_BITS) + GIC_DisableIRQ(interrupt); +#else + NVIC_DisableIRQ(interrupt); +#endif + } +} + +/*! + * @brief Disable the global IRQ + * + * Disable the global interrupt and return the current primask register. User is required to provided the primask + * register for the EnableGlobalIRQ(). + * + * @return Current primask value. + */ +static inline uint32_t DisableGlobalIRQ(void) +{ + uint32_t regPrimask = __get_PRIMASK(); + + __disable_irq(); + + return regPrimask; +} + +/*! + * @brief Enaable the global IRQ + * + * Set the primask register with the provided primask value but not just enable the primask. The idea is for the + * convinience of integration of RTOS. some RTOS get its own management mechanism of primask. User is required to + * use the EnableGlobalIRQ() and DisableGlobalIRQ() in pair. + * + * @param primask value of primask register to be restored. The primask value is supposed to be provided by the + * DisableGlobalIRQ(). + */ +static inline void EnableGlobalIRQ(uint32_t primask) +{ + __set_PRIMASK(primask); +} + +/*! + * @brief install IRQ handler + * + * @param irq IRQ number + * @param irqHandler IRQ handler address + * @return The old IRQ handler address + */ +uint32_t InstallIRQHandler(IRQn_Type irq, uint32_t irqHandler); + +#if (defined(FSL_FEATURE_SOC_SYSCON_COUNT) && (FSL_FEATURE_SOC_SYSCON_COUNT > 0)) +/*! + * @brief Enable specific interrupt for wake-up from deep-sleep mode. + * + * Enable the interrupt for wake-up from deep sleep mode. + * Some interrupts are typically used in sleep mode only and will not occur during + * deep-sleep mode because relevant clocks are stopped. However, it is possible to enable + * those clocks (significantly increasing power consumption in the reduced power mode), + * making these wake-ups possible. + * + * @note This function also enables the interrupt in the NVIC (EnableIRQ() is called internally). + * + * @param interrupt The IRQ number. + */ +void EnableDeepSleepIRQ(IRQn_Type interrupt); + +/*! + * @brief Disable specific interrupt for wake-up from deep-sleep mode. + * + * Disable the interrupt for wake-up from deep sleep mode. + * Some interrupts are typically used in sleep mode only and will not occur during + * deep-sleep mode because relevant clocks are stopped. However, it is possible to enable + * those clocks (significantly increasing power consumption in the reduced power mode), + * making these wake-ups possible. + * + * @note This function also disables the interrupt in the NVIC (DisableIRQ() is called internally). + * + * @param interrupt The IRQ number. + */ +void DisableDeepSleepIRQ(IRQn_Type interrupt); +#endif /* FSL_FEATURE_SOC_SYSCON_COUNT */ + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* _FSL_COMMON_H_ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb.h new file mode 100644 index 00000000..f6366928 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include "usb_osa.h" +#include "usb_misc.h" +#include "usb_spec.h" + +/*! + * @addtogroup usb_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Defines USB stack major version */ +#define USB_STACK_VERSION_MAJOR (1U) +/*! @brief Defines USB stack minor version */ +#define USB_STACK_VERSION_MINOR (6U) +/*! @brief Defines USB stack bugfix version */ +#define USB_STACK_VERSION_BUGFIX (3U) + +/*! @brief USB stack version definition */ +#define USB_MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +/*! @brief USB error code */ +typedef enum _usb_status +{ + kStatus_USB_Success = 0x00U, /*!< Success */ + kStatus_USB_Error, /*!< Failed */ + + kStatus_USB_Busy, /*!< Busy */ + kStatus_USB_InvalidHandle, /*!< Invalid handle */ + kStatus_USB_InvalidParameter, /*!< Invalid parameter */ + kStatus_USB_InvalidRequest, /*!< Invalid request */ + kStatus_USB_ControllerNotFound, /*!< Controller cannot be found */ + kStatus_USB_InvalidControllerInterface, /*!< Invalid controller interface */ + + kStatus_USB_NotSupported, /*!< Configuration is not supported */ + kStatus_USB_Retry, /*!< Enumeration get configuration retry */ + kStatus_USB_TransferStall, /*!< Transfer stalled */ + kStatus_USB_TransferFailed, /*!< Transfer failed */ + kStatus_USB_AllocFail, /*!< Allocation failed */ + kStatus_USB_LackSwapBuffer, /*!< Insufficient swap buffer for KHCI */ + kStatus_USB_TransferCancel, /*!< The transfer cancelled */ + kStatus_USB_BandwidthFail, /*!< Allocate bandwidth failed */ + kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */ + kStatus_USB_EHCIAttached, + kStatus_USB_EHCIDetached, +} usb_status_t; + +/*! @brief USB host handle type define */ +typedef void *usb_host_handle; + +/*! @brief USB device handle type define. For device stack it is the whole device handle; for host stack it is the + * attached device instance handle*/ +typedef void *usb_device_handle; + +/*! @brief USB OTG handle type define */ +typedef void *usb_otg_handle; + +/*! @brief USB controller ID */ +typedef enum _usb_controller_index +{ + kUSB_ControllerKhci0 = 0U, /*!< KHCI 0U */ + kUSB_ControllerKhci1 = 1U, /*!< KHCI 1U, Currently, there are no platforms which have two KHCI IPs, this is reserved + to be used in the future. */ + kUSB_ControllerEhci0 = 2U, /*!< EHCI 0U */ + kUSB_ControllerEhci1 = 3U, /*!< EHCI 1U, Currently, there are no platforms which have two EHCI IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerLpcIp3511Fs0 = 4U, /*!< LPC USB IP3511 FS controller 0 */ + kUSB_ControllerLpcIp3511Fs1 = + 5U, /*!< LPC USB IP3511 FS controller 1, there are no platforms which have two IP3511 IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerLpcIp3511Hs0 = 6U, /*!< LPC USB IP3511 HS controller 0 */ + kUSB_ControllerLpcIp3511Hs1 = + 7U, /*!< LPC USB IP3511 HS controller 1, there are no platforms which have two IP3511 IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerOhci0 = 8U, /*!< OHCI 0U */ + kUSB_ControllerOhci1 = 9U, /*!< OHCI 1U, Currently, there are no platforms which have two OHCI IPs, this is reserved + to be used in the future. */ + + kUSB_ControllerIp3516Hs0 = 10U, /*!< IP3516HS 0U */ + kUSB_ControllerIp3516Hs1 = + 11U, /*!< IP3516HS 1U, Currently, there are no platforms which have two IP3516HS IPs, this is reserved + to be used in the future. */ +} usb_controller_index_t; + +/** +* @brief USB stack version fields +*/ +typedef struct _usb_version +{ + uint8_t major; /*!< Major */ + uint8_t minor; /*!< Minor */ + uint8_t bugfix; /*!< Bug fix */ +} usb_version_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! @} */ + +#endif /* __USB_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device.h new file mode 100644 index 00000000..5c49a516 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device.h @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_DEVICE_H__ +#define __USB_DEVICE_H__ + +/*! + * @addtogroup usb_device_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines Get/Set status Types */ +typedef enum _usb_device_status +{ + kUSB_DeviceStatusTestMode = 1U, /*!< Test mode */ + kUSB_DeviceStatusSpeed, /*!< Current speed */ + kUSB_DeviceStatusOtg, /*!< OTG status */ + kUSB_DeviceStatusDevice, /*!< Device status */ + kUSB_DeviceStatusEndpoint, /*!< Endpoint state usb_device_endpoint_status_t */ + kUSB_DeviceStatusDeviceState, /*!< Device state */ + kUSB_DeviceStatusAddress, /*!< Device address */ + kUSB_DeviceStatusSynchFrame, /*!< Current frame */ + kUSB_DeviceStatusBus, /*!< Bus status */ + kUSB_DeviceStatusBusSuspend, /*!< Bus suspend */ + kUSB_DeviceStatusBusSleep, /*!< Bus suspend */ + kUSB_DeviceStatusBusResume, /*!< Bus resume */ + kUSB_DeviceStatusRemoteWakeup, /*!< Remote wakeup state */ + kUSB_DeviceStatusBusSleepResume, /*!< Bus resume */ +} usb_device_status_t; + +/*! @brief Defines USB 2.0 device state */ +typedef enum _usb_device_state +{ + kUSB_DeviceStateConfigured = 0U, /*!< Device state, Configured*/ + kUSB_DeviceStateAddress, /*!< Device state, Address*/ + kUSB_DeviceStateDefault, /*!< Device state, Default*/ + kUSB_DeviceStateAddressing, /*!< Device state, Address setting*/ + kUSB_DeviceStateTestMode, /*!< Device state, Test mode*/ +} usb_device_state_t; + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) +typedef enum _usb_dcd_detection_sequence_status +{ + kUSB_DcdDetectionNotEnabled = 0x0U, + kUSB_DcdDataPinDetectionCompleted = 0x01U, + kUSB_DcdChargingPortDetectionCompleted = 0x02U, + kUSB_DcdChargerTypeDetectionCompleted = 0x03U, +} usb_dcd_detection_sequence_status_t; + +typedef enum _usb_dcd_detection_sequence_results +{ + kUSB_DcdDetectionNoResults = 0x0U, + kUSB_DcdDetectionStandardHost = 0x01U, + kUSB_DcdDetectionChargingPort = 0x02U, + kUSB_DcdDetectionDedicatedCharger = 0x03U, +} usb_dcd_detection_sequence_results_t; +#endif + +/*! @brief Defines endpoint state */ +typedef enum _usb_endpoint_status +{ + kUSB_DeviceEndpointStateIdle = 0U, /*!< Endpoint state, idle*/ + kUSB_DeviceEndpointStateStalled, /*!< Endpoint state, stalled*/ +} usb_device_endpoint_status_t; + +/*! @brief Control endpoint index */ +#define USB_CONTROL_ENDPOINT (0U) +/*! @brief Control endpoint maxPacketSize */ +#define USB_CONTROL_MAX_PACKET_SIZE (64U) + +#if (USB_DEVICE_CONFIG_EHCI && (USB_CONTROL_MAX_PACKET_SIZE != (64U))) +#error For high speed, USB_CONTROL_MAX_PACKET_SIZE must be 64!!! +#endif + +/*! @brief The setup packet size of USB control transfer. */ +#define USB_SETUP_PACKET_SIZE (8U) +/*! @brief USB endpoint mask */ +#define USB_ENDPOINT_NUMBER_MASK (0x0FU) + +/*! @brief Default invalid value or the endpoint callback length of cancelled transfer */ +#define USB_UNINITIALIZED_VAL_32 (0xFFFFFFFFU) + +/*! @brief Available common EVENT types in device callback */ +typedef enum _usb_device_event +{ + kUSB_DeviceEventBusReset = 1U, /*!< USB bus reset signal detected */ + kUSB_DeviceEventSuspend, /*!< USB bus suspend signal detected */ + kUSB_DeviceEventResume, /*!< USB bus resume signal detected. The resume signal is driven by itself or a host */ + kUSB_DeviceEventSleeped, /*!< USB bus LPM suspend signal detected */ + kUSB_DeviceEventLPMResume, /*!< USB bus LPM resume signal detected. The resume signal is driven by itself or a host + */ + kUSB_DeviceEventError, /*!< An error is happened in the bus. */ + kUSB_DeviceEventDetach, /*!< USB device is disconnected from a host. */ + kUSB_DeviceEventAttach, /*!< USB device is connected to a host. */ + kUSB_DeviceEventSetConfiguration, /*!< Set configuration. */ + kUSB_DeviceEventSetInterface, /*!< Set interface. */ + + kUSB_DeviceEventGetDeviceDescriptor, /*!< Get device descriptor. */ + kUSB_DeviceEventGetConfigurationDescriptor, /*!< Get configuration descriptor. */ + kUSB_DeviceEventGetStringDescriptor, /*!< Get string descriptor. */ + kUSB_DeviceEventGetHidDescriptor, /*!< Get HID descriptor. */ + kUSB_DeviceEventGetHidReportDescriptor, /*!< Get HID report descriptor. */ + kUSB_DeviceEventGetHidPhysicalDescriptor, /*!< Get HID physical descriptor. */ + kUSB_DeviceEventGetBOSDescriptor, /*!< Get configuration descriptor. */ + kUSB_DeviceEventGetDeviceQualifierDescriptor, /*!< Get device qualifier descriptor. */ + kUSB_DeviceEventVendorRequest, /*!< Vendor request. */ + kUSB_DeviceEventSetRemoteWakeup, /*!< Enable or disable remote wakeup function. */ + kUSB_DeviceEventGetConfiguration, /*!< Get current configuration index */ + kUSB_DeviceEventGetInterface, /*!< Get current interface alternate setting value */ + kUSB_DeviceEventSetBHNPEnable, +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) + kUSB_DeviceEventDcdTimeOut, /*!< Dcd detect result is timeout */ + kUSB_DeviceEventDcdUnknownType, /*!< Dcd detect result is unknown type */ + kUSB_DeviceEventSDPDetected, /*!< The SDP facility is detected */ + kUSB_DeviceEventChargingPortDetected, /*!< The charging port is detected */ + kUSB_DeviceEventChargingHostDetected, /*!< The CDP facility is detected */ + kUSB_DeviceEventDedicatedChargerDetected, /*!< The DCP facility is detected */ +#endif +} usb_device_event_t; + +/*! @brief Endpoint callback message structure */ +typedef struct _usb_device_endpoint_callback_message_struct +{ + uint8_t *buffer; /*!< Transferred buffer */ + uint32_t length; /*!< Transferred data length */ + uint8_t isSetup; /*!< Is in a setup phase */ +} usb_device_endpoint_callback_message_struct_t; + +/*! + * @brief Endpoint callback function typedef. + * + * This callback function is used to notify the upper layer what the transfer result is. + * This callback pointer is passed when a specified endpoint is initialized by calling API #USB_DeviceInitEndpoint. + * + * @param handle The device handle. It equals to the value returned from #USB_DeviceInit. + * @param message The result of a transfer, which includes transfer buffer, transfer length, and whether is in a + * setup phase. + * phase for control pipe. + * @param callbackParam The parameter for this callback. It is same with + * usb_device_endpoint_callback_struct_t::callbackParam. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_device_endpoint_callback_t)(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam); + +/*! + * @brief Device callback function typedef. + * + * This callback function is used to notify the upper layer that the device status has changed. + * This callback pointer is passed by calling API #USB_DeviceInit. + * + * @param handle The device handle. It equals the value returned from #USB_DeviceInit. + * @param callbackEvent The callback event type. See enumeration #usb_device_event_t. + * @param eventParam The event parameter for this callback. The parameter type is determined by the callback event. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_device_callback_t)(usb_device_handle handle, uint32_t callbackEvent, void *eventParam); + +/*! @brief Endpoint callback structure */ +typedef struct _usb_device_endpoint_callback_struct +{ + usb_device_endpoint_callback_t callbackFn; /*!< Endpoint callback function*/ + void *callbackParam; /*!< Parameter for callback function*/ + uint8_t isBusy; +} usb_device_endpoint_callback_struct_t; + +/*! @brief Endpoint initialization structure */ +typedef struct _usb_device_endpoint_init_struct +{ + uint16_t maxPacketSize; /*!< Endpoint maximum packet size */ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t transferType; /*!< Endpoint transfer type*/ + uint8_t zlt; /*!< ZLT flag*/ +} usb_device_endpoint_init_struct_t; + +/*! @brief Endpoint status structure */ +typedef struct _usb_device_endpoint_status_struct +{ + uint8_t endpointAddress; /*!< Endpoint address */ + uint16_t endpointStatus; /*!< Endpoint status : idle or stalled */ +} usb_device_endpoint_status_struct_t; + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) +/*! @brief USB DCD charge timing specification structure */ +typedef struct _usb_device_dcd_charging_time +{ + uint16_t dcdSeqInitTime; /*!< The dcd sequence init time */ + uint16_t dcdDbncTime; /*!< The debounce time period on DP signal */ + uint16_t dcdDpSrcOnTime; /*!< The time period comparator enabled */ + uint16_t dcdTimeWaitAfterPrD; /*!< The time period between primary and secondary detection */ + uint8_t dcdTimeDMSrcOn; /*!< The amount of time that the modules enable the Vdm_src */ +} usb_device_dcd_charging_time_t; +#endif + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @name USB device APIs + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the USB device stack. + * + * This function initializes the USB device module specified by the controllerId. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * @param[in] deviceCallback Function pointer of the device callback. + * @param[out] handle It is an out parameter used to return the pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller according to the controller id. + * @retval kStatus_USB_InvalidControllerInterface The controller driver interfaces is invalid. There is an empty + * interface entity. + * @retval kStatus_USB_Error The macro USB_DEVICE_CONFIG_ENDPOINTS is more than the IP's endpoint number. + * Or, the device has been initialized. + * Or, the mutex or message queue is created failed. + */ +extern usb_status_t USB_DeviceInit(uint8_t controllerId, + usb_device_callback_t deviceCallback, + usb_device_handle *handle); + +/*! + * @brief Enables the device functionality. + * + * The function enables the device functionality, so that the device can be recognized by the host when the device + * detects that it has been connected to a host. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +extern usb_status_t USB_DeviceRun(usb_device_handle handle); + +/*! + * @brief Disables the device functionality. + * + * The function disables the device functionality. After this function called, even if the device is detached to the + * host, + * it can't work. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer or the controller handle is invalid. + */ +extern usb_status_t USB_DeviceStop(usb_device_handle handle); + +/*! + * @brief De-initializes the device controller. + * + * The function de-initializes the device controller specified by the handle. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer or the controller handle is invalid. + */ +extern usb_status_t USB_DeviceDeinit(usb_device_handle handle); + +/*! + * @brief Sends data through a specified endpoint. + * + * The function is used to send data through a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to hold the data need to be sent. The function is not reentrant. + * @param[in] length The data length need to be sent. + * + * @retval kStatus_USB_Success The send request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate DTDS for current transfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value indicates whether the sending request is successful or not. The transfer done is notified by + * the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue on the application level. + * The subsequent transfer can begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +extern usb_status_t USB_DeviceSendRequest(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Receives data through a specified endpoint. + * + * The function is used to receive data through a specified endpoint. The function is not reentrant. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to save the received data. + * @param[in] length The data length want to be received. + * + * @retval kStatus_USB_Success The receive request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate DTDS for current transfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value indicates whether the receiving request is successful or not. The transfer done is notified by + * the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue on the application level. + * The subsequent transfer can begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +extern usb_status_t USB_DeviceRecvRequest(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Cancels the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The transfer is cancelled. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceCancel(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Initializes a specified endpoint. + * + * The function is used to initialize a specified endpoint. The corresponding endpoint callback is also initialized. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] epInit Endpoint initialization structure. See the structure usb_device_endpoint_init_struct_t. + * @param[in] endpointCallback Endpoint callback structure. See the structure + * usb_device_endpoint_callback_struct_t. + * + * @retval kStatus_USB_Success The endpoint is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The epInit or endpointCallback is NULL pointer. Or the endpoint number is + * more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceInitEndpoint(usb_device_handle handle, + usb_device_endpoint_init_struct_t *epInit, + usb_device_endpoint_callback_struct_t *endpointCallback); + +/*! + * @brief Deinitializes a specified endpoint. + * + * The function is used to deinitializes a specified endpoint. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is de-initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceDeinitEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Stalls a specified endpoint. + * + * The function is used to stall a specified endpoint. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceStallEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Unstalls a specified endpoint. + * + * The function is used to unstall a specified endpoint. + * + * @param[in] handle The device handle received from #USB_DeviceInit. + * @param[in] endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, and 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is unstalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +extern usb_status_t USB_DeviceUnstallEndpoint(usb_device_handle handle, uint8_t endpointAddress); + +/*! + * @brief Gets the status of the selected item. + * + * The function is used to get the status of the selected item. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] type The selected item. See the structure #usb_device_status_t. + * @param[out] param The parameter type is determined by the selected item. + * + * @retval kStatus_USB_Success Get status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The parameter is NULL pointer. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type. + */ +extern usb_status_t USB_DeviceGetStatus(usb_device_handle handle, usb_device_status_t type, void *param); + +/*! + * @brief Sets the status of the selected item. + * + * The function is used to set the status of the selected item. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] type The selected item. See the structure #usb_device_status_t. + * @param[in] param The parameter type is determined by the selected item. + * + * @retval kStatus_USB_Success Set status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type or the parameter is NULL pointer. + */ +extern usb_status_t USB_DeviceSetStatus(usb_device_handle handle, usb_device_status_t type, void *param); + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) +/*! + * @brief Initializes the device dcd module. + * + * The function initializes the device dcd module. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] time_param The time parameter used to config the dcd timing registers. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +extern usb_status_t USB_DeviceDcdInitModule(usb_device_handle handle, void *time_param); + +/*! + * @brief De-initializes the device dcd module. + * + * The function de-initializes the device dcd module specified by the handle. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer or the controller handle is invalid. + */ +extern usb_status_t USB_DeviceDcdDeinitModule(usb_device_handle handle); + +/*! + * @brief Get the device attach status. + * + * The function Get the device attach status. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_EHCIAttached The device is attached. + * @retval kStatus_USB_EHCIDetached The device is detached. + */ +extern usb_status_t USB_DeviceGetAttachStatus(usb_device_handle handle); +#endif +/*! + * @brief Device task function. + * + * The function is used to handle the controller message. + * This function should not be called in the application directly. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceTaskFunction(void *deviceHandle); + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/*! + * @brief Device KHCI task function. + * + * The function is used to handle the KHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +#define USB_DeviceKhciTaskFunction(deviceHandle) USB_DeviceTaskFunction(deviceHandle) +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/*! + * @brief Device EHCI task function. + * + * The function is used to handle the EHCI controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +#define USB_DeviceEhciTaskFunction(deviceHandle) USB_DeviceTaskFunction(deviceHandle) +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) +/*! + * @brief Device EHCI DCD ISR function. + * + * The function is the EHCI DCD interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceDcdHSIsrFunction(void *deviceHandle); +#endif +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +/*! + * @brief Device LPC ip3511 controller task function. + * + * The function is used to handle the LPC ip3511 controller message. + * In the bare metal environment, this function should be called periodically in the main function. + * In the RTOS environment, this function should be used as a function entry to create a task. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +#define USB_DeviceLpcIp3511TaskFunction(deviceHandle) USB_DeviceTaskFunction(deviceHandle) +#endif + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/*! + * @brief Device KHCI ISR function. + * + * The function is the KHCI interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceKhciIsrFunction(void *deviceHandle); +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) +/*! + * @brief Device KHCI DCD ISR function. + * + * The function is the KHCI DCD interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceDcdIsrFunction(void *deviceHandle); +#endif +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/*! + * @brief Device EHCI ISR function. + * + * The function is the EHCI interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceEhciIsrFunction(void *deviceHandle); +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +/*! + * @brief Device LPC USB ISR function. + * + * The function is the LPC USB interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceLpcIp3511IsrFunction(void *deviceHandle); +#endif + +/*! + * @brief Gets the device stack version function. + * + * The function is used to get the device stack version. + * + * @param[out] version The version structure pointer to keep the device stack version. + * + */ +extern void USB_DeviceGetVersion(uint32_t *version); + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) +/*! + * @brief Update the hardware tick. + * + * The function is used to update the hardware tick. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] tick Current hardware tick(uint is ms). + * + */ +extern usb_status_t USB_DeviceUpdateHwTick(usb_device_handle handle, uint64_t tick); +#endif + +/*! @}*/ + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/*! @}*/ + +#endif /* __USB_DEVICE_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.c new file mode 100644 index 00000000..e22c9f1b --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "usb_device_config.h" +#include "usb.h" +#include "usb_device.h" + +#if USB_DEVICE_CONFIG_CDC_ACM +#include "usb_device_cdc_acm.h" + +#endif diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.h new file mode 100644 index 00000000..407b7105 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_cdc_acm.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef _USB_DEVICE_CDC_ACM_H_ +#define _USB_DEVICE_CDC_ACM_H_ 1 +/******************************************************************************* +* Definitions +******************************************************************************/ + +#define USB_DEVICE_CONFIG_CDC_ACM_MAX_INSTANCE (1) + +#define USB_DEVICE_CONFIG_CDC_COMM_CLASS_CODE (0x02) +#define USB_DEVICE_CONFIG_CDC_DATA_CLASS_CODE (0x0A) + +/* Class specific request Codes */ +#define USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND (0x00) +#define USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE (0x01) +#define USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE (0x02) +#define USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE (0x03) +#define USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE (0x04) +#define USB_DEVICE_CDC_REQUEST_SET_AUX_LINE_STATE (0x10) +#define USB_DEVICE_CDC_REQUEST_SET_HOOK_STATE (0x11) +#define USB_DEVICE_CDC_REQUEST_PULSE_SETUP (0x12) +#define USB_DEVICE_CDC_REQUEST_SEND_PULSE (0x13) +#define USB_DEVICE_CDC_REQUEST_SET_PULSE_TIME (0x14) +#define USB_DEVICE_CDC_REQUEST_RING_AUX_JACK (0x15) +#define USB_DEVICE_CDC_REQUEST_SET_LINE_CODING (0x20) +#define USB_DEVICE_CDC_REQUEST_GET_LINE_CODING (0x21) +#define USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE (0x22) +#define USB_DEVICE_CDC_REQUEST_SEND_BREAK (0x23) +#define USB_DEVICE_CDC_REQUEST_SET_RINGER_PARAMS (0x30) +#define USB_DEVICE_CDC_REQUEST_GET_RINGER_PARAMS (0x31) +#define USB_DEVICE_CDC_REQUEST_SET_OPERATION_PARAM (0x32) +#define USB_DEVICE_CDC_REQUEST_GET_OPERATION_PARAM (0x33) +#define USB_DEVICE_CDC_REQUEST_SET_LINE_PARAMS (0x34) +#define USB_DEVICE_CDC_REQUEST_GET_LINE_PARAMS (0x35) +#define USB_DEVICE_CDC_REQUEST_DIAL_DIGITS (0x36) +#define USB_DEVICE_CDC_REQUEST_SET_UNIT_PARAMETER (0x37) +#define USB_DEVICE_CDC_REQUEST_GET_UNIT_PARAMETER (0x38) +#define USB_DEVICE_CDC_REQUEST_CLEAR_UNIT_PARAMETER (0x39) +#define USB_DEVICE_CDC_REQUEST_GET_PROFILE (0x3A) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_MULTICAST_FILTERS (0x40) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_POW_PATTER_FILTER (0x41) +#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_POW_PATTER_FILTER (0x42) +#define USB_DEVICE_CDC_REQUEST_SET_ETHERNET_PACKET_FILTER (0x43) +#define USB_DEVICE_CDC_REQUEST_GET_ETHERNET_STATISTIC (0x44) +#define USB_DEVICE_CDC_REQUEST_SET_ATM_DATA_FORMAT (0x50) +#define USB_DEVICE_CDC_REQUEST_GET_ATM_DEVICE_STATISTICS (0x51) +#define USB_DEVICE_CDC_REQUEST_SET_ATM_DEFAULT_VC (0x52) +#define USB_DEVICE_CDC_REQUEST_GET_ATM_VC_STATISTICS (0x53) +#define USB_DEVICE_CDC_REQUEST_MDLM_SPECIFIC_REQUESTS_MASK (0x7F) + +#define USB_DEVICE_CDC_REQUEST_GET_ABSTRACT_STATE (0x23) +#define USB_DEVICE_CDC_REQUEST_GET_COUNTRY_SETTING (0x24) +#define USB_DEVICE_CDC_REQUEST_SET_ABSTRACT_STATE (0x25) +#define USB_DEVICE_CDC_REQUEST_SET_COUNTRY_SETTING (0x26) +/* Class Specific Notification Codes */ +#define USB_DEVICE_CDC_REQUEST_NETWORK_CONNECTION_NOTIF (0x00) +#define USB_DEVICE_CDC_REQUEST_RESPONSE_AVAIL_NOTIF (0x01) +#define USB_DEVICE_CDC_REQUEST_AUX_JACK_HOOK_STATE_NOTIF (0x08) +#define USB_DEVICE_CDC_REQUEST_RING_DETECT_NOTIF (0x09) +#define USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF (0x20) +#define USB_DEVICE_CDC_REQUEST_CALL_STATE_CHANGE_NOTIF (0x28) +#define USB_DEVICE_CDC_REQUEST_LINE_STATE_CHANGE_NOTIF (0x29) +#define USB_DEVICE_CDC_REQUEST_CONNECTION_SPEED_CHANGE_NOTIF (0x2A) +/* Communications Feature Selector Codes */ +#define USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE (0x01) +#define USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING (0x02) +/* Control Signal Bitmap Values */ +#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION (0x02) +#define USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE (0x01) +/* UART State Bitmap Values */ +#define USB_DEVICE_CDC_UART_STATE_RX_CARRIER (0x01) +#define USB_DEVICE_CDC_UART_STATE_TX_CARRIER (0x02) +#define USB_DEVICE_CDC_UART_STATE_BREAK (0x04) +#define USB_DEVICE_CDC_UART_STATE_RING_SIGNAL (0x08) +#define USB_DEVICE_CDC_UART_STATE_FRAMING (0x10) +#define USB_DEVICE_CDC_UART_STATE_PARITY (0x20) +#define USB_DEVICE_CDC_UART_STATE_OVERRUN (0x40) + +#endif /* _USB_DEVICE_CDC_ACM_H_ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.c new file mode 100644 index 00000000..79515d01 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" +#include "usb_device_ch9.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @brief Standard request callback function typedef. + * + * This function is used to handle the standard request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @return A USB error code or kStatus_USB_Success. + */ +typedef usb_status_t (*usb_standard_request_callback_t)(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +/******************************************************************************* +* Prototypes +******************************************************************************/ +/*! + * @brief Get the setup packet buffer. + * + * The function is used to get the setup packet buffer to save the setup packet data. + * + * @param handle The device handle. + * @param setupBuffer It is an OUT parameter, return the setup buffer address to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer); + +/*! + * @brief Handle the class request. + * + * The function is used to handle the class request. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length It is an OUT parameter, return the data length need to be sent to host. + * @param buffer It is an OUT parameter, return the data buffer address. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/*! + * @brief Get the buffer to save the class specific data sent from host. + * + * The function is used to get the buffer to save the class specific data sent from host. + * The function will be called when the device receives a setup pakcet, and the host needs to send data to the device in + * the data stage. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length Pass the length the host needs to sent. + * @param buffer It is an OUT parameter, return the data buffer address to save the host's data. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/* standard request */ +/*! + * @brief Get the descritpor. + * + * The function is used to get the descritpor, including the device descritpor, configuration descriptor, and string + * descriptor, etc. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length It is an OUT parameter, return the data length need to be sent to host. + * @param buffer It is an OUT parameter, return the data buffer address. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer); + +/*! + * @brief Set the device configuration. + * + * The function is used to set the device configuration. + * + * @param handle The device handle. + * @param configure The configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceSetConfigure(usb_device_handle handle, uint8_t configure); + +/*! + * @brief Get the device configuration. + * + * The function is used to get the device configuration. + * + * @param handle The device handle. + * @param configure It is an OUT parameter, save the current configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetConfigure(usb_device_handle handle, uint8_t *configure); + +/*! + * @brief Set an interface alternate setting. + * + * The function is used to set an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting The new alternate setting value. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceSetInterface(usb_device_handle handle, uint8_t interface, uint8_t alternateSetting); + +/*! + * @brief Get an interface alternate setting. + * + * The function is used to get an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting It is an OUT parameter, save the new alternate setting value of the interface. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceGetInterface(usb_device_handle handle, uint8_t interface, uint8_t *alternateSetting); + +/*! + * @brief Configure a specified endpoint status. + * + * The function is used to configure a specified endpoint status, idle or halt. + * + * @param handle The device handle. + * @param endpointAddress The endpoint address, the BIT7 is the direction, 0 - USB_OUT, 1 - USB_IN. + * @param status The new status of the endpoint, 0 - idle, 1 - halt. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t status); + +/*! + * @brief Configure the device remote wakeup feature. + * + * The function is used to configure the device remote wakeup feature, enable or disbale the remote wakeup feature. + * + * @param handle The device handle. + * @param enable The new feature value of the device remote wakeup, 0 - disable, 1 - enable. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable); + +static usb_status_t USB_DeviceCh9GetStatus(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetAddress(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SynchFrame(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* The function list to handle the standard request. */ +static const usb_standard_request_callback_t s_UsbDeviceStandardRequest[] = { + USB_DeviceCh9GetStatus, + USB_DeviceCh9SetClearFeature, + (usb_standard_request_callback_t)NULL, + USB_DeviceCh9SetClearFeature, + (usb_standard_request_callback_t)NULL, + USB_DeviceCh9SetAddress, + USB_DeviceCh9GetDescriptor, + (usb_standard_request_callback_t)NULL, /* USB_DeviceCh9SetDescriptor */ + USB_DeviceCh9GetConfiguration, + USB_DeviceCh9SetConfiguration, + USB_DeviceCh9GetInterface, + USB_DeviceCh9SetInterface, + USB_DeviceCh9SynchFrame, +}; + +/* + * The internal global variable. + * This variable is used in: + * get status request + * get configuration request + * get interface request + * set interface request + * get sync frame request + */ +static uint16_t s_UsbDeviceStandardRx; + +/******************************************************************************* +* Code +******************************************************************************/ +/*! + * @brief Handle get status request. + * + * This function is used to handle get status request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetStatus(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return error; + } + + if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) + { + /* Get the device status */ + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusDevice, &s_UsbDeviceStandardRx); + s_UsbDeviceStandardRx = s_UsbDeviceStandardRx & USB_GET_STATUS_DEVICE_MASK; + s_UsbDeviceStandardRx = USB_SHORT_TO_LITTLE_ENDIAN(s_UsbDeviceStandardRx); + /* The device status length must be USB_DEVICE_STATUS_SIZE. */ + *length = USB_DEVICE_STATUS_SIZE; + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_INTERFACE) + { + /* Get the interface status */ + error = kStatus_USB_Success; + s_UsbDeviceStandardRx = 0U; + /* The interface status length must be USB_INTERFACE_STATUS_SIZE. */ + *length = USB_INTERFACE_STATUS_SIZE; + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) + { + /* Get the endpoint status */ + usb_device_endpoint_status_struct_t endpointStatus; + endpointStatus.endpointAddress = (uint8_t)setup->wIndex; + endpointStatus.endpointStatus = kUSB_DeviceEndpointStateIdle; + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusEndpoint, &endpointStatus); + s_UsbDeviceStandardRx = endpointStatus.endpointStatus & USB_GET_STATUS_ENDPOINT_MASK; + s_UsbDeviceStandardRx = USB_SHORT_TO_LITTLE_ENDIAN(s_UsbDeviceStandardRx); + /* The endpoint status length must be USB_INTERFACE_STATUS_SIZE. */ + *length = USB_ENDPOINT_STATUS_SIZE; + } + else + { + } + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + + return error; +} + +/*! + * @brief Handle set or clear device feature request. + * + * This function is used to handle set or clear device feature request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + uint8_t isSet = 0U; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return error; + } + + /* Identify the request is set or clear the feature. */ + if (USB_REQUEST_STANDARD_SET_FEATURE == setup->bRequest) + { + isSet = 1U; + } + + if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_DEVICE) + { + /* Set or Clear the device featrue. */ + if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP == setup->wValue) + { +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusRemoteWakeup, &isSet); +#endif + /* Set or Clear the device remote wakeup featrue. */ + error = USB_DeviceConfigureRemoteWakeup(handle, isSet); + } +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE == setup->wValue) + { + state = kUSB_DeviceStateTestMode; + error = USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + } +#endif + else + { + } + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) + { + /* Set or Clear the endpoint featrue. */ + if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT == setup->wValue) + { + if (USB_CONTROL_ENDPOINT == (setup->wIndex & USB_ENDPOINT_NUMBER_MASK)) + { + /* Set or Clear the control endpoint status(halt or not). */ + if (isSet) + { + USB_DeviceStallEndpoint(handle, (uint8_t)setup->wIndex); + } + else + { + USB_DeviceUnstallEndpoint(handle, (uint8_t)setup->wIndex); + } + } + + /* Set or Clear the endpoint status featrue. */ + error = USB_DeviceConfigureEndpointStatus(handle, setup->wIndex, isSet); + } + else + { + } + } + else + { + } + + return error; +} + +/*! + * @brief Handle set address request. + * + * This function is used to handle set address request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state. + */ +static usb_status_t USB_DeviceCh9SetAddress(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddressing != state) && (kUSB_DeviceStateAddress != state) && + (kUSB_DeviceStateDefault != state)) + { + return error; + } + + if (kUSB_DeviceStateAddressing != state) + { + /* If the device address is not setting, pass the address and the device state will change to + * kUSB_DeviceStateAddressing internally. */ + state = setup->wValue & 0xFFU; + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusAddress, &state); + } + else + { + /* If the device address is setting, set device address and the address will be write into the controller + * internally. */ + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusAddress, NULL); + /* And then change the device state to kUSB_DeviceStateAddress. */ + if (kStatus_USB_Success == error) + { + state = kUSB_DeviceStateAddress; + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + } + } + + return error; +} + +/*! + * @brief Handle get descriptor request. + * + * This function is used to handle get descriptor request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state) && + (kUSB_DeviceStateDefault != state)) + { + return kStatus_USB_InvalidRequest; + } + + return USB_DeviceGetDescriptor(handle, setup, length, buffer); +} + +/*! + * @brief Handle get current configuration request. + * + * This function is used to handle get current configuration request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && ((kUSB_DeviceStateConfigured != state))) + { + return kStatus_USB_InvalidRequest; + } + + *length = USB_CONFIGURE_SIZE; + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + return USB_DeviceGetConfigure(handle, (uint8_t *)&s_UsbDeviceStandardRx); +} + +/*! + * @brief Handle set current configuration request. + * + * This function is used to handle set current configuration request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state)) + { + return kStatus_USB_InvalidRequest; + } + + /* The device state is changed to kUSB_DeviceStateConfigured */ + state = kUSB_DeviceStateConfigured; + USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + if (!setup->wValue) + { + /* If the new configuration is zero, the device state is changed to kUSB_DeviceStateAddress */ + state = kUSB_DeviceStateAddress; + USB_DeviceSetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + } + + return USB_DeviceSetConfigure(handle, setup->wValue); +} + +/*! + * @brief Handle get the alternate setting of a interface request. + * + * This function is used to handle get the alternate setting of a interface request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9GetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + *length = USB_INTERFACE_SIZE; + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + + return USB_DeviceGetInterface(handle, setup->wIndex & 0xFFU, (uint8_t *)&s_UsbDeviceStandardRx); +} + +/*! + * @brief Handle set the alternate setting of a interface request. + * + * This function is used to handle set the alternate setting of a interface request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SetInterface(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return kStatus_USB_InvalidRequest; + } + + return USB_DeviceSetInterface(handle, (setup->wIndex & 0xFFU), (setup->wValue & 0xFFU)); +} + +/*! + * @brief Handle get sync frame request. + * + * This function is used to handle get sync frame request. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @retval kStatus_USB_Success The requst is handled successfully. + * @retval kStatus_USB_InvalidRequest The request can not be handle in current device state, + * or, the request is unsupported. + */ +static usb_status_t USB_DeviceCh9SynchFrame(usb_device_handle handle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + + s_UsbDeviceStandardRx = setup->wIndex; + /* Get the sync frame value */ + error = USB_DeviceGetStatus(handle, kUSB_DeviceStatusSynchFrame, &s_UsbDeviceStandardRx); + *buffer = (uint8_t *)&s_UsbDeviceStandardRx; + *length = sizeof(s_UsbDeviceStandardRx); + + return error; +} + +/*! + * @brief Send the reponse to the host. + * + * This function is used to send the reponse to the host. + * + * There are two cases this function will be called. + * Case one when a setup packet is received in control endpoint callback function: + * 1. If there is not data phase in the setup transfer, the function will prime an IN transfer with the data + * length is zero for status phase. + * 2. If there is an IN data phase, the function will prime an OUT transfer with the actual length to need to + * send for data phase. And then prime an IN transfer with the data length is zero for status phase. + * 3. If there is an OUT data phase, the function will prime an IN transfer with the actual length to want to + * receive for data phase. + * + * Case two when is not a setup packet received in control endpoint callback function: + * 1. The function will prime an IN transfer with data length is zero for status phase. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param setup The pointer of the setup packet. + * @param error The error code returned from the standard request fucntion. + * @param stage The stage of the control transfer. + * @param buffer It is an out parameter, is used to save the buffer address to response the host's request. + * @param length It is an out parameter, the data length. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceControlCallbackFeedback(usb_device_handle handle, + usb_setup_struct_t *setup, + usb_status_t error, + usb_device_control_read_write_sequence_t stage, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t errorCode = kStatus_USB_Error; + uint8_t direction = USB_IN; + + if (kStatus_USB_InvalidRequest == error) + { + /* Stall the control pipe when the request is unsupported. */ + if ((!((setup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_STANDARD)) && + ((setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) && (setup->wLength) && + (kUSB_DeviceControlPipeSetupStage == stage)) + { + direction = USB_OUT; + } + errorCode = USB_DeviceStallEndpoint( + handle, + (USB_CONTROL_ENDPOINT) | (uint8_t)((uint32_t)direction << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + } + else + { + if (*length > setup->wLength) + { + *length = setup->wLength; + } + errorCode = USB_DeviceSendRequest(handle, (USB_CONTROL_ENDPOINT), *buffer, *length); + + if ((kStatus_USB_Success == errorCode) && + (USB_REQUEST_TYPE_DIR_IN == (setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK))) + { + errorCode = USB_DeviceRecvRequest(handle, (USB_CONTROL_ENDPOINT), (uint8_t *)NULL, 0U); + } + } + return errorCode; +} + +/*! + * @brief Control endpoint callback function. + * + * This callback function is used to notify uplayer the tranfser result of a transfer. + * This callback pointer is passed when a sepcified endpoint initialied by calling API USB_DeviceInitEndpoint. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The result of a transfer, includes transfer buffer, transfer length and whether is in setup + * phase for control pipe. + * @param callbackParam The paramter for this callback. It is same with + * usb_device_endpoint_callback_struct_t::callbackParam. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceControlCallback(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_setup_struct_t *deviceSetup; + uint8_t *setupOutBuffer; + uint8_t *buffer = (uint8_t *)NULL; + uint32_t length = 0U; + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if (USB_UNINITIALIZED_VAL_32 == message->length) + { + return error; + } + + USB_DeviceGetSetupBuffer(handle, &deviceSetup); + USB_DeviceGetStatus(handle, kUSB_DeviceStatusDeviceState, &state); + + if (message->isSetup) + { + if ((USB_SETUP_PACKET_SIZE != message->length) || (NULL == message->buffer)) + { + /* If a invalid setup is received, the control pipes should be de-init and init again. + * Due to the IP can not meet this require, it is revesed for feature. + */ + /* + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + USB_DeviceControlPipeInit(handle); + */ + return error; + } + /* Receive a setup request */ + usb_setup_struct_t *setup = (usb_setup_struct_t *)(message->buffer); + /* Copy the setup packet to the application buffer */ + deviceSetup->wValue = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wValue); + deviceSetup->wIndex = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wIndex); + deviceSetup->wLength = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wLength); + deviceSetup->bRequest = setup->bRequest; + deviceSetup->bmRequestType = setup->bmRequestType; + + if ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_MASK) == USB_REQUEST_TYPE_TYPE_STANDARD) + { + /* Handle the standard request */ + if (s_UsbDeviceStandardRequest[deviceSetup->bRequest] != (usb_standard_request_callback_t)NULL) + { + error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](handle, deviceSetup, &buffer, &length); + } + } + else + { + if ((deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) + { + /* Class or vendor request with the OUT data phase. */ + if ((deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_CLASS) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Get data buffer to receive the data from the host. */ + length = deviceSetup->wLength; + error = USB_DeviceGetClassReceiveBuffer(handle, deviceSetup, &length, &setupOutBuffer); + length = 0U; + } + else + { + } + if (kStatus_USB_Success == error) + { + /* Prime an OUT transfer */ + error = USB_DeviceRecvRequest(handle, USB_CONTROL_ENDPOINT, setupOutBuffer, deviceSetup->wLength); + return error; + } + } + else + { + /* Class or vendor request with the IN data phase. */ + if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_CLASS) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Get data buffer to response the host. */ + error = USB_DeviceProcessClassRequest(handle, deviceSetup, &length, &buffer); + } + else + { + } + } + } + /* Send the reponse to the host. */ + error = USB_DeviceControlCallbackFeedback(handle, deviceSetup, error, kUSB_DeviceControlPipeSetupStage, &buffer, + &length); + } + else if (kUSB_DeviceStateAddressing == state) + { + /* Set the device address to controller. */ + error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](handle, deviceSetup, &buffer, &length); + } +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + else if (kUSB_DeviceStateTestMode == state) + { + uint8_t portTestControl = (uint8_t)(deviceSetup->wIndex >> 8); + /* Set the controller.into test mode. */ + error = USB_DeviceSetStatus(handle, kUSB_DeviceStatusTestMode, &portTestControl); + } +#endif + else if ((message->length) && (deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)) + { + if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_CLASS) == USB_REQUEST_TYPE_TYPE_CLASS)) + { + /* Data received in OUT phase, and notify the class driver. */ + error = USB_DeviceProcessClassRequest(handle, deviceSetup, &message->length, &message->buffer); + } + else + { + } + /* Send the reponse to the host. */ + error = USB_DeviceControlCallbackFeedback(handle, deviceSetup, error, kUSB_DeviceControlPipeDataStage, &buffer, + &length); + } + else + { + } + return error; +} + +/*! + * @brief Control endpoint initialization function. + * + * This callback function is used to initialize the control pipes. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param param The up layer handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle) +{ + usb_device_endpoint_init_struct_t epInitStruct; + usb_device_endpoint_callback_struct_t endpointCallback; + usb_status_t error; + + endpointCallback.callbackFn = USB_DeviceControlCallback; + endpointCallback.callbackParam = handle; + + epInitStruct.zlt = 1U; + epInitStruct.transferType = USB_ENDPOINT_CONTROL; + epInitStruct.endpointAddress = USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + epInitStruct.maxPacketSize = USB_CONTROL_MAX_PACKET_SIZE; + /* Initialize the control IN pipe */ + error = USB_DeviceInitEndpoint(handle, &epInitStruct, &endpointCallback); + + if (kStatus_USB_Success != error) + { + return error; + } + epInitStruct.endpointAddress = USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + /* Initialize the control OUT pipe */ + error = USB_DeviceInitEndpoint(handle, &epInitStruct, &endpointCallback); + + if (kStatus_USB_Success != error) + { + USB_DeviceDeinitEndpoint(handle, + USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + return error; + } + + return kStatus_USB_Success; +} diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.h new file mode 100644 index 00000000..89676fbd --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_ch9.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_DEVICE_CH9_H__ +#define __USB_DEVICE_CH9_H__ + +/******************************************************************************* +* Definitions +******************************************************************************/ +/*! + * @addtogroup usb_device_ch9 + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines USB device status size when the host request to get device status */ +#define USB_DEVICE_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device interface status size when the host request to get interface status */ +#define USB_INTERFACE_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device endpoint status size when the host request to get endpoint status */ +#define USB_ENDPOINT_STATUS_SIZE (0x02U) + +/*! @brief Defines USB device configuration size when the host request to get current configuration */ +#define USB_CONFIGURE_SIZE (0X01U) + +/*! @brief Defines USB device interface alternate setting size when the host request to get interface alternate setting + */ +#define USB_INTERFACE_SIZE (0X01U) + +/*! @brief Defines USB device status mask */ +#define USB_GET_STATUS_DEVICE_MASK (0x03U) + +/*! @brief Defines USB device interface status mask */ +#define USB_GET_STATUS_INTERFACE_MASK (0x03U) + +/*! @brief Defines USB device endpoint status mask */ +#define USB_GET_STATUS_ENDPOINT_MASK (0x03U) + +/*! @brief Control read and write sequence */ +typedef enum _usb_device_control_read_write_sequence +{ + kUSB_DeviceControlPipeSetupStage = 0U, /*!< Setup stage */ + kUSB_DeviceControlPipeDataStage, /*!< Data stage */ + kUSB_DeviceControlPipeStatusStage, /*!< status stage */ +} usb_device_control_read_write_sequence_t; + +/******************************************************************************* +* API +******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initialize the control pipes. + * + * The function is used to initialize the control pipes. This function should be called when event + * kUSB_DeviceEventBusReset is received. + * + * @param handle The device handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle); + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* __USB_DEVICE_CH9_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_config.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_config.h new file mode 100644 index 00000000..869556e6 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_config.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef _USB_DEVICE_CONFIG_H_ +#define _USB_DEVICE_CONFIG_H_ + +/******************************************************************************* +* Definitions +******************************************************************************/ +/*! + * @addtogroup usb_device_configuration + * @{ + */ + +/*! + * @name Hardware instance define + * @{ + */ + +/*! @brief KHCI instance count */ +#define USB_DEVICE_CONFIG_KHCI (1U) + +/*! @brief EHCI instance count */ +#define USB_DEVICE_CONFIG_EHCI (0U) + +/*! @brief LPC USB IP3511 FS instance count */ +#define USB_DEVICE_CONFIG_LPCIP3511FS (0U) + +/*! @brief LPC USB IP3511 HS instance count */ +#define USB_DEVICE_CONFIG_LPCIP3511HS (0U) + +/*! @brief Device instance count, the sum of KHCI and EHCI instance counts*/ +#define USB_DEVICE_CONFIG_NUM \ + (USB_DEVICE_CONFIG_KHCI + USB_DEVICE_CONFIG_EHCI + USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) + +/* @} */ + +/*! + * @name class instance define + * @{ + */ + +/*! @brief HID instance count */ +#define USB_DEVICE_CONFIG_HID (0U) + +/*! @brief CDC ACM instance count */ +#define USB_DEVICE_CONFIG_CDC_ACM (1U) + +/*! @brief MSC instance count */ +#define USB_DEVICE_CONFIG_MSC (0U) + +/*! @brief Audio instance count */ +#define USB_DEVICE_CONFIG_AUDIO (0U) + +/*! @brief PHDC instance count */ +#define USB_DEVICE_CONFIG_PHDC (0U) + +/*! @brief Video instance count */ +#define USB_DEVICE_CONFIG_VIDEO (0U) + +/*! @brief CCID instance count */ +#define USB_DEVICE_CONFIG_CCID (0U) + +/*! @brief Printer instance count */ +#define USB_DEVICE_CONFIG_PRINTER (0U) + +/*! @brief DFU instance count */ +#define USB_DEVICE_CONFIG_DFU (0U) + +/* @} */ + +/*! @brief Whether device is self power. 1U supported, 0U not supported */ +#define USB_DEVICE_CONFIG_SELF_POWER (1U) + +/*! @brief How many endpoints are supported in the stack. */ +#define USB_DEVICE_CONFIG_ENDPOINTS (4U) + +/*! @brief Whether the device task is enabled. */ +#define USB_DEVICE_CONFIG_USE_TASK (0U) + +/*! @brief How many the notification message are supported when the device task is enabled. */ +#define USB_DEVICE_CONFIG_MAX_MESSAGES (8U) + +/*! @brief Whether test mode enabled. */ +#define USB_DEVICE_CONFIG_USB20_TEST_MODE (0U) + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + +/*! @brief The MAX buffer length for the KHCI DMA workaround.*/ +#define USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH (64U) +/*! @brief Whether handle the USB KHCI bus error. */ +#define USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING (0U) +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/*! @brief How many the DTD are supported. */ +#define USB_DEVICE_CONFIG_EHCI_MAX_DTD (16U) +/*! @brief Whether handle the USB EHCI bus error. */ +#define USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING (0U) + +/*! @brief Whether the EHCI ID pin detect feature enabled. */ +#define USB_DEVICE_CONFIG_EHCI_ID_PIN_DETECT (0U) +#endif + +/*! @brief Whether the keep alive feature enabled. */ +#define USB_DEVICE_CONFIG_KEEP_ALIVE_MODE (0U) + +/*! @brief Whether the transfer buffer is cache-enabled or not. */ +#define USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U) + +/*! @brief Whether the low power mode is enabled or not. */ +#define USB_DEVICE_CONFIG_LOW_POWER_MODE (0U) + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +/*! @brief Whether device remote wakeup supported. 1U supported, 0U not supported */ +#define USB_DEVICE_CONFIG_REMOTE_WAKEUP (0U) + +/*! @brief Whether LPM is supported. 1U supported, 0U not supported */ +#define USB_DEVICE_CONFIG_LPM_L1 (0U) +#else +/*! @brief The device remote wakeup is unsupported. */ +#define USB_DEVICE_CONFIG_REMOTE_WAKEUP (0U) +#endif + +/*! @brief Whether the device detached feature is enabled or not. */ +#define USB_DEVICE_CONFIG_DETACH_ENABLE (0U) + +/* @} */ + +#endif /* _USB_DEVICE_CONFIG_H_ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.c new file mode 100644 index 00000000..7d847912 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.c @@ -0,0 +1,1469 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" + +#include "MK22F51212.h" + +#if ((defined(USB_DEVICE_CONFIG_NUM)) && (USB_DEVICE_CONFIG_NUM > 0U)) + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +#include "usb_device_khci.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +#include "usb_device_ehci.h" +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +#include "usb_device_lpcip3511.h" +#endif + +#include "usb_device_ch9.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static usb_status_t USB_DeviceAllocateHandle(uint8_t controllerId, usb_device_struct_t **handle); +static usb_status_t USB_DeviceFreeHandle(usb_device_struct_t *handle); +static usb_status_t USB_DeviceGetControllerInterface( + uint8_t controllerId, const usb_device_controller_interface_struct_t **controllerInterface); +static usb_status_t USB_DeviceTransfer(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); +static usb_status_t USB_DeviceControl(usb_device_handle handle, usb_device_control_type_t type, void *param); +static usb_status_t USB_DeviceResetNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +static usb_status_t USB_DeviceSuspendNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +static usb_status_t USB_DeviceResumeNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) +static usb_status_t USB_DeviceSleepNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); + +#endif +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) +static usb_status_t USB_DeviceDetachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +static usb_status_t USB_DeviceAttachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message); +#endif +static usb_status_t USB_DeviceNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +USB_GLOBAL static usb_device_struct_t s_UsbDevice[USB_DEVICE_CONFIG_NUM]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Allocate a device handle. + * + * This function allocates a device handle. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param handle It is out parameter, is used to return pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_Error The device has been initialized. + */ +static usb_status_t USB_DeviceAllocateHandle(uint8_t controllerId, usb_device_struct_t **handle) +{ + uint32_t count; + USB_OSA_SR_ALLOC(); + + USB_OSA_ENTER_CRITICAL(); + /* Check the controller is initialized or not. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDevice[count].controllerHandle) && (controllerId == s_UsbDevice[count].controllerId)) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Error; + } + } + /* Get a free device handle. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if (NULL == s_UsbDevice[count].controllerHandle) + { + s_UsbDevice[count].controllerId = controllerId; + *handle = &s_UsbDevice[count]; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Busy; +} + +/*! + * @brief Free a device handle. + * + * This function frees a device handle. + * + * @param handle The device handle. + * + * @retval kStatus_USB_Success Free device handle successfully. + */ +static usb_status_t USB_DeviceFreeHandle(usb_device_struct_t *handle) +{ + USB_OSA_SR_ALLOC(); + + USB_OSA_ENTER_CRITICAL(); + handle->controllerHandle = NULL; + handle->controllerId = 0U; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; +} + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) +/* KHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceKhciInterface = { + USB_DeviceKhciInit, USB_DeviceKhciDeinit, USB_DeviceKhciSend, + USB_DeviceKhciRecv, USB_DeviceKhciCancel, USB_DeviceKhciControl}; +#endif + +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) +/* EHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceEhciInterface = { + USB_DeviceEhciInit, USB_DeviceEhciDeinit, USB_DeviceEhciSend, + USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl}; +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +/* EHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceLpc3511IpInterface = { + USB_DeviceLpc3511IpInit, USB_DeviceLpc3511IpDeinit, USB_DeviceLpc3511IpSend, + USB_DeviceLpc3511IpRecv, USB_DeviceLpc3511IpCancel, USB_DeviceLpc3511IpControl}; +#endif + +/*! + * @brief Get the controller interface handle. + * + * This function is used to get the controller interface handle. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param controllerInterface It is out parameter, is used to return pointer of the device controller handle to the + * caller. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_ControllerNotFound The controller id is invalided. + */ +static usb_status_t USB_DeviceGetControllerInterface( + uint8_t controllerId, const usb_device_controller_interface_struct_t **controllerInterface) +{ + usb_status_t error = kStatus_USB_ControllerNotFound; + switch (controllerId) + { +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + /* Get the KHCI controller driver interface */ + case kUSB_ControllerKhci0: + case kUSB_ControllerKhci1: + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceKhciInterface; + error = kStatus_USB_Success; + break; +#endif +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) + /* Get the EHCI controller driver interface */ + case kUSB_ControllerEhci0: + case kUSB_ControllerEhci1: + error = kStatus_USB_Success; + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceEhciInterface; + break; +#endif +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) + /* Get the EHCI controller driver interface */ + case kUSB_ControllerLpcIp3511Fs0: + case kUSB_ControllerLpcIp3511Fs1: + case kUSB_ControllerLpcIp3511Hs0: + case kUSB_ControllerLpcIp3511Hs1: + error = kStatus_USB_Success; + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceLpc3511IpInterface; + break; +#endif + default: + break; + } + return error; +} + +/*! + * @brief Start a new transfer. + * + * This function is used to start a new transfer. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param endpointAddress Endpoint address. Bit7 is direction, 0U - USB_OUT, 1U - USB_IN. + * @param buffer The memory address to be transferred, or the memory address to hold the data need to be + * sent. + * @param length The length of the data. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_InvalidHandle The device handle is invalided. + * @retval kStatus_USB_ControllerNotFound The controller interface is not found. + * @retval kStatus_USB_Error The device is doing reset. + */ +static usb_status_t USB_DeviceTransfer(usb_device_handle handle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + uint8_t endpoint = endpointAddress & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + if (deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy) + { + return kStatus_USB_Busy; + } + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 1U; + if (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) + { +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + if (length) + { + USB_CacheFlushLines((void *)buffer, length); + } +#endif + /* Call the controller send interface. */ + error = deviceHandle->controllerInterface->deviceSend(deviceHandle->controllerHandle, endpointAddress, + buffer, length); + } + else + { +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + if (length) + { + USB_CacheInvalidateLines((void *)buffer, length); + } +#endif + /* Call the controller receive interface. */ + error = deviceHandle->controllerInterface->deviceRecv(deviceHandle->controllerHandle, endpointAddress, + buffer, length); + } + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Control the status of the selected item. + * + * This function is used to control the status of the selected item.. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param type The control type, please refer to the enumeration usb_device_control_type_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_InvalidHandle The device handle is invalided. + * @retval kStatus_USB_ControllerNotFound The controller interface is not found. + * @retval kStatus_USB_Error Unsupport type. + * Or, the param is NULL pointer. + */ +static usb_status_t USB_DeviceControl(usb_device_handle handle, usb_device_control_type_t type, void *param) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + /* Call the controller control interface. */ + error = deviceHandle->controllerInterface->deviceControl(deviceHandle->controllerHandle, type, param); + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Handle the reset notification. + * + * This function is used to handle the reset notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @retval kStatus_USB_Success Get a device handle successfully. + */ +static usb_status_t USB_DeviceResetNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_SR_ALLOC(); +#endif + + handle->isResetting = 1U; + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + /* Clear remote wakeup feature */ + handle->remotewakeup = 0U; +#endif + +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_ENTER_CRITICAL(); + handle->epCallbackDirectly = 1; + USB_OSA_EXIT_CRITICAL(); +#endif + /* Set the controller to default status. */ + USB_DeviceControl(handle, kUSB_DeviceControlSetDefaultStatus, NULL); +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_ENTER_CRITICAL(); + handle->epCallbackDirectly = 0; + USB_OSA_EXIT_CRITICAL(); +#endif + + handle->state = kUSB_DeviceStateDefault; + handle->deviceAddress = 0U; + + for (uint32_t count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + handle->endpointCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + handle->endpointCallback[count].callbackParam = NULL; + handle->endpointCallback[count].isBusy = 0U; + } + + /* Call device callback to notify the application that the USB bus reset signal detected. */ + handle->deviceCallback(handle, kUSB_DeviceEventBusReset, NULL); + + handle->isResetting = 0U; + return kStatus_USB_Success; +} + +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +/*! + * @brief Handle the suspend notification. + * + * This function is used to handle the suspend notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceSuspendNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus suspend signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventSuspend, NULL); +} + +/*! + * @brief Handle the resume notification. + * + * This function is used to handle the resume notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceResumeNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus resume signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventResume, NULL); +} +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) +/*! + * @brief Handle the suspend notification. + * + * This function is used to handle the suspend notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceSleepNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus suspend signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventSleeped, NULL); +} +#endif +/*! + * @brief Handle the remotewakeup notification. + * + * This function is used to handle the remotewakeup notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param flag The buffer pointer to store remotewakeup flag. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetRemoteWakeUp(usb_device_struct_t *handle, uint8_t **flag) +{ + /* Call device callback to notify the application that the USB bus suspend signal detected. */ + return USB_DeviceControl(handle, kUSB_DeviceControlGetRemoteWakeUp, flag); +} + +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + +#if (defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) || \ + (defined(USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) +usb_status_t USB_DeviceErrorNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the USB bus error signal detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventError, NULL); +} +#endif + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) +/*! + * @brief Handle the detach notification. + * + * This function is used to handle the detach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDetachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device is disconnected from a host. */ + return handle->deviceCallback(handle, kUSB_DeviceEventDetach, NULL); +} + +/*! + * @brief Handle the attach notification. + * + * This function is used to handle the attach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceAttachNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device is connected to a host. */ + return handle->deviceCallback(handle, kUSB_DeviceEventAttach, NULL); +} +#endif + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) || \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))) +/*! + * @brief Handle the dcd module timeout notification. + * + * This function is used to handle the dcd module timeout notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDcdTimeOutNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device charger detect timeout happened. */ + return handle->deviceCallback(handle, kUSB_DeviceEventDcdTimeOut, NULL); +} + +/*! + * @brief Handle the dcd module unknown port type notification. + * + * This function is used to handle the dcd module unknown port type notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDcdUnknownPortTypeNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the device charger detect unknown port type happened. */ + return handle->deviceCallback(handle, kUSB_DeviceEventDcdUnknownType, NULL); +} + +/*! + * @brief Handle the SDP facility is detected notification. + * + * This function is used to handle the SDP facility is detectednotification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDcdSDPDetectNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the SDP facility is detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventSDPDetected, NULL); +} + +/*! + * @brief Handle the charging port is detected notification. + * + * This function is used to handle the charging port is detectednotification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDcdChargingPortDetectNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the charing port is detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventChargingPortDetected, NULL); +} + +/*! + * @brief Handle the CDP facility is detected notification. + * + * This function is used to handle the CDP facility is detectednotification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceDcdChargingHostDetectNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the CDP facility is detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventChargingHostDetected, NULL); +} + +/*! + * @brief Handle the DCP facility is detected notification. + * + * This function is used to handle the DCP facility is detectednotification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ + +static usb_status_t USB_DeviceDcdDedicatedChargerDetectNotification(usb_device_struct_t *handle, + usb_device_callback_message_struct_t *message) +{ + /* Call device callback to notify the application that the DCP facility is detected. */ + return handle->deviceCallback(handle, kUSB_DeviceEventDedicatedChargerDetected, NULL); +} +#endif + +/*! + * @brief Handle the attach notification. + * + * This function is used to handle the attach notification. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceNotification(usb_device_struct_t *handle, usb_device_callback_message_struct_t *message) +{ + uint8_t endpoint = message->code & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = (message->code & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + usb_status_t error = kStatus_USB_Error; + + switch (message->code) + { + case kUSB_DeviceNotifyBusReset: + error = USB_DeviceResetNotification(handle, message); + break; +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + case kUSB_DeviceNotifySuspend: + error = USB_DeviceSuspendNotification(handle, message); + break; + case kUSB_DeviceNotifyResume: + error = USB_DeviceResumeNotification(handle, message); + break; +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + case kUSB_DeviceNotifyLPMSleep: + error = USB_DeviceSleepNotification(handle, message); + break; +#endif +#endif + +#if (defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) || \ + (defined(USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) && USB_DEVICE_CONFIG_EHCI_ERROR_HANDLING) + case kUSB_DeviceNotifyError: + error = USB_DeviceErrorNotification(handle, message); + break; +#endif + +#if USB_DEVICE_CONFIG_DETACH_ENABLE + case kUSB_DeviceNotifyDetach: + error = USB_DeviceDetachNotification(handle, message); + break; + case kUSB_DeviceNotifyAttach: + error = USB_DeviceAttachNotification(handle, message); + break; +#endif +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) || \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))) + case kUSB_DeviceNotifyDcdTimeOut: + error = USB_DeviceDcdTimeOutNotification(handle, message); + break; + case kUSB_DeviceNotifyDcdUnknownPortType: + error = USB_DeviceDcdUnknownPortTypeNotification(handle, message); + break; + case kUSB_DeviceNotifySDPDetected: + error = USB_DeviceDcdSDPDetectNotification(handle, message); + break; + case kUSB_DeviceNotifyChargingPortDetected: + error = USB_DeviceDcdChargingPortDetectNotification(handle, message); + break; + case kUSB_DeviceNotifyChargingHostDetected: + error = USB_DeviceDcdChargingHostDetectNotification(handle, message); + break; + case kUSB_DeviceNotifyDedicatedChargerDetected: + error = USB_DeviceDcdDedicatedChargerDetectNotification(handle, message); + break; +#endif + + default: + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + if (handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn) + { + usb_device_endpoint_callback_message_struct_t endpointCallbackMessage; + endpointCallbackMessage.buffer = message->buffer; + endpointCallbackMessage.length = message->length; + endpointCallbackMessage.isSetup = message->isSetup; + if (message->isSetup) + { + handle->endpointCallback[0].isBusy = 0U; + handle->endpointCallback[1].isBusy = 0U; + } + else + { + handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U; + } + /* Call endpoint callback */ + error = handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn( + handle, &endpointCallbackMessage, + handle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam); + } + } + break; + } + return error; +} + +/*! + * @brief Notify the device that the controller status changed. + * + * This function is used to notify the device that the controller status changed. + * + * @param handle The device handle. It equals the value returned from USB_DeviceInit. + * @param message The device callback message handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_device_callback_message_struct_t *message = (usb_device_callback_message_struct_t *)msg; + + if ((NULL == msg) || (NULL == handle)) + { + return kStatus_USB_InvalidHandle; + } + + /* The device callback is invalid or not. */ + if (!deviceHandle->deviceCallback) + { + return kStatus_USB_Error; + } + +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + if (deviceHandle->epCallbackDirectly) + { + if ((message->code & USB_ENDPOINT_NUMBER_MASK) && (!(message->code & 0x70U))) + { + return USB_DeviceNotification(deviceHandle, message); + } + } + + /* Add the message to message queue when the device task is enabled. */ + if (kStatus_USB_OSA_Success != USB_OsaMsgqSend(deviceHandle->notificationQueue, (void *)message)) + { + return kStatus_USB_Busy; + } + return kStatus_USB_Success; +#else + /* Handle the notification by calling USB_DeviceNotification. */ + return USB_DeviceNotification(deviceHandle, message); +#endif +} + +/*! + * @brief Initialize the USB device stack. + * + * This function initializes the USB device module specified by the controllerId. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param deviceCallback Function pointer of the device callback. + * @param handle It is out parameter, is used to return pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. + * @retval kStatus_USB_Busy Cannot allocate a device handle. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller according to the controller id. + * @retval kStatus_USB_InvalidControllerInterface The controller driver interfaces is invaild, There is an empty + * interface entity. + * @retval kStatus_USB_Error The macro USB_DEVICE_CONFIG_ENDPOINTS is more than IP's endpoint number. + * Or, the device has been initialized. + * Or, the message queue is created failed. + */ +usb_status_t USB_DeviceInit(uint8_t controllerId, usb_device_callback_t deviceCallback, usb_device_handle *handle) +{ + usb_device_struct_t *deviceHandle = NULL; + usb_status_t error; + uint32_t count; + + if (NULL == handle) + { + return kStatus_USB_InvalidHandle; + } + + /* Allocate a device handle by using the controller id. */ + error = USB_DeviceAllocateHandle(controllerId, &deviceHandle); + + if (kStatus_USB_Success != error) + { + return error; + } + + /* Save the device callback */ + deviceHandle->deviceCallback = deviceCallback; + /* Save the controller id */ + deviceHandle->controllerId = controllerId; + /* Clear the device address */ + deviceHandle->deviceAddress = 0U; + /* Clear the device reset state */ + deviceHandle->isResetting = 0U; + + /* Initialize the enpoints */ + for (count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + deviceHandle->endpointCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + deviceHandle->endpointCallback[count].callbackParam = NULL; + deviceHandle->endpointCallback[count].isBusy = 0U; + } + + /* Get the controller interface according to the controller id */ + error = USB_DeviceGetControllerInterface(controllerId, &deviceHandle->controllerInterface); + if (kStatus_USB_Success != error) + { + USB_DeviceFreeHandle(deviceHandle); + return error; + } + if (NULL == deviceHandle->controllerInterface) + { + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_ControllerNotFound; + } + if (((usb_device_controller_init_t)NULL == deviceHandle->controllerInterface->deviceInit) || + ((usb_device_controller_deinit_t)NULL == deviceHandle->controllerInterface->deviceDeinit) || + ((usb_device_controller_send_t)NULL == deviceHandle->controllerInterface->deviceSend) || + ((usb_device_controller_recv_t)NULL == deviceHandle->controllerInterface->deviceRecv) || + ((usb_device_controller_cancel_t)NULL == deviceHandle->controllerInterface->deviceCancel) || + ((usb_device_controller_control_t)NULL == deviceHandle->controllerInterface->deviceControl)) + { + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_InvalidControllerInterface; + } + +#if USB_DEVICE_CONFIG_USE_TASK + /* Create a message queue when the device handle is enabled. */ + if (kStatus_USB_OSA_Success != + USB_OsaMsgqCreate(&deviceHandle->notificationQueue, USB_DEVICE_CONFIG_MAX_MESSAGES, + (1U + (sizeof(usb_device_callback_message_struct_t) - 1U) / sizeof(uint32_t)))) + { + USB_DeviceDeinit(deviceHandle); + return kStatus_USB_Error; + } +#endif + /* Initialize the controller */ + error = deviceHandle->controllerInterface->deviceInit(controllerId, deviceHandle, &deviceHandle->controllerHandle); + if (kStatus_USB_Success != error) + { + USB_DeviceDeinit(deviceHandle); + return error; + } + /* Set the device to deafult state */ + deviceHandle->state = kUSB_DeviceStateDefault; + *handle = deviceHandle; + + return error; +} + +/*! + * @brief Enable the device functionality. + * + * The function enables the device functionality, so that the device can be recognized by the host when the device + * detects that it has been connected to a host. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +usb_status_t USB_DeviceRun(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlRun, NULL); +} +/*! + * @brief Disable the device functionality. + * + * The function disables the device functionality, after this function called, even the device is detached to the host, + * and the device can't work. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + */ +usb_status_t USB_DeviceStop(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlStop, NULL); +} +/*! + * @brief De-initialize the device controller. + * + * The function de-initializes the device controller specified by the handle. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is stopped successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + */ +usb_status_t USB_DeviceDeinit(usb_device_handle handle) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + /* De-initialize the controller */ + if (NULL != deviceHandle->controllerInterface) + { + deviceHandle->controllerInterface->deviceDeinit(deviceHandle->controllerHandle); + deviceHandle->controllerInterface = (usb_device_controller_interface_struct_t *)NULL; + } + +#if USB_DEVICE_CONFIG_USE_TASK + /* Destroy the message queue. */ + if (NULL != deviceHandle->notificationQueue) + { + USB_OsaMsgqDestroy(deviceHandle->notificationQueue); + deviceHandle->notificationQueue = NULL; + } +#endif + + /* Free the device handle. */ + USB_DeviceFreeHandle(deviceHandle); + return kStatus_USB_Success; +} + +/*! + * @brief Send data through a specified endpoint. + * + * The function is used to send data through a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to hold the data need to be sent. + * @param length The data length need to be sent. + * + * @retval kStatus_USB_Success The send request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate dtds for current tansfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value just means if the sending request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceSendRequest(usb_device_handle handle, uint8_t endpointAddress, uint8_t *buffer, uint32_t length) +{ + return USB_DeviceTransfer(handle, (endpointAddress & USB_ENDPOINT_NUMBER_MASK) | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT), + buffer, length); +} + +/*! + * @brief Receive data through a specified endpoint. + * + * The function is used to receive data through a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to save the received data. + * @param length The data length want to be received. + * + * @retval kStatus_USB_Success The receive request is sent successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_Busy Cannot allocate dtds for current tansfer in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error The device is doing reset. + * + * @note The return value just means if the receiving request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceRecvRequest(usb_device_handle handle, uint8_t endpointAddress, uint8_t *buffer, uint32_t length) +{ + return USB_DeviceTransfer(handle, (endpointAddress & USB_ENDPOINT_NUMBER_MASK) | + (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT), + buffer, length); +} + +/*! + * @brief Cancel the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The transfer is cancelled. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceCancel(usb_device_handle handle, uint8_t endpointAddress) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + usb_status_t error = kStatus_USB_Error; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + error = deviceHandle->controllerInterface->deviceCancel(deviceHandle->controllerHandle, endpointAddress); + } + else + { + error = kStatus_USB_ControllerNotFound; + } + return error; +} + +/*! + * @brief Initialize a specified endpoint. + * + * The function is used to initialize a specified endpoint and the corresponding endpoint callback is also initialized. + * + * @param handle The device handle got from USB_DeviceInit. + * @param epInit Endpoint initizlization structure. Please refer to the structure usb_device_endpoint_init_struct_t. + * @param endpointCallback Endpoint callback structure. Please refer to the structure + * usb_device_endpoint_callback_struct_t. + * + * @retval kStatus_USB_Success The endpoint is initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The epInit or endpointCallback is NULL pointer. Or the endpoint number is + * more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceInitEndpoint(usb_device_handle handle, + usb_device_endpoint_init_struct_t *epInit, + usb_device_endpoint_callback_struct_t *endpointCallback) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + uint8_t endpoint; + uint8_t direction; + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if ((!epInit) || (!endpointCallback)) + { + return kStatus_USB_InvalidParameter; + } + + endpoint = epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK; + direction = (epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = + endpointCallback->callbackFn; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = + endpointCallback->callbackParam; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U; + } + else + { + return kStatus_USB_InvalidParameter; + } + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointInit, epInit); +} + +/*! + * @brief De-initizlize a specified endpoint. + * + * The function is used to de-initizlize a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is de-initialized successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_Busy The endpoint is busy in EHCI driver. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceDeinitEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + uint8_t endpoint = endpointAddress & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = (endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + usb_status_t error = kStatus_USB_Error; +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_SR_ALLOC(); +#endif + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_ENTER_CRITICAL(); + deviceHandle->epCallbackDirectly = 1; + USB_OSA_EXIT_CRITICAL(); +#endif + error = USB_DeviceControl(handle, kUSB_DeviceControlEndpointDeinit, &endpointAddress); +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + USB_OSA_ENTER_CRITICAL(); + deviceHandle->epCallbackDirectly = 0; + USB_OSA_EXIT_CRITICAL(); +#endif + + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = + (usb_device_endpoint_callback_t)NULL; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = NULL; + deviceHandle->endpointCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U; + } + else + { + return kStatus_USB_InvalidParameter; + } + return error; +} + +/*! + * @brief Stall a specified endpoint. + * + * The function is used to stall a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceStallEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + if ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointStall, &endpointAddress); + } + else + { + return kStatus_USB_InvalidParameter; + } +} + +/*! + * @brief Un-stall a specified endpoint. + * + * The function is used to un-stall a specified endpoint. + * + * @param handle The device handle got from USB_DeviceInit. + * @param endpointAddress Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @retval kStatus_USB_Success The endpoint is un-stalled successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The endpoint number is more than USB_DEVICE_CONFIG_ENDPOINTS. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + */ +usb_status_t USB_DeviceUnstallEndpoint(usb_device_handle handle, uint8_t endpointAddress) +{ + if ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + return USB_DeviceControl(handle, kUSB_DeviceControlEndpointUnstall, &endpointAddress); + } + else + { + return kStatus_USB_InvalidParameter; + } +} + +/*! + * @brief Get the status of the selected item. + * + * The function is used to get the status of the selected item. + * + * @param handle The device handle got from USB_DeviceInit. + * @param type The selected item. Please refer to the structure usb_device_status_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Get status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_InvalidParameter The param is NULL pointer. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type. + */ +usb_status_t USB_DeviceGetStatus(usb_device_handle handle, usb_device_status_t type, void *param) +{ + uint8_t *temp8; + usb_status_t error = kStatus_USB_Error; + + if (NULL == param) + { + return kStatus_USB_InvalidParameter; + } + switch (type) + { + case kUSB_DeviceStatusSpeed: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetSpeed, param); + break; + case kUSB_DeviceStatusOtg: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetOtgStatus, param); + break; + case kUSB_DeviceStatusDeviceState: + temp8 = (uint8_t *)param; + error = kStatus_USB_Success; + *temp8 = ((usb_device_struct_t *)handle)->state; + break; + case kUSB_DeviceStatusAddress: + temp8 = (uint8_t *)param; + error = kStatus_USB_Success; + *temp8 = ((usb_device_struct_t *)handle)->deviceAddress; + break; + case kUSB_DeviceStatusDevice: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetDeviceStatus, param); + break; + case kUSB_DeviceStatusEndpoint: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetEndpointStatus, param); + break; + case kUSB_DeviceStatusSynchFrame: + error = USB_DeviceControl(handle, kUSB_DeviceControlGetSynchFrame, param); + break; +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + case kUSB_DeviceStatusRemoteWakeup: + temp8 = (uint8_t *)param; + error = kStatus_USB_Success; + *temp8 = ((usb_device_struct_t *)handle)->remotewakeup; + break; +#endif + default: + break; + } + return error; +} + +/*! + * @brief Set the status of the selected item. + * + * The function is used to set the status of the selected item. + * + * @param handle The device handle got from USB_DeviceInit. + * @param type The selected item. Please refer to the structure usb_device_status_t. + * @param param The param type is determined by the selected item. + * + * @retval kStatus_USB_Success Set status successfully. + * @retval kStatus_USB_InvalidHandle The handle is a NULL pointer. Or the controller handle is invalid. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_Error Unsupported type, or the param is NULL pointer. + */ +usb_status_t USB_DeviceSetStatus(usb_device_handle handle, usb_device_status_t type, void *param) +{ + usb_status_t error = kStatus_USB_Error; + switch (type) + { +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U) || \ + (defined(USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) && \ + (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + case kUSB_DeviceStatusTestMode: + error = USB_DeviceControl(handle, kUSB_DeviceControlSetTestMode, param); + break; +#endif + case kUSB_DeviceStatusOtg: + error = USB_DeviceControl(handle, kUSB_DeviceControlSetOtgStatus, param); + break; + case kUSB_DeviceStatusDeviceState: + if (NULL != param) + { + error = kStatus_USB_Success; + ((usb_device_struct_t *)handle)->state = (uint8_t)(*(uint8_t *)param); + } + break; + case kUSB_DeviceStatusAddress: + if (kUSB_DeviceStateAddressing != ((usb_device_struct_t *)handle)->state) + { + if (NULL != param) + { + error = kStatus_USB_Success; + ((usb_device_struct_t *)handle)->deviceAddress = (uint8_t)(*(uint8_t *)param); + ((usb_device_struct_t *)handle)->state = kUSB_DeviceStateAddressing; + } + } + else + { + error = USB_DeviceControl(handle, kUSB_DeviceControlSetDeviceAddress, + &((usb_device_struct_t *)handle)->deviceAddress); + } + break; + case kUSB_DeviceStatusBusResume: + error = USB_DeviceControl(handle, kUSB_DeviceControlResume, param); + break; + case kUSB_DeviceStatusBusSleepResume: + error = USB_DeviceControl(handle, kUSB_DeviceControlSleepResume, param); + break; +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + case kUSB_DeviceStatusRemoteWakeup: + if (NULL != param) + { + error = kStatus_USB_Success; + ((usb_device_struct_t *)handle)->remotewakeup = (uint8_t)(*(uint8_t *)param); + } + break; +#endif + case kUSB_DeviceStatusBusSuspend: + error = USB_DeviceControl(handle, kUSB_DeviceControlSuspend, param); + break; + case kUSB_DeviceStatusBusSleep: + error = USB_DeviceControl(handle, kUSB_DeviceControlSleep, param); + break; + default: + break; + } + return error; +} + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) || \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))) +/*! + * @brief Initializes the device dcd module. + * + * The function initializes the device dcd module. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +usb_status_t USB_DeviceDcdInitModule(usb_device_handle handle, void *time_param) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlDcdInitModule, time_param); +} + +/*! + * @brief De-initializes the device dcd module. + * + * The function de-intializes the device dcd module. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +usb_status_t USB_DeviceDcdDeinitModule(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlDcdDeinitModule, NULL); +} + +#if (defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) +/*! + * @brief Get the current attach status of this device. + * + * The function get the current attach status of this device. + * + * @param handle The device handle got from USB_DeviceInit. + * + * @retval kStatus_USB_Success The device is run successfully. + * @retval kStatus_USB_ControllerNotFound Cannot find the controller. + * @retval kStatus_USB_InvalidHandle The device handle is a NULL pointer. Or the controller handle is invalid. + * + */ +usb_status_t USB_DeviceGetAttachStatus(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlGetDeviceAttachStatus, NULL); +} +#endif +#endif + +#if USB_DEVICE_CONFIG_USE_TASK +/*! + * @brief Device task function. + * + * The function is used to handle controller message. + * This function should not be called in applicartion directly. + * + * @param handle The device handle got from USB_DeviceInit. + */ +void USB_DeviceTaskFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + static usb_device_callback_message_struct_t message; + + if (deviceHandle) + { + /* Get the message from the queue */ + if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(handle->notificationQueue, (uint32_t *)&message, 0U)) + { + /* Handle the message */ + USB_DeviceNotification(handle, &message); + } + } +} +#endif + +/*! + * @brief Get dvice stack version function. + * + * The function is used to get dvice stack version. + * + * @param[out] version The version structure pointer to keep the device stack version. + * + */ +void USB_DeviceGetVersion(uint32_t *version) +{ + if (version) + { + *version = + (uint32_t)USB_MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX); + } +} + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) +/*! + * @brief Update the hardware tick. + * + * The function is used to update the hardware tick. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * @param[in] tick Current hardware tick. + * + */ +usb_status_t USB_DeviceUpdateHwTick(usb_device_handle handle, uint64_t tick) +{ + usb_device_struct_t *deviceHandle; + usb_status_t status = kStatus_USB_Success; + + if (handle == NULL) + { + return kStatus_USB_InvalidHandle; + } + deviceHandle = (usb_device_struct_t *)handle; + + deviceHandle->hwTick = tick; + + return status; +} +#endif +#endif /* USB_DEVICE_CONFIG_NUM */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.h new file mode 100644 index 00000000..b98a43a4 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_dci.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_DEVICE_DCI_H__ +#define __USB_DEVICE_DCI_H__ + +/*! + * @addtogroup usb_device_controller_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Macro to define controller handle */ +#define usb_device_controller_handle usb_device_handle + +/*! @brief Available notify types for device notification */ +typedef enum _usb_device_notification +{ + kUSB_DeviceNotifyBusReset = 0x10U, /*!< Reset signal detected */ + kUSB_DeviceNotifySuspend, /*!< Suspend signal detected */ + kUSB_DeviceNotifyResume, /*!< Resume signal detected */ + kUSB_DeviceNotifyLPMSleep, /*!< LPM signal detected */ + kUSB_DeviceNotifyLPMResume, /*!< Resume signal detected */ + kUSB_DeviceNotifyError, /*!< Errors happened in bus */ + kUSB_DeviceNotifyDetach, /*!< Device disconnected from a host */ + kUSB_DeviceNotifyAttach, /*!< Device connected to a host */ +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) + kUSB_DeviceNotifyDcdTimeOut, /*!< Device charger detection timeout */ + kUSB_DeviceNotifyDcdUnknownPortType, /*!< Device charger detection unknown port type */ + kUSB_DeviceNotifySDPDetected, /*!< The SDP facility is detected */ + kUSB_DeviceNotifyChargingPortDetected, /*!< The charging port is detected */ + kUSB_DeviceNotifyChargingHostDetected, /*!< The CDP facility is detected */ + kUSB_DeviceNotifyDedicatedChargerDetected, /*!< The DCP facility is detected */ +#endif +} usb_device_notification_t; + +/*! @brief Device notification message structure */ +typedef struct _usb_device_callback_message_struct +{ + uint8_t *buffer; /*!< Transferred buffer */ + uint32_t length; /*!< Transferred data length */ + uint8_t code; /*!< Notification code */ + uint8_t isSetup; /*!< Is in a setup phase */ +} usb_device_callback_message_struct_t; + +/*! @brief Control type for controller */ +typedef enum _usb_device_control_type +{ + kUSB_DeviceControlRun = 0U, /*!< Enable the device functionality */ + kUSB_DeviceControlStop, /*!< Disable the device functionality */ + kUSB_DeviceControlEndpointInit, /*!< Initialize a specified endpoint */ + kUSB_DeviceControlEndpointDeinit, /*!< De-initialize a specified endpoint */ + kUSB_DeviceControlEndpointStall, /*!< Stall a specified endpoint */ + kUSB_DeviceControlEndpointUnstall, /*!< Unstall a specified endpoint */ + kUSB_DeviceControlGetDeviceStatus, /*!< Get device status */ + kUSB_DeviceControlGetEndpointStatus, /*!< Get endpoint status */ + kUSB_DeviceControlSetDeviceAddress, /*!< Set device address */ + kUSB_DeviceControlGetSynchFrame, /*!< Get current frame */ + kUSB_DeviceControlResume, /*!< Drive controller to generate a resume signal in USB bus */ + kUSB_DeviceControlSleepResume, /*!< Drive controller to generate a LPM resume signal in USB bus */ + kUSB_DeviceControlSuspend, /*!< Drive controller to enetr into suspend mode */ + kUSB_DeviceControlSleep, /*!< Drive controller to enetr into sleep mode */ + kUSB_DeviceControlSetDefaultStatus, /*!< Set controller to default status */ + kUSB_DeviceControlGetSpeed, /*!< Get current speed */ + kUSB_DeviceControlGetOtgStatus, /*!< Get OTG status */ + kUSB_DeviceControlSetOtgStatus, /*!< Set OTG status */ + kUSB_DeviceControlSetTestMode, /*!< Drive xCHI into test mode */ + kUSB_DeviceControlGetRemoteWakeUp, /*!< Get flag of LPM Remote Wake-up Enabled by USB host. */ +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) + kUSB_DeviceControlDcdInitModule, + kUSB_DeviceControlDcdDeinitModule, + kUSB_DeviceControlGetDeviceAttachStatus, +#endif +} usb_device_control_type_t; + +/*! @brief USB device controller initialization function typedef */ +typedef usb_status_t (*usb_device_controller_init_t)(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *controllerHandle); + +/*! @brief USB device controller de-initialization function typedef */ +typedef usb_status_t (*usb_device_controller_deinit_t)(usb_device_controller_handle controllerHandle); + +/*! @brief USB device controller send data function typedef */ +typedef usb_status_t (*usb_device_controller_send_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! @brief USB device controller receive data function typedef */ +typedef usb_status_t (*usb_device_controller_recv_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! @brief USB device controller cancel transfer function in a specified endpoint typedef */ +typedef usb_status_t (*usb_device_controller_cancel_t)(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress); + +/*! @brief USB device controller control function typedef */ +typedef usb_status_t (*usb_device_controller_control_t)(usb_device_controller_handle controllerHandle, + usb_device_control_type_t command, + void *param); + +/*! @brief USB device controller interface structure */ +typedef struct _usb_device_controller_interface_struct +{ + usb_device_controller_init_t deviceInit; /*!< Controller initialization */ + usb_device_controller_deinit_t deviceDeinit; /*!< Controller de-initialization */ + usb_device_controller_send_t deviceSend; /*!< Controller send data */ + usb_device_controller_recv_t deviceRecv; /*!< Controller receive data */ + usb_device_controller_cancel_t deviceCancel; /*!< Controller cancel transfer */ + usb_device_controller_control_t deviceControl; /*!< Controller control */ +} usb_device_controller_interface_struct_t; + +/*! @brief USB device status structure */ +typedef struct _usb_device_struct +{ +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + volatile uint64_t hwTick; /*!< Current hw tick(ms)*/ +#endif + usb_device_controller_handle controllerHandle; /*!< Controller handle */ + const usb_device_controller_interface_struct_t *controllerInterface; /*!< Controller interface handle */ +#if USB_DEVICE_CONFIG_USE_TASK + usb_osa_msgq_handle notificationQueue; /*!< Message queue */ +#endif + usb_device_callback_t deviceCallback; /*!< Device callback function pointer */ + usb_device_endpoint_callback_struct_t + endpointCallback[USB_DEVICE_CONFIG_ENDPOINTS << 1U]; /*!< Endpoint callback function structure */ + uint8_t deviceAddress; /*!< Current device address */ + uint8_t controllerId; /*!< Controller ID */ + uint8_t state; /*!< Current device state */ +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + uint8_t remotewakeup; /*!< Remote wakeup is enabled or not */ +#endif + uint8_t isResetting; /*!< Is doing device reset or not */ +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + uint8_t epCallbackDirectly; /*!< Whether call ep callback directly when the task is enabled */ +#endif +} usb_device_struct_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! @}*/ + +#endif /* __USB_DEVICE_DCI_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.c new file mode 100644 index 00000000..a511aca2 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#include "usb_device_config.h" +#include "usb.h" +#include "usb_device.h" + +#include "usb_device_cdc_acm.h" + +#include "usb_device_descriptor.h" + +/******************************************************************************* +* Variables +******************************************************************************/ +uint8_t g_currentConfigure = 0; +uint8_t g_interface[USB_CDC_VCOM_INTERFACE_COUNT]; + +/* Define device descriptor */ +uint8_t g_UsbDeviceDescriptor[USB_DESCRIPTOR_LENGTH_DEVICE] = { + /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_LENGTH_DEVICE, + /* DEVICE Descriptor Type */ + USB_DESCRIPTOR_TYPE_DEVICE, + /* USB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). */ + USB_SHORT_GET_LOW(USB_DEVICE_SPECIFIC_BCD_VERSION), USB_SHORT_GET_HIGH(USB_DEVICE_SPECIFIC_BCD_VERSION), + /* Class code (assigned by the USB-IF). */ + USB_DEVICE_CLASS, + /* Subclass code (assigned by the USB-IF). */ + USB_DEVICE_SUBCLASS, + /* Protocol code (assigned by the USB-IF). */ + USB_DEVICE_PROTOCOL, + /* Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid) */ + USB_CONTROL_MAX_PACKET_SIZE, + /* Vendor ID (assigned by the USB-IF) */ + 0xC9U, 0x1FU, + /* Product ID (assigned by the manufacturer) */ + 0x94, 0x00, + /* Device release number in binary-coded decimal */ + USB_SHORT_GET_LOW(USB_DEVICE_DEMO_BCD_VERSION), USB_SHORT_GET_HIGH(USB_DEVICE_DEMO_BCD_VERSION), + /* Index of string descriptor describing manufacturer */ + 0x01, + /* Index of string descriptor describing product */ + 0x02, + /* Index of string descriptor describing the device's serial number */ + 0x00, + /* Number of possible configurations */ + USB_DEVICE_CONFIGURATION_COUNT, +}; + +/* Define configuration descriptor */ +uint8_t g_UsbDeviceConfigurationDescriptor[USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL] = { + /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_LENGTH_CONFIGURE, + /* CONFIGURATION Descriptor Type */ + USB_DESCRIPTOR_TYPE_CONFIGURE, + /* Total length of data returned for this configuration. */ + USB_SHORT_GET_LOW(USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL), + USB_SHORT_GET_HIGH(USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL), + /* Number of interfaces supported by this configuration */ + USB_CDC_VCOM_INTERFACE_COUNT, + /* Value to use as an argument to the SetConfiguration() request to select this configuration */ + USB_CDC_VCOM_CONFIGURE_INDEX, + /* Index of string descriptor describing this configuration */ + 0, + /* Configuration characteristics D7: Reserved (set to one) D6: Self-powered D5: Remote Wakeup D4...0: Reserved + (reset to zero) */ + (USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK) | + (USB_DEVICE_CONFIG_SELF_POWER << USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT) | + (USB_DEVICE_CONFIG_REMOTE_WAKEUP << USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_SHIFT), + /* Maximum power consumption of the USB * device from the bus in this specific * configuration when the device is + fully * operational. Expressed in 2 mA units * (i.e., 50 = 100 mA). */ + USB_DEVICE_MAX_POWER, + + /* Communication Interface Descriptor */ + USB_DESCRIPTOR_LENGTH_INTERFACE, USB_DESCRIPTOR_TYPE_INTERFACE, USB_CDC_VCOM_COMM_INTERFACE_INDEX, 0x00, + USB_CDC_VCOM_ENDPOINT_CIC_COUNT, USB_CDC_VCOM_CIC_CLASS, USB_CDC_VCOM_CIC_SUBCLASS, USB_CDC_VCOM_CIC_PROTOCOL, + 0x00, /* Interface Description String Index*/ + + /* CDC Class-Specific descriptor */ + USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC, /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, /* CS_INTERFACE Descriptor Type */ + USB_CDC_HEADER_FUNC_DESC, 0x10, + 0x01, /* USB Class Definitions for Communications the Communication specification version 1.10 */ + + USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG, /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, /* CS_INTERFACE Descriptor Type */ + USB_CDC_CALL_MANAGEMENT_FUNC_DESC, + 0x01, /*Bit 0: Whether device handle call management itself 1, Bit 1: Whether device can send/receive call + management information over a Data Class Interface 0 */ + 0x01, /* Indicates multiplexed commands are handled via data interface */ + + USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT, /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, /* CS_INTERFACE Descriptor Type */ + USB_CDC_ABSTRACT_CONTROL_FUNC_DESC, + 0x06, /* Bit 0: Whether device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and + Get_Comm_Feature 0, Bit 1: Whether device supports the request combination of Set_Line_Coding, + Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State 1, Bit ... */ + + USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC, /* Size of this descriptor in bytes */ + USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE, /* CS_INTERFACE Descriptor Type */ + USB_CDC_UNION_FUNC_DESC, 0x00, /* The interface number of the Communications or Data Class interface */ + 0x01, /* Interface number of subordinate interface in the Union */ + + /*Notification Endpoint descriptor */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, USB_DESCRIPTOR_TYPE_ENDPOINT, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT | (USB_IN << 7U), + USB_ENDPOINT_INTERRUPT, USB_SHORT_GET_LOW(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE), FS_CDC_VCOM_INTERRUPT_IN_INTERVAL, + + /* Data Interface Descriptor */ + USB_DESCRIPTOR_LENGTH_INTERFACE, USB_DESCRIPTOR_TYPE_INTERFACE, USB_CDC_VCOM_DATA_INTERFACE_INDEX, 0x00, + USB_CDC_VCOM_ENDPOINT_DIC_COUNT, USB_CDC_VCOM_DIC_CLASS, USB_CDC_VCOM_DIC_SUBCLASS, USB_CDC_VCOM_DIC_PROTOCOL, + 0x00, /* Interface Description String Index*/ + + /*Bulk IN Endpoint descriptor */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, USB_DESCRIPTOR_TYPE_ENDPOINT, USB_CDC_VCOM_BULK_IN_ENDPOINT | (USB_IN << 7U), + USB_ENDPOINT_BULK, USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_IN_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_IN_PACKET_SIZE), 0x00, /* The polling interval value is every 0 Frames */ + + /*Bulk OUT Endpoint descriptor */ + USB_DESCRIPTOR_LENGTH_ENDPOINT, USB_DESCRIPTOR_TYPE_ENDPOINT, USB_CDC_VCOM_BULK_OUT_ENDPOINT | (USB_OUT << 7U), + USB_ENDPOINT_BULK, USB_SHORT_GET_LOW(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE), + USB_SHORT_GET_HIGH(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE), 0x00, /* The polling interval value is every 0 Frames */ +}; + +/* Define string descriptor */ +uint8_t g_UsbDeviceString0[USB_DESCRIPTOR_LENGTH_STRING0] = {sizeof(g_UsbDeviceString0), USB_DESCRIPTOR_TYPE_STRING, + 0x09, 0x04}; + +uint8_t g_UsbDeviceString1[USB_DESCRIPTOR_LENGTH_STRING1] = { + sizeof(g_UsbDeviceString1), + USB_DESCRIPTOR_TYPE_STRING, + 'N', + 0x00U, + 'X', + 0x00U, + 'P', + 0x00U, + ' ', + 0x00U, + 'S', + 0x00U, + 'E', + 0x00U, + 'M', + 0x00U, + 'I', + 0x00U, + 'C', + 0x00U, + 'O', + 0x00U, + 'N', + 0x00U, + 'D', + 0x00U, + 'U', + 0x00U, + 'C', + 0x00U, + 'T', + 0x00U, + 'O', + 0x00U, + 'R', + 0x00U, + 'S', + 0x00U, +}; + +uint8_t g_UsbDeviceString2[USB_DESCRIPTOR_LENGTH_STRING2] = {sizeof(g_UsbDeviceString2), + USB_DESCRIPTOR_TYPE_STRING, + 'M', + 0, + 'C', + 0, + 'U', + 0, + ' ', + 0, + 'V', + 0, + 'I', + 0, + 'R', + 0, + 'T', + 0, + 'U', + 0, + 'A', + 0, + 'L', + 0, + ' ', + 0, + 'C', + 0, + 'O', + 0, + 'M', + 0, + ' ', + 0, + 'D', + 0, + 'E', + 0, + 'M', + 0, + 'O', + 0}; + +uint8_t *g_UsbDeviceStringDescriptorArray[USB_DEVICE_STRING_COUNT] = {g_UsbDeviceString0, g_UsbDeviceString1, + g_UsbDeviceString2}; + +/* Define string descriptor size */ +uint32_t g_UsbDeviceStringDescriptorLength[USB_DEVICE_STRING_COUNT] = { + sizeof(g_UsbDeviceString0), sizeof(g_UsbDeviceString1), sizeof(g_UsbDeviceString2)}; +usb_language_t g_UsbDeviceLanguage[USB_DEVICE_LANGUAGE_COUNT] = {{ + g_UsbDeviceStringDescriptorArray, g_UsbDeviceStringDescriptorLength, (uint16_t)0x0409, +}}; + +usb_language_list_t g_UsbDeviceLanguageList = { + g_UsbDeviceString0, sizeof(g_UsbDeviceString0), g_UsbDeviceLanguage, USB_DEVICE_LANGUAGE_COUNT, +}; + +/******************************************************************************* +* Code +******************************************************************************/ +/*! + * @brief Get the descritpor. + * + * The function is used to get the descritpor, including the device descritpor, configuration descriptor, and string + * descriptor, etc. + * + * @param handle The device handle. + * @param setup The setup packet buffer address. + * @param length It is an OUT parameter, return the data length need to be sent to host. + * @param buffer It is an OUT parameter, return the data buffer address. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetDescriptor(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer) +{ + uint8_t descriptorType = (uint8_t)((setup->wValue & 0xFF00U) >> 8U); + uint8_t descriptorIndex = (uint8_t)((setup->wValue & 0x00FFU)); + usb_status_t ret = kStatus_USB_Success; + if (USB_REQUEST_STANDARD_GET_DESCRIPTOR != setup->bRequest) + { + return kStatus_USB_InvalidRequest; + } + switch (descriptorType) + { + case USB_DESCRIPTOR_TYPE_STRING: + { + if (descriptorIndex == 0) + { + *buffer = (uint8_t *)g_UsbDeviceLanguageList.languageString; + *length = g_UsbDeviceLanguageList.stringLength; + } + else + { + uint8_t langId = 0; + uint8_t langIndex = USB_DEVICE_STRING_COUNT; + + for (; langId < USB_DEVICE_LANGUAGE_COUNT; langId++) + { + if (setup->wIndex == g_UsbDeviceLanguageList.languageList[langId].languageId) + { + if (descriptorIndex < USB_DEVICE_STRING_COUNT) + { + langIndex = descriptorIndex; + } + break; + } + } + + if (USB_DEVICE_STRING_COUNT == langIndex) + { + langId = 0; + } + *buffer = (uint8_t *)g_UsbDeviceLanguageList.languageList[langId].string[langIndex]; + *length = g_UsbDeviceLanguageList.languageList[langId].length[langIndex]; + } + } + break; + case USB_DESCRIPTOR_TYPE_DEVICE: + { + *buffer = g_UsbDeviceDescriptor; + *length = USB_DESCRIPTOR_LENGTH_DEVICE; + } + break; + case USB_DESCRIPTOR_TYPE_CONFIGURE: + { + *buffer = g_UsbDeviceConfigurationDescriptor; + *length = USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL; + } + break; + default: + ret = kStatus_USB_InvalidRequest; + break; + } /* End Switch */ + return ret; +} + +/*! + * @brief Set the device configuration. + * + * The function is used to set the device configuration. + * + * @param handle The device handle. + * @param configure The configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceSetConfigure(usb_device_handle handle, uint8_t configure) +{ + if (!configure) + { + return kStatus_USB_Error; + } + g_currentConfigure = configure; + return USB_DeviceCallback(handle, kUSB_DeviceEventSetConfiguration, &configure); +} + +/*! + * @brief Get the device configuration. + * + * The function is used to get the device configuration. + * + * @param handle The device handle. + * @param configure It is an OUT parameter, save the current configuration value. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetConfigure(usb_device_handle handle, uint8_t *configure) +{ + *configure = g_currentConfigure; + return kStatus_USB_Success; +} + +/*! + * @brief Set an interface alternate setting. + * + * The function is used to set an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting The new alternate setting value. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceSetInterface(usb_device_handle handle, uint8_t interface, uint8_t alternateSetting) +{ + g_interface[interface] = alternateSetting; + return USB_DeviceCallback(handle, kUSB_DeviceEventSetInterface, &interface); +} + +/*! + * @brief Get an interface alternate setting. + * + * The function is used to get an interface alternate setting. + * + * @param handle The device handle. + * @param interface The interface index. + * @param alternateSetting It is an OUT parameter, save the new alternate setting value of the interface. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetInterface(usb_device_handle handle, uint8_t interface, uint8_t *alternateSetting) +{ + *alternateSetting = g_interface[interface]; + return kStatus_USB_Success; +} + +/*! + * @brief USB device set speed function. + * + * This function sets the speed of the USB device. + * + * Due to the difference of HS and FS descriptors, the device descriptors and configurations need to be updated to match + * current speed. + * As the default, the device descriptors and configurations are configured by using FS parameters for both EHCI and + * KHCI. + * When the EHCI is enabled, the application needs to call this fucntion to update device by using current speed. + * The updated information includes endpoint max packet size, endpoint interval, etc. + * + * @param handle The USB device handle. + * @param speed Speed type. USB_SPEED_HIGH/USB_SPEED_FULL/USB_SPEED_LOW. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed) +{ + usb_descriptor_union_t *ptr1; + usb_descriptor_union_t *ptr2; + + ptr1 = (usb_descriptor_union_t *)(&g_UsbDeviceConfigurationDescriptor[0]); + ptr2 = (usb_descriptor_union_t *)(&g_UsbDeviceConfigurationDescriptor[USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL - 1]); + + while (ptr1 < ptr2) + { + if (ptr1->common.bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT) + { + if (USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT == (ptr1->endpoint.bEndpointAddress & 0x0FU)) + { + if (USB_SPEED_HIGH == speed) + { + ptr1->endpoint.bInterval = HS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + else + { + ptr1->endpoint.bInterval = FS_CDC_VCOM_INTERRUPT_IN_INTERVAL; + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE, + ptr1->endpoint.wMaxPacketSize); + } + } + else if (USB_CDC_VCOM_BULK_IN_ENDPOINT == (ptr1->endpoint.bEndpointAddress & 0x0FU)) + { + if (USB_SPEED_HIGH == speed) + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_IN_PACKET_SIZE, ptr1->endpoint.wMaxPacketSize); + } + else + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_IN_PACKET_SIZE, ptr1->endpoint.wMaxPacketSize); + } + } + else if (USB_CDC_VCOM_BULK_OUT_ENDPOINT == (ptr1->endpoint.bEndpointAddress & 0x0FU)) + { + if (USB_SPEED_HIGH == speed) + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(HS_CDC_VCOM_BULK_OUT_PACKET_SIZE, ptr1->endpoint.wMaxPacketSize); + } + else + { + USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(FS_CDC_VCOM_BULK_OUT_PACKET_SIZE, ptr1->endpoint.wMaxPacketSize); + } + } + else + { + } + } + ptr1 = (usb_descriptor_union_t *)((uint8_t *)ptr1 + ptr1->common.bLength); + } + return kStatus_USB_Success; +} diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.h new file mode 100644 index 00000000..6a909177 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_descriptor.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#ifndef _USB_DEVICE_DESCRIPTOR_H_ +#define _USB_DEVICE_DESCRIPTOR_H_ 1 + +/******************************************************************************* +* Definitions +******************************************************************************/ +#define USB_DEVICE_SPECIFIC_BCD_VERSION (0x0200) +#define USB_DEVICE_DEMO_BCD_VERSION (0x0101U) + +/* Communication Class Codes */ +#define CDC_COMM_CLASS (0x02) +/* Data Class Codes */ +#define CDC_DATA_CLASS (0x0A) + +/* Communication Class SubClass Codes */ +#define USB_CDC_DIRECT_LINE_CONTROL_MODEL (0x01) +#define USB_CDC_ABSTRACT_CONTROL_MODEL (0x02) +#define USB_CDC_TELEPHONE_CONTROL_MODEL (0x03) +#define USB_CDC_MULTI_CHANNEL_CONTROL_MODEL (0x04) +#define USB_CDC_CAPI_CONTROL_MOPDEL (0x05) +#define USB_CDC_ETHERNET_NETWORKING_CONTROL_MODEL (0x06) +#define USB_CDC_ATM_NETWORKING_CONTROL_MODEL (0x07) +#define USB_CDC_WIRELESS_HANDSET_CONTROL_MODEL (0x08) +#define USB_CDC_DEVICE_MANAGEMENT (0x09) +#define USB_CDC_MOBILE_DIRECT_LINE_MODEL (0x0A) +#define USB_CDC_OBEX (0x0B) +#define USB_CDC_ETHERNET_EMULATION_MODEL (0x0C) + +/* Communication Class Protocol Codes */ +#define USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL (0x00) /*also for Data Class Protocol Code */ +#define USB_CDC_AT_250_PROTOCOL (0x01) +#define USB_CDC_AT_PCCA_101_PROTOCOL (0x02) +#define USB_CDC_AT_PCCA_101_ANNEX_O (0x03) +#define USB_CDC_AT_GSM_7_07 (0x04) +#define USB_CDC_AT_3GPP_27_007 (0x05) +#define USB_CDC_AT_TIA_CDMA (0x06) +#define USB_CDC_ETHERNET_EMULATION_PROTOCOL (0x07) +#define USB_CDC_EXTERNAL_PROTOCOL (0xFE) +#define USB_CDC_VENDOR_SPECIFIC (0xFF) /*also for Data Class Protocol Code */ + +/* Data Class Protocol Codes */ +#define USB_CDC_PYHSICAL_INTERFACE_PROTOCOL (0x30) +#define USB_CDC_HDLC_PROTOCOL (0x31) +#define USB_CDC_TRANSPARENT_PROTOCOL (0x32) +#define USB_CDC_MANAGEMENT_PROTOCOL (0x50) +#define USB_CDC_DATA_LINK_Q931_PROTOCOL (0x51) +#define USB_CDC_DATA_LINK_Q921_PROTOCOL (0x52) +#define USB_CDC_DATA_COMPRESSION_V42BIS (0x90) +#define USB_CDC_EURO_ISDN_PROTOCOL (0x91) +#define USB_CDC_RATE_ADAPTION_ISDN_V24 (0x92) +#define USB_CDC_CAPI_COMMANDS (0x93) +#define USB_CDC_HOST_BASED_DRIVER (0xFD) +#define USB_CDC_UNIT_FUNCTIONAL (0xFE) + +/* Descriptor SubType in Communications Class Functional Descriptors */ +#define USB_CDC_HEADER_FUNC_DESC (0x00) +#define USB_CDC_CALL_MANAGEMENT_FUNC_DESC (0x01) +#define USB_CDC_ABSTRACT_CONTROL_FUNC_DESC (0x02) +#define USB_CDC_DIRECT_LINE_FUNC_DESC (0x03) +#define USB_CDC_TELEPHONE_RINGER_FUNC_DESC (0x04) +#define USB_CDC_TELEPHONE_REPORT_FUNC_DESC (0x05) +#define USB_CDC_UNION_FUNC_DESC (0x06) +#define USB_CDC_COUNTRY_SELECT_FUNC_DESC (0x07) +#define USB_CDC_TELEPHONE_MODES_FUNC_DESC (0x08) +#define USB_CDC_TERMINAL_FUNC_DESC (0x09) +#define USB_CDC_NETWORK_CHANNEL_FUNC_DESC (0x0A) +#define USB_CDC_PROTOCOL_UNIT_FUNC_DESC (0x0B) +#define USB_CDC_EXTENSION_UNIT_FUNC_DESC (0x0C) +#define USB_CDC_MULTI_CHANNEL_FUNC_DESC (0x0D) +#define USB_CDC_CAPI_CONTROL_FUNC_DESC (0x0E) +#define USB_CDC_ETHERNET_NETWORKING_FUNC_DESC (0x0F) +#define USB_CDC_ATM_NETWORKING_FUNC_DESC (0x10) +#define USB_CDC_WIRELESS_CONTROL_FUNC_DESC (0x11) +#define USB_CDC_MOBILE_DIRECT_LINE_FUNC_DESC (0x12) +#define USB_CDC_MDLM_DETAIL_FUNC_DESC (0x13) +#define USB_CDC_DEVICE_MANAGEMENT_FUNC_DESC (0x14) +#define USB_CDC_OBEX_FUNC_DESC (0x15) +#define USB_CDC_COMMAND_SET_FUNC_DESC (0x16) +#define USB_CDC_COMMAND_SET_DETAIL_FUNC_DESC (0x17) +#define USB_CDC_TELEPHONE_CONTROL_FUNC_DESC (0x18) +#define USB_CDC_OBEX_SERVICE_ID_FUNC_DESC (0x19) + +/* usb descritpor length */ +#define USB_DESCRIPTOR_LENGTH_CONFIGURATION_ALL (67) +#define USB_DESCRIPTOR_LENGTH_CDC_HEADER_FUNC (5) +#define USB_DESCRIPTOR_LENGTH_CDC_CALL_MANAG (5) +#define USB_DESCRIPTOR_LENGTH_CDC_ABSTRACT (4) +#define USB_DESCRIPTOR_LENGTH_CDC_UNION_FUNC (5) + +#define USB_DEVICE_CONFIGURATION_COUNT (1) +#define USB_DEVICE_STRING_COUNT (3) +#define USB_DEVICE_LANGUAGE_COUNT (1) + +#define USB_CDC_VCOM_CONFIGURE_INDEX (1) + +#define USB_CDC_VCOM_ENDPOINT_CIC_COUNT (1) +#define USB_CDC_VCOM_ENDPOINT_DIC_COUNT (2) +#define USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT (1) +#define USB_CDC_VCOM_BULK_IN_ENDPOINT (2) +#define USB_CDC_VCOM_BULK_OUT_ENDPOINT (3) +#define USB_CDC_VCOM_INTERFACE_COUNT (2) +#define USB_CDC_VCOM_COMM_INTERFACE_INDEX (0) +#define USB_CDC_VCOM_DATA_INTERFACE_INDEX (1) + +#define HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16) +#define FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE (16) +#define HS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x07) /* 2^(7-1) = 8ms */ +#define FS_CDC_VCOM_INTERRUPT_IN_INTERVAL (0x08) +#define HS_CDC_VCOM_BULK_IN_PACKET_SIZE (512) +#define FS_CDC_VCOM_BULK_IN_PACKET_SIZE (64) +#define HS_CDC_VCOM_BULK_OUT_PACKET_SIZE (512) +#define FS_CDC_VCOM_BULK_OUT_PACKET_SIZE (64) + +#define USB_DESCRIPTOR_LENGTH_STRING0 (4) +#define USB_DESCRIPTOR_LENGTH_STRING1 (38) +#define USB_DESCRIPTOR_LENGTH_STRING2 (42) + +#define USB_DESCRIPTOR_TYPE_CDC_CS_INTERFACE (0x24) +#define USB_DESCRIPTOR_TYPE_CDC_CS_ENDPOINT (0x25) + +#define USB_DEVICE_CLASS (0x02) +#define USB_DEVICE_SUBCLASS (0x00) +#define USB_DEVICE_PROTOCOL (0x00) + +#define USB_DEVICE_MAX_POWER (0x32) + +#define USB_CDC_VCOM_CIC_CLASS (CDC_COMM_CLASS) +#define USB_CDC_VCOM_CIC_SUBCLASS (USB_CDC_ABSTRACT_CONTROL_MODEL) +#define USB_CDC_VCOM_CIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL) + +#define USB_CDC_VCOM_DIC_CLASS (CDC_DATA_CLASS) +#define USB_CDC_VCOM_DIC_SUBCLASS (0x00) +#define USB_CDC_VCOM_DIC_PROTOCOL (USB_CDC_NO_CLASS_SPECIFIC_PROTOCOL) + +/******************************************************************************* +* API +******************************************************************************/ +/*! + * @brief USB device callback function. + * + * This function handles the usb device specific requests. + * + * @param handle The USB device handle. + * @param event The USB device event type. + * @param param The parameter of the device specific request. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param); + +/*! + * @brief USB device set speed function. + * + * This function sets the speed of the USB device. + * + * Due to the difference of HS and FS descriptors, the device descriptors and configurations need to be updated to match + * current speed. + * As the default, the device descriptors and configurations are configured by using FS parameters for both EHCI and + * KHCI. + * When the EHCI is enabled, the application needs to call this fucntion to update device by using current speed. + * The updated information includes endpoint max packet size, endpoint interval, etc. + * + * @param handle The USB device handle. + * @param speed Speed type. USB_SPEED_HIGH/USB_SPEED_FULL/USB_SPEED_LOW. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceSetSpeed(usb_device_handle handle, uint8_t speed); + +#endif /* _USB_DEVICE_DESCRIPTOR_H_ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.c new file mode 100644 index 00000000..601b80f1 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.c @@ -0,0 +1,1568 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" + +#include "MK22F51212.h" + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + +#include "usb_khci.h" +#include "usb_device_dci.h" + +#include "usb_device_khci.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM > 0U) + +/* USB_STACK_USE_DEDICATED_RAM */ +#if defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + +#if (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL) +#if (FSL_FEATURE_USB_KHCI_USB_RAM > 512U) +#else +#error The dedicated RAM length is not more than 512 Bytes, the SOC does not support this case. +#endif +#endif /* USB_STACK_USE_DEDICATED_RAM */ + +#else +#error The SOC does not suppoort dedicated RAM case. +#endif /* USB_STACK_USE_DEDICATED_RAM */ + +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static usb_status_t USB_DeviceKhciEndpointTransfer( + usb_device_khci_state_struct_t *khciState, uint8_t endpoint, uint8_t direction, uint8_t *buffer, uint32_t length); +static void USB_DeviceKhciPrimeNextSetup(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciSetDefaultState(usb_device_khci_state_struct_t *khciState); +static usb_status_t USB_DeviceKhciEndpointInit(usb_device_khci_state_struct_t *khciState, + usb_device_endpoint_init_struct_t *epInit); +static usb_status_t USB_DeviceKhciEndpointDeinit(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static usb_status_t USB_DeviceKhciEndpointStall(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static usb_status_t USB_DeviceKhciEndpointUnstall(usb_device_khci_state_struct_t *khciState, uint8_t ep); +static void USB_DeviceKhciInterruptTokenDone(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciInterruptReset(usb_device_khci_state_struct_t *khciState); +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +static void USB_DeviceKhciInterruptSleep(usb_device_khci_state_struct_t *khciState); +static void USB_DeviceKhciInterruptResume(usb_device_khci_state_struct_t *khciState); +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ +static void USB_DeviceKhciInterruptStall(usb_device_khci_state_struct_t *khciState); +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) +static void USB_DeviceKhciInterruptError(usb_device_khci_state_struct_t *khciState); +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + +extern usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* Apply for BDT buffer, 512-byte alignment */ +USB_BDT USB_RAM_ADDRESS_ALIGNMENT(512) static uint8_t s_UsbDeviceKhciBdtBuffer[USB_DEVICE_CONFIG_KHCI][512U]; + +/* Apply for khci device state structure */ +USB_GLOBAL static usb_device_khci_state_struct_t s_UsbDeviceKhciState[USB_DEVICE_CONFIG_KHCI]; + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) +/* Apply for device dcd state structure */ +USB_GLOBAL static usb_device_dcd_state_struct_t s_UsbDeviceDcdState[USB_DEVICE_CONFIG_KHCI]; +#endif + +/* Apply for KHCI DMA aligned buffer when marco USB_DEVICE_CONFIG_KHCI_DMA_ALIGN enabled */ +USB_GLOBAL static uint32_t s_UsbDeviceKhciDmaAlignBuffer + [USB_DEVICE_CONFIG_KHCI][((USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH - 1U) >> 2U) + 1U]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Write the BDT to start a transfer. + * + * The function is used to start a transfer by writing the BDT. + * + * @param khciState Pointer of the device KHCI state structure. + * @param endpoint Endpoint number. + * @param direction The direction of the endpoint, 0U - USB_OUT, 1U - USB_IN. + * @param buffer The memory address to save the received data, or the memory address to hold the data need to + * be sent. + * @param length The length of the data. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointTransfer( + usb_device_khci_state_struct_t *khciState, uint8_t endpoint, uint8_t direction, uint8_t *buffer, uint32_t length) +{ + uint32_t index = ((uint32_t)endpoint << 1U) | (uint32_t)direction; + USB_OSA_SR_ALLOC(); + + /* Enter critical */ + USB_OSA_ENTER_CRITICAL(); + + /* Flag the endpoint is busy. */ + khciState->endpointState[index].stateUnion.stateBitField.transferring = 1U; + + /* Add the data buffer address to the BDT. */ + USB_KHCI_BDT_SET_ADDRESS((uint32_t)khciState->bdt, endpoint, direction, + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, (uint32_t)buffer); + + /* Change the BDT control field to start the transfer. */ + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, + USB_LONG_TO_LITTLE_ENDIAN(USB_KHCI_BDT_BC(length) | USB_KHCI_BDT_OWN | USB_KHCI_BDT_DTS | + USB_KHCI_BDT_DATA01(khciState->endpointState[index].stateUnion.stateBitField.data0))); + + /* Exit critical */ + USB_OSA_EXIT_CRITICAL(); + + /* Clear the token busy state */ + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + return kStatus_USB_Success; +} + +/*! + * @brief Prime a next setup transfer. + * + * The function is used to prime a buffer in control out pipe to wait for receiving the host's setup packet. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciPrimeNextSetup(usb_device_khci_state_struct_t *khciState) +{ +/* Update the endpoint state */ +/* Save the buffer address used to receive the setup packet. */ +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + /* In case of lowpower mode enabled, it requires to put the setup packet buffer(16 bytes) into the USB RAM so + * that the setup packet would wake up the USB. + */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer = + (uint8_t *)(khciState->bdt + 0x200U - 0x10U) + + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.bdtOdd * + USB_SETUP_PACKET_SIZE; +#else + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer = + (uint8_t *)&khciState->setupPacketBuffer[0] + + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.bdtOdd * + USB_SETUP_PACKET_SIZE; +#endif + /* Clear the transferred length. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferDone = 0U; + /* Save the data length expected to get from a host. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferLength = USB_SETUP_PACKET_SIZE; + /* Save the data buffer DMA align flag. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.dmaAlign = 1U; + /* Set the DATA0/1 to DATA0. */ + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.data0 = 0U; + + USB_DeviceKhciEndpointTransfer(khciState, USB_CONTROL_ENDPOINT, USB_OUT, + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].transferBuffer, + USB_SETUP_PACKET_SIZE); +} + +/*! + * @brief Set device controller state to default state. + * + * The function is used to set device controller state to default state. + * The function will be called when USB_DeviceKhciInit called or the control type kUSB_DeviceControlGetEndpointStatus + * received in USB_DeviceKhciControl. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciSetDefaultState(usb_device_khci_state_struct_t *khciState) +{ + uint8_t interruptFlag; + + /* Clear the error state register */ + khciState->registerBase->ERRSTAT = 0xFFU; + + /* Setting this bit to 1U resets all the BDT ODD ping/pong fields to 0U, which then specifies the EVEN BDT bank. */ + khciState->registerBase->CTL |= USB_CTL_ODDRST_MASK; + + /* Clear the device address */ + khciState->registerBase->ADDR = 0U; + + /* Clear the endpoint state and disable the endpoint */ + for (uint8_t count = 0U; count < USB_DEVICE_CONFIG_ENDPOINTS; count++) + { + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_OUT, 0U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_OUT, 1U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_IN, 0U, 0U); + USB_KHCI_BDT_SET_CONTROL((uint32_t)khciState->bdt, count, USB_IN, 1U, 0U); + + khciState->endpointState[((uint32_t)count << 1U) | USB_OUT].stateUnion.state = 0U; + khciState->endpointState[((uint32_t)count << 1U) | USB_IN].stateUnion.state = 0U; + khciState->registerBase->ENDPOINT[count].ENDPT = 0x00U; + } + khciState->isDmaAlignBufferInusing = 0U; + + /* Clear the BDT odd reset flag */ + khciState->registerBase->CTL &= ~USB_CTL_ODDRST_MASK; + + /* Enable all error */ + khciState->registerBase->ERREN = 0xFFU; + + /* Enable reset, sof, token, stall interrupt */ + interruptFlag = kUSB_KhciInterruptReset +#if 0U + | kUSB_KhciInterruptSofToken +#endif + | kUSB_KhciInterruptTokenDone | kUSB_KhciInterruptStall; + +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + /* Enable suspend interruprt */ + interruptFlag |= kUSB_KhciInterruptSleep; +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) + /* Enable error interruprt */ + interruptFlag |= kUSB_KhciInterruptError; +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + /* Write the interrupt enable register */ + khciState->registerBase->INTEN = interruptFlag; + + /* Clear reset flag */ + khciState->isResetting = 0U; + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; +} + +/*! + * @brief Initialize a specified endpoint. + * + * The function is used to initialize a specified endpoint. + * + * @param khciState Pointer of the device KHCI state structure. + * @param epInit The endpoint initialization structure pointer. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointInit(usb_device_khci_state_struct_t *khciState, + usb_device_endpoint_init_struct_t *epInit) +{ + uint16_t maxPacketSize = epInit->maxPacketSize; + uint8_t endpoint = (epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK); + uint8_t direction = (epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Make the endpoint max packet size align with USB Specification 2.0. */ + if (USB_ENDPOINT_ISOCHRONOUS == epInit->transferType) + { + if (maxPacketSize > USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE) + { + maxPacketSize = USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE; + } + } + else + { + if (maxPacketSize > USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE) + { + maxPacketSize = USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE; + } + /* Enable an endpoint to perform handshaking during a transaction to this endpoint. */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT |= USB_ENDPT_EPHSHK_MASK; + } + /* Set the endpoint idle */ + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + /* Save the max packet size of the endpoint */ + khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize = maxPacketSize; + /* Set the data toggle to DATA0 */ + khciState->endpointState[index].stateUnion.stateBitField.data0 = 0U; + /* Clear the endpoint stalled state */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 0U; + /* Set the ZLT field */ + khciState->endpointState[index].stateUnion.stateBitField.zlt = epInit->zlt; + /* Enable the endpoint. */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT |= + (USB_IN == direction) ? USB_ENDPT_EPTXEN_MASK : USB_ENDPT_EPRXEN_MASK; + + /* Prime a transfer to receive next setup packet when the endpoint is control out endpoint. */ + if ((USB_CONTROL_ENDPOINT == endpoint) && (USB_OUT == direction)) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize a specified endpoint. + * + * The function is used to de-initialize a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be disabled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointDeinit(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint8_t endpoint = (ep & USB_ENDPOINT_NUMBER_MASK); + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Cancel the transfer of the endpoint */ + USB_DeviceKhciCancel(khciState, ep); + + /* Disable the endpoint */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT = 0x00U; + /* Clear the max packet size */ + khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize = 0U; + + return kStatus_USB_Success; +} + +/*! + * @brief Stall a specified endpoint. + * + * The function is used to stall a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be stalled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointStall(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint8_t endpoint = ep & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Cancel the transfer of the endpoint */ + USB_DeviceKhciCancel(khciState, ep); + + /* Set endpoint stall flag. */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 1U; + + /* Set endpoint stall in BDT. And then if the host send a IN/OUT tanscation, the device will response a STALL state. + */ + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, khciState->endpointState[index].stateUnion.stateBitField.bdtOdd, + USB_LONG_TO_LITTLE_ENDIAN( + (uint32_t)(USB_KHCI_BDT_BC(khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) | + USB_KHCI_BDT_DTS | USB_KHCI_BDT_STALL | USB_KHCI_BDT_OWN))); + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Un-stall a specified endpoint. + * + * The function is used to un-stall a specified endpoint. + * Current transfer of the endpoint will be canceled and the specified endpoint will be un-stalled. + * + * @param khciState Pointer of the device KHCI state structure. + * @param ep The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceKhciEndpointUnstall(usb_device_khci_state_struct_t *khciState, uint8_t ep) +{ + uint32_t control; + uint8_t endpoint = ep & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = + (ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + uint8_t index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + /* Clear the endpoint stall state */ + khciState->endpointState[index].stateUnion.stateBitField.stalled = 0U; + /* Reset the endpoint data toggle to DATA0 */ + khciState->endpointState[index].stateUnion.stateBitField.data0 = 0U; + + /* Clear stall state in BDT */ + for (uint8_t i = 0U; i < 2U; i++) + { + control = USB_KHCI_BDT_GET_CONTROL((uint32_t)khciState->bdt, endpoint, direction, i); + if (control & USB_KHCI_BDT_STALL) + { + USB_KHCI_BDT_SET_CONTROL( + (uint32_t)khciState->bdt, endpoint, direction, i, + USB_LONG_TO_LITTLE_ENDIAN( + (uint32_t)(USB_KHCI_BDT_BC(khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) | + USB_KHCI_BDT_DTS | USB_KHCI_BDT_DATA01(0U)))); + } + } + + /* Clear stall state in endpoint control register */ + khciState->registerBase->ENDPOINT[endpoint].ENDPT &= ~USB_ENDPT_EPSTALL_MASK; + + /* Prime a transfer to receive next setup packet when the endpoint is a control out endpoint. */ + if ((USB_CONTROL_ENDPOINT == endpoint) && (USB_OUT == direction)) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Handle the token done interrupt. + * + * The function is used to handle the token done interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptTokenDone(usb_device_khci_state_struct_t *khciState) +{ + uint32_t control; + uint32_t length; + uint32_t remainingLength; + uint8_t *bdtBuffer; + usb_device_callback_message_struct_t message; + uint8_t endpoint; + uint8_t direction; + uint8_t bdtOdd; + uint8_t isSetup; + uint8_t index; + uint8_t stateRegister = khciState->registerBase->STAT; + + /* Get the endpoint number to identify which one triggers the token done interrupt. */ + endpoint = (stateRegister & USB_STAT_ENDP_MASK) >> USB_STAT_ENDP_SHIFT; + + /* Get the direction of the endpoint number. */ + direction = (stateRegister & USB_STAT_TX_MASK) >> USB_STAT_TX_SHIFT; + + /* Get the finished BDT ODD. */ + bdtOdd = (stateRegister & USB_STAT_ODD_MASK) >> USB_STAT_ODD_SHIFT; + + /* Clear token done interrupt flag. */ + khciState->registerBase->ISTAT = kUSB_KhciInterruptTokenDone; + + /* Get the Control field of the BDT element according to the endpoint number, the direction and finished BDT ODD. */ + control = USB_KHCI_BDT_GET_CONTROL((uint32_t)khciState->bdt, endpoint, direction, bdtOdd); + + /* Get the buffer field of the BDT element according to the endpoint number, the direction and finished BDT ODD. */ + bdtBuffer = (uint8_t *)USB_KHCI_BDT_GET_ADDRESS((uint32_t)khciState->bdt, endpoint, direction, bdtOdd); + + /* Get the transferred length. */ + length = ((USB_LONG_FROM_LITTLE_ENDIAN(control)) >> 16U) & 0x3FFU; + + /* Get the transferred length. */ + isSetup = (USB_KHCI_BDT_DEVICE_SETUP_TOKEN == ((uint8_t)(((USB_LONG_FROM_LITTLE_ENDIAN(control)) >> 2U) & 0x0FU))) ? + 1U : + 0U; + + index = ((uint8_t)((uint32_t)endpoint << 1U)) | (uint8_t)direction; + + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + return; + } + + if (isSetup) + { + khciState->setupBufferIndex = bdtOdd; + } + + /* USB_IN, Send completed */ + if (direction == USB_IN) + { + /* The transferred length */ + khciState->endpointState[index].transferDone += length; + + /* Remaining length */ + remainingLength = khciState->endpointState[index].transferLength - khciState->endpointState[index].transferDone; + + /* Change the data toggle flag */ + khciState->endpointState[index].stateUnion.stateBitField.data0 ^= 1U; + /* Change the BDT odd toggle flag */ + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd ^= 1U; + + /* Whether the transfer is completed or not. */ + /* + * The transfer is completed when one of the following conditions meet: + * 1. The remaining length is zero. + * 2. The length of current transcation is less than the max packet size of the current pipe. + */ + if ((0U == remainingLength) || + (khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize > length)) + { + message.length = khciState->endpointState[index].transferDone; + message.buffer = khciState->endpointState[index].transferBuffer; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + + /* + * Whether need to send ZLT when the pipe is control in pipe and the transferred length of current + * transaction equals to max packet size. + */ + if ((length) && (!(length % khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize))) + { + if (USB_CONTROL_ENDPOINT == endpoint) + { + usb_setup_struct_t *setup_packet = + (usb_setup_struct_t + *)(&khciState->setupPacketBuffer[(USB_SETUP_PACKET_SIZE * khciState->setupBufferIndex)]); + /* + * Send the ZLT and terminate the token done interrupt service when the tranferred length in data + * phase + * is less than the host request. + */ + if (USB_SHORT_FROM_LITTLE_ENDIAN(setup_packet->wLength) > + khciState->endpointState[index].transferLength) + { + (void)USB_DeviceKhciEndpointTransfer(khciState, endpoint, USB_IN, (uint8_t *)NULL, 0U); + return; + } + } + else if (khciState->endpointState[index].stateUnion.stateBitField.zlt) + { + (void)USB_DeviceKhciEndpointTransfer(khciState, endpoint, USB_IN, (uint8_t *)NULL, 0U); + return; + } + else + { + } + } + } + else + { + /* Send remaining data and terminate the token done interrupt service. */ + (void)USB_DeviceKhciSend(khciState, endpoint | (USB_IN << 0x07U), + khciState->endpointState[index].transferBuffer, remainingLength); + return; + } + } + else + { + if ((USB_CONTROL_ENDPOINT == endpoint) && (0U == length)) + { + message.length = 0U; + message.buffer = (uint8_t *)NULL; + } + else + { + if (0U == khciState->endpointState[index].stateUnion.stateBitField.dmaAlign) + { + uint8_t *buffer = (uint8_t *)USB_LONG_FROM_LITTLE_ENDIAN( + USB_KHCI_BDT_GET_ADDRESS((uint32_t)khciState->bdt, endpoint, USB_OUT, + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd)); + uint8_t *transferBuffer = + khciState->endpointState[index].transferBuffer + khciState->endpointState[index].transferDone; + if (buffer != transferBuffer) + { + for (uint32_t i = 0U; i < length; i++) + { + transferBuffer[i] = buffer[i]; + } + } + khciState->isDmaAlignBufferInusing = 0U; + } + /* The transferred length */ + khciState->endpointState[index].transferDone += length; + /* Remaining length */ + remainingLength = + khciState->endpointState[index].transferLength - khciState->endpointState[index].transferDone; + + if ((USB_CONTROL_ENDPOINT == endpoint) && isSetup) + { + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.data0 = 1U; + khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_IN].stateUnion.stateBitField.data0 = 1U; + } + else + { + khciState->endpointState[index].stateUnion.stateBitField.data0 ^= 1U; + } + khciState->endpointState[index].stateUnion.stateBitField.bdtOdd ^= 1U; + if ((!khciState->endpointState[index].transferLength) || (!remainingLength) || + (khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize > length)) + { + message.length = khciState->endpointState[index].transferDone; + if (isSetup) + { + message.buffer = bdtBuffer; + } + else + { + message.buffer = khciState->endpointState[index].transferBuffer; + } + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + } + else + { + /* Receive remaining data and terminate the token done interrupt service. */ + USB_DeviceKhciRecv(khciState, (endpoint) | (USB_OUT << 0x07U), + khciState->endpointState[index].transferBuffer, remainingLength); + return; + } + } + } + + message.isSetup = isSetup; + message.code = (endpoint) | (uint8_t)(((uint32_t)direction << 0x07U)); + + /* Notify the up layer the KHCI status changed. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); + + khciState->registerBase->CTL &= ~USB_CTL_TXSUSPENDTOKENBUSY_MASK; +} + +/*! + * @brief Handle the USB bus reset interrupt. + * + * The function is used to handle the USB bus reset interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptReset(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Set KHCI reset flag */ + khciState->isResetting = 1U; + + /* Clear the reset interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptReset); +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + /* Clear the suspend interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSleep); + khciState->registerBase->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; +#endif + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyBusReset; + message.length = 0U; + message.isSetup = 0U; + /* Notify up layer the USB bus reset signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/* The USB suspend and resume signals need to be detected and handled when the low power or remote wakeup function + * enabled. */ +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + +/*! + * @brief Handle the suspend interrupt. + * + * The function is used to handle the suspend interrupt when the suspend signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptSleep(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Enable the resume interrupt */ + khciState->registerBase->INTEN |= kUSB_KhciInterruptResume; + khciState->registerBase->USBTRC0 |= USB_USBTRC0_USBRESMEN_MASK; + khciState->registerBase->USBCTRL |= USB_USBCTRL_SUSP_MASK; + /* Disable the suspend interrupt */ + khciState->registerBase->INTEN &= ~((uint32_t)kUSB_KhciInterruptSleep); + + /* Clear the suspend interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSleep); + /* Clear the resume interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifySuspend; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB suspend signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/*! + * @brief Handle the resume interrupt. + * + * The function is used to handle the resume interrupt when the resume signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptResume(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + khciState->registerBase->USBCTRL &= ~USB_USBCTRL_SUSP_MASK; + /* Enable the suspend interrupt */ + khciState->registerBase->INTEN |= kUSB_KhciInterruptSleep; + /* Disable the resume interrupt */ + khciState->registerBase->INTEN &= ~((uint32_t)kUSB_KhciInterruptResume); + khciState->registerBase->USBTRC0 &= ~USB_USBTRC0_USBRESMEN_MASK; + + /* Clear the resume interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); + /* Clear the suspend interrupt */ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSleep); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyResume; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB resume signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) +/*! + * @brief Handle the VBUS rising interrupt. + * + * The function is used to handle the VBUS rising interrupt when the VBUS rising signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptVbusRising(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Disable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL &= ~USB_MISCCTRL_VREDG_EN_MASK; + /* Enable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VREDG_EN_MASK; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyAttach; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB VBUS rising signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} + +/*! + * @brief Handle the VBUS falling interrupt. + * + * The function is used to handle the VBUS falling interrupt when the VBUS falling signal detected. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptVbusFalling(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + /* Disable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL &= ~USB_MISCCTRL_VFEDG_EN_MASK; + /* Enable the VBUS rising interrupt */ + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VFEDG_EN_MASK; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyDetach; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB VBUS falling signal detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE || FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED */ + +#if 0U +/*! + * @brief Handle the sof interrupt. + * + * The function is used to handle the sof interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +void USB_DeviceKhciInterruptSof(usb_device_khci_state_struct_t *khciState) +{ + khciState->registerBase->ISTAT = (kUSB_KhciInterruptSofToken); + + khciState->registerBase->ISTAT = (kUSB_KhciInterruptResume); +} +#endif + +/*! + * @brief Handle endpoint stalled interrupt. + * + * The function is used to handle endpoint stalled interrupt. + * + * @param khciState Pointer of the device KHCI state structure. + * + */ +static void USB_DeviceKhciInterruptStall(usb_device_khci_state_struct_t *khciState) +{ + /* Clear the endpoint stalled interrupt flag */ + while (khciState->registerBase->ISTAT & (kUSB_KhciInterruptStall)) + { + khciState->registerBase->ISTAT = (kUSB_KhciInterruptStall); + } + + /* Un-stall the control in and out pipe when the control in or out pipe stalled. */ + if ((khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_IN].stateUnion.stateBitField.stalled) || + (khciState->endpointState[(USB_CONTROL_ENDPOINT << 1U) | USB_OUT].stateUnion.stateBitField.stalled)) + { + USB_DeviceKhciEndpointUnstall( + khciState, (USB_CONTROL_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))); + USB_DeviceKhciEndpointUnstall( + khciState, (USB_CONTROL_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))); + } +} + +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) +static void USB_DeviceKhciInterruptError(usb_device_khci_state_struct_t *khciState) +{ + usb_device_callback_message_struct_t message; + + khciState->registerBase->ISTAT = (kUSB_KhciInterruptError); + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyError; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB error detected. */ + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); +} +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + +/*! + * @brief Initialize the USB device KHCI instance. + * + * This function initizlizes the USB device KHCI module specified by the controllerId. + * + * @param controllerId The controller id of the USB IP. Please refer to enumeration type usb_controller_index_t. + * @param handle Pointer of the device handle, used to identify the device object is belonged to. + * @param khciHandle It is out parameter, is used to return pointer of the device KHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *khciHandle) +{ + usb_device_khci_state_struct_t *khciState; + uint32_t khci_base[] = USB_BASE_ADDRS; +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) + usb_device_dcd_state_struct_t *dcdState; + uint32_t dcd_base[] = USBDCD_BASE_ADDRS; +#endif + + if (((controllerId - kUSB_ControllerKhci0) >= (uint8_t)USB_DEVICE_CONFIG_KHCI) || + ((controllerId - kUSB_ControllerKhci0) >= (sizeof(khci_base) / sizeof(uint32_t)))) + { + return kStatus_USB_ControllerNotFound; + } + khciState = &s_UsbDeviceKhciState[controllerId - kUSB_ControllerKhci0]; + + khciState->controllerId = controllerId; + + khciState->registerBase = (USB_Type *)khci_base[controllerId - kUSB_ControllerKhci0]; + + khciState->dmaAlignBuffer = (uint8_t *)&s_UsbDeviceKhciDmaAlignBuffer[controllerId - kUSB_ControllerKhci0][0]; + + /* Clear all interrupt flags. */ + khciState->registerBase->ISTAT = 0xFFU; + +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + khciState->otgStatus = 0U; +#else + /* Disable the device functionality. */ + USB_DeviceKhciControl(khciState, kUSB_DeviceControlStop, NULL); +#endif + + khciState->bdt = s_UsbDeviceKhciBdtBuffer[controllerId - kUSB_ControllerKhci0]; + + /* Set BDT buffer address */ + khciState->registerBase->BDTPAGE1 = (uint8_t)((((uint32_t)khciState->bdt) >> 8U) & 0xFFU); + khciState->registerBase->BDTPAGE2 = (uint8_t)((((uint32_t)khciState->bdt) >> 16U) & 0xFFU); + khciState->registerBase->BDTPAGE3 = (uint8_t)((((uint32_t)khciState->bdt) >> 24U) & 0xFFU); + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_VREDG_EN_MASK | USB_MISCCTRL_VFEDG_EN_MASK; +#endif + +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + khciState->registerBase->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK; + khciState->registerBase->KEEP_ALIVE_CTRL = + USB_KEEP_ALIVE_CTRL_KEEP_ALIVE_EN_MASK | USB_KEEP_ALIVE_CTRL_OWN_OVERRD_EN_MASK | + USB_KEEP_ALIVE_CTRL_WAKE_INT_EN_MASK | FSL_FEATURE_USB_KHCI_KEEP_ALIVE_MODE_CONTROL; + /* wake on out and setup transaction */ + khciState->registerBase->KEEP_ALIVE_WKCTRL = 0x1U; +#if defined(FSL_FEATURE_SOC_MCGLITE_COUNT) && (FSL_FEATURE_SOC_MCGLITE_COUNT > 0U) + MCG->MC |= MCG_MC_HIRCLPEN_MASK; +#endif + PMC->REGSC |= PMC_REGSC_BGEN_MASK | PMC_REGSC_VLPO_MASK; +#endif + /* Set KHCI device state to default value. */ + USB_DeviceKhciSetDefaultState(khciState); + + *khciHandle = khciState; + khciState->deviceHandle = (usb_device_struct_t *)handle; +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) + dcdState = &s_UsbDeviceDcdState[controllerId - kUSB_ControllerKhci0]; + + dcdState->controllerId = controllerId; + + dcdState->dcdRegisterBase = (USBDCD_Type *)dcd_base[controllerId - kUSB_ControllerKhci0]; + + dcdState->deviceHandle = (usb_device_struct_t *)handle; +#endif + + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize the USB device KHCI instance. + * + * This function de-initizlizes the USB device KHCI module. + * + * @param khciHandle Pointer of the device KHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciDeinit(usb_device_controller_handle khciHandle) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + + if (!khciHandle) + { + return kStatus_USB_InvalidHandle; + } + /* Clear all interrupt flags. */ + khciState->registerBase->ISTAT = 0xFFU; + /* Disable all interrupts. */ + khciState->registerBase->INTEN &= ~(0xFFU); + /* Clear device address. */ + khciState->registerBase->ADDR = (0U); + + /* Clear USB_CTL register */ + khciState->registerBase->CTL = 0x00U; + khciState->registerBase->USBCTRL |= USB_USBCTRL_PDE_MASK | USB_USBCTRL_SUSP_MASK; + + return kStatus_USB_Success; +} + +/*! + * @brief Send data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to hold the data need to be sent. + * @param length The data length need to be sent. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value just means if the sending request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciSend(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + uint32_t index = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) | USB_IN; + usb_status_t error = kStatus_USB_Error; + + /* Save the tansfer information */ + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + khciState->endpointState[index].transferDone = 0U; + khciState->endpointState[index].transferBuffer = buffer; + khciState->endpointState[index].transferLength = length; + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 1U; + } + + /* Data length needs to less than max packet size in each call. */ + if (length > khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) + { + length = khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize; + } + + /* Send data when the device is not resetting. */ + if (0U == khciState->isResetting) + { + error = USB_DeviceKhciEndpointTransfer(khciState, endpointAddress & USB_ENDPOINT_NUMBER_MASK, USB_IN, + (uint8_t *)((uint32_t)khciState->endpointState[index].transferBuffer + + (uint32_t)khciState->endpointState[index].transferDone), + length); + } + + /* Prime a transfer to receive next setup packet if the dat length is zero in a control in endpoint. */ + if ((0U == khciState->endpointState[index].transferDone) && (0U == length) && + (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK))) + { + USB_DeviceKhciPrimeNextSetup(khciState); + } + return error; +} + +/*! + * @brief Receive data through a specified endpoint. + * + * This function Receives data through a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param endpointAddress Endpoint index. + * @param buffer The memory address to save the received data. + * @param length The data length want to be received. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value just means if the receiving request is successful or not; the transfer done is notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for one specific endpoint. + * If there is a specific requirement to support multiple transfer requests for one specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer could begin only when the previous transfer is done (get notification through the endpoint + * callback). + */ +usb_status_t USB_DeviceKhciRecv(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + uint32_t index = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) | USB_OUT; + usb_status_t error = kStatus_USB_Error; + + if ((0U == length) && (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK))) + { + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + USB_DeviceKhciPrimeNextSetup(khciState); + } + else + { + /* Save the tansfer information */ + if (0U == khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + khciState->endpointState[index].transferDone = 0U; + khciState->endpointState[index].transferBuffer = buffer; + khciState->endpointState[index].transferLength = length; + } + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 1U; + + /* Data length needs to less than max packet size in each call. */ + if (length > khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize) + { + length = khciState->endpointState[index].stateUnion.stateBitField.maxPacketSize; + } + + buffer = (uint8_t *)((uint32_t)buffer + (uint32_t)khciState->endpointState[index].transferDone); + + if ((khciState->dmaAlignBuffer) && (0U == khciState->isDmaAlignBufferInusing) && + (USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH >= length) && + ((length & 0x03U) || (((uint32_t)buffer) & 0x03U))) + { + khciState->endpointState[index].stateUnion.stateBitField.dmaAlign = 0U; + buffer = khciState->dmaAlignBuffer; + khciState->isDmaAlignBufferInusing = 1U; + } + + /* Receive data when the device is not resetting. */ + if (0U == khciState->isResetting) + { + error = USB_DeviceKhciEndpointTransfer(khciState, endpointAddress & USB_ENDPOINT_NUMBER_MASK, USB_OUT, + buffer, length); + } + } + return error; +} + +/*! + * @brief Cancel the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciCancel(usb_device_controller_handle khciHandle, uint8_t ep) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + usb_device_callback_message_struct_t message; + uint8_t index = ((ep & USB_ENDPOINT_NUMBER_MASK) << 1U) | ((ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + + /* Cancel the transfer and notify the up layer when the endpoint is busy. */ + if (khciState->endpointState[index].stateUnion.stateBitField.transferring) + { + message.length = USB_UNINITIALIZED_VAL_32; + message.buffer = khciState->endpointState[index].transferBuffer; + message.code = ep; + message.isSetup = 0U; + khciState->endpointState[index].stateUnion.stateBitField.transferring = 0U; + USB_DeviceNotificationTrigger(khciState->deviceHandle, &message); + } + return kStatus_USB_Success; +} + +/*! + * @brief Control the status of the selected item. + * + * The function is used to control the status of the selected item. + * + * @param khciHandle Pointer of the device KHCI handle. + * @param type The selected item. Please refer to enumeration type usb_device_control_type_t. + * @param param The param type is determined by the selected item. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciControl(usb_device_controller_handle khciHandle, usb_device_control_type_t type, void *param) +{ + usb_device_khci_state_struct_t *khciState = (usb_device_khci_state_struct_t *)khciHandle; + uint16_t *temp16; + uint8_t *temp8; +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) + usb_device_dcd_state_struct_t *dcdState; + dcdState = &s_UsbDeviceDcdState[khciState->controllerId - kUSB_ControllerKhci0]; + usb_device_dcd_charging_time_t *deviceDcdTimingConfig = (usb_device_dcd_charging_time_t *)param; +#endif +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + usb_device_struct_t *deviceHandle; + uint64_t startTick; +#endif + usb_status_t error = kStatus_USB_Error; + + if (!khciHandle) + { + return kStatus_USB_InvalidHandle; + } + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + deviceHandle = (usb_device_struct_t *)khciState->deviceHandle; +#endif + + switch (type) + { + case kUSB_DeviceControlRun: + khciState->registerBase->USBCTRL = 0U; +#if defined(FSL_FEATURE_USB_KHCI_OTG_ENABLED) && (FSL_FEATURE_USB_KHCI_OTG_ENABLED > 0U) + if (khciState->registerBase->OTGCTL & USB_OTGCTL_OTGEN_MASK) + { + khciState->registerBase->OTGCTL |= USB_OTGCTL_DPHIGH_MASK; + } +#endif /* FSL_FEATURE_USB_KHCI_OTG_ENABLED */ + khciState->registerBase->CONTROL |= USB_CONTROL_DPPULLUPNONOTG_MASK; + khciState->registerBase->CTL |= USB_CTL_USBENSOFEN_MASK; + + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlStop: +#if defined(FSL_FEATURE_USB_KHCI_OTG_ENABLED) && (FSL_FEATURE_USB_KHCI_OTG_ENABLED > 0U) + if (khciState->registerBase->OTGCTL & USB_OTGCTL_OTGEN_MASK) + { + khciState->registerBase->OTGCTL &= ~USB_OTGCTL_DPHIGH_MASK; + } +#endif /* FSL_FEATURE_USB_KHCI_OTG_ENABLED */ + khciState->registerBase->CONTROL &= ~USB_CONTROL_DPPULLUPNONOTG_MASK; + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlEndpointInit: + if (param) + { + error = USB_DeviceKhciEndpointInit(khciState, (usb_device_endpoint_init_struct_t *)param); + } + break; + case kUSB_DeviceControlEndpointDeinit: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointDeinit(khciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointStall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointStall(khciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointUnstall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceKhciEndpointUnstall(khciState, *temp8); + } + break; + case kUSB_DeviceControlGetDeviceStatus: + if (param) + { + temp16 = (uint16_t *)param; + *temp16 = (USB_DEVICE_CONFIG_SELF_POWER << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT)) +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + | ((uint16_t)(((uint32_t)deviceHandle->remotewakeup) + << (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT))) +#endif + ; + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetEndpointStatus: + if (param) + { + usb_device_endpoint_status_struct_t *endpointStatus = (usb_device_endpoint_status_struct_t *)param; + + if (((endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK) < USB_DEVICE_CONFIG_ENDPOINTS) + { + endpointStatus->endpointStatus = + (uint16_t)( + khciState + ->endpointState[(((endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK) << 1U) | + (((endpointStatus->endpointAddress) & + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)] + .stateUnion.stateBitField.stalled == 1U) ? + kUSB_DeviceEndpointStateStalled : + kUSB_DeviceEndpointStateIdle; + error = kStatus_USB_Success; + } + } + break; + case kUSB_DeviceControlSetDeviceAddress: + if (param) + { + temp8 = (uint8_t *)param; + khciState->registerBase->ADDR = (*temp8); + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetSynchFrame: + break; +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +#if defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U) + case kUSB_DeviceControlResume: + khciState->registerBase->CTL |= USB_CTL_RESUME_MASK; + startTick = deviceHandle->hwTick; + while ((deviceHandle->hwTick - startTick) < 10) + { + __ASM("nop"); + } + khciState->registerBase->CTL &= ~USB_CTL_RESUME_MASK; + error = kStatus_USB_Success; + break; +#endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + case kUSB_DeviceControlSuspend: + error = kStatus_USB_Success; + break; +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + case kUSB_DeviceControlSetDefaultStatus: + for (uint8_t count = 0U; count < USB_DEVICE_CONFIG_ENDPOINTS; count++) + { + USB_DeviceKhciEndpointDeinit(khciState, (count | (USB_IN << 0x07U))); + USB_DeviceKhciEndpointDeinit(khciState, (count | (USB_OUT << 0x07U))); + } + USB_DeviceKhciSetDefaultState(khciState); + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlGetSpeed: + if (param) + { + temp8 = (uint8_t *)param; + *temp8 = USB_SPEED_FULL; + error = kStatus_USB_Success; + } + break; +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + case kUSB_DeviceControlGetOtgStatus: + *((uint8_t *)param) = khciState->otgStatus; + break; + case kUSB_DeviceControlSetOtgStatus: + khciState->otgStatus = *((uint8_t *)param); + break; +#endif + case kUSB_DeviceControlSetTestMode: + break; +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) + case kUSB_DeviceControlDcdInitModule: + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + dcdState->dcdRegisterBase->TIMER0 = USBDCD_TIMER0_TSEQ_INIT(deviceDcdTimingConfig->dcdSeqInitTime); + dcdState->dcdRegisterBase->TIMER1 = USBDCD_TIMER1_TDCD_DBNC(deviceDcdTimingConfig->dcdDbncTime); + dcdState->dcdRegisterBase->TIMER1 |= USBDCD_TIMER1_TVDPSRC_ON(deviceDcdTimingConfig->dcdDpSrcOnTime); + dcdState->dcdRegisterBase->TIMER2_BC12 = + USBDCD_TIMER2_BC12_TWAIT_AFTER_PRD(deviceDcdTimingConfig->dcdTimeWaitAfterPrD); + dcdState->dcdRegisterBase->TIMER2_BC12 |= + USBDCD_TIMER2_BC12_TVDMSRC_ON(deviceDcdTimingConfig->dcdTimeDMSrcOn); + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_IE_MASK; + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_BC12_MASK; + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_START_MASK; + break; + case kUSB_DeviceControlDcdDeinitModule: + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + break; +#endif + + default: + break; + } + + return error; +} + +/*! + * @brief Handle the KHCI device interrupt. + * + * The function is used to handle the KHCI device interrupt. + * + * @param deviceHandle The device handle got from USB_DeviceInit. + * + */ +void USB_DeviceKhciIsrFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_khci_state_struct_t *khciState; + uint8_t status; + + if (NULL == deviceHandle) + { + return; + } + + khciState = (usb_device_khci_state_struct_t *)(handle->controllerHandle); + + status = khciState->registerBase->ISTAT; +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + /* Clear EEP_ALIVE_CTRL_WAKE_INT interrupt state */ + if (khciState->registerBase->KEEP_ALIVE_CTRL & USB_KEEP_ALIVE_CTRL_WAKE_INT_STS_MASK) + { + khciState->registerBase->KEEP_ALIVE_CTRL |= USB_KEEP_ALIVE_CTRL_WAKE_INT_STS_MASK; + } + /* Clear SOFTOK interrupt state */ + if (khciState->registerBase->ISTAT & USB_ISTAT_SOFTOK_MASK) + { + khciState->registerBase->ISTAT = USB_ISTAT_SOFTOK_MASK; + } +#endif +#if defined(USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING) && (USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING > 0U) + /* Error interrupt */ + if (status & kUSB_KhciInterruptError) + { + USB_DeviceKhciInterruptError(khciState); + } +#endif /* USB_DEVICE_CONFIG_KHCI_ERROR_HANDLING */ + /* Token done interrupt */ + if (status & kUSB_KhciInterruptTokenDone) + { + USB_DeviceKhciInterruptTokenDone(khciState); + } + + /* Reset interrupt */ + if (status & kUSB_KhciInterruptReset) + { + USB_DeviceKhciInterruptReset(khciState); + } + +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + /* Suspend interrupt */ + if (status & kUSB_KhciInterruptSleep) + { + USB_DeviceKhciInterruptSleep(khciState); + } + + /* Resume interrupt */ + if (status & kUSB_KhciInterruptResume) + { + USB_DeviceKhciInterruptResume(khciState); + } + + if (khciState->registerBase->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) + { + USB_DeviceKhciInterruptResume(khciState); + } +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + + /* Endpoint stalled interrupt */ + if (status & kUSB_KhciInterruptStall) + { + USB_DeviceKhciInterruptStall(khciState); + } + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED) && (FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED > 0U)) + if (khciState->registerBase->USBTRC0 & USB_USBTRC0_VREDG_DET_MASK) + { + USB_DeviceKhciInterruptVbusRising(khciState); + } + + if (khciState->registerBase->USBTRC0 & USB_USBTRC0_VFEDG_DET_MASK) + { + USB_DeviceKhciInterruptVbusFalling(khciState); + } +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE && FSL_FEATURE_USB_KHCI_VBUS_DETECT_ENABLED */ + +#if 0U + /* Sof token interrupt */ + if (status & kUSB_KhciInterruptSofToken) + { + USB_DeviceKhciInterruptSof(khciState); + } +#endif + +#if ((defined FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED) && \ + (FSL_FEATURE_USB_KHCI_IRC48M_MODULE_CLOCK_ENABLED > 0U)) + status = khciState->registerBase->CLK_RECOVER_INT_STATUS; + if (status) + { + /* USB RECOVER interrupt is happenned */ + if (USB_CLK_RECOVER_INT_STATUS_OVF_ERROR_MASK & status) + { + /* Indicates that the USB clock recovery algorithm has detected that the frequency trim adjustment needed + * for the IRC48M output clock is outside the available TRIM_FINE adjustment range for the IRC48M + * module. + */ + } + khciState->registerBase->CLK_RECOVER_INT_STATUS = status; + } +#endif +} + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) +/*! + * @brief Handle the device DCD module interrupt. + * + * The function is used to handle the device DCD module interrupt. + * + * @param deviceHandle The device handle got from USB_DeviceInit. + * + */ +void USB_DeviceDcdIsrFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_khci_state_struct_t *khciState; + usb_device_dcd_state_struct_t *dcdState; + uint32_t status; + uint32_t chargerType; + usb_device_callback_message_struct_t message; + + if (NULL == deviceHandle) + { + return; + } + + khciState = (usb_device_khci_state_struct_t *)(handle->controllerHandle); + + dcdState = &s_UsbDeviceDcdState[khciState->controllerId - kUSB_ControllerKhci0]; + + /* Read the STATUS register in the interrupt routine. */ + status = dcdState->dcdRegisterBase->STATUS; + + /* Clear the interrupt flag bit. */ + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_IACK_MASK; + + message.buffer = (uint8_t *)NULL; + message.length = 0U; + message.isSetup = 0U; + + if (status & USBDCD_STATUS_ERR_MASK) + { + if (status & USBDCD_STATUS_TO_MASK) + { + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + message.code = kUSB_DeviceNotifyDcdTimeOut; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + else + { + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + message.code = kUSB_DeviceNotifyDcdUnknownPortType; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + } + else + { + switch (status & USBDCD_STATUS_SEQ_STAT_MASK) + { + case USBDCD_STATUS_SEQ_STAT(kUSB_DcdChargingPortDetectionCompleted): + chargerType = status & USBDCD_STATUS_SEQ_RES_MASK; + if (chargerType == USBDCD_STATUS_SEQ_RES(kUSB_DcdDetectionStandardHost)) + { + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + message.code = kUSB_DeviceNotifySDPDetected; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + else if (chargerType == USBDCD_STATUS_SEQ_RES(kUSB_DcdDetectionChargingPort)) + { + message.code = kUSB_DeviceNotifyChargingPortDetected; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + break; + case USBDCD_STATUS_SEQ_STAT(kUSB_DcdChargerTypeDetectionCompleted): + chargerType = status & USBDCD_STATUS_SEQ_RES_MASK; + if (chargerType == USBDCD_STATUS_SEQ_RES(kUSB_DcdDetectionChargingPort)) + { + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + message.code = kUSB_DeviceNotifyChargingHostDetected; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + else if (chargerType == USBDCD_STATUS_SEQ_RES(kUSB_DcdDetectionDedicatedCharger)) + { + dcdState->dcdRegisterBase->CONTROL |= USBDCD_CONTROL_SR_MASK; + message.code = kUSB_DeviceNotifyDedicatedChargerDetected; + USB_DeviceNotificationTrigger(dcdState->deviceHandle, &message); + } + break; + + default: + break; + } + } +} +#endif +#endif /* USB_DEVICE_CONFIG_KHCI */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.h new file mode 100644 index 00000000..dbffec29 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_device_khci.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_DEVICE_KHCI_H__ +#define __USB_DEVICE_KHCI_H__ + +/*! + * @addtogroup usb_device_controller_khci_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief The maximum value of ISO maximum packet size for FS in USB specification 2.0 */ +#define USB_DEVICE_MAX_FS_ISO_MAX_PACKET_SIZE (1023U) + +/*! @brief The maximum value of non-ISO maximum packet size for FS in USB specification 2.0 */ +#define USB_DEVICE_MAX_FS_NONE_ISO_MAX_PACKET_SIZE (64U) + +/*! @brief Set BDT buffer address */ +#define USB_KHCI_BDT_SET_ADDRESS(bdt_base, ep, direction, odd, address) \ + *((volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) + \ + 1U) = address + +/*! @brief Set BDT control fields*/ +#define USB_KHCI_BDT_SET_CONTROL(bdt_base, ep, direction, odd, control) \ + *(volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) = control + +/*! @brief Get BDT buffer address*/ +#define USB_KHCI_BDT_GET_ADDRESS(bdt_base, ep, direction, odd) \ + (*((volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U)) + \ + 1U)) + +/*! @brief Get BDT control fields*/ +#define USB_KHCI_BDT_GET_CONTROL(bdt_base, ep, direction, odd) \ + (*(volatile uint32_t *)((bdt_base & 0xfffffe00U) | (((uint32_t)ep & 0x0fU) << 5U) | \ + (((uint32_t)direction & 1U) << 4U) | (((uint32_t)odd & 1U) << 3U))) + +/*! @brief Endpoint state structure */ +typedef struct _usb_device_khci_endpoint_state_struct +{ + uint8_t *transferBuffer; /*!< Address of buffer containing the data to be transmitted */ + uint32_t transferLength; /*!< Length of data to transmit. */ + uint32_t transferDone; /*!< The data length has been transferred*/ + union + { + uint32_t state; /*!< The state of the endpoint */ + struct + { + uint32_t maxPacketSize : 10U; /*!< The maximum packet size of the endpoint */ + uint32_t stalled : 1U; /*!< The endpoint is stalled or not */ + uint32_t data0 : 1U; /*!< The data toggle of the transaction */ + uint32_t bdtOdd : 1U; /*!< The BDT toggle of the endpoint */ + uint32_t dmaAlign : 1U; /*!< Whether the transferBuffer is DMA aligned or not */ + uint32_t transferring : 1U; /*!< The endpoint is transferring */ + uint32_t zlt : 1U; /*!< zlt flag */ + } stateBitField; + } stateUnion; +} usb_device_khci_endpoint_state_struct_t; + +/*! @brief KHCI state structure */ +typedef struct _usb_device_khci_state_struct +{ + usb_device_struct_t *deviceHandle; /*!< Device handle used to identify the device object belongs to */ + uint8_t *bdt; /*!< BDT buffer address */ + USB_Type *registerBase; /*!< The base address of the register */ + uint8_t setupPacketBuffer[USB_SETUP_PACKET_SIZE * 2]; /*!< The setup request buffer */ + uint8_t *dmaAlignBuffer; /*!< This buffer is used to fix the transferBuffer or transferLength does + not align to 4-bytes when the function USB_DeviceKhciRecv is called. + The macro USB_DEVICE_CONFIG_KHCI_DMA_ALIGN is used to enable or disable this feature. + If the feature is enabled, when the transferBuffer or transferLength does not align to + 4-bytes, + the transferLength is not more than USB_DEVICE_CONFIG_KHCI_DMA_ALIGN_BUFFER_LENGTH, and + the flag isDmaAlignBufferInusing is zero, the dmaAlignBuffer is used to receive data + and the flag isDmaAlignBufferInusing is set to 1. + When the transfer is done, the received data, kept in dmaAlignBuffer, is copied + to the transferBuffer, and the flag isDmaAlignBufferInusing is cleared. + */ + usb_device_khci_endpoint_state_struct_t + endpointState[USB_DEVICE_CONFIG_ENDPOINTS * 2]; /*!< Endpoint state structures */ + uint8_t isDmaAlignBufferInusing; /*!< The dmaAlignBuffer is used or not */ + uint8_t isResetting; /*!< Is doing device reset or not */ + uint8_t controllerId; /*!< Controller ID */ + uint8_t setupBufferIndex; /*!< A valid setup buffer flag */ +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + uint8_t otgStatus; +#endif +} usb_device_khci_state_struct_t; + +#if (defined(USB_DEVICE_CHARGER_DETECT_ENABLE) && (USB_DEVICE_CHARGER_DETECT_ENABLE > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBDCD_COUNT) && (FSL_FEATURE_SOC_USBDCD_COUNT > 0U)) +typedef struct _usb_device_dcd_state_struct +{ + usb_device_struct_t *deviceHandle; /*!< Device handle used to identify the device object belongs to */ + USBDCD_Type *dcdRegisterBase; /*!< The base address of the dcd module */ + uint8_t controllerId; /*!< Controller ID */ +} usb_device_dcd_state_struct_t; +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB device KHCI functions + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the USB device KHCI instance. + * + * This function initializes the USB device KHCI module specified by the controllerId. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration type usb_controller_index_t. + * @param[in] handle Pointer of the device handle used to identify the device object belongs to. + * @param[out] khciHandle An out parameter used to return the pointer of the device KHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *khciHandle); + +/*! + * @brief Deinitializes the USB device KHCI instance. + * + * This function deinitializes the USB device KHCI module. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciDeinit(usb_device_controller_handle khciHandle); + +/*! + * @brief Sends data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to hold the data need to be sent. + * @param[in] length The data length need to be sent. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value indicates whether the sending request is successful or not. The transfer completion is + * notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for a specific endpoint. + * If there is a specific requirement to support multiple transfer requests for a specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer can begin only when the previous transfer is done (a notification is obtained through the + * endpoint + * callback). + */ +usb_status_t USB_DeviceKhciSend(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Receives data through a specified endpoint. + * + * This function receives data through a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] endpointAddress Endpoint index. + * @param[in] buffer The memory address to save the received data. + * @param[in] length The data length to be received. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value indicates whether the receiving request is successful or not. The transfer completion is + * notified by the + * corresponding callback function. + * Currently, only one transfer request can be supported for a specific endpoint. + * If there is a specific requirement to support multiple transfer requests for a specific endpoint, the application + * should implement a queue in the application level. + * The subsequent transfer can begin only when the previous transfer is done (a notification is obtained through the + * endpoint + * callback). + */ +usb_status_t USB_DeviceKhciRecv(usb_device_controller_handle khciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Cancels the pending transfer in a specified endpoint. + * + * The function is used to cancel the pending transfer in a specified endpoint. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, abd 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciCancel(usb_device_controller_handle khciHandle, uint8_t ep); + +/*! + * @brief Controls the status of the selected item. + * + * The function is used to control the status of the selected item. + * + * @param[in] khciHandle Pointer of the device KHCI handle. + * @param[in] type The selected item. See enumeration type usb_device_control_type_t. + * @param[in,out] param The parameter type is determined by the selected item. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceKhciControl(usb_device_controller_handle khciHandle, + usb_device_control_type_t type, + void *param); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* __USB_DEVICE_KHCI_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_khci.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_khci.h new file mode 100644 index 00000000..1d51a6ee --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_khci.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_KHCI_H__ +#define __USB_KHCI_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_KHCI_BDT_DEVICE_OUT_TOKEN (0x01U) +#define USB_KHCI_BDT_DEVICE_IN_TOKEN (0x09U) +#define USB_KHCI_BDT_DEVICE_SETUP_TOKEN (0x0DU) + +#define USB_KHCI_BDT_OWN (0x80U) +#define USB_KHCI_BDT_DATA01(x) ((((uint32_t)(x)) & 0x01U) << 0x06U) +#define USB_KHCI_BDT_BC(x) ((((uint32_t)(x)) & 0x3FFU) << 0x10U) +#define UBS_KHCI_BDT_KEEP (0x20U) +#define UBS_KHCI_BDT_NINC (0x10U) +#define USB_KHCI_BDT_DTS (0x08U) +#define USB_KHCI_BDT_STALL (0x04U) + +typedef enum _usb_khci_interrupt_type +{ + kUSB_KhciInterruptReset = 0x01U, + kUSB_KhciInterruptError = 0x02U, + kUSB_KhciInterruptSofToken = 0x04U, + kUSB_KhciInterruptTokenDone = 0x08U, + kUSB_KhciInterruptSleep = 0x10U, + kUSB_KhciInterruptResume = 0x20U, + kUSB_KhciInterruptAttach = 0x40U, + kUSB_KhciInterruptStall = 0x80U, +} usb_khci_interrupt_type_t; + +#endif /* __USB_KHCI_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_misc.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_misc.h new file mode 100644 index 00000000..c5aef679 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_misc.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_MISC_H__ +#define __USB_MISC_H__ + +#ifndef ENDIANNESS + +#error ENDIANNESS should be defined, and then rebulid the project. + +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define USB printf */ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +extern int DbgConsole_Printf(const char *fmt_s, ...); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#if defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE < 1) +#define usb_echo printf +#else +#define usb_echo +#endif + +#if defined(__ICCARM__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED __packed +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED +#endif + +#elif defined(__GNUC__) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED __attribute__((__packed__)) +#endif + +#elif defined(__CC_ARM) + +#ifndef STRUCT_PACKED +#define STRUCT_PACKED _Pragma("pack(1U)") +#endif + +#ifndef STRUCT_UNPACKED +#define STRUCT_UNPACKED _Pragma("pack()") +#endif + +#endif + +#define USB_SHORT_GET_LOW(x) (((uint16_t)x) & 0xFFU) +#define USB_SHORT_GET_HIGH(x) ((uint8_t)(((uint16_t)x) >> 8U) & 0xFFU) + +#define USB_LONG_GET_BYTE0(x) ((uint8_t)(((uint32_t)(x))) & 0xFFU) +#define USB_LONG_GET_BYTE1(x) ((uint8_t)(((uint32_t)(x)) >> 8U) & 0xFFU) +#define USB_LONG_GET_BYTE2(x) ((uint8_t)(((uint32_t)(x)) >> 16U) & 0xFFU) +#define USB_LONG_GET_BYTE3(x) ((uint8_t)(((uint32_t)(x)) >> 24U) & 0xFFU) + +#define USB_MEM4_ALIGN_MASK (0x03U) + +/* accessory macro */ +#define USB_MEM4_ALIGN(n) ((n + 3U) & (0xFFFFFFFCu)) +#define USB_MEM32_ALIGN(n) ((n + 31U) & (0xFFFFFFE0u)) +#define USB_MEM64_ALIGN(n) ((n + 63U) & (0xFFFFFFC0u)) + +/* big/little endian */ +#define SWAP2BYTE_CONST(n) ((((n)&0x00FFU) << 8U) | (((n)&0xFF00U) >> 8U)) +#define SWAP4BYTE_CONST(n) \ + ((((n)&0x000000FFU) << 24U) | (((n)&0x0000FF00U) << 8U) | (((n)&0x00FF0000U) >> 8U) | (((n)&0xFF000000U) >> 24U)) + +#define USB_ASSIGN_VALUE_ADDRESS_LONG_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = *((uint8_t *)&(m)); \ + *((uint8_t *)&(n) + 1) = *((uint8_t *)&(m) + 1); \ + *((uint8_t *)&(n) + 2) = *((uint8_t *)&(m) + 2); \ + *((uint8_t *)&(n) + 3) = *((uint8_t *)&(m) + 3); \ + } + +#define USB_ASSIGN_VALUE_ADDRESS_SHORT_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = *((uint8_t *)&(m)); \ + *((uint8_t *)&(n) + 1) = *((uint8_t *)&(m) + 1); \ + } + +#define USB_ASSIGN_MACRO_VALUE_ADDRESS_LONG_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = (uint8_t)m; \ + *((uint8_t *)&(n) + 1) = (uint8_t)(m >> 8); \ + *((uint8_t *)&(n) + 2) = (uint8_t)(m >> 16); \ + *((uint8_t *)&(n) + 3) = (uint8_t)(m >> 24); \ + } + +#define USB_ASSIGN_MACRO_VALUE_ADDRESS_SHORT_BY_BYTE(n, m) \ + { \ + *((uint8_t *)&(n)) = (uint8_t)m; \ + *((uint8_t *)&(n) + 1) = (uint8_t)(m >> 8); \ + } + +#if (ENDIANNESS == USB_BIG_ENDIAN) + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) SWAP2BYTE_CONST(n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) (n) +#define USB_LONG_TO_BIG_ENDIAN(n) (n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) (n) +#define USB_LONG_FROM_BIG_ENDIAN(n) (n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 24U) & 0xFFU); \ + m[1] = ((n >> 16U) & 0xFFU); \ + m[2] = ((n >> 8U) & 0xFFU); \ + m[3] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[0] << 24U) | ((uint32_t)n[1] << 16U) | ((uint32_t)n[2] << 8U) | ((uint32_t)n[3] << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((n >> 24U) & 0xFFU); \ + m[2] = ((n >> 16U) & 0xFFU); \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[3] << 24U) | ((uint32_t)n[2] << 16U) | ((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 8U) & 0xFFU); \ + m[1] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[0] << 8U) | ((uint32_t)n[1] << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#else + +#define USB_SHORT_TO_LITTLE_ENDIAN(n) (n) +#define USB_LONG_TO_LITTLE_ENDIAN(n) (n) +#define USB_SHORT_FROM_LITTLE_ENDIAN(n) (n) +#define USB_LONG_FROM_LITTLE_ENDIAN(n) (n) + +#define USB_SHORT_TO_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_TO_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) +#define USB_SHORT_FROM_BIG_ENDIAN(n) SWAP2BYTE_CONST(n) +#define USB_LONG_FROM_BIG_ENDIAN(n) SWAP4BYTE_CONST(n) + +#define USB_LONG_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[3] = ((n >> 24U) & 0xFFU); \ + m[2] = ((n >> 16U) & 0xFFU); \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[3] << 24U) | ((uint32_t)n[2] << 16U) | ((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 24U) & 0xFFU); \ + m[1] = ((n >> 16U) & 0xFFU); \ + m[2] = ((n >> 8U) & 0xFFU); \ + m[3] = (n & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)(((uint32_t)n[0] << 24U) | ((uint32_t)n[1] << 16U) | ((uint32_t)n[2] << 8U) | ((uint32_t)n[3] << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((n >> 8U) & 0xFFU); \ + m[0] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[1] << 8U) | ((uint32_t)n[0] << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((n >> 8U) & 0xFFU); \ + m[1] = (n & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)(((uint32_t)n[0] << 8U) | ((uint32_t)n[1] << 0U))) +#endif + +/* + * The following MACROs (USB_GLOBAL, USB_BDT, USB_RAM_ADDRESS_ALIGNMENT, etc) are only used for USB device stack. + * The USB device global variables are put into the section m_usb_global and m_usb_bdt or the section + * .bss.m_usb_global and .bss.m_usb_bdt by using the MACRO USB_GLOBAL and USB_BDT. In this way, the USB device + * global variables can be linked into USB dedicated RAM by USB_STACK_USE_DEDICATED_RAM. + * The MACRO USB_STACK_USE_DEDICATED_RAM is used to decide the USB stack uses dedicated RAM or not. The value of + * the marco can be set as 0, USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL, or USB_STACK_DEDICATED_RAM_TYPE_BDT. + * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL means USB device global variables, including USB_BDT and + * USB_GLOBAL, are put into the USB dedicated RAM. This feature can only be enabled when the USB dedicated RAM + * is not less than 2K Bytes. + * The MACRO USB_STACK_DEDICATED_RAM_TYPE_BDT means USB device global variables, only including USB_BDT, are put + * into the USB dedicated RAM, the USB_GLOBAL will be put into .bss section. This feature is used for some SOCs, + * the USB dedicated RAM size is not more than 512 Bytes. + */ +#define USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL 1 +#define USB_STACK_DEDICATED_RAM_TYPE_BDT 2 + +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL) + +#if defined(__ICCARM__) + +#define USB_GLOBAL _Pragma("location = \"m_usb_global\"") +#define USB_BDT _Pragma("location = \"m_usb_bdt\"") + +/* disable misra 19.13 */ +_Pragma("diag_suppress=Pm120") +#define USB_ALIGN_PRAGMA(x) _Pragma(#x) + _Pragma("diag_default=Pm120") + +#define USB_RAM_ADDRESS_ALIGNMENT(n) USB_ALIGN_PRAGMA(data_alignment = n) + +#elif defined(__CC_ARM) + +#define USB_GLOBAL __attribute__((section("m_usb_global"))) __attribute__((zero_init)) +#define USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#elif defined(__GNUC__) + +#define USB_GLOBAL __attribute__((section("m_usb_global, \"aw\", %nobits @"))) +#define USB_BDT __attribute__((section("m_usb_bdt, \"aw\", %nobits @"))) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#else +#error The tool-chain is not supported. +#endif + +#elif defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT) + +#if defined(__ICCARM__) + +#define USB_GLOBAL _Pragma("location = \".bss.m_usb_global\"") +#define USB_BDT _Pragma("location = \"m_usb_bdt\"") + +/* disable misra 19.13 */ +_Pragma("diag_suppress=Pm120") +#define USB_ALIGN_PRAGMA(x) _Pragma(#x) + _Pragma("diag_default=Pm120") + +#define USB_RAM_ADDRESS_ALIGNMENT(n) USB_ALIGN_PRAGMA(data_alignment = n) + +#elif defined(__CC_ARM) + +#define USB_GLOBAL __attribute__((section(".bss.m_usb_global"))) __attribute__((zero_init)) +#define USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#elif defined(__GNUC__) + +#define USB_GLOBAL __attribute__((section(".bss.m_usb_global, \"aw\", %nobits @"))) +#define USB_BDT __attribute__((section("m_usb_bdt, \"aw\", %nobits @"))) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#else +#error The tool-chain is not supported. +#endif + +#else + +#if defined(__ICCARM__) + +#define USB_GLOBAL _Pragma("location = \".bss.m_usb_global\"") +#define USB_BDT _Pragma("location = \".bss.m_usb_bdt\"") + +/* disable misra 19.13 */ +_Pragma("diag_suppress=Pm120") +#define USB_ALIGN_PRAGMA(x) _Pragma(#x) + _Pragma("diag_default=Pm120") + +#define USB_RAM_ADDRESS_ALIGNMENT(n) USB_ALIGN_PRAGMA(data_alignment = n) + +#elif defined(__CC_ARM) + +#define USB_GLOBAL __attribute__((section(".bss.m_usb_global"))) __attribute__((zero_init)) +#define USB_BDT __attribute__((section(".bss.m_usb_bdt"))) __attribute__((zero_init)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#elif defined(__GNUC__) + +#define USB_GLOBAL __attribute__((section(".bss.m_usb_global, \"aw\", %nobits @"))) +#define USB_BDT __attribute__((section(".bss.m_usb_bdt, \"aw\", %nobits @"))) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) + +#else +#error The tool-chain is not supported. +#endif + +#endif + +#if defined(__ICCARM__) + +#define USB_GLOBAL_DEDICATED_RAM _Pragma("location = \"m_usb_global\"") + +#elif defined(__CC_ARM) + +#define USB_GLOBAL_DEDICATED_RAM __attribute__((section("m_usb_global"))) __attribute__((zero_init)) + +#elif defined(__GNUC__) + +#define USB_GLOBAL_DEDICATED_RAM __attribute__((section("m_usb_global, \"aw\", %nobits @"))) + +#else +#error The tool-chain is not supported. +#endif + +#if (((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U))) +#define USB_DATA_ALIGNMENT USB_RAM_ADDRESS_ALIGNMENT(64) +#else +#define USB_DATA_ALIGNMENT +#endif + +#endif /* __USB_MISC_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa.h new file mode 100644 index 00000000..ef3f0f8f --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa.h @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_OSA_H__ +#define __USB_OSA_H__ + +/*! + * @addtogroup usb_os_abstraction + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define big endian */ +#define USB_BIG_ENDIAN (0U) +/*! @brief Define little endian */ +#define USB_LITTLE_ENDIAN (1U) + +/*! @brief Define current endian */ +#define ENDIANNESS USB_LITTLE_ENDIAN + +/*! @brief Define USB OSA event handle */ +typedef void *usb_osa_event_handle; + +/*! @brief Define USB OSA semaphore handle */ +typedef void *usb_osa_sem_handle; + +/*! @brief Define USB OSA mutex handle */ +typedef void *usb_osa_mutex_handle; + +/*! @brief Define USB OSA message queue handle */ +typedef void *usb_osa_msgq_handle; + +/*! @brief USB OSA error code */ +typedef enum _usb_osa_status +{ + kStatus_USB_OSA_Success = 0x00U, /*!< Success */ + kStatus_USB_OSA_Error, /*!< Failed */ + kStatus_USB_OSA_TimeOut, /*!< Timeout occurs while waiting */ +} usb_osa_status_t; + +/*! @brief The event flags are cleared automatically or manually.*/ +typedef enum _usb_osa_event_mode +{ + kUSB_OsaEventManualClear = 0U, /*!< The flags of the event is cleared manually. */ + kUSB_OsaEventAutoClear = 1U, /*!< The flags of the event is cleared automatically. */ +} usb_osa_event_mode_t; + +#include "usb_osa_bm.h" + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB OSA Memory Management + * @{ + */ + +/*! + * @brief Reserves the requested amount of memory in bytes. + * + * The function is used to reserve the requested amount of memory in bytes and initializes it to 0. + * + * @param length Amount of bytes to reserve. + * + * @return Pointer to the reserved memory. NULL if memory can't be allocated. + */ +void *USB_OsaMemoryAllocate(uint32_t length); + +/*! + * @brief Frees the memory previously reserved. + * + * The function is used to free the memory block previously reserved. + * + * @param p Pointer to the start of the memory block previously reserved. + * + */ +extern void USB_OsaMemoryFree(void *p); + +/* @} */ + +/*! + * @name USB OSA Event + * @{ + */ + +/*! + * @brief Creates an event object with all flags cleared. + * + * This function creates an event object and sets its clear mode. If the clear mode + * is kUSB_OsaEventAutoClear, when a task gets the event flags, these flags are + * cleared automatically. If the clear mode is kUSB_OsaEventManualClear, the flags must + * be cleared manually. + * + * @param handle It is an out parameter, which is used to return the pointer of the event object. + * @param flag The event is auto-clear or manual-clear. See the enumeration #usb_osa_event_mode_t. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_event_handle eventHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaEventCreate(&eventHandle, kUSB_OsaEventManualClear); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag); + +/*! + * @brief Destroys a created event object. + * + * @param handle Pointer to the event object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventDestroy(eventHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle); + +/*! + * @brief Sets an event flag. + * + * Sets specified flags for an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to be set. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventSet(eventHandle, 0x01U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask); + +/*! + * @brief Waits for an event flag. + * + * This function waits for a combination of flags to be set in an event object. + * An applications can wait for any/all bits to be set. This function can + * get the flags that wake up the waiting task. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to wait. + * @param flag Wait all flags or any flag to be set. 0U - wait any flag, others, wait all flags. + * @param timeout The maximum number of milliseconds to wait for the event. + * If the wait condition is not met, passing 0U + * waits indefinitely when the environment is an RTOS and returns the kStatus_OSA_Timeout + * immediately. Pass any value for the bare metal. + * @param bitSet Flags that wake up the waiting task are obtained by this parameter. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventWait(eventHandle, 0x01U, 0U, 0U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet); + +/*! + * @brief Checks an event flag. + * + * This function checks for a combination of flags to be set in an event object. + * + * @param handle Pointer to the event object. + * @param bitMask Event flags to check. + * @param bitSet Flags have been set. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + uint32_t bitSet; + ... + usbOsaStatus = USB_OsaEventCheck(eventHandle, 0x01U, &bitSet); + @endcode + * + */ +extern usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet); + +/*! + * @brief Clears an event flag. + * + * This function clears flags of an event object. + * + * @param handle Pointer to the event object + * @param bitMask Event flags to be cleared. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaEventClear(eventHandle, 0x01U); + @endcode + */ +extern usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask); +/* @} */ + +/*! + * @name USB OSA Semaphore + * @{ + */ + +/*! + * @brief Creates a semaphore with a given value. + * + * This function creates a semaphore and sets the default count. + * + * @param handle It is an out parameter, which is used to return pointer of the semaphore object. + * @param count Initializes a value of the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaSemCreate(&semHandle, 1U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count); + +/*! + * @brief Destroys a semaphore object. + * + * This function destroys a semaphore object. + * + * @param handle Pointer to the semaphore. + * + * @return An USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemDestroy(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle); + +/*! + * @brief Posts a semaphore. + * + * This function wakes up a task waiting on the semaphore. If a task is not pending, increases the semaphore's + value. + * + * @param handle Pointer to the semaphore. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemPost(semHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle); + +/*! + * @brief Waits on a semaphore. + * + * This function checks the semaphore's value. If it is positive, it decreases the semaphore's value and return + kStatus_OSA_Success. + * + * @param handle Pointer to the semaphore. + * @param timeout The maximum number of milliseconds to wait for the semaphore. + * If the wait condition is not met, passing 0U + * waits indefinitely when environment is RTOS. And return kStatus_OSA_Timeout + * immediately for bare metal no matter what value has been passed. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_sem_handle semHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaSemWait(semHandle, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout); +/* @} */ + +/*! + * @name USB OSA Mutex + * @{ + */ + +/*! + * @brief Creates a mutex. + * + * This function creates a mutex and sets it to an unlocked status. + * + * @param handle It is out parameter, which is used to return the pointer of the mutex object. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMutexCreate(&mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle); + +/*! + * @brief Destroys a mutex. + * + * This function destroys a mutex and sets it to an unlocked status. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexDestroy(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle); + +/*! + * @brief Waits for a mutex and locks it. + * + * This function checks the mutex status. If it is unlocked, it locks it and returns the + * kStatus_OSA_Success. Otherwise, it waits forever to lock in RTOS and returns the + * kStatus_OSA_Success immediately for bare metal. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexLock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle); + +/*! + * @brief Unlocks a mutex. + * + * This function unlocks a mutex. + * + * @param handle Pointer to the mutex. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_mutex_handle mutexHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMutexUnlock(mutexHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle); +/* @} */ + +/*! + * @name USB OSA Message Queue + * @{ + */ + +/*! + * @brief Creates a message queue. + * + * This function creates a message queue. + * + * @param handle It is an out parameter, which is used to return a pointer of the message queue object. + * @param count The count of elements in the queue. + * @param size Size of every elements in words. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + usbOsaStatus = USB_OsaMsgqCreate(msgqHandle, 8U, 4U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size); + +/*! + * @brief Destroys a message queue. + * + * This function destroys a message queue. + * + * @param handle Pointer to a message queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqDestroy(msgqHandle); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle); + +/*! + * @brief Sends a message. + * + * This function sends a message to the tail of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to a message to be put into the queue. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqSend(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg); + +/*! + * @brief Receives a message. + * + * This function receives a message from the head of the message queue. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * @param timeout The maximum number of milliseconds to wait for a message. + * If the wait condition is not met, passing 0U + * waits indefinitely when an environment is RTOS and returns the kStatus_OSA_Timeout + * immediately for bare metal. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqRecv(msgqHandle, &message, 0U); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout); + +/*! + * @brief Checks a message queue and receives a message if the queue is not empty. + * + * This function checks a message queue and receives a message if the queue is not empty. + * + * @param handle Pointer to a message queue. + * @param msg The pointer to save a received message. + * + * @return A USB OSA error code or kStatus_OSA_Success. + * + * Example: + @code + usb_osa_msgq_handle msgqHandle; + message_struct_t message; + usb_osa_status_t usbOsaStatus; + ... + usbOsaStatus = USB_OsaMsgqCheck(msgqHandle, &message); + @endcode + * + */ +extern usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/* @} */ + +#endif /* __USB_OSA_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.c b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.c new file mode 100644 index 00000000..4033089b --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.c @@ -0,0 +1,539 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#include "stdint.h" +#include "usb.h" +#include "usb_osa.h" +#include "stdlib.h" +#include "MK22F51212.h" +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define USB_OSA_BM_EVENT_COUNT (2U) +#define USB_OSA_BM_SEM_COUNT (1U) +#define USB_OSA_BM_MSGQ_COUNT (1U) +#define USB_OSA_BM_MSG_COUNT (8U) +#define USB_OSA_BM_MSG_SIZE (4U) + +/* BM Event status structure */ +typedef struct _usb_osa_event_struct +{ + uint32_t value; /* Event mask */ + uint32_t flag; /* Event flags, includes auto clear flag */ + uint8_t isUsed; /* Is used */ +} usb_osa_event_struct_t; + +/* BM semaphore status structure */ +typedef struct _usb_osa_sem_struct +{ + uint32_t value; /* Semaphore count */ + uint8_t isUsed; /* Is used */ +} usb_osa_sem_struct_t; + +/* BM msg status structure */ +typedef struct _usb_osa_msg_struct +{ + uint32_t msg[USB_OSA_BM_MSG_SIZE]; /* Message entity pointer */ +} usb_osa_msg_struct_t; + +/* BM msgq status structure */ +typedef struct _usb_osa_msgq_struct +{ + usb_osa_msg_struct_t msgs[USB_OSA_BM_MSG_COUNT]; /* Message entity list */ + uint32_t count; /* Max message entity count */ + uint32_t msgSize; /* Size of each message */ + uint32_t msgCount; /* Valid messages */ + uint32_t index; /* The first empty message entity index */ + uint32_t current; /* The vaild message index */ + uint8_t isUsed; /* Is used */ +} usb_osa_msgq_struct_t; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +USB_GLOBAL static usb_osa_sem_struct_t s_UsbBmSemStruct[USB_OSA_BM_SEM_COUNT]; +USB_GLOBAL static usb_osa_event_struct_t s_UsbBmEventStruct[USB_OSA_BM_EVENT_COUNT]; +USB_GLOBAL static usb_osa_msgq_struct_t s_UsbBmMsgqStruct[USB_OSA_BM_MSGQ_COUNT]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +void *USB_OsaMemoryAllocate(uint32_t length) +{ + void *p = (void *)malloc(length); + uint8_t *temp = (uint8_t *)p; + if (p) + { + for (uint32_t count = 0U; count < length; count++) + { + temp[count] = 0U; + } + } + return p; +} + +void USB_OsaMemoryFree(void *p) +{ + free(p); +} + +void USB_OsaEnterCritical(uint32_t *sr) +{ + *sr = DisableGlobalIRQ(); + __ASM("CPSID I"); +} + +void USB_OsaExitCritical(uint32_t sr) +{ + EnableGlobalIRQ(sr); +} + +usb_osa_status_t USB_OsaEventCreate(usb_osa_event_handle *handle, uint32_t flag) +{ + usb_osa_event_struct_t *event = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_EVENT_COUNT; i++) + { + if (0 == s_UsbBmEventStruct[i].isUsed) + { + event = &s_UsbBmEventStruct[i]; + break; + } + } + + if (NULL == event) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + event->value = 0U; + event->flag = flag; + event->isUsed = 1; + *handle = event; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaEventDestroy(usb_osa_event_handle handle) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventSet(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + event->value |= bitMask; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventWait( + usb_osa_event_handle handle, uint32_t bitMask, uint32_t flag, uint32_t timeout, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + if (flag) + { + if (bits != bitMask) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + else + { + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + } + if (bitSet) + { + *bitSet = bits; + } + if (event->flag) + { + event->value &= ~bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventCheck(usb_osa_event_handle handle, uint32_t bitMask, uint32_t *bitSet) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + + if (!bits) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + if (bitSet) + { + *bitSet = bits; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaEventClear(usb_osa_event_handle handle, uint32_t bitMask) +{ + usb_osa_event_struct_t *event = (usb_osa_event_struct_t *)handle; + uint32_t bits; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + bits = event->value & bitMask; + event->value &= ~bits; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemCreate(usb_osa_sem_handle *handle, uint32_t count) +{ + usb_osa_sem_struct_t *sem = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + for (uint32_t i = 0; i < USB_OSA_BM_SEM_COUNT; i++) + { + if (0 == s_UsbBmSemStruct[i].isUsed) + { + sem = &s_UsbBmSemStruct[i]; + break; + } + } + if (NULL == sem) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + sem->value = count; + sem->isUsed = 1; + *handle = sem; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemDestroy(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (handle) + { + USB_OSA_ENTER_CRITICAL(); + sem->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; + } + return kStatus_USB_OSA_Error; +} + +usb_osa_status_t USB_OsaSemPost(usb_osa_sem_handle handle) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + sem->value++; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaSemWait(usb_osa_sem_handle handle, uint32_t timeout) +{ + usb_osa_sem_struct_t *sem = (usb_osa_sem_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + if (sem->value) + { + sem->value--; + } + else + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexCreate(usb_osa_mutex_handle *handle) +{ + if (!handle) + { + return kStatus_USB_OSA_Error; + } + *handle = (usb_osa_mutex_handle)0xFFFF0000U; + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMutexDestroy(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexLock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} +usb_osa_status_t USB_OsaMutexUnlock(usb_osa_mutex_handle handle) +{ + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCreate(usb_osa_msgq_handle *handle, uint32_t count, uint32_t size) +{ + usb_osa_msgq_struct_t *msgq = NULL; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + + for (uint32_t i = 0; i < USB_OSA_BM_MSGQ_COUNT; i++) + { + if (0 == s_UsbBmMsgqStruct[i].isUsed) + { + msgq = &s_UsbBmMsgqStruct[i]; + break; + } + } + if ((NULL == msgq) || (count > USB_OSA_BM_MSG_COUNT) || (size > USB_OSA_BM_MSG_SIZE)) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + msgq->count = count; + msgq->msgSize = size; + msgq->msgCount = 0U; + msgq->index = 0U; + msgq->current = 0U; + msgq->isUsed = 1; + *handle = msgq; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqDestroy(usb_osa_msgq_handle handle) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + msgq->isUsed = 0; + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqSend(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount >= msgq->count) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_Error; + } + + msgEntity = &msgq->msgs[msgq->index]; + p = (uint32_t *)&msgEntity->msg[0]; + q = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + if (0U == msgq->msgCount) + { + msgq->current = msgq->index; + } + + msgq->msgCount++; + msgq->index++; + msgq->index = msgq->index % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqRecv(usb_osa_msgq_handle handle, void *msg, uint32_t timeout) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + usb_osa_msg_struct_t *msgEntity; + uint32_t *p; + uint32_t *q; + uint32_t count; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + USB_OSA_ENTER_CRITICAL(); + if (msgq->msgCount < 1U) + { + USB_OSA_EXIT_CRITICAL(); + return kStatus_USB_OSA_TimeOut; + } + + msgEntity = &msgq->msgs[msgq->current]; + q = (uint32_t *)&msgEntity->msg[0]; + p = (uint32_t *)msg; + + for (count = 0U; count < msgq->msgSize; count++) + { + p[count] = q[count]; + } + + msgq->msgCount--; + msgq->current++; + msgq->current = msgq->current % msgq->count; + + USB_OSA_EXIT_CRITICAL(); + + return kStatus_USB_OSA_Success; +} + +usb_osa_status_t USB_OsaMsgqCheck(usb_osa_msgq_handle handle, void *msg) +{ + usb_osa_msgq_struct_t *msgq = (usb_osa_msgq_struct_t *)handle; + uint32_t msgCount; + USB_OSA_SR_ALLOC(); + + if (!handle) + { + return kStatus_USB_OSA_Error; + } + + USB_OSA_ENTER_CRITICAL(); + msgCount = msgq->msgCount; + USB_OSA_EXIT_CRITICAL(); + + if (msgCount) + { + if (kStatus_USB_OSA_Success == USB_OsaMsgqRecv(msgq, msg, 0U)) + { + return kStatus_USB_OSA_Success; + } + } + + return kStatus_USB_OSA_Error; +} diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.h new file mode 100644 index 00000000..a55d154b --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_osa_bm.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_OSA_BM_H__ +#define __USB_OSA_BM_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#define USB_OSA_SR_ALLOC() uint32_t usbOsaCurrentSr; +#define USB_OSA_ENTER_CRITICAL() USB_OsaEnterCritical(&usbOsaCurrentSr) +#define USB_OSA_EXIT_CRITICAL() USB_OsaExitCritical(usbOsaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +extern void USB_OsaEnterCritical(uint32_t *sr); +extern void USB_OsaExitCritical(uint32_t sr); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_OSA_BM_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/usb_spec.h b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_spec.h new file mode 100644 index 00000000..d77b7d35 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/usb_spec.h @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +#ifndef __USB_SPEC_H__ +#define __USB_SPEC_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* USB speed (the value cannot be changed because EHCI QH use the value directly)*/ +#define USB_SPEED_FULL (0x00U) +#define USB_SPEED_LOW (0x01U) +#define USB_SPEED_HIGH (0x02U) + +/* Set up packet structure */ +typedef struct _usb_setup_struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} usb_setup_struct_t; + +/* USB standard descriptor endpoint type */ +#define USB_ENDPOINT_CONTROL (0x00U) +#define USB_ENDPOINT_ISOCHRONOUS (0x01U) +#define USB_ENDPOINT_BULK (0x02U) +#define USB_ENDPOINT_INTERRUPT (0x03U) + +/* USB standard descriptor transfer direction (cannot change the value because iTD use the value directly) */ +#define USB_OUT (0U) +#define USB_IN (1U) + +/* USB standard descriptor length */ +#define USB_DESCRIPTOR_LENGTH_DEVICE (0x12U) +#define USB_DESCRIPTOR_LENGTH_CONFIGURE (0x09U) +#define USB_DESCRIPTOR_LENGTH_INTERFACE (0x09U) +#define USB_DESCRIPTOR_LENGTH_ENDPOINT (0x07U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_QUALITIER (0x0AU) +#define USB_DESCRIPTOR_LENGTH_OTG_DESCRIPTOR (5U) +#define USB_DESCRIPTOR_LENGTH_BOS_DESCRIPTOR (5U) + +/* USB Device Capability Type Codes */ +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_WIRELESS (0x01U) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_USB20_EXTENSION (0x02U) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY_SUPERSPEED (0x03U) + +/* USB standard descriptor type */ +#define USB_DESCRIPTOR_TYPE_DEVICE (0x01U) +#define USB_DESCRIPTOR_TYPE_CONFIGURE (0x02U) +#define USB_DESCRIPTOR_TYPE_STRING (0x03U) +#define USB_DESCRIPTOR_TYPE_INTERFACE (0x04U) +#define USB_DESCRIPTOR_TYPE_ENDPOINT (0x05U) +#define USB_DESCRIPTOR_TYPE_DEVICE_QUALITIER (0x06U) +#define USB_DESCRIPTOR_TYPE_OTHER_SPEED_CONFIGURATION (0x07U) +#define USB_DESCRIPTOR_TYPE_INTERFAACE_POWER (0x08U) +#define USB_DESCRIPTOR_TYPE_OTG (0x09U) +#define USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION (0x0BU) +#define USB_DESCRIPTOR_TYPE_BOS (0x0F) +#define USB_DESCRIPTOR_TYPE_DEVICE_CAPABILITY (0x10) + +#define USB_DESCRIPTOR_TYPE_HID (0x21U) +#define USB_DESCRIPTOR_TYPE_HID_REPORT (0x22U) +#define USB_DESCRIPTOR_TYPE_HID_PHYSICAL (0x23U) + +/* USB standard request type */ +#define USB_REQUEST_TYPE_DIR_MASK (0x80U) +#define USB_REQUEST_TYPE_DIR_SHIFT (7U) +#define USB_REQUEST_TYPE_DIR_OUT (0x00U) +#define USB_REQUEST_TYPE_DIR_IN (0x80U) + +#define USB_REQUEST_TYPE_TYPE_MASK (0x60U) +#define USB_REQUEST_TYPE_TYPE_SHIFT (5U) +#define USB_REQUEST_TYPE_TYPE_STANDARD (0U) +#define USB_REQUEST_TYPE_TYPE_CLASS (0x20U) +#define USB_REQUEST_TYPE_TYPE_VENDOR (0x40U) + +#define USB_REQUEST_TYPE_RECIPIENT_MASK (0x1FU) +#define USB_REQUEST_TYPE_RECIPIENT_SHIFT (0U) +#define USB_REQUEST_TYPE_RECIPIENT_DEVICE (0x00U) +#define USB_REQUEST_TYPE_RECIPIENT_INTERFACE (0x01U) +#define USB_REQUEST_TYPE_RECIPIENT_ENDPOINT (0x02U) +#define USB_REQUEST_TYPE_RECIPIENT_OTHER (0x03U) + +/* USB standard request */ +#define USB_REQUEST_STANDARD_GET_STATUS (0x00U) +#define USB_REQUEST_STANDARD_CLEAR_FEATURE (0x01U) +#define USB_REQUEST_STANDARD_SET_FEATURE (0x03U) +#define USB_REQUEST_STANDARD_SET_ADDRESS (0x05U) +#define USB_REQUEST_STANDARD_GET_DESCRIPTOR (0x06U) +#define USB_REQUEST_STANDARD_SET_DESCRIPTOR (0x07U) +#define USB_REQUEST_STANDARD_GET_CONFIGURATION (0x08U) +#define USB_REQUEST_STANDARD_SET_CONFIGURATION (0x09U) +#define USB_REQUEST_STANDARD_GET_INTERFACE (0x0AU) +#define USB_REQUEST_STANDARD_SET_INTERFACE (0x0BU) +#define USB_REQUEST_STANDARD_SYNCH_FRAME (0x0CU) + +/* USB standard request GET Status */ +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_SELF_POWERED_SHIFT (0U) +#define USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT (1U) + +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_MASK (0x01U) +#define USB_REQUEST_STANDARD_GET_STATUS_ENDPOINT_HALT_SHIFT (0U) + +#define USB_REQUEST_STANDARD_GET_STATUS_OTG_STATUS_SELECTOR (0xF000U) + +/* USB standard request CLEAR/SET feature */ +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT (0U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_REMOTE_WAKEUP (1U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE (2U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_B_HNP_ENABLE (3U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_A_HNP_SUPPORT (4U) +#define USB_REQUEST_STANDARD_FEATURE_SELECTOR_A_ALT_HNP_SUPPORT (5U) + +/* USB standard descriptor configure bmAttributes */ +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_MASK (0x80U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_D7_SHIFT (7U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_MASK (0x40U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_SHIFT (6U) + +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_MASK (0x20U) +#define USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_REMOTE_WAKEUP_SHIFT (5U) + +/* USB standard descriptor endpoint bmAttributes */ +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK (0x80U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT (7U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT (0U) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN (0x80U) + +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK (0x0FU) +#define USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK (0x03U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_NUMBER_SHFIT (0U) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_MASK (0x0CU) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SHFIT (2U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_NO_SYNC (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ASYNC (0x04U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_ADAPTIVE (0x08U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_SYNC_TYPE_SYNC (0x0CU) + +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_MASK (0x30U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_SHFIT (4U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_DATA_ENDPOINT (0x00U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_FEEDBACK_ENDPOINT (0x10U) +#define USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_USAGE_TYPE_IMPLICIT_FEEDBACK_DATA_ENDPOINT (0x20U) + +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK (0x07FFu) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK (0x1800u) +#define USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT (11U) + +/* USB standard descriptor otg bmAttributes */ +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_SRP_MASK (0x01u) +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_HNP_MASK (0x02u) +#define USB_DESCRIPTOR_OTG_ATTRIBUTES_ADP_MASK (0x04u) + +/* USB standard descriptor device capability usb20 extension bmAttributes */ +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_LPM_MASK (0x02U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_LPM_SHIFT (1U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_BESL_MASK (0x04U) +#define USB_DESCRIPTOR_DEVICE_CAPABILITY_USB20_EXTENSION_BESL_SHIFT (2U) + + +/* Language structure */ +typedef struct _usb_language +{ + uint8_t **string; /* The Strings descriptor array */ + uint32_t *length; /* The strings descriptor length array */ + uint16_t languageId; /* The language id of current language */ +} usb_language_t; + +typedef struct _usb_language_list +{ + uint8_t *languageString; /* The String 0U pointer */ + uint32_t stringLength; /* The String 0U Length */ + usb_language_t *languageList; /* The language list */ + uint8_t count; /* The language count */ +} usb_language_list_t; + +typedef struct _usb_descriptor_common +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bData[1]; /* Data */ +} usb_descriptor_common_t; + +typedef struct _usb_descriptor_device +{ + uint8_t bLength; /* Size of this descriptor in bytes */ + uint8_t bDescriptorType; /* DEVICE Descriptor Type */ + uint8_t bcdUSB[2]; /* UUSB Specification Release Number in Binary-Coded Decimal, e.g. 0x0200U */ + uint8_t bDeviceClass; /* Class code */ + uint8_t bDeviceSubClass; /* Sub-Class code */ + uint8_t bDeviceProtocol; /* Protocol code */ + uint8_t bMaxPacketSize0; /* Maximum packet size for endpoint zero */ + uint8_t idVendor[2]; /* Vendor ID (assigned by the USB-IF) */ + uint8_t idProduct[2]; /* Product ID (assigned by the manufacturer) */ + uint8_t bcdDevice[2]; /* Device release number in binary-coded decimal */ + uint8_t iManufacturer; /* Index of string descriptor describing manufacturer */ + uint8_t iProduct; /* Index of string descriptor describing product */ + uint8_t iSerialNumber; /* Index of string descriptor describing the device serial number */ + uint8_t bNumConfigurations; /* Number of possible configurations */ +} usb_descriptor_device_t; + +typedef struct _usb_descriptor_configuration +{ + uint8_t bLength; /* Descriptor size in bytes = 9U */ + uint8_t bDescriptorType; /* CONFIGURATION type = 2U or 7U */ + uint8_t wTotalLength[2]; /* Length of concatenated descriptors */ + uint8_t bNumInterfaces; /* Number of interfaces, this configuration. */ + uint8_t bConfigurationValue; /* Value to set this configuration. */ + uint8_t iConfiguration; /* Index to configuration string */ + uint8_t bmAttributes; /* Configuration characteristics */ + uint8_t bMaxPower; /* Maximum power from bus, 2 mA units */ +} usb_descriptor_configuration_t; + +typedef struct _usb_descriptor_interface +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_descriptor_interface_t; + +typedef struct _usb_descriptor_endpoint +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSize[2]; + uint8_t bInterval; +} usb_descriptor_endpoint_t; + +typedef struct _usb_descriptor_binary_device_object_store +{ + uint8_t bLength; /* Descriptor size in bytes = 5U */ + uint8_t bDescriptorType; /* BOS Descriptor type = 0FU*/ + uint8_t wTotalLength[2]; /*Length of this descriptor and all of its sub descriptors*/ + uint8_t bNumDeviceCaps; /*The number of separate device capability descriptors in the BOS*/ +} usb_descriptor_bos_t; + +typedef struct _usb_descriptor_usb20_extension +{ + uint8_t bLength; /* Descriptor size in bytes = 7U */ + uint8_t bDescriptorType; /* DEVICE CAPABILITY Descriptor type = 0x10U*/ + uint8_t bDevCapabilityType; /*Length of this descriptor and all of its sub descriptors*/ + uint8_t bmAttributes[4]; /*Bitmap encoding of supported device level features.*/ +} usb_descriptor_usb20_extension_t; + +typedef union _usb_descriptor_union +{ + usb_descriptor_common_t common; /* Common descriptor */ + usb_descriptor_device_t device; /* Device descriptor */ + usb_descriptor_configuration_t configuration; /* Configuration descriptor */ + usb_descriptor_interface_t interface; /* Interface descriptor */ + usb_descriptor_endpoint_t endpoint; /* Endpoint descriptor */ +} usb_descriptor_union_t; + +#endif /* __USB_SPEC_H__ */ diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.c b/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.c new file mode 100644 index 00000000..11651b1d --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.c @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#include "MK22F51212.h" +#include "gpio.h" + +#include +#include +#include + +#include "usb_device_config.h" +#include "usb.h" +#include "usb_device.h" + +#include "usb_device_cdc_acm.h" +#include "usb_device_ch9.h" +// #include "fsl_debug_console.h" + +#include "usb_device_descriptor.h" +#include "virtual_com.h" +#if (defined(FSL_FEATURE_SOC_SYSMPU_COUNT) && (FSL_FEATURE_SOC_SYSMPU_COUNT > 0U)) +#include "fsl_sysmpu.h" +#endif /* FSL_FEATURE_SOC_SYSMPU_COUNT */ +#if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0) +#include "usb_phy.h" +#endif +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) +#include "fsl_smc.h" +#endif + +#include "fsl_common.h" + +/******************************************************************************* +* Definitions +******************************************************************************/ +/* USB clock source and frequency*/ +#define USB_FS_CLK_SRC kCLOCK_UsbSrcIrc48M +#define USB_FS_CLK_FREQ 48000000U + +/******************************************************************************* +* Variables +******************************************************************************/ +/* Data structure of virtual com device */ +static usb_cdc_vcom_struct_t s_cdcVcom; + +/* Line codinig of cdc device */ +static uint8_t s_lineCoding[LINE_CODING_SIZE] = { + /* E.g. 0x00,0xC2,0x01,0x00 : 0x0001C200 is 115200 bits per second */ + (LINE_CODING_DTERATE >> 0U) & 0x000000FFU, + (LINE_CODING_DTERATE >> 8U) & 0x000000FFU, + (LINE_CODING_DTERATE >> 16U) & 0x000000FFU, + (LINE_CODING_DTERATE >> 24U) & 0x000000FFU, + LINE_CODING_CHARFORMAT, + LINE_CODING_PARITYTYPE, + LINE_CODING_DATABITS}; + +/* Abstract state of cdc device */ +static uint8_t s_abstractState[COMM_FEATURE_DATA_SIZE] = {(STATUS_ABSTRACT_STATE >> 0U) & 0x00FFU, + (STATUS_ABSTRACT_STATE >> 8U) & 0x00FFU}; + +/* Country code of cdc device */ +static uint8_t s_countryCode[COMM_FEATURE_DATA_SIZE] = {(COUNTRY_SETTING >> 0U) & 0x00FFU, + (COUNTRY_SETTING >> 8U) & 0x00FFU}; + +/* CDC ACM information */ +USB_DATA_ALIGNMENT static usb_cdc_acm_info_t s_usbCdcAcmInfo = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0}; +/* Data buffer for receiving and sending*/ +USB_DATA_ALIGNMENT static uint8_t s_currRecvBuf[DATA_BUFF_SIZE]; +USB_DATA_ALIGNMENT static uint8_t s_currSendBuf[DATA_BUFF_SIZE]; +volatile static uint32_t s_recvSize = 0; +volatile static uint32_t s_sendSize = 0; +static uint32_t s_usbBulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) +volatile static uint8_t s_waitForDataReceive = 0; +volatile static uint8_t s_comOpen = 0; +#endif +/******************************************************************************* +* Prototypes +******************************************************************************/ + +/******************************************************************************* +* Code +******************************************************************************/ +/*! + * @brief Interrupt in pipe callback function. + * + * This function serves as the callback function for interrupt in pipe. + * + * @param handle The USB device handle. + * @param message The endpoint callback message + * @param callbackParam The parameter of the callback. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceCdcAcmInterruptIn(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_status_t error = kStatus_USB_Error; + s_cdcVcom.hasSentState = 0; + return error; +} + +/*! + * @brief Bulk in pipe callback function. + * + * This function serves as the callback function for bulk in pipe. + * + * @param handle The USB device handle. + * @param message The endpoint callback message + * @param callbackParam The parameter of the callback. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_status_t error = kStatus_USB_Error; + + if ((message->length != 0) && (!(message->length % s_usbBulkMaxPacketSize))) + { + /* If the last packet is the size of endpoint, then send also zero-ended packet, + ** meaning that we want to inform the host that we do not have any additional + ** data, so it can flush the output. + */ + USB_DeviceSendRequest(handle, USB_CDC_VCOM_BULK_IN_ENDPOINT, NULL, 0); + } + else if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) + { + if ((message->buffer != NULL) || ((message->buffer == NULL) && (message->length == 0))) + { + /* User: add your own code for send complete event */ + /* Schedule buffer for next receive event */ + USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize); +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + s_waitForDataReceive = 1; + USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK; +#endif + } + } + else + { + } + return error; +} + +/*! + * @brief Bulk out pipe callback function. + * + * This function serves as the callback function for bulk out pipe. + * + * @param handle The USB device handle. + * @param message The endpoint callback message + * @param callbackParam The parameter of the callback. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle, + usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_status_t error = kStatus_USB_Error; + + if ((1 == s_cdcVcom.attach) && (1 == s_cdcVcom.startTransactions)) + { + s_recvSize = message->length; + +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + s_waitForDataReceive = 0; + USB0->INTEN |= USB_INTEN_SOFTOKEN_MASK; +#endif + if (!s_recvSize) + { + /* Schedule buffer for next receive event */ + USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, s_usbBulkMaxPacketSize); +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + s_waitForDataReceive = 1; + USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK; +#endif + } + } + return error; +} + +/*! + * @brief Get the setup packet buffer. + * + * This function provides the buffer for setup packet. + * + * @param handle The USB device handle. + * @param setupBuffer The pointer to the address of setup packet buffer. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetSetupBuffer(usb_device_handle handle, usb_setup_struct_t **setupBuffer) +{ + static uint32_t cdcVcomSetup[2]; + if (NULL == setupBuffer) + { + return kStatus_USB_InvalidParameter; + } + *setupBuffer = (usb_setup_struct_t *)&cdcVcomSetup; + return kStatus_USB_Success; +} + +/*! + * @brief Get the setup packet data buffer. + * + * This function gets the data buffer for setup packet. + * + * @param handle The USB device handle. + * @param setup The pointer to the setup packet. + * @param length The pointer to the length of the data buffer. + * @param buffer The pointer to the address of setup packet data buffer. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceGetClassReceiveBuffer(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer) +{ + static uint8_t setupOut[8]; + if ((NULL == buffer) || ((*length) > sizeof(setupOut))) + { + return kStatus_USB_InvalidRequest; + } + *buffer = setupOut; + return kStatus_USB_Success; +} + +/*! + * @brief Configure remote wakeup feature. + * + * This function configures the remote wakeup feature. + * + * @param handle The USB device handle. + * @param enable 1: enable, 0: disable. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceConfigureRemoteWakeup(usb_device_handle handle, uint8_t enable) +{ + return kStatus_USB_InvalidRequest; +} + +/*! + * @brief CDC class specific callback function. + * + * This function handles the CDC class specific requests. + * + * @param handle The USB device handle. + * @param setup The pointer to the setup packet. + * @param length The pointer to the length of the data buffer. + * @param buffer The pointer to the address of setup packet data buffer. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceProcessClassRequest(usb_device_handle handle, + usb_setup_struct_t *setup, + uint32_t *length, + uint8_t **buffer) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + + usb_cdc_acm_info_t *acmInfo = &s_usbCdcAcmInfo; + uint32_t len; + uint16_t *uartBitmap; + if (setup->wIndex != USB_CDC_VCOM_COMM_INTERFACE_INDEX) + { + return error; + } + + switch (setup->bRequest) + { + case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND: + break; + case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE: + break; + case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE: + if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) + { + *buffer = s_abstractState; + } + else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) + { + *buffer = s_countryCode; + } + else + { + } + error = kStatus_USB_Success; + break; + case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE: + if (USB_DEVICE_CDC_FEATURE_ABSTRACT_STATE == setup->wValue) + { + *buffer = s_abstractState; + *length = COMM_FEATURE_DATA_SIZE; + } + else if (USB_DEVICE_CDC_FEATURE_COUNTRY_SETTING == setup->wValue) + { + *buffer = s_countryCode; + *length = COMM_FEATURE_DATA_SIZE; + } + else + { + } + error = kStatus_USB_Success; + break; + case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE: + break; + case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING: + *buffer = s_lineCoding; + *length = LINE_CODING_SIZE; + error = kStatus_USB_Success; + break; + case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING: + *buffer = s_lineCoding; + error = kStatus_USB_Success; + break; + case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE: + { + error = kStatus_USB_Success; + acmInfo->dteStatus = setup->wValue; + /* activate/deactivate Tx carrier */ + if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) + { + acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_TX_CARRIER; + } + else + { + acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_TX_CARRIER; + } + + /* activate carrier and DTE */ + if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) + { + acmInfo->uartState |= USB_DEVICE_CDC_UART_STATE_RX_CARRIER; + } + else + { + acmInfo->uartState &= (uint16_t)~USB_DEVICE_CDC_UART_STATE_RX_CARRIER; + } + + /* Indicates to DCE if DTE is present or not */ + acmInfo->dtePresent = (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) ? true : false; + + /* Initialize the serial state buffer */ + acmInfo->serialStateBuf[0] = NOTIF_REQUEST_TYPE; /* bmRequestType */ + acmInfo->serialStateBuf[1] = USB_DEVICE_CDC_REQUEST_SERIAL_STATE_NOTIF; /* bNotification */ + acmInfo->serialStateBuf[2] = 0x00; /* wValue */ + acmInfo->serialStateBuf[3] = 0x00; + acmInfo->serialStateBuf[4] = 0x00; /* wIndex */ + acmInfo->serialStateBuf[5] = 0x00; + acmInfo->serialStateBuf[6] = UART_BITMAP_SIZE; /* wLength */ + acmInfo->serialStateBuf[7] = 0x00; + /* Notifiy to host the line state */ + acmInfo->serialStateBuf[4] = setup->wIndex; + /* Lower byte of UART BITMAP */ + uartBitmap = (uint16_t *)&acmInfo->serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE - 2]; + *uartBitmap = acmInfo->uartState; + len = (uint32_t)(NOTIF_PACKET_SIZE + UART_BITMAP_SIZE); + if (0 == s_cdcVcom.hasSentState) + { + error = USB_DeviceSendRequest(handle, USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT, acmInfo->serialStateBuf, len); + if (kStatus_USB_Success != error) + { + usb_echo("kUSB_DeviceCdcEventSetControlLineState error!"); + } + s_cdcVcom.hasSentState = 1; + } + /* Update status */ + if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_CARRIER_ACTIVATION) + { + /* To do: CARRIER_ACTIVATED */ + } + else + { + /* To do: CARRIER_DEACTIVATED */ + } + if (acmInfo->dteStatus & USB_DEVICE_CDC_CONTROL_SIG_BITMAP_DTE_PRESENCE) + { + /* DTE_ACTIVATED */ + if (1 == s_cdcVcom.attach) + { + s_cdcVcom.startTransactions = 1; +#if defined(FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED) && (FSL_FEATURE_USB_KHCI_KEEP_ALIVE_ENABLED > 0U) && \ + defined(USB_DEVICE_CONFIG_KEEP_ALIVE_MODE) && (USB_DEVICE_CONFIG_KEEP_ALIVE_MODE > 0U) && \ + defined(FSL_FEATURE_USB_KHCI_USB_RAM) && (FSL_FEATURE_USB_KHCI_USB_RAM > 0U) + s_waitForDataReceive = 1; + USB0->INTEN &= ~USB_INTEN_SOFTOKEN_MASK; + s_comOpen = 1; + usb_echo("USB_APP_CDC_DTE_ACTIVATED\r\n"); +#endif + } + } + else + { + /* DTE_DEACTIVATED */ + if (1 == s_cdcVcom.attach) + { + s_cdcVcom.startTransactions = 0; + } + } + } + break; + case USB_DEVICE_CDC_REQUEST_SEND_BREAK: + break; + default: + break; + } + + return error; +} + +/*! + * @brief USB device callback function. + * + * This function handles the usb device specific requests. + * + * @param handle The USB device handle. + * @param event The USB device event type. + * @param param The parameter of the device specific request. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceCallback(usb_device_handle handle, uint32_t event, void *param) +{ + usb_status_t error = kStatus_USB_Error; + uint8_t *temp8 = (uint8_t *)param; + + switch (event) + { + case kUSB_DeviceEventBusReset: + { + USB_DeviceControlPipeInit(s_cdcVcom.deviceHandle); + s_cdcVcom.attach = 0; + } + break; + case kUSB_DeviceEventSetConfiguration: + if (param) + { + s_cdcVcom.attach = 1; + s_cdcVcom.currentConfiguration = *temp8; + if (USB_CDC_VCOM_CONFIGURE_INDEX == (*temp8)) + { + usb_device_endpoint_init_struct_t epInitStruct; + usb_device_endpoint_callback_struct_t endpointCallback; + + /* Initiailize endpoint for interrupt pipe */ + endpointCallback.callbackFn = USB_DeviceCdcAcmInterruptIn; + endpointCallback.callbackParam = handle; + + epInitStruct.zlt = 0; + epInitStruct.transferType = USB_ENDPOINT_INTERRUPT; + epInitStruct.endpointAddress = USB_CDC_VCOM_INTERRUPT_IN_ENDPOINT | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + if (USB_SPEED_HIGH == s_cdcVcom.speed) + { + epInitStruct.maxPacketSize = HS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE; + } + else + { + epInitStruct.maxPacketSize = FS_CDC_VCOM_INTERRUPT_IN_PACKET_SIZE; + } + + USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback); + + /* Initiailize endpoints for bulk pipe */ + endpointCallback.callbackFn = USB_DeviceCdcAcmBulkIn; + endpointCallback.callbackParam = handle; + + epInitStruct.zlt = 0; + epInitStruct.transferType = USB_ENDPOINT_BULK; + epInitStruct.endpointAddress = + USB_CDC_VCOM_BULK_IN_ENDPOINT | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + if (USB_SPEED_HIGH == s_cdcVcom.speed) + { + epInitStruct.maxPacketSize = HS_CDC_VCOM_BULK_IN_PACKET_SIZE; + } + else + { + epInitStruct.maxPacketSize = FS_CDC_VCOM_BULK_IN_PACKET_SIZE; + } + + USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback); + + endpointCallback.callbackFn = USB_DeviceCdcAcmBulkOut; + endpointCallback.callbackParam = handle; + + epInitStruct.zlt = 0; + epInitStruct.transferType = USB_ENDPOINT_BULK; + epInitStruct.endpointAddress = + USB_CDC_VCOM_BULK_OUT_ENDPOINT | (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + if (USB_SPEED_HIGH == s_cdcVcom.speed) + { + epInitStruct.maxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + else + { + epInitStruct.maxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + + USB_DeviceInitEndpoint(s_cdcVcom.deviceHandle, &epInitStruct, &endpointCallback); + + if (USB_SPEED_HIGH == s_cdcVcom.speed) + { + s_usbBulkMaxPacketSize = HS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + else + { + s_usbBulkMaxPacketSize = FS_CDC_VCOM_BULK_OUT_PACKET_SIZE; + } + /* Schedule buffer for receive */ + USB_DeviceRecvRequest(handle, USB_CDC_VCOM_BULK_OUT_ENDPOINT, s_currRecvBuf, + s_usbBulkMaxPacketSize); + } + } + break; + default: + break; + } + + return error; +} + +/*! + * @brief USB configure endpoint function. + * + * This function configure endpoint status. + * + * @param handle The USB device handle. + * @param ep Endpoint address. + * @param status A flag to indicate whether to stall the endpoint. 1: stall, 0: unstall. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceConfigureEndpointStatus(usb_device_handle handle, uint8_t ep, uint8_t status) +{ + if (status) + { + return USB_DeviceStallEndpoint(handle, ep); + } + else + { + return USB_DeviceUnstallEndpoint(handle, ep); + } +} + +/*! + * @brief USB Interrupt service routine. + * + * This function serves as the USB interrupt service routine. + * + * @return None. + */ +void USB0_IRQHandler(void) +{ + USB_DeviceKhciIsrFunction(s_cdcVcom.deviceHandle); +} + +/*! + * @brief Application initialization function. + * + * This function initializes the application. + * + * @return None. + */ +void APPInit(void) +{ + + + SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0) + | SIM_CLKDIV2_USBFRAC(0); + SIM->SOPT2 = SIM_SOPT2_USBSRC(1U) + | SIM_SOPT2_PLLFLLSEL(3U); + SIM->SCGC4 |= SIM_SCGC4_USBOTG(1); + + USB0->CLK_RECOVER_IRC_EN = 0x03U; + USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK; + + s_cdcVcom.speed = USB_SPEED_FULL; + s_cdcVcom.attach = 0; + s_cdcVcom.deviceHandle = NULL; + + if (kStatus_USB_Success != USB_DeviceInit(CONTROLLER_ID, USB_DeviceCallback, &s_cdcVcom.deviceHandle)) + { + usb_echo("USB device vcom failed\r\n"); + return; + } + else + { + usb_echo("USB device CDC virtual com demo\r\n"); + } + + NVIC_SetPriority(USB0_IRQn, 3); + NVIC_EnableIRQ(USB0_IRQn); + + USB_DeviceRun(s_cdcVcom.deviceHandle); +} + +void APPTest(void) +{ + char *str = "blablabla\r\n"; + memcpy(s_currSendBuf, str, sizeof(str)); + USB_DeviceSendRequest(s_cdcVcom.deviceHandle, USB_CDC_VCOM_BULK_IN_ENDPOINT, + s_currSendBuf, sizeof(str)); +} diff --git a/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.h b/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.h new file mode 100644 index 00000000..ab50c7b9 --- /dev/null +++ b/platform/mcu/MK22FN512xxx12/drivers/usb/virtual_com.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ +#ifndef _USB_CDC_VCOM_H_ +#define _USB_CDC_VCOM_H_ 1 + +#include "usb.h" +#include "usb_device_descriptor.h" + +/******************************************************************************* +* Definitions +******************************************************************************/ +#if defined(USB_DEVICE_CONFIG_EHCI) && (USB_DEVICE_CONFIG_EHCI > 0) +#define CONTROLLER_ID kUSB_ControllerEhci0 +#define DATA_BUFF_SIZE HS_CDC_VCOM_BULK_OUT_PACKET_SIZE + +#endif +#if defined(USB_DEVICE_CONFIG_KHCI) && (USB_DEVICE_CONFIG_KHCI > 0) +#define CONTROLLER_ID kUSB_ControllerKhci0 +#define DATA_BUFF_SIZE FS_CDC_VCOM_BULK_OUT_PACKET_SIZE + +#endif +#if defined(USB_DEVICE_CONFIG_LPCIP3511FS) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Fs0 +#define DATA_BUFF_SIZE FS_CDC_VCOM_BULK_OUT_PACKET_SIZE + +#endif + +#if defined(USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U) +#define CONTROLLER_ID kUSB_ControllerLpcIp3511Hs0 +#define DATA_BUFF_SIZE HS_CDC_VCOM_BULK_OUT_PACKET_SIZE +#endif + +#define USB_DEVICE_INTERRUPT_PRIORITY (3U) + +/* Currently configured line coding */ +#define LINE_CODING_SIZE (0x07) +#define LINE_CODING_DTERATE (115200) +#define LINE_CODING_CHARFORMAT (0x00) +#define LINE_CODING_PARITYTYPE (0x00) +#define LINE_CODING_DATABITS (0x08) + +/* Communications feature */ +#define COMM_FEATURE_DATA_SIZE (0x02) +#define STATUS_ABSTRACT_STATE (0x0000) +#define COUNTRY_SETTING (0x0000) + +/* Notification of serial state */ +#define NOTIF_PACKET_SIZE (0x08) +#define UART_BITMAP_SIZE (0x02) +#define NOTIF_REQUEST_TYPE (0xA1) + +/* Define the types for application */ +typedef struct _usb_cdc_vcom_struct +{ + usb_device_handle deviceHandle; /* USB device handle. */ + volatile uint8_t attach; /* A flag to indicate whether a usb device is attached. 1: attached, 0: not attached */ + uint8_t speed; /* Speed of USB device. USB_SPEED_FULL/USB_SPEED_LOW/USB_SPEED_HIGH. */ + volatile uint8_t + startTransactions; /* A flag to indicate whether a CDC device is ready to transmit and receive data. */ + uint8_t currentConfiguration; /* Current configuration value. */ + uint8_t currentInterfaceAlternateSetting + [USB_CDC_VCOM_INTERFACE_COUNT]; /* Current alternate setting value for each interface. */ + uint8_t hasSentState; /*!< 1: The device has primed the state in interrupt pipe, 0: Not primed the state. */ +} usb_cdc_vcom_struct_t; + +/* Define the infomation relates to abstract control model */ +typedef struct _usb_cdc_acm_info +{ + uint8_t serialStateBuf[NOTIF_PACKET_SIZE + UART_BITMAP_SIZE]; /* Serial state buffer of the CDC device to notify the + serial state to host. */ + bool dtePresent; /* A flag to indicate whether DTE is present. */ + uint16_t breakDuration; /* Length of time in milliseconds of the break signal */ + uint8_t dteStatus; /* Status of data terminal equipment */ + uint8_t currentInterface; /* Current interface index. */ + uint16_t uartState; /* UART state of the CDC device. */ +} usb_cdc_acm_info_t; +#endif /* _USB_CDC_VCOM_H_ */