diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/mbed_overrides.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/mbed_overrides.c index 63fd85d1f6..09c66522b6 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/mbed_overrides.c +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/mbed_overrides.c @@ -1,5 +1,6 @@ /* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited + * Copyright (c) 2006-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,9 +21,17 @@ #include "fsl_iomuxc.h" #include "fsl_gpio.h" #include "lpm.h" +#include "usb_phy.h" +#include "usb_device_config.h" #define LPSPI_CLOCK_SOURCE_DIVIDER (7U) #define LPI2C_CLOCK_SOURCE_DIVIDER (5U) + +/* USB PHY condfiguration */ +#define BOARD_USB_PHY_D_CAL (0x0CU) +#define BOARD_USB_PHY_TXCAL45DP (0x06U) +#define BOARD_USB_PHY_TXCAL45DM (0x06U) + uint8_t mbed_otp_mac_address(char *mac); void mbed_default_mac_address(char *mac); @@ -311,3 +320,28 @@ void mbed_default_mac_address(char *mac) { return; } + +void USB_DeviceClockInit(void) +{ + usb_phy_config_struct_t phyConfig = { + BOARD_USB_PHY_D_CAL, + BOARD_USB_PHY_TXCAL45DP, + BOARD_USB_PHY_TXCAL45DM, + }; + + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); + + USB_EhciPhyInit(CONTROLLER_ID, BOARD_XTAL0_CLK_HZ, &phyConfig); +} + +uint32_t USB_DeviceGetIrqNumber(void) +{ + uint8_t irqNumber; + + uint8_t usbDeviceEhciIrq[] = USBHS_IRQS; + irqNumber = usbDeviceEhciIrq[CONTROLLER_ID - kUSB_ControllerEhci0]; + + return irqNumber; +} + diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.c new file mode 100644 index 0000000000..61bf4dd813 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.c @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" +#include "usb_device_class.h" +#include "usb_device_ch9.h" +#if ((defined(USB_DEVICE_CONFIG_NUM)) && (USB_DEVICE_CONFIG_NUM > 0U)) +/******************************************************************************* + * 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static usb_status_t USB_DeviceCh9GetStatus(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetClearFeature(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); + +static usb_status_t USB_DeviceCh9SetAddress(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetDescriptor(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetConfiguration(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetConfiguration(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9GetInterface(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SetInterface(usb_device_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length); +static usb_status_t USB_DeviceCh9SynchFrame(usb_device_common_class_struct_t *classHandle, + 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_DeviceCh9GetConfiguration, + USB_DeviceCh9SetConfiguration, + USB_DeviceCh9GetInterface, + USB_DeviceCh9SetInterface, + USB_DeviceCh9SynchFrame, +}; + +/******************************************************************************* + * 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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(classHandle->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) + { +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + if (setup->wIndex == USB_REQUEST_STANDARD_GET_STATUS_OTG_STATUS_SELECTOR) + { + error = + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusOtg, &classHandle->standardTranscationBuffer); + classHandle->standardTranscationBuffer = USB_SHORT_TO_LITTLE_ENDIAN(classHandle->standardTranscationBuffer); + /* The device status length must be USB_DEVICE_STATUS_SIZE. */ + *length = 1; + } + else /* Get the device status */ + { +#endif + error = USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDevice, + &classHandle->standardTranscationBuffer); + classHandle->standardTranscationBuffer = + classHandle->standardTranscationBuffer & USB_GET_STATUS_DEVICE_MASK; + classHandle->standardTranscationBuffer = USB_SHORT_TO_LITTLE_ENDIAN(classHandle->standardTranscationBuffer); + /* The device status length must be USB_DEVICE_STATUS_SIZE. */ + *length = USB_DEVICE_STATUS_SIZE; +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + } +#endif + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_INTERFACE) + { + /* Get the interface status */ + error = kStatus_USB_Success; + classHandle->standardTranscationBuffer = 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(classHandle->handle, kUSB_DeviceStatusEndpoint, &endpointStatus); + classHandle->standardTranscationBuffer = endpointStatus.endpointStatus & USB_GET_STATUS_ENDPOINT_MASK; + classHandle->standardTranscationBuffer = USB_SHORT_TO_LITTLE_ENDIAN(classHandle->standardTranscationBuffer); + /* The endpoint status length must be USB_INTERFACE_STATUS_SIZE. */ + *length = USB_ENDPOINT_STATUS_SIZE; + } + else + { + } + *buffer = (uint8_t *)&classHandle->standardTranscationBuffer; + + 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 request 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_common_class_struct_t *classHandle, + 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(classHandle->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 feature. */ + 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 feature. */ + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetRemoteWakeup, &isSet); + } +#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)) + else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_DEVICE_TEST_MODE == setup->wValue) + { + state = kUSB_DeviceStateTestMode; + error = USB_DeviceSetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + } +#endif +#if (defined(USB_DEVICE_CONFIG_OTG) && (USB_DEVICE_CONFIG_OTG)) + else if (USB_REQUEST_STANDARD_FEATURE_SELECTOR_B_HNP_ENABLE == setup->wValue) + { + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetBHNPEnable, &isSet); + } +#endif + else + { + } + } + else if ((setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) == USB_REQUEST_TYPE_RECIPIENT_ENDPOINT) + { + /* Set or Clear the endpoint feature. */ + 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(classHandle->handle, (uint8_t)setup->wIndex); + } + else + { + USB_DeviceUnstallEndpoint(classHandle->handle, (uint8_t)setup->wIndex); + } + } + + /* Set or Clear the endpoint status feature. */ + if (isSet) + { + error = USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetEndpointHalt, &setup->wIndex); + } + else + { + error = + USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventClearEndpointHalt, &setup->wIndex); + } + } + 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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddressing != state) && (kUSB_DeviceStateAddress != state) && + (kUSB_DeviceStateDefault != state) && (kUSB_DeviceStateConfigured != 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(classHandle->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(classHandle->handle, kUSB_DeviceStatusAddress, NULL); + /* And then change the device state to kUSB_DeviceStateAddress. */ + if (kStatus_USB_Success == error) + { + state = kUSB_DeviceStateAddress; + error = USB_DeviceSetStatus(classHandle->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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_device_get_descriptor_common_union_t commonDescriptor; + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + uint8_t descriptorType = (uint8_t)((setup->wValue & 0xFF00U) >> 8U); + uint8_t descriptorIndex = (uint8_t)((setup->wValue & 0x00FFU)); + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && (kUSB_DeviceStateConfigured != state) && + (kUSB_DeviceStateDefault != state)) + { + return error; + } + commonDescriptor.commonDescriptor.length = setup->wLength; + if (USB_DESCRIPTOR_TYPE_DEVICE == descriptorType) + { + /* Get the device descriptor */ + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetDeviceDescriptor, + &commonDescriptor.deviceDescriptor); + } + else if (USB_DESCRIPTOR_TYPE_CONFIGURE == descriptorType) + { + /* Get the configuration descriptor */ + commonDescriptor.configurationDescriptor.configuration = descriptorIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetConfigurationDescriptor, + &commonDescriptor.configurationDescriptor); + } + else if (USB_DESCRIPTOR_TYPE_STRING == descriptorType) + { + /* Get the string descriptor */ + commonDescriptor.stringDescriptor.stringIndex = descriptorIndex; + commonDescriptor.stringDescriptor.languageId = setup->wIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetStringDescriptor, + &commonDescriptor.stringDescriptor); + } +#if (defined(USB_DEVICE_CONFIG_HID) && (USB_DEVICE_CONFIG_HID > 0U)) + else if (USB_DESCRIPTOR_TYPE_HID == descriptorType) + { + /* Get the hid descriptor */ + commonDescriptor.hidDescriptor.interfaceNumber = setup->wIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetHidDescriptor, + &commonDescriptor.hidDescriptor); + } + else if (USB_DESCRIPTOR_TYPE_HID_REPORT == descriptorType) + { + /* Get the hid report descriptor */ + commonDescriptor.hidReportDescriptor.interfaceNumber = setup->wIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetHidReportDescriptor, + &commonDescriptor.hidReportDescriptor); + } + else if (USB_DESCRIPTOR_TYPE_HID_PHYSICAL == descriptorType) + { + /* Get the hid physical descriptor */ + commonDescriptor.hidPhysicalDescriptor.index = descriptorIndex; + commonDescriptor.hidPhysicalDescriptor.interfaceNumber = setup->wIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetHidPhysicalDescriptor, + &commonDescriptor.hidPhysicalDescriptor); + } +#endif +#if (defined(USB_DEVICE_CONFIG_CV_TEST) && (USB_DEVICE_CONFIG_CV_TEST > 0U)) + else if (USB_DESCRIPTOR_TYPE_DEVICE_QUALITIER == descriptorType) + { + /* Get the device descriptor */ + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetDeviceQualifierDescriptor, + &commonDescriptor.deviceDescriptor); + } +#endif +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + else if (USB_DESCRIPTOR_TYPE_BOS == descriptorType) + { + /* Get the configuration descriptor */ + commonDescriptor.configurationDescriptor.configuration = descriptorIndex; + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetBOSDescriptor, + &commonDescriptor.configurationDescriptor); + } +#endif + else + { + } + *buffer = commonDescriptor.commonDescriptor.buffer; + *length = commonDescriptor.commonDescriptor.length; + return error; +} + +/*! + * @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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if ((kUSB_DeviceStateAddress != state) && ((kUSB_DeviceStateConfigured != state))) + { + return kStatus_USB_InvalidRequest; + } + + *length = USB_CONFIGURE_SIZE; + *buffer = (uint8_t *)&classHandle->standardTranscationBuffer; + return USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetConfiguration, + &classHandle->standardTranscationBuffer); +} + +/*! + * @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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(classHandle->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(classHandle->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(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + } + + /* Notify the class layer the configuration is changed */ + USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetConfiguration, &setup->wValue); + /* Notify the application the configuration is changed */ + return USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetConfiguration, &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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + *length = USB_INTERFACE_SIZE; + *buffer = (uint8_t *)&classHandle->standardTranscationBuffer; + classHandle->standardTranscationBuffer = (uint16_t)(((uint32_t)setup->wIndex & 0xFFU) << 8U); + /* The Bit[15~8] is used to save the interface index, and the alternate setting will be saved in Bit[7~0] by + * application. */ + error = USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventGetInterface, + &classHandle->standardTranscationBuffer); + classHandle->standardTranscationBuffer = USB_SHORT_TO_LITTLE_ENDIAN(classHandle->standardTranscationBuffer); + return error; +} + +/*! + * @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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + uint8_t state; + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return kStatus_USB_InvalidRequest; + } + classHandle->standardTranscationBuffer = ((setup->wIndex & 0xFFU) << 8U) | (setup->wValue & 0xFFU); + /* Notify the class driver the alternate setting of the interface is changed. */ + /* The Bit[15~8] is used to save the interface index, and the alternate setting is saved in Bit[7~0]. */ + USB_DeviceClassEvent(classHandle->handle, kUSB_DeviceClassEventSetInterface, + &classHandle->standardTranscationBuffer); + /* Notify the application the alternate setting of the interface is changed. */ + /* The Bit[15~8] is used to save the interface index, and the alternate setting will is saved in Bit[7~0]. */ + return USB_DeviceClassCallback(classHandle->handle, kUSB_DeviceEventSetInterface, + &classHandle->standardTranscationBuffer); +} + +/*! + * @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 request 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_common_class_struct_t *classHandle, + usb_setup_struct_t *setup, + uint8_t **buffer, + uint32_t *length) +{ + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusDeviceState, &state); + + if (state != kUSB_DeviceStateConfigured) + { + return error; + } + + classHandle->standardTranscationBuffer = USB_SHORT_FROM_LITTLE_ENDIAN(setup->wIndex); + /* Get the sync frame value */ + error = + USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusSynchFrame, &classHandle->standardTranscationBuffer); + *buffer = (uint8_t *)&classHandle->standardTranscationBuffer; + *length = sizeof(classHandle->standardTranscationBuffer); + + return error; +} + +/*! + * @brief Send the response to the host. + * + * This function is used to send the response 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 function. + * @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 transfser result of a transfer. + * This callback pointer is passed when a specified endpoint initialized 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 parameter 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, *setup; + usb_device_common_class_struct_t *classHandle; + uint8_t *buffer = (uint8_t *)NULL; + uint32_t length = 0U; + usb_status_t error = kStatus_USB_InvalidRequest; + uint8_t state; + + if ((0xFFFFFFFFU == message->length) || (NULL == callbackParam)) + { + return error; + } + + classHandle = (usb_device_common_class_struct_t *)callbackParam; + deviceSetup = (usb_setup_struct_t *)&classHandle->setupBuffer[0]; + 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 reserved 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, callbackParam); + */ + return error; + } + /* Receive a setup request */ + 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, only handle the request in request array. */ + if(deviceSetup->bRequest < (sizeof(s_UsbDeviceStandardRequest)/4)) + { + if (s_UsbDeviceStandardRequest[deviceSetup->bRequest] != (usb_standard_request_callback_t)NULL) + { + error = s_UsbDeviceStandardRequest[deviceSetup->bRequest](classHandle, 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. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = (uint8_t *)NULL; + controlRequest.isSetup = 1U; + controlRequest.setup = deviceSetup; + controlRequest.length = deviceSetup->wLength; + error = USB_DeviceClassEvent(handle, kUSB_DeviceClassEventClassRequest, &controlRequest); + length = controlRequest.length; + buffer = controlRequest.buffer; + } + else if ((deviceSetup->wLength) && + ((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_VENDOR) == USB_REQUEST_TYPE_TYPE_VENDOR)) + { + /* Get data buffer to receive the data from the host. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = (uint8_t *)NULL; + controlRequest.isSetup = 1U; + controlRequest.setup = deviceSetup; + controlRequest.length = deviceSetup->wLength; + error = USB_DeviceClassCallback(handle, kUSB_DeviceEventVendorRequest, &controlRequest); + length = controlRequest.length; + buffer = controlRequest.buffer; + } + else + { + } + if (kStatus_USB_Success == error) + { + /* Prime an OUT transfer */ + error = USB_DeviceRecvRequest(handle, USB_CONTROL_ENDPOINT, buffer, 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. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = (uint8_t *)NULL; + controlRequest.isSetup = 1U; + controlRequest.setup = deviceSetup; + controlRequest.length = deviceSetup->wLength; + error = USB_DeviceClassEvent(handle, kUSB_DeviceClassEventClassRequest, &controlRequest); + length = controlRequest.length; + buffer = controlRequest.buffer; + } + else if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_VENDOR) == USB_REQUEST_TYPE_TYPE_VENDOR)) + { + /* Get data buffer to response the host. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = (uint8_t *)NULL; + controlRequest.isSetup = 1U; + controlRequest.setup = deviceSetup; + controlRequest.length = deviceSetup->wLength; + error = USB_DeviceClassCallback(handle, kUSB_DeviceEventVendorRequest, &controlRequest); + length = controlRequest.length; + buffer = controlRequest.buffer; + } + else + { + } + } + } + /* Send the response 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](classHandle, deviceSetup, &buffer, &length); + } +#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)) + 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. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = message->buffer; + controlRequest.isSetup = 0U; + controlRequest.setup = deviceSetup; + controlRequest.length = message->length; + error = USB_DeviceClassEvent(handle, kUSB_DeviceClassEventClassRequest, &controlRequest); + } + else if (((deviceSetup->bmRequestType & USB_REQUEST_TYPE_TYPE_VENDOR) == USB_REQUEST_TYPE_TYPE_VENDOR)) + { + /* Data received in OUT phase, and notify the application. */ + usb_device_control_request_struct_t controlRequest; + controlRequest.buffer = message->buffer; + controlRequest.isSetup = 0U; + controlRequest.setup = deviceSetup; + controlRequest.length = message->length; + error = USB_DeviceClassCallback(handle, kUSB_DeviceEventVendorRequest, &controlRequest); + } + else + { + } + /* Send the response 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, void *param) +{ + usb_device_endpoint_init_struct_t epInitStruct; + usb_device_endpoint_callback_struct_t epCallback; + usb_status_t error; + + epCallback.callbackFn = USB_DeviceControlCallback; + epCallback.callbackParam = param; + + epInitStruct.zlt = 1U; + epInitStruct.transferType = USB_ENDPOINT_CONTROL; + epInitStruct.interval = 0; + 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, &epCallback); + + 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, &epCallback); + + 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; +} +#endif /* USB_DEVICE_CONFIG_NUM */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.h new file mode 100644 index 0000000000..e26d357a30 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_ch9.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DEVICE_CH9_H__ +#define __USB_DEVICE_CH9_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! + * @addtogroup usb_device_ch9 + * @{ + */ +/*! @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; + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the control pipes. + * + * The function is used to initialize the control pipes. This function should be called when event + * kUSB_DeviceEventBusReset is received. + * + * @param[in] handle The device handle. + * @param[in] param The event parameter. + * + * @return A USB error code or kStatus_USB_Success. + */ +extern usb_status_t USB_DeviceControlPipeInit(usb_device_handle handle, void *param); + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* __USB_DEVICE_CH9_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.c new file mode 100644 index 0000000000..9bc94d2156 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_ch9.h" +#include "usb_device_class.h" + +#if ((defined(USB_DEVICE_CONFIG_NUM)) && (USB_DEVICE_CONFIG_NUM > 0U)) +/* Include the class drivers according to the usb_device_config.h. */ +#if ((defined(USB_DEVICE_CONFIG_HID)) && (USB_DEVICE_CONFIG_HID > 0U)) +#include "usb_device_hid.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_CDC_ACM)) && (USB_DEVICE_CONFIG_CDC_ACM > 0U)) +#include "usb_device_cdc_acm.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_MSC)) && (USB_DEVICE_CONFIG_MSC > 0U)) +#include "usb_device_msc.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_AUDIO)) && (USB_DEVICE_CONFIG_AUDIO > 0U)) +#include "usb_device_audio.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_PHDC)) && (USB_DEVICE_CONFIG_PHDC > 0U)) +#include "usb_device_phdc.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_VIDEO)) && (USB_DEVICE_CONFIG_VIDEO > 0U)) +#include "usb_device_video.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_PRINTER)) && (USB_DEVICE_CONFIG_PRINTER > 0U)) +#include "usb_device_printer.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_DFU)) && (USB_DEVICE_CONFIG_DFU > 0U)) +#include "usb_device_dfu.h" +#endif + +#if ((defined(USB_DEVICE_CONFIG_CCID)) && (USB_DEVICE_CONFIG_CCID > 0U)) +#include "usb_device_ccid.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static usb_status_t USB_DeviceClassAllocateHandle(uint8_t controllerId, usb_device_common_class_struct_t **handle); +static usb_status_t USB_DeviceClassFreeHandle(uint8_t controllerId); +static usb_status_t USB_DeviceClassGetHandleByControllerId(uint8_t controllerId, + usb_device_common_class_struct_t **handle); +static usb_status_t USB_DeviceClassGetHandleByDeviceHandle(usb_device_handle deviceHandle, + usb_device_common_class_struct_t **handle); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* The device class driver list. */ +static const usb_device_class_map_t s_UsbDeviceClassInterfaceMap[] = { +#if ((defined(USB_DEVICE_CONFIG_HID)) && (USB_DEVICE_CONFIG_HID > 0U)) + {USB_DeviceHidInit, USB_DeviceHidDeinit, USB_DeviceHidEvent, kUSB_DeviceClassTypeHid}, +#endif + +#if ((defined(USB_DEVICE_CONFIG_CDC_ACM)) && (USB_DEVICE_CONFIG_CDC_ACM > 0U)) + {USB_DeviceCdcAcmInit, USB_DeviceCdcAcmDeinit, USB_DeviceCdcAcmEvent, kUSB_DeviceClassTypeCdc}, +#endif + +#if ((defined(USB_DEVICE_CONFIG_MSC)) && (USB_DEVICE_CONFIG_MSC > 0U)) + {USB_DeviceMscInit, USB_DeviceMscDeinit, USB_DeviceMscEvent, kUSB_DeviceClassTypeMsc}, +#endif + +#if ((defined USB_DEVICE_CONFIG_AUDIO) && (USB_DEVICE_CONFIG_AUDIO > 0U)) + {USB_DeviceAudioInit, USB_DeviceAudioDeinit, USB_DeviceAudioEvent, kUSB_DeviceClassTypeAudio}, +#endif + +#if ((defined USB_DEVICE_CONFIG_PHDC) && (USB_DEVICE_CONFIG_PHDC > 0U)) + {USB_DevicePhdcInit, USB_DevicePhdcDeinit, USB_DevicePhdcEvent, kUSB_DeviceClassTypePhdc}, +#endif + +#if ((defined USB_DEVICE_CONFIG_VIDEO) && (USB_DEVICE_CONFIG_VIDEO > 0U)) + {USB_DeviceVideoInit, USB_DeviceVideoDeinit, USB_DeviceVideoEvent, kUSB_DeviceClassTypeVideo}, +#endif + +#if ((defined USB_DEVICE_CONFIG_PRINTER) && (USB_DEVICE_CONFIG_PRINTER > 0U)) + {USB_DevicePrinterInit, USB_DevicePrinterDeinit, USB_DevicePrinterEvent, kUSB_DeviceClassTypePrinter}, +#endif + +#if ((defined USB_DEVICE_CONFIG_DFU) && (USB_DEVICE_CONFIG_DFU > 0U)) + {USB_DeviceDfuInit, USB_DeviceDfuDeinit, USB_DeviceDfuEvent, kUSB_DeviceClassTypeDfu}, +#endif + +#if ((defined USB_DEVICE_CONFIG_CCID) && (USB_DEVICE_CONFIG_CCID > 0U)) + {USB_DeviceCcidInit, USB_DeviceCcidDeinit, USB_DeviceCcidEvent, kUSB_DeviceClassTypeCcid}, +#endif + + {(usb_device_class_init_call_t)NULL, (usb_device_class_deinit_call_t)NULL, (usb_device_class_event_callback_t)NULL, + (usb_device_class_type_t)0}, +}; + +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_common_class_struct_t + s_UsbDeviceCommonClassStruct[USB_DEVICE_CONFIG_NUM]; +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint8_t + s_UsbDeviceSetupBuffer[USB_DEVICE_CONFIG_NUM][USB_DATA_ALIGN_SIZE_MULTIPLE(USB_SETUP_PACKET_SIZE)]; + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Allocate a device common class handle. + * + * This function allocates a a device common class 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 common class handle to the + * caller. + * + * @retval kStatus_USB_Success Get a device handle successfully. + * @retval kStatus_USB_Busy Cannot allocate a common class handle. + * @retval kStatus_USB_Error The common class has been initialized. + */ +static usb_status_t USB_DeviceClassAllocateHandle(uint8_t controllerId, usb_device_common_class_struct_t **handle) +{ + uint32_t count; + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + /* Check the controller is initialized or not. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) && + (controllerId == s_UsbDeviceCommonClassStruct[count].controllerId)) + { + OSA_EXIT_CRITICAL(); + return kStatus_USB_Error; + } + } + /* Get a free common class handle. */ + for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++) + { + if (NULL == s_UsbDeviceCommonClassStruct[count].handle) + { + s_UsbDeviceCommonClassStruct[count].controllerId = controllerId; + s_UsbDeviceCommonClassStruct[count].setupBuffer = s_UsbDeviceSetupBuffer[count]; + *handle = &s_UsbDeviceCommonClassStruct[count]; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + + OSA_EXIT_CRITICAL(); + return kStatus_USB_Busy; +} + +/*! + * @brief Free a device common class handle. + * + * This function frees a device common class handle. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * + * @retval kStatus_USB_Success Free device handle successfully. + * @retval kStatus_USB_InvalidParameter The common class can not be found. + */ +static usb_status_t USB_DeviceClassFreeHandle(uint8_t controllerId) +{ + uint32_t count = 0U; + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + for (; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) && + (controllerId == s_UsbDeviceCommonClassStruct[count].controllerId)) + { + s_UsbDeviceCommonClassStruct[count].handle = NULL; + s_UsbDeviceCommonClassStruct[count].configList = (usb_device_class_config_list_struct_t *)NULL; + s_UsbDeviceCommonClassStruct[count].controllerId = 0U; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + OSA_EXIT_CRITICAL(); + + return kStatus_USB_InvalidParameter; +} + +/*! + * @brief Get the device common class handle according to the controller id. + * + * This function gets the device common class handle according to the controller id. + * + * @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 common class handle to the + * caller. + * + * @retval kStatus_USB_Success Free device handle successfully. + * @retval kStatus_USB_InvalidParameter The common class can not be found. + */ +static usb_status_t USB_DeviceClassGetHandleByControllerId(uint8_t controllerId, + usb_device_common_class_struct_t **handle) +{ + uint32_t count = 0U; + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + for (; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) && + (controllerId == s_UsbDeviceCommonClassStruct[count].controllerId)) + { + *handle = &s_UsbDeviceCommonClassStruct[count]; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + OSA_EXIT_CRITICAL(); + return kStatus_USB_InvalidParameter; +} + +/*! + * @brief Get the device common class handle according to the device handle. + * + * This function gets the device common class handle according to the device handle. + * + * @param deviceHandle The device handle, got from the USB_DeviceInit. + * @param handle It is out parameter, is used to return pointer of the device common class handle to the + * caller. + * + * @retval kStatus_USB_Success Free device handle successfully. + * @retval kStatus_USB_InvalidParameter The common class can not be found. + */ +static usb_status_t USB_DeviceClassGetHandleByDeviceHandle(usb_device_handle deviceHandle, + usb_device_common_class_struct_t **handle) +{ + uint32_t count = 0U; + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + for (; count < USB_DEVICE_CONFIG_NUM; count++) + { + if (deviceHandle == s_UsbDeviceCommonClassStruct[count].handle) + { + *handle = &s_UsbDeviceCommonClassStruct[count]; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + OSA_EXIT_CRITICAL(); + return kStatus_USB_InvalidParameter; +} + +/*! + * @brief Get the device handle according to the controller id. + * + * This function gets the device handle according to the controller id. + * + * @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 Free device handle successfully. + * @retval kStatus_USB_InvalidParameter The device handle not be found. + */ +usb_status_t USB_DeviceClassGetDeviceHandle(uint8_t controllerId, usb_device_handle *handle) +{ + uint32_t count = 0U; + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + for (; count < USB_DEVICE_CONFIG_NUM; count++) + { + if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) && + (controllerId == s_UsbDeviceCommonClassStruct[count].controllerId)) + { + *handle = s_UsbDeviceCommonClassStruct[count].handle; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + OSA_EXIT_CRITICAL(); + return kStatus_USB_InvalidParameter; +} + +/*! + * @brief Handle the event passed to the class drivers. + * + * This function handles the event passed to the class drivers. + * + * @param handle The device handle, got from the USB_DeviceInit. + * @param event The event codes. Please refer to the enumeration usb_device_class_event_t. + * @param param The param type is determined by the event code. + * + * @return A USB error code or kStatus_USB_Success. + * @retval kStatus_USB_Success A valid request has been handled. + * @retval kStatus_USB_InvalidParameter The device handle not be found. + * @retval kStatus_USB_InvalidRequest The request is invalid, and the control pipe will be stalled by the caller. + */ +usb_status_t USB_DeviceClassEvent(usb_device_handle handle, usb_device_class_event_t event, void *param) +{ + usb_device_common_class_struct_t *classHandle; + uint8_t mapIndex; + uint8_t classIndex; + usb_status_t errorReturn = kStatus_USB_Error; + usb_status_t error = kStatus_USB_Error; + + if (NULL == param) + { + return kStatus_USB_InvalidParameter; + } + + /* Get the common class handle according to the device handle. */ + errorReturn = USB_DeviceClassGetHandleByDeviceHandle(handle, &classHandle); + if (kStatus_USB_Success != errorReturn) + { + return kStatus_USB_InvalidParameter; + } + + for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++) + { + for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t)); + mapIndex++) + { + if (s_UsbDeviceClassInterfaceMap[mapIndex].type == + classHandle->configList->config[classIndex].classInfomation->type) + { + /* Call class event callback of supported class */ + errorReturn = s_UsbDeviceClassInterfaceMap[mapIndex].classEventCallback( + (void *)classHandle->configList->config[classIndex].classHandle, event, param); + /* Return the error code kStatus_USB_InvalidRequest immediately, when a class returns + * kStatus_USB_InvalidRequest. */ + if (kStatus_USB_InvalidRequest == errorReturn) + { + return kStatus_USB_InvalidRequest; + } + /* For composite device, it should return kStatus_USB_Success once a valid request has been handled */ + if (kStatus_USB_Success == errorReturn) + { + error = kStatus_USB_Success; + } + break; + } + } + } + + return error; +} + +/*! + * @brief Handle the common class callback. + * + * This function handles the common class callback. + * + * @param handle The device handle, got from the USB_DeviceInit. + * @param event The event codes. Please refer to the enumeration usb_device_event_t. + * @param param The param type is determined by the event code. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassCallback(usb_device_handle handle, uint32_t event, void *param) +{ + usb_device_common_class_struct_t *classHandle; + usb_status_t error = kStatus_USB_Error; + + /* Get the common class handle according to the device handle. */ + error = USB_DeviceClassGetHandleByDeviceHandle(handle, &classHandle); + if (kStatus_USB_Success != error) + { + return error; + } + + if (kUSB_DeviceEventBusReset == event) + { + /* Initialize the control pipes */ + USB_DeviceControlPipeInit(handle, classHandle); + + /* Notify the classes the USB bus reset signal detected. */ + USB_DeviceClassEvent(handle, kUSB_DeviceClassEventDeviceReset, classHandle); + } + + /* Call the application device callback function. deviceCallback is from the second parameter of + USB_DeviceClassInit */ + error = classHandle->configList->deviceCallback(handle, event, param); + return error; +} + +/*! + * @brief Initialize the common class and the supported classes. + * + * This function is used to initialize the common class and the supported classes. + * + * @param[in] controllerId The controller id of the USB IP. Please refer to the enumeration #usb_controller_index_t. + * @param[in] configList The class configurations. The pointer must point to the global variable. + * Please refer to the structure #usb_device_class_config_list_struct_t. + * @param[out] handle It is out parameter, is used to return pointer of the device handle to the caller. + * The value of parameter is a pointer points the device handle, and this design is used to + * make simple device align with composite device. For composite device, there are many + * kinds of class handle, but there is only one device handle. So the handle points to + * a device instead of a class. And the class handle can be got from the + * #usb_device_class_config_struct_t::classHandle after the function successfully. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassInit( + uint8_t controllerId, /*!< [IN] Controller ID */ + usb_device_class_config_list_struct_t *configList, /*!< [IN] Pointer to class configuration list */ + usb_device_handle *handle /*!< [OUT] Pointer to the device handle */ +) +{ + usb_device_common_class_struct_t *classHandle; + usb_status_t error = kStatus_USB_Error; + uint8_t mapIndex; + uint8_t classIndex; + + if ((NULL == handle) || (NULL == configList) || ((usb_device_callback_t)NULL == configList->deviceCallback)) + { + return kStatus_USB_InvalidParameter; + } + + /* Allocate a common class driver handle. */ + error = USB_DeviceClassAllocateHandle(controllerId, &classHandle); + if (kStatus_USB_Success != error) + { + return error; + } + /* Save the configuration list */ + classHandle->configList = configList; + + /* Initialize the device stack. */ + error = USB_DeviceInit(controllerId, USB_DeviceClassCallback, &classHandle->handle); + + if (kStatus_USB_Success != error) + { + USB_DeviceDeinit(classHandle->handle); + USB_DeviceClassFreeHandle(controllerId); + return error; + } + + /* Initialize the all supported classes according to the configuration list. */ + for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++) + { + for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t)); + mapIndex++) + { + if (classHandle->configList->config[classIndex].classInfomation->type == + s_UsbDeviceClassInterfaceMap[mapIndex].type) + { + (void)s_UsbDeviceClassInterfaceMap[mapIndex].classInit( + controllerId, &classHandle->configList->config[classIndex], + &classHandle->configList->config[classIndex].classHandle); + } + } + } + + *handle = classHandle->handle; + return error; +} + +/*! + * @brief De-initialize the common class and the supported classes. + * + * This function is used to de-initialize the common class and the supported classes. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassDeinit(uint8_t controllerId /*!< [IN] Controller ID */ +) +{ + usb_device_common_class_struct_t *classHandle; + usb_status_t error = kStatus_USB_Error; + uint8_t mapIndex; + uint8_t classIndex; + + /* Get the common class handle according to the controller id. */ + error = USB_DeviceClassGetHandleByControllerId(controllerId, &classHandle); + + if (kStatus_USB_Success != error) + { + return error; + } + + /* De-initialize the all supported classes according to the configuration list. */ + for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++) + { + for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t)); + mapIndex++) + { + if (classHandle->configList->config[classIndex].classInfomation->type == + s_UsbDeviceClassInterfaceMap[mapIndex].type) + { + (void)s_UsbDeviceClassInterfaceMap[mapIndex].classDeinit( + classHandle->configList->config[classIndex].classHandle); + } + } + } + + /* De-initialize the USB device stack. */ + error = USB_DeviceDeinit(classHandle->handle); + if (kStatus_USB_Success == error) + { + /* Free the common class handle. */ + (void)USB_DeviceClassFreeHandle(controllerId); + } + return error; +} + +/*! + * @brief Get the USB bus speed. + * + * This function is used to get the USB bus speed. + * + * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. + * @param speed It is an OUT parameter, return current speed of the controller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassGetSpeed(uint8_t controllerId, /*!< [IN] Controller ID */ + uint8_t *speed /*!< [OUT] Current speed */ +) +{ + usb_device_common_class_struct_t *classHandle; + usb_status_t error = kStatus_USB_Error; + + /* Get the common class handle according to the controller id. */ + error = USB_DeviceClassGetHandleByControllerId(controllerId, &classHandle); + + if (kStatus_USB_Success != error) + { + return error; + } + + /* Get the current speed. */ + error = USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusSpeed, speed); + + return error; +} +#endif /* USB_DEVICE_CONFIG_NUM */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.h new file mode 100644 index 0000000000..95b1d0f37e --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_class.h @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DEVICE_CLASS_H__ +#define __USB_DEVICE_CLASS_H__ + +/*! + * @addtogroup usb_device_class_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Macro to define class handle */ +typedef void *class_handle_t; + +/*! @brief Available class types. */ +typedef enum _usb_usb_device_class_type +{ + kUSB_DeviceClassTypeHid = 1U, + kUSB_DeviceClassTypeCdc, + kUSB_DeviceClassTypeMsc, + kUSB_DeviceClassTypeAudio, + kUSB_DeviceClassTypePhdc, + kUSB_DeviceClassTypeVideo, + kUSB_DeviceClassTypePrinter, + kUSB_DeviceClassTypeDfu, + kUSB_DeviceClassTypeCcid, +} usb_device_class_type_t; + +/*! @brief Available common class events. */ +typedef enum _usb_device_class_event +{ + kUSB_DeviceClassEventClassRequest = 1U, + kUSB_DeviceClassEventDeviceReset, + kUSB_DeviceClassEventSetConfiguration, + kUSB_DeviceClassEventSetInterface, + kUSB_DeviceClassEventSetEndpointHalt, + kUSB_DeviceClassEventClearEndpointHalt, +} usb_device_class_event_t; + +/*! + * @brief Obtains the endpoint data structure. + * + * Define the endpoint data structure. + * + */ +typedef struct _usb_device_endpoint_struct +{ + uint8_t endpointAddress; /*!< Endpoint address*/ + uint8_t transferType; /*!< Endpoint transfer type*/ + uint16_t maxPacketSize; /*!< Endpoint maximum packet size */ + uint8_t interval; /*!< Endpoint interval*/ +} usb_device_endpoint_struct_t; + +/*! +* @brief Obtains the endpoint group. +* +* Structure representing endpoints and the number of endpoints that the user wants. +* +*/ +typedef struct _usb_device_endpoint_list +{ + uint8_t count; /*!< How many endpoints in current interface*/ + usb_device_endpoint_struct_t *endpoint; /*!< Endpoint structure list*/ +} usb_device_endpoint_list_t; + +/*! + * @brief Obtains the interface list data structure. + * + * Structure representing an interface. + * + */ +typedef struct _usb_device_interface_struct +{ + uint8_t alternateSetting; /*!< Alternate setting number*/ + usb_device_endpoint_list_t endpointList; /*!< Endpoints of the interface*/ + void *classSpecific; /*!< Class specific structure handle*/ +} usb_device_interface_struct_t; + +/*! + * @brief Obtains the interface data structure. + * + * Structure representing interface. + * + */ +typedef struct _usb_device_interfaces_struct +{ + uint8_t classCode; /*!< Class code of the interface*/ + uint8_t subclassCode; /*!< Subclass code of the interface*/ + uint8_t protocolCode; /*!< Protocol code of the interface*/ + uint8_t interfaceNumber; /*!< Interface number*/ + usb_device_interface_struct_t *interface; /*!< Interface structure list*/ + uint8_t count; /*!< Number of interfaces in the current interface*/ +} usb_device_interfaces_struct_t; + +/*! + * @brief Obtains the interface group. + * + * Structure representing how many interfaces in one class type. + * + */ +typedef struct _usb_device_interface_list +{ + uint8_t count; /*!< Number of interfaces of the class*/ + usb_device_interfaces_struct_t *interfaces; /*!< All interfaces*/ +} usb_device_interface_list_t; + +/*! + * @brief Obtains the class data structure. + * + * Structure representing how many configurations in one class type. + * + */ +typedef struct _usb_device_class_struct +{ + usb_device_interface_list_t *interfaceList; /*!< Interfaces of the class*/ + usb_device_class_type_t type; /*!< Class type*/ + uint8_t configurations; /*!< Number of configurations of the class*/ +} usb_device_class_struct_t; + +/*callback function pointer structure for application to provide class parameters*/ +typedef usb_status_t (*usb_device_class_callback_t)(class_handle_t classHandle, + uint32_t callbackEvent, + void *eventParam); + +/*! + * @brief Obtains the device class information structure. + * + * Structure representing the device class information. This structure only can be stored in RAM space. + * + */ +typedef struct _usb_device_class_config_struct +{ + usb_device_class_callback_t classCallback; /*!< Class callback function to handle the device status-related event + for the specified type of class*/ + class_handle_t classHandle; /*!< The class handle of the class, filled by the common driver.*/ + usb_device_class_struct_t *classInfomation; /*!< Detailed information of the class*/ +} usb_device_class_config_struct_t; + +/*! + * @brief Obtains the device class configuration structure. + * + * Structure representing the device class configuration information. + * + */ +typedef struct _usb_device_class_config_list_struct +{ + usb_device_class_config_struct_t *config; /*!< Array of class configuration structures */ + usb_device_callback_t deviceCallback; /*!< Device callback function */ + uint8_t count; /*!< Number of class supported */ +} usb_device_class_config_list_struct_t; + +/*! + * @brief Obtains the control request structure. + * + * This structure is used to pass the control request information. + * The structure is used in following two cases. + * 1. Case one, the host wants to send data to the device in the control data stage: @n + * a. If a setup packet is received, the structure is used to pass the setup packet data and wants to get the + * buffer to receive data sent from the host. + * The field isSetup is 1. + * The length is the requested buffer length. + * The buffer is filled by the class or application by using the valid buffer address. + * The setup is the setup packet address. + * b. If the data received is sent by the host, the structure is used to pass the data buffer address and the + * data + * length sent by the host. + * In this way, the field isSetup is 0. + * The buffer is the address of the data sent from the host. + * The length is the received data length. + * The setup is the setup packet address. @n + * 2. Case two, the host wants to get data from the device in control data stage: @n + * If the setup packet is received, the structure is used to pass the setup packet data and wants to get the + * data buffer address to send data to the host. + * The field isSetup is 1. + * The length is the requested data length. + * The buffer is filled by the class or application by using the valid buffer address. + * The setup is the setup packet address. + * + */ +typedef struct _usb_device_control_request_struct +{ + usb_setup_struct_t *setup; /*!< The pointer of the setup packet data. */ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length or requested length. */ + uint8_t isSetup; /*!< Indicates whether a setup packet is received. */ +} usb_device_control_request_struct_t; + +/*! @brief Obtains the control get descriptor request common structure. */ +typedef struct _usb_device_get_descriptor_common_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ +} usb_device_get_descriptor_common_struct_t; + +/*! @brief Obtains the control get device descriptor request structure. */ +typedef struct _usb_device_get_device_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ +} usb_device_get_device_descriptor_struct_t; + +/*! @brief Obtains the control get device qualifier descriptor request structure. */ +typedef struct _usb_device_get_device_qualifier_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ +} usb_device_get_device_qualifier_descriptor_struct_t; + +/*! @brief Obtains the control get configuration descriptor request structure. */ +typedef struct _usb_device_get_configuration_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ + uint8_t configuration; /*!< The configuration number. */ +} usb_device_get_configuration_descriptor_struct_t; + +/*! @brief Obtains the control get bos descriptor request structure. */ +typedef struct _usb_device_get_bos_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ +} usb_device_get_bos_descriptor_struct_t; + +/*! @brief Obtains the control get string descriptor request structure. */ +typedef struct _usb_device_get_string_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ + uint16_t languageId; /*!< Language ID. */ + uint8_t stringIndex; /*!< String index. */ +} usb_device_get_string_descriptor_struct_t; + +/*! @brief Obtains the control get HID descriptor request structure. */ +typedef struct _usb_device_get_hid_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ + uint8_t interfaceNumber; /*!< The interface number. */ +} usb_device_get_hid_descriptor_struct_t; + +/*! @brief Obtains the control get HID report descriptor request structure. */ +typedef struct _usb_device_get_hid_report_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ + uint8_t interfaceNumber; /*!< The interface number. */ +} usb_device_get_hid_report_descriptor_struct_t; + +/*! @brief Obtains the control get HID physical descriptor request structure. */ +typedef struct _usb_device_get_hid_physical_descriptor_struct +{ + uint8_t *buffer; /*!< Pass the buffer address. */ + uint32_t length; /*!< Pass the buffer length. */ + uint8_t index; /*!< Physical index */ + uint8_t interfaceNumber; /*!< The interface number. */ +} usb_device_get_hid_physical_descriptor_struct_t; + +/*! @brief Obtains the control get descriptor request common union. */ +typedef union _usb_device_get_descriptor_common_union +{ + usb_device_get_descriptor_common_struct_t commonDescriptor; /*!< Common structure. */ + usb_device_get_device_descriptor_struct_t deviceDescriptor; /*!< The structure to get device descriptor. */ + usb_device_get_device_qualifier_descriptor_struct_t + deviceQualifierDescriptor; /*!< The structure to get device qualifier descriptor. */ + usb_device_get_configuration_descriptor_struct_t + configurationDescriptor; /*!< The structure to get configuration descriptor. */ + usb_device_get_string_descriptor_struct_t stringDescriptor; /*!< The structure to get string descriptor. */ + usb_device_get_hid_descriptor_struct_t hidDescriptor; /*!< The structure to get HID descriptor. */ + usb_device_get_hid_report_descriptor_struct_t + hidReportDescriptor; /*!< The structure to get HID report descriptor. */ + usb_device_get_hid_physical_descriptor_struct_t + hidPhysicalDescriptor; /*!< The structure to get HID physical descriptor. */ +} usb_device_get_descriptor_common_union_t; + +/*! @brief Define function type for class device instance initialization */ +typedef usb_status_t (*usb_device_class_init_call_t)(uint8_t controllerId, + usb_device_class_config_struct_t *classConfig, + class_handle_t *classHandle); +/*! @brief Define function type for class device instance deinitialization, internal */ +typedef usb_status_t (*usb_device_class_deinit_call_t)(class_handle_t handle); +/*! @brief Define function type for class device instance Event change */ +typedef usb_status_t (*usb_device_class_event_callback_t)(void *classHandle, uint32_t event, void *param); + +/*! @brief Define class driver interface structure. */ +typedef struct _usb_device_class_map +{ + usb_device_class_init_call_t classInit; /*!< Class driver initialization- entry of the class driver */ + usb_device_class_deinit_call_t classDeinit; /*!< Class driver de-initialization*/ + usb_device_class_event_callback_t classEventCallback; /*!< Class driver event callback*/ + usb_device_class_type_t type; /*!< Class type*/ +} usb_device_class_map_t; + +/*! @brief Structure holding common class state information */ +typedef struct _usb_device_common_class_struct +{ + usb_device_handle handle; /*!< USB device handle*/ + usb_device_class_config_list_struct_t *configList; /*!< USB device configure list*/ + uint8_t *setupBuffer; /*!< Setup packet data buffer*/ + uint16_t standardTranscationBuffer; /*!< + * This variable is used in: + * get status request + * get configuration request + * get interface request + * set interface request + * get sync frame request + */ + uint8_t controllerId; /*!< Controller ID*/ +} usb_device_common_class_struct_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Initializes the common class and the supported classes. + * + * This function is used to initialize the common class and the supported classes. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * @param[in] configList The class configurations. The pointer must point to the global variable. + * See the structure #usb_device_class_config_list_struct_t. + * @param[out] handle A parameter used to return pointer of the device handle to the caller. + * The value of the parameter is a pointer to the device handle. This design is used to + * make a simple device align with the composite device. For the composite device, there are + * many + * kinds of class handles. However, there is only one device handle. Therefore, the handle + * points to + * a device instead of a class. The class handle can be received from the + * #usb_device_class_config_struct_t::classHandle after the function successfully. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassInit(uint8_t controllerId, + usb_device_class_config_list_struct_t *configList, + usb_device_handle *handle); + +/*! + * @brief Deinitializes the common class and the supported classes. + * + * This function is used to deinitialize the common class and the supported classes. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassDeinit(uint8_t controllerId); + +/*! + * @brief Gets the USB bus speed. + * + * This function is used to get the USB bus speed. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * @param[out] speed It is an OUT parameter, which returns the current speed of the controller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassGetSpeed(uint8_t controllerId, uint8_t *speed); + +/*! + * @brief Handles the event passed to the class drivers. + * + * This function handles the event passed to the class drivers. + * + * @param[in] handle The device handle received from the #USB_DeviceInit. + * @param[in] event The event codes. See the enumeration #usb_device_class_event_t. + * @param[in,out] param The parameter type is determined by the event code. + * + * @return A USB error code or kStatus_USB_Success. + * @retval kStatus_USB_Success A valid request has been handled. + * @retval kStatus_USB_InvalidParameter The device handle not be found. + * @retval kStatus_USB_InvalidRequest The request is invalid, and the control pipe is stalled by the caller. + */ +usb_status_t USB_DeviceClassEvent(usb_device_handle handle, usb_device_class_event_t event, void *param); + +/*! + * @brief Handles the common class callback. + * + * This function handles the common class callback. + * + * @param[in] handle The device handle received from the #USB_DeviceInit. + * @param[in] event The event codes. See the enumeration #usb_device_event_t. + * @param[in,out] param The parameter type is determined by the event code. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceClassCallback(usb_device_handle handle, uint32_t event, void *param); + +/*! + * @brief Gets the device handle according to the controller ID. + * + * This function gets the device handle according to the controller ID. + * + * @param[in] controllerId The controller ID of the USB IP. See the enumeration #usb_controller_index_t. + * @param[out] handle An out parameter used to return the pointer of the device handle to the caller. + * + * @retval kStatus_USB_Success Get device handle successfully. + * @retval kStatus_USB_InvalidParameter The device handle can't be found. + */ +usb_status_t USB_DeviceClassGetDeviceHandle(uint8_t controllerId, usb_device_handle *handle); + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* __USB_DEVICE_CLASS_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_config.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_config.h new file mode 100644 index 0000000000..be7c34d85b --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/usb_device_config.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _USB_DEVICE_CONFIG_H_ +#define _USB_DEVICE_CONFIG_H_ + +#include "usb.h" + +/******************************************************************************* +* Definitions +******************************************************************************/ +/*! + * @addtogroup usb_device_configuration + * @{ + */ + +/*! + * @name Hardware instance define + * @{ + */ + +#define CONTROLLER_ID kUSB_ControllerEhci0 + +#define USB_INSTANCE 1 + +/*! @brief KHCI instance count */ +#define USB_DEVICE_CONFIG_KHCI (0U) + +/*! @brief EHCI instance count */ +#define USB_DEVICE_CONFIG_EHCI (1U) + +/*! @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 (0U) + +/*! @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) + +/*! @brief Whether device CV test is enabled. */ +#define USB_DEVICE_CONFIG_CV_TEST (0U) + +/*! @brief Whether device compliance test is enabled. If the macro is enabled, + the test mode and CV test macroes will be set.*/ +#define USB_DEVICE_CONFIG_COMPLIANCE_TEST (0U) + +#if ((defined(USB_DEVICE_CONFIG_COMPLIANCE_TEST)) && (USB_DEVICE_CONFIG_COMPLIANCE_TEST > 0U)) + +/*! @brief Undefine the macro USB_DEVICE_CONFIG_USB20_TEST_MODE. */ +#undef USB_DEVICE_CONFIG_USB20_TEST_MODE +/*! @brief Undefine the macro USB_DEVICE_CONFIG_CV_TEST. */ +#undef USB_DEVICE_CONFIG_CV_TEST + +/*! @brief enable the test mode. */ +#define USB_DEVICE_CONFIG_USB20_TEST_MODE (1U) + +/*! @brief enable the CV test */ +#define USB_DEVICE_CONFIG_CV_TEST (1U) + +#endif + +#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) +#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 test mode enabled. */ +#define USB_DEVICE_CONFIG_EHCI_TEST_MODE (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. */ +#ifndef USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE +#define USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U) +#endif +/*! @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) + +/*! @brief Whether handle the USB bus error. */ +#define USB_DEVICE_CONFIG_ERROR_HANDLING (0U) + +/* @} */ + +#endif /* _USB_DEVICE_CONFIG_H_ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBEndpoints_MCUXpresso.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBEndpoints_MCUXpresso.h new file mode 100644 index 0000000000..855dc3b152 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBEndpoints_MCUXpresso.h @@ -0,0 +1,62 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define NUMBER_OF_LOGICAL_ENDPOINTS (4) +#define NUMBER_OF_PHYSICAL_ENDPOINTS (NUMBER_OF_LOGICAL_ENDPOINTS * 2) + +/* Define physical endpoint numbers */ + +/* Endpoint No. */ +/* ---------------- */ +#define EP0OUT (0x00) +#define EP0IN (0x80) +#define EP1OUT (0x01) +#define EP1IN (0x81) +#define EP2OUT (0x02) +#define EP2IN (0x82) +#define EP3OUT (0x03) +#define EP3IN (0x83) + +/* Maximum Packet sizes */ + +#define MAX_PACKET_SIZE_EP0 (64) +#define MAX_PACKET_SIZE_EP1 (64) +#define MAX_PACKET_SIZE_EP2 (64) +#define MAX_PACKET_SIZE_EP3 (1023) + +/* Generic endpoints - intended to be portable accross devices */ +/* and be suitable for simple USB devices. */ + +/* Bulk endpoints */ +#define EPBULK_OUT (EP2OUT) +#define EPBULK_IN (EP2IN) +#define EPBULK_OUT_callback EP2_OUT_callback +#define EPBULK_IN_callback EP2_IN_callback +/* Interrupt endpoints */ +#define EPINT_OUT (EP1OUT) +#define EPINT_IN (EP1IN) +#define EPINT_OUT_callback EP1_OUT_callback +#define EPINT_IN_callback EP1_IN_callback +/* Isochronous endpoints */ +#define EPISO_OUT (EP3OUT) +#define EPISO_IN (EP3IN) +#define EPISO_OUT_callback EP3_OUT_callback +#define EPISO_IN_callback EP3_IN_callback + +#define MAX_PACKET_SIZE_EPBULK (MAX_PACKET_SIZE_EP2) +#define MAX_PACKET_SIZE_EPINT (MAX_PACKET_SIZE_EP1) +#define MAX_PACKET_SIZE_EPISO (MAX_PACKET_SIZE_EP3) diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhyHw_MCUXpresso.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhyHw_MCUXpresso.h new file mode 100644 index 0000000000..89ae143ba9 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhyHw_MCUXpresso.h @@ -0,0 +1,80 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef USBPHYHW_H +#define USBPHYHW_H + +#include "mbed.h" +#include "USBPhy.h" +#include "usb_device_config.h" +#include "usb_device.h" +#include "usb_device_ch9.h" + + +class USBPhyHw : public USBPhy { +public: + USBPhyHw(); + virtual ~USBPhyHw(); + virtual void init(USBPhyEvents *events); + virtual void deinit(); + virtual bool powered(); + virtual void connect(); + virtual void disconnect(); + virtual void configure(); + virtual void unconfigure(); + virtual void sof_enable(); + virtual void sof_disable(); + virtual void set_address(uint8_t address); + virtual void remote_wakeup(); + virtual const usb_ep_table_t *endpoint_table(); + + virtual uint32_t ep0_set_max_packet(uint32_t max_packet); + virtual void ep0_setup_read_result(uint8_t *buffer, uint32_t size); + virtual void ep0_read(uint8_t *data, uint32_t size); + virtual uint32_t ep0_read_result(); + virtual void ep0_write(uint8_t *buffer, uint32_t size); + virtual void ep0_stall(); + + virtual bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type); + virtual void endpoint_remove(usb_ep_t endpoint); + virtual void endpoint_stall(usb_ep_t endpoint); + virtual void endpoint_unstall(usb_ep_t endpoint); + + virtual bool endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual uint32_t endpoint_read_result(usb_ep_t endpoint); + virtual bool endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size); + virtual void endpoint_abort(usb_ep_t endpoint); + + virtual void process(); + +private: + USBPhyEvents *events; + uint8_t *read_buffers[16]; + uint16_t read_sizes[16]; + + bool endpoint_read_core(usb_ep_t endpoint, uint32_t max_packet); + bool endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytesRead); + + + static void _usbisr(void); + + friend usb_status_t USBPhy_DeviceCallback(usb_device_handle handle, uint32_t event, void *param); + friend usb_status_t USBPhy_EndpointCallback(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam); +}; + +#endif diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhy_MCUXpresso.cpp b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhy_MCUXpresso.cpp new file mode 100644 index 0000000000..77f92abf9f --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/USBPhy_MCUXpresso.cpp @@ -0,0 +1,514 @@ +/* mbed Microcontroller Library + * Copyright (c) 2018-2020 ARM Limited + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if defined(DEVICE_USBDEVICE) && DEVICE_USBDEVICE + +#include "USBPhyHw_MCUXpresso.h" +#include "USBEndpoints_MCUXpresso.h" +#include "fsl_clock_config.h" + +static USBPhyHw *instance; + +static volatile int epComplete = 0; + +static uint32_t usb_irq = 0; + +usb_device_handle g_deviceHandle; + +static USB_Type * const usb_addrs[] = USB_BASE_PTRS; + +// Convert physical endpoint number to register bit +#define EP(endpoint) (1<<(endpoint)) + +// Conversion macros +#define PHY_TO_LOG(endpoint) ((endpoint)>>1) +#define DESC_TO_LOG(endpoint) ((endpoint) & 0xF) +#define DESC_TO_PHY(endpoint) ((((endpoint)&0x0F)<<1) | (((endpoint) & 0x80) ? 1:0)) +#define PHY_TO_DESC(endpoint) (((endpoint)>>1)|(((endpoint)&1)?0x80:0)) + +// Get endpoint direction +#define DESC_EP_IN(endpoint) ((endpoint) & 0x80U ? true : false) +#define DESC_EP_OUT(endpoint) ((endpoint) & 0x80U ? false : true) + +#define TX 1 +#define RX 0 +#define ODD 0 +#define EVEN 1 +// this macro waits a physical endpoint number +#define EP_BDT_IDX(ep, dir, odd) (((ep * 4) + (2 * dir) + (1 * odd))) + +uint8_t *endpoint_buffer[NUMBER_OF_PHYSICAL_ENDPOINTS * 2]; +uint16_t endpoint_packet_size[NUMBER_OF_PHYSICAL_ENDPOINTS]; +USB_CONTROLLER_DATA uint32_t ep0_buffer[2][MAX_PACKET_SIZE_EP0 / 4]; +USB_CONTROLLER_DATA uint32_t ep1_buffer[2][MAX_PACKET_SIZE_EP1 / 4]; +USB_CONTROLLER_DATA uint32_t ep2_buffer[2][MAX_PACKET_SIZE_EP2 / 4]; +USB_CONTROLLER_DATA uint32_t ep3_buffer[2][MAX_PACKET_SIZE_EP3 / 4]; + +static uint8_t set_addr = 0; + +extern "C" uint32_t USB_DeviceGetIrqNumber(void); +extern "C" void USB_DeviceClockInit(void); + +static uint32_t frameNumber() +{ + return (usb_addrs[USB_INSTANCE]->FRINDEX >> 3); +} + +USBPhy *get_usb_phy() +{ + static USBPhyHw usbphy; + return &usbphy; +} + +USBPhyHw::USBPhyHw(): events(NULL) +{ + +} + +USBPhyHw::~USBPhyHw() +{ +} + +usb_status_t USBPhy_DeviceCallback(usb_device_handle handle, uint32_t event, void *param) +{ + switch (event) { + // reset interrupt + case kUSB_DeviceEventBusReset: + instance->endpoint_add(EP0OUT, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); + instance->endpoint_add(EP0IN, MAX_PACKET_SIZE_EP0, USB_EP_TYPE_CTRL); + + memset(instance->read_buffers, 0, sizeof(instance->read_buffers)); + memset(instance->read_sizes, 0, sizeof(instance->read_sizes)); + + // reset bus for USBDevice layer + instance->events->reset(); + break; + case kUSB_DeviceEventResume: + instance->events->suspend(false); + break; + case kUSB_DeviceEventSuspend: + instance->events->suspend(true); + break; + default: + break; + } + + return kStatus_USB_Success; +} + +usb_status_t USBPhy_EndpointCallback(usb_device_handle handle, usb_device_endpoint_callback_message_struct_t *message, + void *callbackParam) +{ + usb_ep_t endpoint = (usb_ep_t )((long)callbackParam); + int phy_ep = DESC_TO_PHY(endpoint); + uint8_t state; + + if (message->length == USB_UNINITIALIZED_VAL_32) { + return kStatus_USB_Success; + } + + /* Update the read size to what was actually read */ + instance->read_sizes[phy_ep] = message->length; + + // setup packet + if (message->isSetup) { + memcpy(&ep0_buffer[0][0], message->buffer, 8U); + + // EP0 SETUP event (SETUP data received) + instance->events->ep0_setup(); + } else { + if (DESC_EP_IN(endpoint)) { + if ((endpoint & USB_ENDPOINT_NUMBER_MASK) == 0) { + instance->events->ep0_in(); + if (set_addr == 1) { + state = (uint8_t)kUSB_DeviceStateAddress; + USB_DeviceSetStatus(g_deviceHandle, kUSB_DeviceStatusAddress, &state); + set_addr = 0; + } + } else { + epComplete |= EP(phy_ep); + instance->events->in(endpoint); + } + } else { + if ((endpoint & USB_ENDPOINT_NUMBER_MASK) == 0) { + instance->events->ep0_out(); + } else { + epComplete |= EP(phy_ep); + instance->events->out(endpoint); + } + } + } + + return kStatus_USB_Success; +} + +void USBPhyHw::init(USBPhyEvents *events) +{ + if (this->events == NULL) { + sleep_manager_lock_deep_sleep(); + } + + this->events = events; + + usb_irq = USB_DeviceGetIrqNumber(); + + // Disable IRQ + NVIC_DisableIRQ((IRQn_Type)usb_irq); + + // Attach IRQ + instance = this; + + USB_DeviceClockInit(); + + if (kStatus_USB_Success != USB_DeviceInit(CONTROLLER_ID, USBPhy_DeviceCallback, &g_deviceHandle)) { + return; + } + + /* Allocate control endpoint buffers */ + endpoint_buffer[EP_BDT_IDX(0, TX, ODD)] = (uint8_t*)ep0_buffer[TX]; + endpoint_buffer[EP_BDT_IDX(0, RX, ODD)] = (uint8_t*)ep0_buffer[RX]; + endpoint_buffer[EP_BDT_IDX(1, TX, ODD)] = (uint8_t*)ep1_buffer[TX]; + endpoint_buffer[EP_BDT_IDX(1, RX, ODD)] = (uint8_t*)ep1_buffer[RX]; + endpoint_buffer[EP_BDT_IDX(2, TX, ODD)] = (uint8_t*)ep2_buffer[TX]; + endpoint_buffer[EP_BDT_IDX(2, RX, ODD)] = (uint8_t*)ep2_buffer[RX]; + endpoint_buffer[EP_BDT_IDX(3, TX, ODD)] = (uint8_t*)ep3_buffer[TX]; + endpoint_buffer[EP_BDT_IDX(3, RX, ODD)] = (uint8_t*)ep3_buffer[RX]; + endpoint_packet_size[0] = sizeof (ep0_buffer[TX]); + endpoint_packet_size[1] = sizeof (ep0_buffer[RX]); + endpoint_packet_size[2] = sizeof (ep1_buffer[TX]); + endpoint_packet_size[3] = sizeof (ep1_buffer[RX]); + endpoint_packet_size[4] = sizeof (ep2_buffer[TX]); + endpoint_packet_size[5] = sizeof (ep2_buffer[RX]); + endpoint_packet_size[6] = sizeof (ep3_buffer[TX]); + endpoint_packet_size[7] = sizeof (ep3_buffer[RX]); + + NVIC_SetVector((IRQn_Type)usb_irq, (uint32_t)&_usbisr); + NVIC_EnableIRQ((IRQn_Type)usb_irq); +} + +void USBPhyHw::deinit() +{ + USB_DeviceDeinit(g_deviceHandle); + + disconnect(); + NVIC_DisableIRQ((IRQn_Type)usb_irq); + + if (events != NULL) { + sleep_manager_unlock_deep_sleep(); + } + events = NULL; +} + +bool USBPhyHw::powered() +{ + return true; +} + +void USBPhyHw::connect() +{ + USB_DeviceRun(g_deviceHandle); +} + +void USBPhyHw::disconnect() +{ + // disable all endpoints to prevent them from nacking when disconnected + for (uint8_t i = 0; i < (USB_DEVICE_CONFIG_ENDPOINTS); i++) { + USB_DeviceDeinitEndpoint(g_deviceHandle, + (i & USB_ENDPOINT_NUMBER_MASK) | + (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + USB_DeviceDeinitEndpoint(g_deviceHandle, + (i & USB_ENDPOINT_NUMBER_MASK) | + (USB_OUT << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)); + + } + + USB_DeviceStop(g_deviceHandle); +} + +void USBPhyHw::configure() +{ + +} + +void USBPhyHw::unconfigure() +{ + +} + +void USBPhyHw::sof_enable() +{ + usb_addrs[USB_INSTANCE]->USBINTR |= USBHS_USBINTR_SRE_MASK; +} + +void USBPhyHw::sof_disable() +{ + usb_addrs[USB_INSTANCE]->USBINTR &= ~USBHS_USBINTR_SRE_MASK; +} + +void USBPhyHw::set_address(uint8_t address) +{ + uint8_t state; + + // we don't set the address now, we set a flag instead. + // see usbisr when an IN token is received + set_addr = 1; + + state = address & 0xFFU; + + USB_DeviceSetStatus(g_deviceHandle, kUSB_DeviceStatusAddress, &state); +} + +void USBPhyHw::remote_wakeup() +{ + +} + +#define ALLOW_BULK_OR_INT_ENDPOINTS (USB_EP_ATTR_ALLOW_BULK | USB_EP_ATTR_ALLOW_INT) +#define ALLOW_NO_ENDPOINTS 0 + +const usb_ep_table_t *USBPhyHw::endpoint_table() +{ + static const usb_ep_table_t endpoint_table = { + 1, // No cost per endpoint - everything allocated up front + { + {USB_EP_ATTR_ALLOW_CTRL | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_BULK_OR_INT_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_BULK_OR_INT_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {USB_EP_ATTR_ALLOW_ISO | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0}, + {ALLOW_NO_ENDPOINTS | USB_EP_ATTR_DIR_IN_AND_OUT, 0, 0} + } + }; + return &endpoint_table; +} + +uint32_t USBPhyHw::ep0_set_max_packet(uint32_t max_packet) +{ + return USB_CONTROL_MAX_PACKET_SIZE; +} + +// read setup packet +void USBPhyHw::ep0_setup_read_result(uint8_t *buffer, uint32_t size) +{ + memcpy(buffer, &ep0_buffer[0][0], 8U); +} + +void USBPhyHw::ep0_read(uint8_t *data, uint32_t size) +{ + endpoint_read(EP0OUT, data, size); +} + +uint32_t USBPhyHw::ep0_read_result() +{ + return endpoint_read_result(EP0OUT); +} + +void USBPhyHw::ep0_write(uint8_t *buffer, uint32_t size) +{ + endpoint_write(EP0IN, buffer, size); +} + +void USBPhyHw::ep0_stall() +{ + endpoint_stall(EP0IN); + endpoint_stall(EP0OUT); +} + +bool USBPhyHw::endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type) +{ + usb_device_endpoint_init_struct_t epInit; + usb_device_endpoint_callback_struct_t epCallback; + + memset(&epInit, 0, sizeof(epInit)); + memset(&epCallback, 0, sizeof(epCallback)); + + if (DESC_TO_PHY(endpoint) > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) { + return false; + } + + epInit.transferType = (uint8_t)type; + epInit.maxPacketSize = (uint16_t)max_packet; + epInit.endpointAddress = endpoint; + if (type == USB_EP_TYPE_CTRL) { + epInit.zlt = 1; + } + + epCallback.callbackFn = USBPhy_EndpointCallback; + epCallback.callbackParam = (void *)((long)endpoint); + + if (USB_DeviceInitEndpoint(g_deviceHandle, &epInit, &epCallback) != kStatus_USB_Success) { + return false; + } + + return true; +} + +void USBPhyHw::endpoint_remove(usb_ep_t endpoint) +{ + USB_DeviceDeinitEndpoint(g_deviceHandle, endpoint); +} + +void USBPhyHw::endpoint_stall(usb_ep_t endpoint) +{ + USB_DeviceStallEndpoint(g_deviceHandle, endpoint); +} + +void USBPhyHw::endpoint_unstall(usb_ep_t endpoint) +{ + USB_DeviceUnstallEndpoint(g_deviceHandle, endpoint); +} + +bool USBPhyHw::endpoint_read(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + uint8_t log = DESC_TO_PHY(endpoint); + + read_buffers[log] = data; + read_sizes[log] = size; + return endpoint_read_core(endpoint, size); +} + +bool USBPhyHw::endpoint_read_core(usb_ep_t endpoint, uint32_t max_packet) +{ + uint8_t log_endpoint = DESC_TO_LOG(endpoint); + uint8_t *buf; + + buf = &endpoint_buffer[EP_BDT_IDX(log_endpoint, RX, ODD)][0]; + + if (USB_DeviceRecvRequest(g_deviceHandle, endpoint, buf, (max_packet > endpoint_packet_size[log_endpoint] ? endpoint_packet_size[log_endpoint] : max_packet)) != kStatus_USB_Success) { + return false; + } + + return true; +} + +uint32_t USBPhyHw::endpoint_read_result(usb_ep_t endpoint) +{ + uint8_t log = DESC_TO_PHY(endpoint); + + uint32_t bytes_read = 0; + endpoint_read_result_core(endpoint, read_buffers[log], read_sizes[log], &bytes_read); + read_buffers[log] = NULL; + read_sizes[log] = 0; + + return bytes_read; +} + + +bool USBPhyHw::endpoint_read_result_core(usb_ep_t endpoint, uint8_t *data, uint32_t size, uint32_t *bytes_read) +{ + uint32_t n, idx; + uint8_t *ep_buf; + + uint32_t log_endpoint = DESC_TO_LOG(endpoint); + + if (DESC_TO_PHY(endpoint) > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) { + return false; + } + + // if read on a IN endpoint -> error + if (DESC_EP_IN(endpoint)) { + return false; + } + + idx = EP_BDT_IDX(log_endpoint, RX, 0); + + if ((log_endpoint != 0) && !(epComplete & EP(DESC_TO_PHY(endpoint)))) { + return false; + } + + ep_buf = endpoint_buffer[idx]; + + for (n = 0; n < read_sizes[DESC_TO_PHY(endpoint)]; n++) { + data[n] = ep_buf[n]; + } + + *bytes_read = read_sizes[DESC_TO_PHY(endpoint)]; + + epComplete &= ~EP(DESC_TO_PHY(endpoint)); + return true; +} + +bool USBPhyHw::endpoint_write(usb_ep_t endpoint, uint8_t *data, uint32_t size) +{ + uint32_t idx, n; + uint8_t *ep_buf; + + if (DESC_TO_PHY(endpoint) > NUMBER_OF_PHYSICAL_ENDPOINTS - 1) { + return false; + } + + // if write on a OUT endpoint -> error + if (DESC_EP_OUT(endpoint)) { + return false; + } + + idx = EP_BDT_IDX(DESC_TO_LOG(endpoint), TX, 0); + + ep_buf = endpoint_buffer[idx]; + + if (size > endpoint_packet_size[DESC_TO_LOG(endpoint)]) { + size = endpoint_packet_size[DESC_TO_LOG(endpoint)]; + } + for (n = 0; n < size; n++) { + ep_buf[n] = data[n]; + } + + if (USB_DeviceSendRequest(g_deviceHandle, endpoint, ep_buf, size) != kStatus_USB_Success) { + return false; + } + + return true; +} + +void USBPhyHw::endpoint_abort(usb_ep_t endpoint) +{ + USB_DeviceCancel(g_deviceHandle, endpoint); +} + +void USBPhyHw::process() +{ + uint32_t istat = usb_addrs[USB_INSTANCE]->USBSTS & usb_addrs[USB_INSTANCE]->USBINTR; + + // SOF interrupt + if (istat & USBHS_USBSTS_SRI_MASK) { + // SOF event, read frame number + events->sof(frameNumber()); + } + + USB_DeviceEhciIsrFunction(g_deviceHandle); + + NVIC_ClearPendingIRQ((IRQn_Type)usb_irq); + NVIC_EnableIRQ((IRQn_Type)usb_irq); +} + +void USBPhyHw::_usbisr(void) +{ + NVIC_DisableIRQ((IRQn_Type)usb_irq); + instance->events->start_process(); +} + +#endif diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device.h new file mode 100644 index 0000000000..c047e2e430 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device.h @@ -0,0 +1,615 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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; + + + +/*! @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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + kUSB_DeviceEventDcdDetectionfinished, /*!< The DCD detection finished */ +#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*/ + uint8_t interval; /*!< Endpoint interval*/ +} 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(__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] epCallback 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 epCallback 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 *epCallback); + +/*! + * @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 Un-stall 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 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. + */ +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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) +/*! + * @brief Enable the device dcd module. + * + * The function enable the device dcd module. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device could run. + * @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_DeviceDcdEnable(usb_device_handle handle); + +/*! + * @brief Disable the device dcd module. + * + * The function disable the device dcd module. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The dcd is reset and stopped. + * @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_DeviceDcdDisable(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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 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_DeviceEhciIsrHSDCDFunction(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) +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) +/*! + * @brief Device IP3511 DCD ISR function. + * + * The function is the IP3511 DCD interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceLpcIp3511IsrDCDFunction(void *deviceHandle); +#endif +#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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 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 + +#if (((defined(USB_DEVICE_CONFIG_DWC3)) && (USB_DEVICE_CONFIG_DWC3 > 0U)) || \ + ((defined(USB_DEVICE_CONFIG_DWC3)) && (USB_DEVICE_CONFIG_DWC3 > 0U))) +/*! + * @brief Device USB DWC3 ISR function. + * + * The function is the USB interrupt service routine. + * + * @param[in] deviceHandle The device handle got from #USB_DeviceInit. + */ +extern void USB_DeviceDwc3IsrFunction(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)) || \ + ((defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 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/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.c new file mode 100644 index 0000000000..b138448e54 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.c @@ -0,0 +1,1389 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017,2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" +#include "usb_device_dci.h" + +#include "fsl_device_registers.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 + +#if ((defined(USB_DEVICE_CONFIG_DWC3)) && (USB_DEVICE_CONFIG_DWC3 > 0U)) +#include "usb_device_dwc3.h" +#endif + +#include "usb_device_ch9.h" +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) +#include "fsl_cache.h" +#endif + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "middleware.usb.device_stack" +#endif + +#if defined __CORTEX_M && (__CORTEX_M == 7U) +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) +#warning USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE is not supported. +#endif +#endif + +/******************************************************************************* + * 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; + OSA_SR_ALLOC(); + + 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)) + { + 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]; + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + } + 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) +{ + OSA_SR_ALLOC(); + + OSA_ENTER_CRITICAL(); + handle->controllerHandle = NULL; + handle->controllerId = 0U; + 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 + +#if ((defined(USB_DEVICE_CONFIG_DWC3)) && (USB_DEVICE_CONFIG_DWC3 > 0U)) +/* EHCI device driver interface */ +static const usb_device_controller_interface_struct_t s_UsbDeviceDwc3Interface = { + USB_DeviceDwc3Init, USB_DeviceDwc3Deinit, USB_DeviceDwc3Send, + USB_DeviceDwc3Recv, USB_DeviceDwc3Cancel, USB_DeviceDwc3Control}; +#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 invalid. + */ +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 +#if ((defined(USB_DEVICE_CONFIG_DWC3)) && (USB_DEVICE_CONFIG_DWC3 > 0U)) + /* Get the EHCI controller driver interface */ + case kUSB_ControllerDwc30: + case kUSB_ControllerDwc31: + error = kStatus_USB_Success; + *controllerInterface = (const usb_device_controller_interface_struct_t *)&s_UsbDeviceDwc3Interface; + 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 invalid. + * @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; + OSA_SR_ALLOC(); + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != deviceHandle->controllerInterface) + { + if (deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy) + { + return kStatus_USB_Busy; + } + OSA_ENTER_CRITICAL(); + deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 1U; + OSA_EXIT_CRITICAL(); + 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) + { + DCACHE_CleanByRange((uint32_t)buffer, length); + } +#endif + /* Call the controller send interface, the callbackFn is initialized in + USB_DeviceGetControllerInterface */ + 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) + { + DCACHE_CleanInvalidateByRange((uint32_t)buffer, length); + } +#endif + /* Call the controller receive interface, the callbackFn is initialized in + USB_DeviceGetControllerInterface */ + error = deviceHandle->controllerInterface->deviceRecv(deviceHandle->controllerHandle, endpointAddress, + buffer, length); + } + if (kStatus_USB_Success != error) + { + OSA_ENTER_CRITICAL(); + deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U; + OSA_EXIT_CRITICAL(); + } + } + 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 invalid. + * @retval kStatus_USB_ControllerNotFound The controller interface is not found. + * @retval kStatus_USB_Error Unsupported 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. the controllerInterface is initialized in + USB_DeviceGetControllerInterface */ + 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) +{ + uint32_t count; + +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + 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)) + OSA_ENTER_CRITICAL(); + handle->epCallbackDirectly = 1; + 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)) + OSA_ENTER_CRITICAL(); + handle->epCallbackDirectly = 0; + OSA_EXIT_CRITICAL(); +#endif + + handle->state = kUSB_DeviceStateDefault; + handle->deviceAddress = 0U; + + for (count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + handle->epCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + handle->epCallback[count].callbackParam = NULL; + handle->epCallback[count].isBusy = 0U; + } + + /* Call device callback to notify the application that the USB bus reset signal detected. + the deviceCallback is the second parameter of USB_DeviceInit */ + 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. + the deviceCallback is the second parameter of USB_DeviceInit */ + 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. + the deviceCallback is the second parameter of USB_DeviceInit */ + 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. + the deviceCallback is the second parameter of USB_DeviceInit */ + 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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U)) +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. + the deviceCallback is the second parameter of USB_DeviceInit */ + return handle->deviceCallback(handle, kUSB_DeviceEventError, NULL); +} +#endif /* USB_DEVICE_CONFIG_ERROR_HANDLING */ + +#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. + the deviceCallback is the second parameter of USB_DeviceInit */ + 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. + the deviceCallback is the second parameter of USB_DeviceInit */ + return handle->deviceCallback(handle, kUSB_DeviceEventAttach, NULL); +} +#endif + +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + +/*! + * @brief Handle the DCP detection finished notification. + * + * This function is used to notify detection 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_DeviceDcdDetectFinihsedNotification(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. + the deviceCallback is the second parameter of USB_DeviceInit */ + return handle->deviceCallback(handle, kUSB_DeviceEventDcdDetectionfinished, message->buffer); +} +#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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U)) + 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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + case kUSB_DeviceNotifyDcdDetectFinished: + error = USB_DeviceDcdDetectFinihsedNotification(handle, message); + break; +#endif + + default: + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + if (handle->epCallback[(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->epCallback[0].isBusy = 0U; + handle->epCallback[1].isBusy = 0U; + } + else + { + handle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].isBusy = 0U; + } + /* Call endpoint callback, callbackFn is in the third parameter of USB_DeviceInitEndpoint */ + error = handle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn( + handle, &endpointCallbackMessage, + handle->epCallback[(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 (KOSA_StatusSuccess != OSA_MsgQPut(deviceHandle->notificationQueue, (osa_msg_handle_t)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 endpoints */ + for (count = 0U; count < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); count++) + { + deviceHandle->epCallback[count].callbackFn = (usb_device_endpoint_callback_t)NULL; + deviceHandle->epCallback[count].callbackParam = NULL; + deviceHandle->epCallback[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. */ + deviceHandle->notificationQueue = (osa_msgq_handle_t)&deviceHandle->notificationQueueBuffer[0]; + if (KOSA_StatusSuccess != + OSA_MsgQCreate(deviceHandle->notificationQueue, USB_DEVICE_CONFIG_MAX_MESSAGES, USB_DEVICE_MESSAGES_SIZE)) + { + USB_DeviceDeinit(deviceHandle); + return kStatus_USB_Error; + } +#endif + + *handle = deviceHandle; + + /* Initialize the controller, the callbackFn is initialized in USB_DeviceGetControllerInterface */ + error = deviceHandle->controllerInterface->deviceInit(controllerId, deviceHandle, &deviceHandle->controllerHandle); + if (kStatus_USB_Success != error) + { + USB_DeviceDeinit(deviceHandle); + *handle = NULL; + return error; + } + /* Set the device to deafult state */ + deviceHandle->state = kUSB_DeviceStateDefault; + + 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) + { + /* the callbackFn is initialized in USB_DeviceGetControllerInterface */ + 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) + { + OSA_MsgQDestroy(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 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 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 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 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) + { + /* the callbackFn is initialized in USB_DeviceGetControllerInterface */ + 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 initialization structure. Please refer to the structure usb_device_endpoint_init_struct_t. + * @param epCallback 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 epCallback is NULL pointer. Or the endpoint number is + * not less 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 *epCallback) +{ + usb_device_struct_t *deviceHandle = (usb_device_struct_t *)handle; + uint8_t endpoint; + uint8_t direction; + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if ((!epInit) || (!epCallback)) + { + 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->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = epCallback->callbackFn; + deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = + epCallback->callbackParam; + deviceHandle->epCallback[(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)) + OSA_SR_ALLOC(); +#endif + + if (!deviceHandle) + { + return kStatus_USB_InvalidHandle; + } +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + OSA_ENTER_CRITICAL(); + deviceHandle->epCallbackDirectly = 1; + OSA_EXIT_CRITICAL(); +#endif + error = USB_DeviceControl(handle, kUSB_DeviceControlEndpointDeinit, &endpointAddress); +#if (defined(USB_DEVICE_CONFIG_USE_TASK) && (USB_DEVICE_CONFIG_USE_TASK > 0U)) + OSA_ENTER_CRITICAL(); + deviceHandle->epCallbackDirectly = 0; + OSA_EXIT_CRITICAL(); +#endif + + if (endpoint < USB_DEVICE_CONFIG_ENDPOINTS) + { + deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackFn = + (usb_device_endpoint_callback_t)NULL; + deviceHandle->epCallback[(uint8_t)((uint32_t)endpoint << 1U) | direction].callbackParam = NULL; + deviceHandle->epCallback[(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; + USB_DeviceControl(handle, kUSB_DeviceControlPreSetDeviceAddress, + &((usb_device_struct_t *)handle)->deviceAddress); + } + } + 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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) +/*! + * @brief Enable the device dcd module. + * + * The function enable the device dcd module. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The device could run. + * @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_DeviceDcdEnable(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlDcdEnable, NULL); +} +/*! + * @brief Disable the device dcd module. + * + * The function disable the device dcd module. + * + * @param[in] handle The device handle got from #USB_DeviceInit. + * + * @retval kStatus_USB_Success The dcd is reset and stopped. + * @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_DeviceDcdDisable(usb_device_handle handle) +{ + return USB_DeviceControl(handle, kUSB_DeviceControlDcdDisable, NULL); +} +#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 application 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; + usb_device_callback_message_struct_t message; + + if (deviceHandle) + { + /* Get the message from the queue */ + if (KOSA_StatusSuccess == + OSA_MsgQGet(handle->notificationQueue, (osa_msg_handle_t)&message, USB_OSA_WAIT_TIMEOUT)) + { + /* Handle the message */ + USB_DeviceNotification(handle, &message); + } + } +} +#endif + +/*! + * @brief Get device stack version function. + * + * The function is used to get device 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)) || \ + (((defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 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; +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + status = USB_DeviceControl(handle, kUSB_DeviceControlUpdateHwTick, (void *)(&deviceHandle->hwTick)); +#endif + return status; +} +#endif +#endif /* USB_DEVICE_CONFIG_NUM */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.h new file mode 100644 index 0000000000..aeb1060a32 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_dci.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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 +#define USB_DEVICE_MESSAGES_SIZE (sizeof(uint32_t)*(1U + (sizeof(usb_device_callback_message_struct_t) - 1U) / sizeof(uint32_t))) +/*! @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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + kUSB_DeviceNotifyDcdDetectFinished, /*!< Device charger detection finished */ +#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, /*!< Un-stall 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 enter into suspend mode */ + kUSB_DeviceControlSleep, /*!< Drive controller to enter 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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + kUSB_DeviceControlDcdDisable, /*!< disable dcd module function. */ + kUSB_DeviceControlDcdEnable, /*!< enable dcd module function. */ +#endif + kUSB_DeviceControlPreSetDeviceAddress, /*!< Pre set device address */ + kUSB_DeviceControlUpdateHwTick, /*!< update hardware tick */ +} 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)) || \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 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 + MSGQ_HANDLE_BUFFER_DEFINE(notificationQueueBuffer, USB_DEVICE_CONFIG_MAX_MESSAGES, USB_DEVICE_MESSAGES_SIZE); /*!< Message queue buffer*/ + osa_msgq_handle_t notificationQueue; /*!< Message queue*/ +#endif + usb_device_callback_t deviceCallback; /*!< Device callback function pointer */ + usb_device_endpoint_callback_struct_t + epCallback[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/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.c new file mode 100644 index 0000000000..733c97c7bc --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.c @@ -0,0 +1,1915 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "fsl_device_registers.h" +#include "usb.h" +#include "usb_device.h" +#if ((defined(USB_DEVICE_CONFIG_EHCI)) && (USB_DEVICE_CONFIG_EHCI > 0U)) + +#include "usb_device_dci.h" + +#include "usb_device_ehci.h" +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +#include "usb_phy.h" +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) +#include "usb_hsdcd.h" +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) +#include "usb_phydcd.h" +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM > 0U) + +#error The SOC does not suppoort dedicated RAM case. + +#endif + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void USB_DeviceEhciSetDefaultState(usb_device_ehci_state_struct_t *ehciState); +static usb_status_t USB_DeviceEhciEndpointInit(usb_device_ehci_state_struct_t *ehciState, + usb_device_endpoint_init_struct_t *epInit); +static usb_status_t USB_DeviceEhciEndpointDeinit(usb_device_ehci_state_struct_t *ehciState, uint8_t ep); +static usb_status_t USB_DeviceEhciEndpointStall(usb_device_ehci_state_struct_t *ehciState, uint8_t ep); +static usb_status_t USB_DeviceEhciEndpointUnstall(usb_device_ehci_state_struct_t *ehciState, uint8_t ep); +static void USB_DeviceEhciFillSetupBuffer(usb_device_ehci_state_struct_t *ehciState, uint8_t ep); +static void USB_DeviceEhciCancelControlPipe(usb_device_ehci_state_struct_t *ehciState, + uint8_t endpoint, + uint8_t direction); +static void USB_DeviceEhciInterruptTokenDone(usb_device_ehci_state_struct_t *ehciState); +static void USB_DeviceEhciInterruptPortChange(usb_device_ehci_state_struct_t *ehciState); +static void USB_DeviceEhciInterruptReset(usb_device_ehci_state_struct_t *ehciState); +static void USB_DeviceEhciInterruptSof(usb_device_ehci_state_struct_t *ehciState); +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +static void USB_DeviceEhciInterruptSuspend(usb_device_ehci_state_struct_t *ehciState); +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ +static usb_status_t USB_DeviceEhciTransfer(usb_device_ehci_state_struct_t *ehciState, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +extern usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* Apply for QH buffer, 2048-byte alignment */ +USB_RAM_ADDRESS_ALIGNMENT(2048) +USB_CONTROLLER_DATA static uint8_t qh_buffer[(USB_DEVICE_CONFIG_EHCI - 1) * 2048 + + 2 * USB_DEVICE_CONFIG_ENDPOINTS * 2 * sizeof(usb_device_ehci_qh_struct_t)]; + +/* Apply for DTD buffer, 32-byte alignment */ +USB_RAM_ADDRESS_ALIGNMENT(32) +USB_CONTROLLER_DATA static usb_device_ehci_dtd_struct_t + s_UsbDeviceEhciDtd[USB_DEVICE_CONFIG_EHCI][USB_DEVICE_CONFIG_EHCI_MAX_DTD]; + +/* Apply for ehci device state structure */ +static usb_device_ehci_state_struct_t g_UsbDeviceEhciState[USB_DEVICE_CONFIG_EHCI]; + +/* Apply for whether the corresponding g_UsbDeviceEhciState is used or not, if used, it is set to 1, if not used, it is set to 0 */ +static uint8_t g_UsbDeviceEhciStateStatus[USB_DEVICE_CONFIG_EHCI]= {0}; + + + +/******************************************************************************* + * Code + ******************************************************************************/ +/*! + * @brief EHCI NC get USB NC bass address. + * + * This function is used to get USB NC bass address. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * + * @retval USB NC bass address. + */ +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) +void *USB_EhciNCGetBase(uint8_t controllerId) +{ + void *usbNCBase = NULL; +#if ((defined FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + uint32_t instance; + uint32_t newinstance = 0; + uint32_t usbnc_base_temp[] = USBNC_BASE_ADDRS; + uint32_t usbnc_base[] = USBNC_BASE_ADDRS; + + if (controllerId < kUSB_ControllerEhci0) + { + return NULL; + } + + controllerId = controllerId - kUSB_ControllerEhci0; + + for (instance = 0; instance < (sizeof(usbnc_base_temp) / sizeof(usbnc_base_temp[0])); instance++) + { + if (usbnc_base_temp[instance]) + { + usbnc_base[newinstance++] = usbnc_base_temp[instance]; + } + } + if (controllerId > newinstance) + { + return NULL; + } + + usbNCBase = (void *)usbnc_base[controllerId]; +#endif + return usbNCBase; +} +#endif +#endif + +/*! + * @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_DeviceEhciInit called or the control type kUSB_DeviceControlGetEndpointStatus + * received in USB_DeviceEhciControl. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciSetDefaultState(usb_device_ehci_state_struct_t *ehciState) +{ + usb_device_ehci_dtd_struct_t *p; + + /* Initialize the dtd free queue */ + ehciState->dtdFree = ehciState->dtd; + p = ehciState->dtdFree; + for (uint32_t i = 1U; i < USB_DEVICE_CONFIG_EHCI_MAX_DTD; i++) + { + p->nextDtdPointer = (uint32_t)&ehciState->dtd[i]; + p = (usb_device_ehci_dtd_struct_t *)p->nextDtdPointer; + } + p->nextDtdPointer = 0U; + ehciState->dtdCount = USB_DEVICE_CONFIG_EHCI_MAX_DTD; + + /* Not use interrupt threshold. */ + ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_ITC_MASK; + ehciState->registerBase->USBCMD |= USBHS_USBCMD_ITC(0U); + + /* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */ + ehciState->registerBase->USBMODE |= USBHS_USBMODE_SLOM_MASK; + +/* Set the endian by using CPU's endian */ +#if (ENDIANNESS == USB_BIG_ENDIAN) + ehciState->registerBase->USBMODE |= USBHS_USBMODE_ES_MASK; +#else + ehciState->registerBase->USBMODE &= ~USBHS_USBMODE_ES_MASK; +#endif + /* Initialize the QHs of endpoint. */ + for (uint32_t i = 0U; i < (USB_DEVICE_CONFIG_ENDPOINTS * 2U); i++) + { + ehciState->qh[i].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK; + ehciState->qh[i].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize = + USB_CONTROL_MAX_PACKET_SIZE; + ehciState->dtdHard[i] = NULL; + ehciState->dtdTail[i] = NULL; + ehciState->qh[i].endpointStatusUnion.endpointStatusBitmap.isOpened = 0U; + } + + /* Add QH buffer address to USBHS_EPLISTADDR_REG */ + ehciState->registerBase->EPLISTADDR = (uint32_t)ehciState->qh; + + /* Clear device address */ + ehciState->registerBase->DEVICEADDR = 0U; + +#if defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U) + ehciState->registerBase->OTGSC = ehciState->registerBase->OTGSC & 0x0000FFFF; + ehciState->registerBase->OTGSC |= USBHS_OTGSC_BSVIE_MASK; +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE */ + + /* Enable USB Interrupt, USB Error Interrupt, Port Change detect Interrupt, USB-Reset Interrupt*/ + ehciState->registerBase->USBINTR = + (USBHS_USBINTR_UE_MASK | USBHS_USBINTR_UEE_MASK | USBHS_USBINTR_PCE_MASK | USBHS_USBINTR_URE_MASK +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + | USBHS_USBINTR_SLE_MASK +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + ); + + /* Clear reset flag */ + ehciState->isResetting = 0U; +} + +/*! + * @brief Initialize a specified endpoint. + * + * The function is used to initialize a specified endpoint. + * + * @param ehciState Pointer of the device EHCI state structure. + * @param epInit The endpoint initialization structure pointer. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceEhciEndpointInit(usb_device_ehci_state_struct_t *ehciState, + usb_device_endpoint_init_struct_t *epInit) +{ + uint32_t primeBit = 1U << ((epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK) + + ((epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> 0x03U)); + uint16_t maxPacketSize = epInit->maxPacketSize & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK; + 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)) | direction; + uint8_t transferType = epInit->transferType & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK; + + /* Cancel pending transfer of the endpoint */ + USB_DeviceEhciCancel(ehciState, epInit->endpointAddress); + + if ((ehciState->registerBase->EPPRIME & primeBit) || (ehciState->registerBase->EPSR & primeBit)) + { + return kStatus_USB_Busy; + } + + /* Make the endpoint max packet size align with USB Specification 2.0. */ + if (USB_ENDPOINT_ISOCHRONOUS == transferType) + { + if (maxPacketSize > USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE) + { + maxPacketSize = USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE; + } + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.mult = + 1U + ((epInit->maxPacketSize & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK) >> + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT); + } + else + { + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.mult = 0U; + } + + /* Save the max packet size of the endpoint */ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize = + maxPacketSize; + ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.zlt = epInit->zlt; + if ((USB_CONTROL_ENDPOINT == endpoint)) + { + /* Set ZLT bit. disable control endpoint automatic zlt by default,only send zlt when it is needed*/ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = 1U; + } + else + { + /* Set ZLT bit. */ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = !epInit->zlt; + } + + /* Enable the endpoint. */ + if ((USB_CONTROL_ENDPOINT == endpoint)) + { + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios = 1U; + ehciState->registerBase->EPCR0 |= + (direction ? + (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXR_MASK | ((uint32_t)transferType << USBHS_EPCR_TXT_SHIFT)) : + (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXR_MASK | ((uint32_t)transferType << USBHS_EPCR_RXT_SHIFT))); + } + else + { + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios = 0U; + ehciState->registerBase->EPCR[endpoint - 1U] |= + (direction ? + (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXR_MASK | ((uint32_t)transferType << USBHS_EPCR_TXT_SHIFT)) : + (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXR_MASK | ((uint32_t)transferType << USBHS_EPCR_RXT_SHIFT))); + } + + ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened = 1U; + 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 cancelled and the specified endpoint will be disabled. + * + * @param ehciState Pointer of the device EHCI 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_DeviceEhciEndpointDeinit(usb_device_ehci_state_struct_t *ehciState, uint8_t ep) +{ + uint32_t primeBit = + 1U << ((ep & USB_ENDPOINT_NUMBER_MASK) + ((ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> 0x03U)); + 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)) | direction; + + ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened = 0U; + + /* Cancel the transfer of the endpoint */ + USB_DeviceEhciCancel(ehciState, ep); + + if ((ehciState->registerBase->EPPRIME & primeBit) || (ehciState->registerBase->EPSR & primeBit)) + { + return kStatus_USB_Busy; + } + + /* Clear endpoint state */ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristics = 0U; + /* Disable the endpoint */ + if (!endpoint) + { + ehciState->registerBase->EPCR0 &= + ~(direction ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK) : (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK)); + } + else + { + ehciState->registerBase->EPCR[endpoint - 1U] &= + ~(direction ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK) : (USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK)); + } + + 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 cancelled and the specified endpoint will be stalled. + * + * @param ehciState Pointer of the device EHCI 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_DeviceEhciEndpointStall(usb_device_ehci_state_struct_t *ehciState, 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)) | direction; + + /* Cancel the transfer of the endpoint */ + USB_DeviceEhciCancel(ehciState, ep); + + /* Set endpoint stall flag. */ + if (ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios) + { + if (!endpoint) + { + ehciState->registerBase->EPCR0 |= (USBHS_EPCR_TXS_MASK | USBHS_EPCR_RXS_MASK); + } + else + { + ehciState->registerBase->EPCR[endpoint - 1U] |= (USBHS_EPCR_TXS_MASK | USBHS_EPCR_RXS_MASK); + } + } + else + { + if (!endpoint) + { + ehciState->registerBase->EPCR0 |= (direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK); + } + else + { + ehciState->registerBase->EPCR[endpoint - 1U] |= (direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_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 cancelled and the specified endpoint will be un-stalled. + * + * @param ehciState Pointer of the device EHCI 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_DeviceEhciEndpointUnstall(usb_device_ehci_state_struct_t *ehciState, 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; + + /* Clear the endpoint stall state */ + if (!endpoint) + { + ehciState->registerBase->EPCR0 &= ~(direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK); + } + else + { + ehciState->registerBase->EPCR[endpoint - 1U] &= ~(direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK); + ehciState->registerBase->EPCR[endpoint - 1U] |= (direction ? USBHS_EPCR_TXR_MASK : USBHS_EPCR_RXR_MASK); + } + /* Cancel the transfer of the endpoint */ + USB_DeviceEhciCancel(ehciState, ep); + + return kStatus_USB_Success; +} + +/*! + * @brief Get setup packet data. + * + * The function is used to get setup packet data and copy to a backup buffer. + * + * @param ehciState Pointer of the device EHCI state structure. + * @param ep The endpoint number. + * + */ +static void USB_DeviceEhciFillSetupBuffer(usb_device_ehci_state_struct_t *ehciState, uint8_t ep) +{ + uint8_t waitingSafelyAccess = 1U; + uint8_t index = (ep * 2U) | USB_OUT; + + /* Write 1U to clear corresponding bit in EPSETUPSR. */ + ehciState->registerBase->EPSETUPSR = 1U << ep; + + while (waitingSafelyAccess) + { + /* Set the setup tripwire bit. */ + ehciState->registerBase->USBCMD |= USBHS_USBCMD_SUTW_MASK; + + /* Copy setup packet data to backup buffer */ + ehciState->qh[index].setupBufferBack[0] = ehciState->qh[index].setupBuffer[0]; + ehciState->qh[index].setupBufferBack[1] = ehciState->qh[index].setupBuffer[1]; + + /* Read the USBCMD[SUTW] bit. If set, jump out from the while loop; if cleared continue */ + if (ehciState->registerBase->USBCMD & USBHS_USBCMD_SUTW_MASK) + { + waitingSafelyAccess = 0U; + } + } + /* Clear the setup tripwire bit */ + ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_SUTW_MASK; +} + +/*! + * @brief Cancel the transfer of the control pipe. + * + * The function is used to cancel the transfer of the control pipe. + * + * @param ehciState Pointer of the device EHCI state structure. + * @param endpoint The endpoint number. + * @param direction The direction of the endpoint. + * + */ +static void USB_DeviceEhciCancelControlPipe(usb_device_ehci_state_struct_t *ehciState, + uint8_t endpoint, + uint8_t direction) +{ + usb_device_ehci_dtd_struct_t *currentDtd; + uint32_t index = ((uint32_t)endpoint << 1U) + (uint32_t)direction; + usb_device_callback_message_struct_t message; + + message.buffer = NULL; + message.length = 0U; + /* Get the dtd of the control pipe */ + currentDtd = + (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK); + while (currentDtd) + { + /* Pass the transfer buffer address */ + if (NULL == message.buffer) + { + uint32_t bufferAddress = currentDtd->bufferPointerPage[0]; + message.buffer = (uint8_t *)((bufferAddress & USB_DEVICE_ECHI_DTD_PAGE_MASK) | + (currentDtd->reservedUnion.originalBufferInfo.originalBufferOffest)); + } + /* If the dtd is active, set the message length to USB_UNINITIALIZED_VAL_32. Or set the length by using finished + * length. */ + if (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE) + { + message.length = USB_UNINITIALIZED_VAL_32; + } + else + { + message.length += (currentDtd->reservedUnion.originalBufferInfo.originalBufferLength - + currentDtd->dtdTokenUnion.dtdTokenBitmap.totalBytes); + } + + /* Move the dtd head pointer to next. */ + /* If the pointer of the head equals to the tail, set the dtd queue to null. */ + if (ehciState->dtdHard[index] == ehciState->dtdTail[index]) + { + ehciState->dtdHard[index] = NULL; + ehciState->dtdTail[index] = NULL; + ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK; + ehciState->qh[index].dtdTokenUnion.dtdToken = 0U; + } + else + { + ehciState->dtdHard[index] = (usb_device_ehci_dtd_struct_t *)ehciState->dtdHard[index]->nextDtdPointer; + } + + /* When the ioc is set or the dtd queue is empty, the up layer will be notified. */ + if ((currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) || + (0 == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK))) + { + message.code = endpoint | (uint8_t)((uint32_t)direction << 0x07U); + message.isSetup = 0U; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + message.buffer = NULL; + message.length = 0U; + } + + /* Clear the token field of the dtd. */ + currentDtd->dtdTokenUnion.dtdToken = 0U; + /* Add the dtd to the free dtd queue. */ + currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree; + ehciState->dtdFree = currentDtd; + ehciState->dtdCount++; + + /* Get the next in-used dtd. */ + currentDtd = + (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK); + } +} + +/*! + * @brief Handle the endpoint token done interrupt. + * + * The function is used to handle the endpoint token done interrupt. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciInterruptTokenDone(usb_device_ehci_state_struct_t *ehciState) +{ + uint32_t status; + uint32_t primeBit; + usb_device_ehci_dtd_struct_t *currentDtd; + usb_device_callback_message_struct_t message; + uint8_t endpoint; + uint8_t direction; + uint8_t count; + uint8_t index; + + /* Get the EPSETUPSR to check the setup packect received in which one endpoint. */ + status = ehciState->registerBase->EPSETUPSR; + + if (status) + { + for (endpoint = 0U; endpoint < USB_DEVICE_CONFIG_ENDPOINTS; endpoint++) + { + /* Check the endpoint receive the setup packet. */ + if (status & (1U << endpoint)) + { + /* Get last setup packet */ + usb_setup_struct_t *deviceSetup = + (usb_setup_struct_t *)&ehciState->qh[(uint8_t)((uint32_t)endpoint << 1U) + USB_OUT].setupBufferBack; + + /* Check the direction of the data phase. */ + direction = (deviceSetup->bmRequestType & USB_REQUEST_TYPE_DIR_IN) >> USB_REQUEST_TYPE_DIR_SHIFT; + /* Cancel the data phase transfer */ + USB_DeviceEhciCancelControlPipe(ehciState, endpoint, direction); + /* Cancel the status phase transfer */ + USB_DeviceEhciCancelControlPipe(ehciState, endpoint, 1U ^ direction); + message.code = (endpoint) | (USB_OUT << 0x07U); + message.buffer = (uint8_t *)deviceSetup; + message.length = USB_SETUP_PACKET_SIZE; + message.isSetup = 1U; + /* Fill the setup packet to the backup buffer */ + USB_DeviceEhciFillSetupBuffer(ehciState, endpoint); + /* Notify the up layer the EHCI status changed. */ + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + } + } + } + /* Read the USBHS_EPCOMPLETE_REG to get the endpoint transfer done status */ + status = ehciState->registerBase->EPCOMPLETE; + /* Clear the endpoint transfer done status */ + ehciState->registerBase->EPCOMPLETE = status; + + if (status) + { + for (count = 0U; count < 32U; count++) + { + /* Check the transfer is done or not in the specified endpoint. */ + if (status & ((uint32_t)(1U << count))) + { + if (count > 15U) + { + endpoint = count - 16U; + direction = USB_IN; + } + else + { + endpoint = count; + direction = USB_OUT; + } + if (endpoint >= USB_DEVICE_CONFIG_ENDPOINTS) + { + continue; + } + index = (endpoint << 1U) + direction; + message.buffer = NULL; + message.length = 0U; + if ((USB_CONTROL_ENDPOINT == endpoint) && (USB_IN == direction)) + { + if (1U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.zlt) + { + if(!ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt) + { + /*disable zlt after send zlt*/ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = 1U; + } + } + } + /* Get the in-used dtd of the specified endpoint. */ + currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & + USB_DEVICE_ECHI_DTD_POINTER_MASK); + while (currentDtd) + { + uint8_t isTokenDone = 0; + /* Get the in-used dtd of the specified endpoint. */ + currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & + USB_DEVICE_ECHI_DTD_POINTER_MASK); + + while (currentDtd) + { + /* Don't handle the active dtd. */ + if ((currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE) || + (currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc)) + { + if ((!(currentDtd->dtdTokenUnion.dtdTokenBitmap.status & + USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) && + (currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc)) + { + isTokenDone = 1U; + } + break; + } + currentDtd = (usb_device_ehci_dtd_struct_t *)(currentDtd->nextDtdPointer & + USB_DEVICE_ECHI_DTD_POINTER_MASK); + } + + if ((0 == isTokenDone) && (currentDtd)) + { + break; + } + + /* Get the in-used dtd of the specified endpoint. */ + currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & + USB_DEVICE_ECHI_DTD_POINTER_MASK); + while (currentDtd) + { + /* Don't handle the active dtd. */ + if (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE) + { + break; + } + + /* Save the transfer buffer address */ + if (NULL == message.buffer) + { + message.buffer = + (uint8_t *)((currentDtd->bufferPointerPage[0] & USB_DEVICE_ECHI_DTD_PAGE_MASK) | + (currentDtd->reservedUnion.originalBufferInfo.originalBufferOffest)); + } + /* Save the transferred data length */ + message.length += (currentDtd->reservedUnion.originalBufferInfo.originalBufferLength - + currentDtd->dtdTokenUnion.dtdTokenBitmap.totalBytes); + + /* Move the dtd queue head pointer to next */ + if (ehciState->dtdHard[index] == ehciState->dtdTail[index]) + { + ehciState->dtdHard[index] = NULL; + ehciState->dtdTail[index] = NULL; + ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK; + ehciState->qh[index].dtdTokenUnion.dtdToken = 0U; + } + else + { + ehciState->dtdHard[index] = + (usb_device_ehci_dtd_struct_t *)ehciState->dtdHard[index]->nextDtdPointer; + } + + /* When the ioc is set or the dtd queue is empty, the up layer will be notified. */ + if ((currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) || + (0 == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK))) + { + message.code = endpoint | (uint8_t)((uint32_t)direction << 0x07U); + message.isSetup = 0U; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + message.buffer = NULL; + message.length = 0U; + } + /* Clear the token field of the dtd */ + currentDtd->dtdTokenUnion.dtdToken = 0U; + currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree; + ehciState->dtdFree = currentDtd; + ehciState->dtdCount++; + /* Get the next in-used dtd */ + currentDtd = (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & + USB_DEVICE_ECHI_DTD_POINTER_MASK); + + if ((NULL != currentDtd) && + (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) + { + primeBit = 1U << (endpoint + 16U * direction); + + /* Try to prime the next dtd. */ + ehciState->registerBase->EPPRIME = primeBit; + + /* Whether the endpoint transmit/receive buffer is ready or not. If not, wait for prime bit + * cleared and prime the next dtd. */ + if (!(ehciState->registerBase->EPSR & primeBit)) + { + /* Wait for the endpoint prime bit cleared by HW */ + while (ehciState->registerBase->EPPRIME & primeBit) + { + } + + /* If the endpoint transmit/receive buffer is not ready */ + if (!(ehciState->registerBase->EPSR & primeBit)) + { + /* Prime next dtd and prime the transfer */ + ehciState->qh[index].nextDtdPointer = (uint32_t)currentDtd; + ehciState->qh[index].dtdTokenUnion.dtdToken = 0U; + ehciState->registerBase->EPPRIME = primeBit; + } + } + } + } + } + } + } + } +} + +/*! + * @brief Handle the port status change interrupt. + * + * The function is used to handle the port status change interrupt. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciInterruptPortChange(usb_device_ehci_state_struct_t *ehciState) +{ + usb_device_callback_message_struct_t message; + + message.buffer = (uint8_t *)NULL; + message.length = 0U; + message.isSetup = 0U; + + /* Whether the port is doing reset. */ + if (!(ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_PR_MASK)) + { + /* If not, update the USB speed. */ + if (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_HSP_MASK) + { + ehciState->speed = USB_SPEED_HIGH; + } + else + { + ehciState->speed = USB_SPEED_FULL; + } + + /* If the device reset flag is non-zero, notify the up layer the device reset finished. */ + if (ehciState->isResetting) + { + message.code = kUSB_DeviceNotifyBusReset; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + ehciState->isResetting = 0U; + } + } + +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + if ((ehciState->isSuspending) && (!(ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_SUSP_MASK))) + { + /* Set the resume flag */ + ehciState->isSuspending = 0U; + + message.code = kUSB_DeviceNotifyResume; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + } +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ +} + +/*! + * @brief Handle the reset interrupt. + * + * The function is used to handle the reset interrupt. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciInterruptReset(usb_device_ehci_state_struct_t *ehciState) +{ + uint32_t status = 0U; + + /* Clear the setup flag */ + status = ehciState->registerBase->EPSETUPSR; + ehciState->registerBase->EPSETUPSR = status; + /* Clear the endpoint complete flag */ + status = ehciState->registerBase->EPCOMPLETE; + ehciState->registerBase->EPCOMPLETE = status; + + do + { + /* Flush the pending transfers */ + ehciState->registerBase->EPFLUSH = USBHS_EPFLUSH_FERB_MASK | USBHS_EPFLUSH_FETB_MASK; + } while (ehciState->registerBase->EPPRIME & (USBHS_EPPRIME_PERB_MASK | USBHS_EPPRIME_PETB_MASK)); + + /* Whether is the port reset. If yes, set the isResetting flag. Or, notify the up layer. */ + if (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_PR_MASK) + { + ehciState->isResetting = 1U; + } + else + { + usb_device_callback_message_struct_t message; + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyBusReset; + message.length = 0U; + message.isSetup = 0U; + + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + } +} + +/*! + * @brief Handle the sof interrupt. + * + * The function is used to handle the sof interrupt. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciInterruptSof(usb_device_ehci_state_struct_t *ehciState) +{ +} + +#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. + * + * @param ehciState Pointer of the device EHCI state structure. + * + */ +static void USB_DeviceEhciInterruptSuspend(usb_device_ehci_state_struct_t *ehciState) +{ + /* If the port is in suspend state, notify the up layer */ + if (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_SUSP_MASK) + { +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) +#else + if (ehciState->registerPhyBase->USB1_VBUS_DET_STAT & USBPHY_USB1_VBUS_DET_STAT_VBUS_VALID_3V_MASK) +#endif + { + usb_device_callback_message_struct_t message; + message.buffer = (uint8_t *)NULL; + message.length = 0U; + message.isSetup = 0U; + message.code = kUSB_DeviceNotifySuspend; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + } + } +} +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + +/*! + * @brief Get dtds and link to QH. + * + * The function is used to get dtds and link to QH. + * + * @param ehciState Pointer of the device EHCI state structure. + * @param endpointAddress The endpoint address, Bit7, 0U - USB_OUT, 1U - USB_IN. + * @param buffer The memory address needed to be transferred. + * @param length Data length. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceEhciTransfer(usb_device_ehci_state_struct_t *ehciState, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_ehci_dtd_struct_t *dtd; + usb_device_ehci_dtd_struct_t *dtdHard; + uint32_t index = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) | + ((endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT); + uint32_t primeBit = 1U << ((endpointAddress & USB_ENDPOINT_NUMBER_MASK) + + ((endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> 0x03U)); + uint32_t epStatus = primeBit; + uint32_t sendLength; + uint32_t currentIndex = 0U; + uint32_t dtdRequestCount = (length + USB_DEVICE_ECHI_DTD_TOTAL_BYTES - 1U) / USB_DEVICE_ECHI_DTD_TOTAL_BYTES; + uint8_t qhIdle = 0U; + uint8_t waitingSafelyAccess = 1U; + uint32_t primeTimesCount = 0U; + OSA_SR_ALLOC(); + + if (!ehciState) + { + return kStatus_USB_InvalidHandle; + } + + if (0U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.isOpened) + { + return kStatus_USB_Error; + } + /* Return error when ehci is doing reset */ + if (ehciState->isResetting) + { + return kStatus_USB_Error; + } + + if (!dtdRequestCount) + { + dtdRequestCount = 1U; + } + + OSA_ENTER_CRITICAL(); + /* The free dtd count need to not less than the transfer requests. */ + if (dtdRequestCount > (uint32_t)ehciState->dtdCount) + { + OSA_EXIT_CRITICAL(); + return kStatus_USB_Busy; + } + + do + { + /* The transfer length need to not more than USB_DEVICE_ECHI_DTD_TOTAL_BYTES for each dtd. */ + if (length > USB_DEVICE_ECHI_DTD_TOTAL_BYTES) + { + sendLength = USB_DEVICE_ECHI_DTD_TOTAL_BYTES; + } + else + { + sendLength = length; + } + length -= sendLength; + + /* Get a free dtd */ + dtd = ehciState->dtdFree; + + ehciState->dtdFree = (usb_device_ehci_dtd_struct_t *)dtd->nextDtdPointer; + ehciState->dtdCount--; + + /* Save the dtd head when current active buffer offset is zero. */ + if (!currentIndex) + { + dtdHard = dtd; + } + + /* Set the dtd field */ + dtd->nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK; + dtd->dtdTokenUnion.dtdToken = 0U; + dtd->bufferPointerPage[0] = (uint32_t)(buffer + currentIndex); + dtd->bufferPointerPage[1] = + (dtd->bufferPointerPage[0] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK) & USB_DEVICE_ECHI_DTD_PAGE_MASK; + dtd->bufferPointerPage[2] = dtd->bufferPointerPage[1] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK; + dtd->bufferPointerPage[3] = dtd->bufferPointerPage[2] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK; + dtd->bufferPointerPage[4] = dtd->bufferPointerPage[3] + USB_DEVICE_ECHI_DTD_PAGE_BLOCK; + + dtd->dtdTokenUnion.dtdTokenBitmap.totalBytes = sendLength; + + /* Save the data length needed to be transferred. */ + dtd->reservedUnion.originalBufferInfo.originalBufferLength = sendLength; + /* Save the original buffer address */ + dtd->reservedUnion.originalBufferInfo.originalBufferOffest = + dtd->bufferPointerPage[0] & USB_DEVICE_ECHI_DTD_PAGE_OFFSET_MASK; + dtd->reservedUnion.originalBufferInfo.dtdInvalid = 0U; + + /* Set the IOC field in last dtd. */ + if (!length) + { + dtd->dtdTokenUnion.dtdTokenBitmap.ioc = 1U; + } + + /* Set dtd active */ + dtd->dtdTokenUnion.dtdTokenBitmap.status = USB_DEVICE_ECHI_DTD_STATUS_ACTIVE; + + /* Move the buffer offset index */ + currentIndex += sendLength; + + /* Add dtd to the in-used dtd queue */ + if (ehciState->dtdTail[index]) + { + ehciState->dtdTail[index]->nextDtdPointer = (uint32_t)dtd; + ehciState->dtdTail[index] = dtd; + } + else + { + ehciState->dtdHard[index] = dtd; + ehciState->dtdTail[index] = dtd; + qhIdle = 1U; + } + } while (length); +#if (defined USB_DEVICE_CONTROLLER_AUTO_CONTROL_TRANSFER_ZLP) && (USB_DEVICE_CONTROLLER_AUTO_CONTROL_TRANSFER_ZLP) + if ((USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK)) && (USB_IN == ((endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))) + { + uint8_t setupindex = ((endpointAddress & USB_ENDPOINT_NUMBER_MASK)* 2U); + /* Get last setup packet */ + usb_setup_struct_t *deviceSetup = + (usb_setup_struct_t *)&ehciState->qh[setupindex].setupBufferBack[0]; + if (1U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.zlt) + { + if ((sendLength) && (sendLength < deviceSetup->wLength) && (!(sendLength % ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize))) + { + /* enable ZLT. */ + ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = 0U; + } + } + } +#endif + /* If the QH is not empty */ + if (!qhIdle) + { + /* If the prime bit is set, nothing need to do. */ + if (ehciState->registerBase->EPPRIME & primeBit) + { + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } + + /* To safely a dtd */ + while (waitingSafelyAccess) + { + /* set the ATDTW flag to USBHS_USBCMD_REG. */ + ehciState->registerBase->USBCMD |= USBHS_USBCMD_ATDTW_MASK; + /* Read EPSR */ + epStatus = ehciState->registerBase->EPSR; + /* Wait the ATDTW bit set */ + if (ehciState->registerBase->USBCMD & USBHS_USBCMD_ATDTW_MASK) + { + waitingSafelyAccess = 0U; + } + } + /* Clear the ATDTW bit */ + ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_ATDTW_MASK; + } + + /* If QH is empty or the endpoint is not primed, need to link current dtd head to the QH. */ + /* When the endpoint is not primed if qhIdle is zero, it means the QH is empty. */ + if ((qhIdle) || (!(epStatus & primeBit))) + { + ehciState->qh[index].nextDtdPointer = (uint32_t)dtdHard; + ehciState->qh[index].dtdTokenUnion.dtdToken = 0U; + ehciState->registerBase->EPPRIME = primeBit; + while (!(ehciState->registerBase->EPSR & primeBit)) + { + primeTimesCount++; + if (primeTimesCount == USB_DEVICE_MAX_TRANSFER_PRIME_TIMES) + { + OSA_EXIT_CRITICAL(); + return kStatus_USB_Error; + } + if (ehciState->registerBase->EPCOMPLETE & primeBit) + { + break; + } + else + { + ehciState->registerBase->EPPRIME = primeBit; + } + } + } + + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; +} + +/*! + * @brief Get a valid device EHCI state for the device EHCI instance. + * + * This function gets a valid device EHCI state for the USB device EHCI module specified by the controllerId. + * + * @param instanceIndex The instanceIndex is used for other EHCI device structure to identify their instance index. + * + * @return A valid EHCI state or NULL. + */ +void *USB_EhciGetValidEhciState(uint8_t *instanceIndex) +{ + for (uint8_t instance = 0; instance < USB_DEVICE_CONFIG_EHCI; instance++) + { + if (!g_UsbDeviceEhciStateStatus[instance]) + { + g_UsbDeviceEhciStateStatus[instance] = 1; + *instanceIndex = instance; + return &g_UsbDeviceEhciState[instance]; + } + } + return NULL; +} + +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) +/* The device dcd callback */ +static usb_phydcd_status_t USB_DeviceEhciIsrPHYDCDCallback(void *handle, uint32_t event, void *param) +{ + usb_phydcd_status_t error = kStatus_phydcd_Success; + usb_device_callback_message_struct_t message; + usb_device_ehci_state_struct_t *ehciState = (usb_device_ehci_state_struct_t *)handle; + + if (ehciState == NULL) + { + return kStatus_phydcd_Error; + } + + /*messsgae buffer contain event information*/ + message.buffer = (uint8_t *)param; + message.length = 0U; + message.isSetup = 0U; + message.code = kUSB_DeviceNotifyDcdDetectFinished; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + + return error; +} +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) +/* The device dcd callback */ +static usb_hsdcd_status_t USB_DeviceEhciIsrHSDCDCallback(void *handle, uint32_t event, void *param) +{ + usb_hsdcd_status_t error = kStatus_hsdcd_Success; + usb_device_callback_message_struct_t message; + usb_device_ehci_state_struct_t *ehciState = (usb_device_ehci_state_struct_t *)handle; + + if (ehciState == NULL) + { + return kStatus_hsdcd_Error; + } + + /*messsgae buffer contain event information*/ + message.buffer = (uint8_t *)param; + message.length = 0U; + message.isSetup = 0U; + message.code = kUSB_DeviceNotifyDcdDetectFinished; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + + return error; +} + +void USB_DeviceEhciIsrHSDCDFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_ehci_state_struct_t *ehciState; + if (NULL == deviceHandle) + { + return; + } + ehciState = (usb_device_ehci_state_struct_t *)(handle->controllerHandle); + USB_HSDcdIsrFunction(ehciState->dcdHandle); +} +#endif + +/*! + * @brief Initialize the USB device EHCI instance. + * + * This function initializes the USB device EHCI 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 ehciHandle It is out parameter, is used to return pointer of the device EHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *ehciHandle) +{ + usb_device_ehci_state_struct_t *ehciState; + uint32_t ehci_base[] = USBHS_BASE_ADDRS; + uint8_t intanceIndex; + +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) || \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U))) + + usb_device_callback_message_struct_t message; +#endif + +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + ((defined FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + + uint8_t index; + usb_phydcd_config_struct_t phyDcdParamConfig; + usb_phydcd_status_t phyDcdError = kStatus_phydcd_Success; +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + uint32_t hsdcd_base[] = USBHSDCD_BASE_ADDRS; + USBHSDCD_Type *base; + usb_hsdcd_config_struct_t dcdParamConfig; + usb_hsdcd_status_t dcdError = kStatus_hsdcd_Success; +#endif + if ((controllerId < kUSB_ControllerEhci0) || + ((uint32_t)(controllerId - kUSB_ControllerEhci0) >= (sizeof(ehci_base) / sizeof(uint32_t)))) + { + return kStatus_USB_ControllerNotFound; + } + + ehciState = USB_EhciGetValidEhciState(&intanceIndex); + + ehciState->dtd = s_UsbDeviceEhciDtd[intanceIndex]; + ehciState->qh = (usb_device_ehci_qh_struct_t *)&qh_buffer[intanceIndex * 2048]; + + ehciState->controllerId = controllerId; + + ehciState->registerBase = (USBHS_Type *)ehci_base[controllerId - kUSB_ControllerEhci0]; +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + ehciState->registerPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciState->registerNcBase = (USBNC_Type *)USB_EhciNCGetBase(controllerId); +#endif + +#endif + + /* Get the HW's endpoint count */ + ehciState->endpointCount = + (uint8_t)((ehciState->registerBase->DCCPARAMS & USBHS_DCCPARAMS_DEN_MASK) >> USBHS_DCCPARAMS_DEN_SHIFT); + + if (ehciState->endpointCount < USB_DEVICE_CONFIG_ENDPOINTS) + { + return kStatus_USB_Error; + } + ehciState->deviceHandle = (usb_device_struct_t *)handle; + + /* Clear the controller mode field and set to device mode. */ + ehciState->registerBase->USBMODE &= ~USBHS_USBMODE_CM_MASK; + ehciState->registerBase->USBMODE |= USBHS_USBMODE_CM(0x02U); + + /* Set the EHCI to default status. */ + USB_DeviceEhciSetDefaultState(ehciState); + *ehciHandle = (usb_device_controller_handle)ehciState; +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + + index = controllerId - kUSB_ControllerEhci0; + + phyDcdParamConfig.dcdCallback = USB_DeviceEhciIsrPHYDCDCallback; + phyDcdParamConfig.dcdCallbackParam = (void *)ehciState; + + phyDcdError = USB_PHYDCD_Init(index, (usb_phydcd_config_struct_t *)&phyDcdParamConfig, (void *)&ehciState->dcdHandle); + if(kStatus_phydcd_Success != phyDcdError) + { + return kStatus_USB_Error; + } + + if (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK) + { + /* Device is connected to a host. */ + message.code = kUSB_DeviceNotifyAttach; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + + USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdRun, NULL); + + } +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + base = (USBHSDCD_Type *)hsdcd_base[controllerId - kUSB_ControllerEhci0]; + dcdParamConfig.dcdCallback = USB_DeviceEhciIsrHSDCDCallback; + dcdParamConfig.dcdCallbackParam = (void *)ehciState; + dcdError = USB_HSDCD_Init(base, &dcdParamConfig,&ehciState->dcdHandle); + if(kStatus_hsdcd_Success != dcdError) + { + return kStatus_USB_Error; + } + + if (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK) + { + /* Device is connected to a host. */ + message.code = kUSB_DeviceNotifyAttach; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdRun, NULL); + + } +#endif + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize the USB device EHCI instance. + * + * This function de-initializes the USB device EHCI module. + * + * @param ehciHandle Pointer of the device EHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciDeinit(usb_device_controller_handle ehciHandle) +{ + usb_device_ehci_state_struct_t *ehciState = (usb_device_ehci_state_struct_t *)ehciHandle; + + if (!ehciHandle) + { + return kStatus_USB_InvalidHandle; + } + for (uint8_t instance = 0; instance < USB_DEVICE_CONFIG_EHCI; instance++) + { + if (ehciState == &g_UsbDeviceEhciState[instance]) + { + g_UsbDeviceEhciStateStatus[instance] = 0; + } + } + + /* Disable all interrupt. */ + ehciState->registerBase->USBINTR = 0U; + /* Stop the device functionality. */ + ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_RS_MASK; + /* Reset the controller. */ + ehciState->registerBase->USBCMD |= USBHS_USBCMD_RST_MASK; +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + USB_PHYDCD_Deinit(ehciState->dcdHandle); +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + USB_HSDCD_Deinit(ehciState->dcdHandle); +#endif + return kStatus_USB_Success; +} + +/*! + * @brief Send data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param ehciHandle Pointer of the device EHCI 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_DeviceEhciSend(usb_device_controller_handle ehciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + /* Add dtd to the QH */ + return USB_DeviceEhciTransfer( + (usb_device_ehci_state_struct_t *)ehciHandle, + (endpointAddress & USB_ENDPOINT_NUMBER_MASK) | (USB_IN << USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT), + buffer, length); +} + +/*! + * @brief Receive data through a specified endpoint. + * + * This function Receives data through a specified endpoint. + * + * @param ehciHandle Pointer of the device EHCI 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_DeviceEhciRecv(usb_device_controller_handle ehciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + /* Add dtd to the QH */ + return USB_DeviceEhciTransfer( + (usb_device_ehci_state_struct_t *)ehciHandle, + (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 ehciHandle Pointer of the device EHCI handle. + * @param ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciCancel(usb_device_controller_handle ehciHandle, uint8_t ep) +{ + usb_device_ehci_state_struct_t *ehciState = (usb_device_ehci_state_struct_t *)ehciHandle; + usb_device_callback_message_struct_t message; + usb_device_ehci_dtd_struct_t *currentDtd; + uint32_t primeBit = + 1U << ((ep & USB_ENDPOINT_NUMBER_MASK) + ((ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> 0x03U)); + uint8_t index = + ((ep & USB_ENDPOINT_NUMBER_MASK) << 1U) | ((ep & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> 0x07U); + + OSA_SR_ALLOC(); + + if (!ehciHandle) + { + return kStatus_USB_InvalidHandle; + } + + OSA_ENTER_CRITICAL(); + + message.buffer = NULL; + message.length = USB_UNINITIALIZED_VAL_32; + + /* Get the first dtd */ + currentDtd = + (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK); + + /* In the next loop, USB_DeviceNotificationTrigger function may trigger a new transfer and the context always + * keep in the critical section, so the Dtd sequence would still keep non-empty and the loop would be endless. + * We set the Dtd's dtdInvalid in this while and add an if statement in the next loop so that this issue could + * be fixed. + */ + while (currentDtd) + { + currentDtd->reservedUnion.originalBufferInfo.dtdInvalid = 1U; + currentDtd = (usb_device_ehci_dtd_struct_t *)(currentDtd->nextDtdPointer & USB_DEVICE_ECHI_DTD_POINTER_MASK); + } + + /* Get the first dtd */ + currentDtd = + (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK); + while (currentDtd) + { + /* this if statement is used with the previous while loop to avoid the endless loop */ + if (!currentDtd->reservedUnion.originalBufferInfo.dtdInvalid) + { + break; + } + else + { + if (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE) + { + /* Flush the endpoint to stop a transfer. */ + do + { + /* Set the corresponding bit(s) in the EPFLUSH register */ + ehciState->registerBase->EPFLUSH |= primeBit; + + /* Wait until all bits in the EPFLUSH register are cleared. */ + while (ehciState->registerBase->EPFLUSH & primeBit) + { + } + /* + * Read the EPSR register to ensure that for all endpoints + * commanded to be flushed, that the corresponding bits + * are now cleared. + */ + } while (ehciState->registerBase->EPSR & primeBit); + } + + /* Save the original buffer address. */ + if (NULL == message.buffer) + { + message.buffer = (uint8_t *)((currentDtd->bufferPointerPage[0] & USB_DEVICE_ECHI_DTD_PAGE_MASK) | + (currentDtd->reservedUnion.originalBufferInfo.originalBufferOffest)); + } + + /* Remove the dtd from the dtd in-used queue. */ + if (ehciState->dtdHard[index] == ehciState->dtdTail[index]) + { + ehciState->dtdHard[index] = NULL; + ehciState->dtdTail[index] = NULL; + } + else + { + ehciState->dtdHard[index] = (usb_device_ehci_dtd_struct_t *)ehciState->dtdHard[index]->nextDtdPointer; + } + + /* When the ioc is set or the dtd queue is empty, the up layer will be notified. */ + if ((currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) || + (0 == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK))) + { + message.code = ep; + message.isSetup = 0U; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + message.buffer = NULL; + } + /* Clear the token field. */ + currentDtd->dtdTokenUnion.dtdToken = 0U; + /* Save the dtd to the free queue. */ + currentDtd->nextDtdPointer = (uint32_t)ehciState->dtdFree; + ehciState->dtdFree = currentDtd; + ehciState->dtdCount++; + } + /* Get the next dtd. */ + currentDtd = + (usb_device_ehci_dtd_struct_t *)((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK); + } + if (!currentDtd) + { + /* Set the QH to empty. */ + ehciState->qh[index].nextDtdPointer = USB_DEVICE_ECHI_DTD_TERMINATE_MASK; + ehciState->qh[index].dtdTokenUnion.dtdToken = 0U; + } + OSA_EXIT_CRITICAL(); + 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 ehciHandle Pointer of the device EHCI 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_DeviceEhciControl(usb_device_controller_handle ehciHandle, usb_device_control_type_t type, void *param) +{ + usb_device_ehci_state_struct_t *ehciState = (usb_device_ehci_state_struct_t *)ehciHandle; + usb_status_t error = kStatus_USB_Error; + uint16_t *temp16; + uint8_t *temp8; + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + usb_device_struct_t *deviceHandle; + uint64_t startTick; +#endif + + if (!ehciHandle) + { + return kStatus_USB_InvalidHandle; + } + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + deviceHandle = (usb_device_struct_t *)ehciState->deviceHandle; +#endif + + switch (type) + { + case kUSB_DeviceControlRun: + ehciState->registerBase->USBCMD |= USBHS_USBCMD_RS_MASK; + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlStop: + ehciState->registerBase->USBCMD &= ~USBHS_USBCMD_RS_MASK; + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlEndpointInit: + if (param) + { + error = USB_DeviceEhciEndpointInit(ehciState, (usb_device_endpoint_init_struct_t *)param); + } + break; + case kUSB_DeviceControlEndpointDeinit: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceEhciEndpointDeinit(ehciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointStall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceEhciEndpointStall(ehciState, *temp8); + } + break; + case kUSB_DeviceControlEndpointUnstall: + if (param) + { + temp8 = (uint8_t *)param; + error = USB_DeviceEhciEndpointUnstall(ehciState, *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)) + | (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; + uint8_t ep = (endpointStatus->endpointAddress) & USB_ENDPOINT_NUMBER_MASK; + uint8_t direction = + ((endpointStatus->endpointAddress) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >> + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT; + + if (ep < USB_DEVICE_CONFIG_ENDPOINTS) + { + if (ep) + { + endpointStatus->endpointStatus = (ehciState->registerBase->EPCR[ep - 1U] & + (direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK)) ? + kUSB_DeviceEndpointStateStalled : + kUSB_DeviceEndpointStateIdle; + } + else + { + endpointStatus->endpointStatus = + (ehciState->registerBase->EPCR0 & (direction ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK)) ? + kUSB_DeviceEndpointStateStalled : + kUSB_DeviceEndpointStateIdle; + } + error = kStatus_USB_Success; + } + } + break; + case kUSB_DeviceControlPreSetDeviceAddress: + if (param) + { + temp8 = (uint8_t *)param; + ehciState->registerBase->DEVICEADDR = ((((uint32_t)(*temp8)) << USBHS_DEVICEADDR_USBADR_SHIFT) | USBHS_DEVICEADDR_USBADRA_MASK); + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlSetDeviceAddress: + 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: +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciState->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK; +#else + ehciState->registerBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK; +#endif + ehciState->registerBase->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK; + ehciState->registerBase->PORTSC1 |= USBHS_PORTSC1_FPR_MASK; + startTick = deviceHandle->hwTick; + while ((deviceHandle->hwTick - startTick) < 10) + { + __ASM("nop"); + } + ehciState->registerBase->PORTSC1 &= ~USBHS_PORTSC1_FPR_MASK; + error = kStatus_USB_Success; + break; +#endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + case kUSB_DeviceControlSuspend: + ehciState->registerBase->OTGSC |= 0x007F0000U; + ehciState->registerPhyBase->PWD = 0xFFFFFFFF; + /* ehciState->registerBase->OTGCTL |= ((1U<<10) | (1U<<17) | (1U<<16)); */ + while (ehciState->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK)) + { + __ASM("nop"); + } + /* ehciState->registerPhyBase->CTRL |= ((1U << 21) | (1U << 22) | (1U << 23)); */ + ehciState->registerBase->USBSTS |= USBHS_USBSTS_SRI_MASK; + ehciState->registerBase->PORTSC1 |= USBHS_PORTSC1_PHCD_MASK; +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + ehciState->registerPhyBase->CTRL |= USBPHY_CTRL_ENVBUSCHG_WKUP_MASK | USBPHY_CTRL_ENIDCHG_WKUP_MASK | + USBPHY_CTRL_ENDPDMCHG_WKUP_MASK | USBPHY_CTRL_ENIRQRESUMEDETECT_MASK; + ehciState->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WKUP_ID_EN_MASK | + USBNC_USB_OTGn_CTRL_WKUP_VBUS_EN_MASK | + USBNC_USB_OTGn_CTRL_WKUP_DPDM_EN_MASK; + ehciState->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WIE_MASK; +#else + ehciState->registerBase->USBGENCTRL = USBHS_USBGENCTRL_WU_IE_MASK; +#endif + ehciState->registerPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; + ehciState->isSuspending = 1U; + 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_DeviceEhciEndpointDeinit(ehciState, (count | (USB_IN << 0x07U))); + USB_DeviceEhciEndpointDeinit(ehciState, (count | (USB_OUT << 0x07U))); + } + USB_DeviceEhciSetDefaultState(ehciState); + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlGetSpeed: + if (param) + { + temp8 = (uint8_t *)param; + *temp8 = ehciState->speed; + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetOtgStatus: + break; + case kUSB_DeviceControlSetOtgStatus: + break; +#if (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + case kUSB_DeviceControlSetTestMode: + if (param) + { + temp8 = (uint8_t *)param; + ehciState->registerBase->PORTSC1 |= ((uint32_t)(*temp8) << 16U); + error = kStatus_USB_Success; + } + break; +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + + case kUSB_DeviceControlUpdateHwTick: + /*udpate 1ms time tick*/ +#if (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + USB_PHYDCD_TimerIsrFunction(ehciState->dcdHandle); +#endif + error = kStatus_USB_Success; + break; + case kUSB_DeviceControlDcdEnable: +#if (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + if (kStatus_phydcd_Success == USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdEnable, NULL)) + { + error = kStatus_USB_Success; + } +#endif +#if (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + if(kStatus_hsdcd_Success == USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdEnable, NULL)) + { + error = kStatus_USB_Success; + } +#endif + break; + case kUSB_DeviceControlDcdDisable: +#if (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + if(kStatus_phydcd_Success == USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdDisable, NULL)) + { + error = kStatus_USB_Success; + } +#endif +#if (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + if(kStatus_hsdcd_Success == USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdDisable, NULL)) + { + error = kStatus_USB_Success; + } +#endif + break; +#endif + + default: + break; + } + + return error; +} + +/*! + * @brief Handle the EHCI device interrupt. + * + * The function is used to handle the EHCI device interrupt. + * + * @param deviceHandle The device handle got from USB_DeviceInit. + * + */ +void USB_DeviceEhciIsrFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_ehci_state_struct_t *ehciState; + uint32_t status; + + if (NULL == deviceHandle) + { + return; + } + + ehciState = (usb_device_ehci_state_struct_t *)(handle->controllerHandle); + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + + if (ehciState->registerNcBase->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIE_MASK) + { + if (ehciState->registerNcBase->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIR_MASK) + { + ehciState->registerBase->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK; + ehciState->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK; + } + } + else + { + } + +#else + if (ehciState->registerBase->USBGENCTRL & USBHS_USBGENCTRL_WU_IE_MASK) + { + if (ehciState->registerBase->USBGENCTRL & (1U << 8)) + { + ehciState->registerBase->USBGENCTRL &= ~(1U << 8); + ehciState->registerBase->USBGENCTRL |= USBHS_USBGENCTRL_WU_INT_CLR_MASK; + ehciState->registerBase->PORTSC1 &= ~USBHS_PORTSC1_PHCD_MASK; + ehciState->registerBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK; + } + } + else + { + } +#endif + +#endif + +#if defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE > 0U) + if (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSVIS_MASK) + { + usb_device_callback_message_struct_t message; + + ehciState->registerBase->OTGSC |= USBHS_OTGSC_BSVIS_MASK; + + message.buffer = (uint8_t *)NULL; + message.length = 0U; + message.isSetup = 0U; + if (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK) + { + /* Device is connected to a host. */ + message.code = kUSB_DeviceNotifyAttach; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U)) + USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdRun, NULL); +#endif +#if (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) && \ + (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + + USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdRun, NULL); +#endif + } + else + { + /* Device is disconnected from a host. */ + message.code = kUSB_DeviceNotifyDetach; + USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message); + } + } +#endif /* USB_DEVICE_CONFIG_DETACH_ENABLE */ + + status = ehciState->registerBase->USBSTS; + status &= ehciState->registerBase->USBINTR; + + ehciState->registerBase->USBSTS = status; + +#if defined(USB_DEVICE_CONFIG_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U) + if (status & USBHS_USBSTS_UEI_MASK) + { + /* Error interrupt */ + USB_DeviceEhciInterruptError(ehciState); + } +#endif /* USB_DEVICE_CONFIG_ERROR_HANDLING */ + + if (status & USBHS_USBSTS_URI_MASK) + { + /* Reset interrupt */ + USB_DeviceEhciInterruptReset(ehciState); + } + + if (status & USBHS_USBSTS_UI_MASK) + { + /* Token done interrupt */ + USB_DeviceEhciInterruptTokenDone(ehciState); + } + + if (status & USBHS_USBSTS_PCI_MASK) + { + /* Port status change interrupt */ + USB_DeviceEhciInterruptPortChange(ehciState); + } + +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + if (status & USBHS_USBSTS_SLI_MASK) + { + /* Suspend interrupt */ + USB_DeviceEhciInterruptSuspend(ehciState); + } +#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */ + + if (status & USBHS_USBSTS_SRI_MASK) + { + /* Sof interrupt */ + USB_DeviceEhciInterruptSof(ehciState); + } +} + + + +#endif /* USB_DEVICE_CONFIG_EHCI */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.h new file mode 100644 index 0000000000..2e58836dcf --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_ehci.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DEVICE_EHCI_H__ +#define __USB_DEVICE_EHCI_H__ + + +/*! + * @addtogroup usb_device_controller_ehci_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief The maximum value of ISO type maximum packet size for HS in USB specification 2.0 */ +#define USB_DEVICE_MAX_HS_ISO_MAX_PACKET_SIZE (1024U) + +/*! @brief The maximum value of interrupt type maximum packet size for HS in USB specification 2.0 */ +#define USB_DEVICE_MAX_HS_INTERUPT_MAX_PACKET_SIZE (1024U) + +/*! @brief The maximum value of bulk type maximum packet size for HS in USB specification 2.0 */ +#define USB_DEVICE_MAX_HS_BULK_MAX_PACKET_SIZE (512U) + +/*! @brief The maximum value of control type maximum packet size for HS in USB specification 2.0 */ +#define USB_DEVICE_MAX_HS_CONTROL_MAX_PACKET_SIZE (64U) + +#define USB_DEVICE_MAX_TRANSFER_PRIME_TIMES (10000000U) /* The max prime times of EPPRIME, if still doesn't take effect, means status has been reset*/ + +/* Device QH */ +#define USB_DEVICE_EHCI_QH_POINTER_MASK (0xFFFFFFC0U) +#define USB_DEVICE_EHCI_QH_MULT_MASK (0xC0000000U) +#define USB_DEVICE_EHCI_QH_ZLT_MASK (0x20000000U) +#define USB_DEVICE_EHCI_QH_MAX_PACKET_SIZE_MASK (0x07FF0000U) +#define USB_DEVICE_EHCI_QH_MAX_PACKET_SIZE (0x00000800U) +#define USB_DEVICE_EHCI_QH_IOS_MASK (0x00008000U) + +/* Device DTD */ +#define USB_DEVICE_ECHI_DTD_POINTER_MASK (0xFFFFFFE0U) +#define USB_DEVICE_ECHI_DTD_TERMINATE_MASK (0x00000001U) +#define USB_DEVICE_ECHI_DTD_PAGE_MASK (0xFFFFF000U) +#define USB_DEVICE_ECHI_DTD_PAGE_OFFSET_MASK (0x00000FFFU) +#define USB_DEVICE_ECHI_DTD_PAGE_BLOCK (0x00001000U) +#define USB_DEVICE_ECHI_DTD_TOTAL_BYTES_MASK (0x7FFF0000U) +#define USB_DEVICE_ECHI_DTD_TOTAL_BYTES (0x00004000U) +#define USB_DEVICE_ECHI_DTD_IOC_MASK (0x00008000U) +#define USB_DEVICE_ECHI_DTD_MULTIO_MASK (0x00000C00U) +#define USB_DEVICE_ECHI_DTD_STATUS_MASK (0x000000FFU) +#define USB_DEVICE_EHCI_DTD_STATUS_ERROR_MASK (0x00000068U) +#define USB_DEVICE_ECHI_DTD_STATUS_ACTIVE (0x00000080U) +#define USB_DEVICE_ECHI_DTD_STATUS_HALTED (0x00000040U) +#define USB_DEVICE_ECHI_DTD_STATUS_DATA_BUFFER_ERROR (0x00000020U) +#define USB_DEVICE_ECHI_DTD_STATUS_TRANSACTION_ERROR (0x00000008U) + +typedef struct _usb_device_ehci_qh_struct +{ + union + { + volatile uint32_t capabilttiesCharacteristics; + struct + { + volatile uint32_t reserved1 : 15; + volatile uint32_t ios : 1; + volatile uint32_t maxPacketSize : 11; + volatile uint32_t reserved2 : 2; + volatile uint32_t zlt : 1; + volatile uint32_t mult : 2; + } capabilttiesCharacteristicsBitmap; + } capabilttiesCharacteristicsUnion; + volatile uint32_t currentDtdPointer; + volatile uint32_t nextDtdPointer; + union + { + volatile uint32_t dtdToken; + struct + { + volatile uint32_t status : 8; + volatile uint32_t reserved1 : 2; + volatile uint32_t multiplierOverride : 2; + volatile uint32_t reserved2 : 3; + volatile uint32_t ioc : 1; + volatile uint32_t totalBytes : 15; + volatile uint32_t reserved3 : 1; + } dtdTokenBitmap; + } dtdTokenUnion; + volatile uint32_t bufferPointerPage[5]; + volatile uint32_t reserved1; + uint32_t setupBuffer[2]; + uint32_t setupBufferBack[2]; + union + { + uint32_t endpointStatus; + struct + { + uint32_t isOpened : 1; + uint32_t zlt: 1; + uint32_t : 30; + } endpointStatusBitmap; + } endpointStatusUnion; + uint32_t reserved2; +} usb_device_ehci_qh_struct_t; + +typedef struct _usb_device_ehci_dtd_struct +{ + volatile uint32_t nextDtdPointer; + union + { + volatile uint32_t dtdToken; + struct + { + volatile uint32_t status : 8; + volatile uint32_t reserved1 : 2; + volatile uint32_t multiplierOverride : 2; + volatile uint32_t reserved2 : 3; + volatile uint32_t ioc : 1; + volatile uint32_t totalBytes : 15; + volatile uint32_t reserved3 : 1; + } dtdTokenBitmap; + } dtdTokenUnion; + volatile uint32_t bufferPointerPage[5]; + union + { + volatile uint32_t reserved; + struct + { + uint32_t originalBufferOffest : 12; + uint32_t originalBufferLength : 19; + uint32_t dtdInvalid : 1; + } originalBufferInfo; + } reservedUnion; +} usb_device_ehci_dtd_struct_t; + +/*! @brief EHCI state structure */ +typedef struct _usb_device_ehci_state_struct +{ + usb_device_struct_t *deviceHandle; /*!< Device handle used to identify the device object is belonged to */ + USBHS_Type *registerBase; /*!< The base address of the register */ +#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + USBPHY_Type *registerPhyBase; /*!< The base address of the PHY register */ +#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) + USBNC_Type *registerNcBase; /*!< The base address of the USBNC register */ +#endif +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) || \ + (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U))) + void* dcdHandle; /*!< Dcd handle used to identify the device object belongs to */ +#endif + usb_device_ehci_qh_struct_t *qh; /*!< The QH structure base address */ + usb_device_ehci_dtd_struct_t *dtd; /*!< The DTD structure base address */ + usb_device_ehci_dtd_struct_t *dtdFree; /*!< The idle DTD list head */ + usb_device_ehci_dtd_struct_t + *dtdHard[USB_DEVICE_CONFIG_ENDPOINTS * 2]; /*!< The transferring DTD list head for each endpoint */ + usb_device_ehci_dtd_struct_t + *dtdTail[USB_DEVICE_CONFIG_ENDPOINTS * 2]; /*!< The transferring DTD list tail for each endpoint */ + int8_t dtdCount; /*!< The idle DTD node count */ + uint8_t endpointCount; /*!< The endpoint number of EHCI */ + uint8_t isResetting; /*!< Whether a PORT reset is occurring or not */ + uint8_t controllerId; /*!< Controller ID */ + uint8_t speed; /*!< Current speed of EHCI */ + uint8_t isSuspending; /*!< Is suspending of the PORT */ +} usb_device_ehci_state_struct_t; + + + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name USB device EHCI functions + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Initializes the USB device EHCI instance. + * + * This function initializes the USB device EHCI 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 is belonged to. + * @param[out] ehciHandle An out parameter used to return the pointer of the device EHCI handle to the caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *ehciHandle); + +/*! + * @brief Deinitializes the USB device EHCI instance. + * + * This function deinitializes the USB device EHCI module. + * + * @param[in] ehciHandle Pointer of the device EHCI handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciDeinit(usb_device_controller_handle ehciHandle); + +/*! + * @brief Sends data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param[in] ehciHandle Pointer of the device EHCI 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 to be sent. + * + * @return A USB error code or kStatus_USB_Success. + * + * @note The return value means whether the sending request is successful or not. The transfer completion is indicated + * 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 received through the + * endpoint + * callback). + */ +usb_status_t USB_DeviceEhciSend(usb_device_controller_handle ehciHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length); + +/*! + * @brief Receive data through a specified endpoint. + * + * This function Receives data through a specified endpoint. + * + * @param[in] ehciHandle Pointer of the device EHCI handle. + * @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. + * + * @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_DeviceEhciRecv(usb_device_controller_handle ehciHandle, + 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] ehciHandle Pointer of the device EHCI handle. + * @param[in] ep Endpoint address, bit7 is the direction of endpoint, 1U - IN, 0U - OUT. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceEhciCancel(usb_device_controller_handle ehciHandle, 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] ehciHandle Pointer of the device EHCI 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_DeviceEhciControl(usb_device_controller_handle ehciHandle, + usb_device_control_type_t type, + void *param); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* __USB_DEVICE_EHCI_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.c new file mode 100644 index 0000000000..f9eeee8d82 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.c @@ -0,0 +1,1534 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" + +#include "usb_device.h" + +#include "fsl_device_registers.h" + +#if ((defined(USB_DEVICE_CONFIG_KHCI)) && (USB_DEVICE_CONFIG_KHCI > 0U)) + +#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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U) +static void USB_DeviceKhciInterruptError(usb_device_khci_state_struct_t *khciState); +#endif /* USB_DEVICE_CONFIG_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 USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) 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 USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_dcd_state_struct_t + s_UsbDeviceDcdState[USB_DEVICE_CONFIG_KHCI]; +#endif + +/* Apply for KHCI DMA aligned buffer when macro USB_DEVICE_CONFIG_KHCI_DMA_ALIGN enabled */ +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) 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; + OSA_SR_ALLOC(); + + /* Enter critical */ + 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 */ + 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; + uint8_t count; + + /* 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 (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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U) + /* Enable error interruprt */ + interruptFlag |= kUSB_KhciInterruptError; +#endif /* USB_DEVICE_CONFIG_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; +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_LOW) && (FSL_FEATURE_USB_KHCI_HAS_STALL_LOW > 0U) + /*control endpoint bidirection stall default state should be enable, iso doesn't support stall*/ + if ((USB_ENDPOINT_BULK == epInit->transferType) || (USB_ENDPOINT_INTERRUPT == epInit->transferType)) + { + if (USB_IN == direction) + { + if (endpoint < 8) + { + khciState->registerBase->STALL_IL_DIS |= (1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_IH_DIS |= (1 << (endpoint - 8)); + } +#endif + } + else + { + if (endpoint < 8) + { + khciState->registerBase->STALL_OL_DIS |= (1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_OH_DIS |= (1 << (endpoint - 8)); + } +#endif + } + } + else if ((USB_ENDPOINT_CONTROL == epInit->transferType)) + { + khciState->registerBase->STALL_IL_DIS &= ~(1 << endpoint); + khciState->registerBase->STALL_OL_DIS &= ~(1 << endpoint); + } + else + { + } +#endif + + /* 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; +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_LOW) && (FSL_FEATURE_USB_KHCI_HAS_STALL_LOW > 0U) + if (USB_CONTROL_ENDPOINT != endpoint) + { + if (USB_IN == direction) + { + if (endpoint < 8) + { + khciState->registerBase->STALL_IL_DIS &= ~(1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_IH_DIS &= ~(1 << (endpoint - 8)); + } +#endif + } + else + { + if (endpoint < 8) + { + khciState->registerBase->STALL_OL_DIS &= ~(1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_OH_DIS &= ~(1 << (endpoint - 8)); + } +#endif + } + } +#endif + /* Set endpoint stall in BDT. And then if the host send a IN/OUT tansaction, 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) +{ + 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; + uint8_t i; + + /* 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 (i = 0U; i < 2U; i++) + { + 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; +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_LOW) && (FSL_FEATURE_USB_KHCI_HAS_STALL_LOW > 0U) + if (USB_CONTROL_ENDPOINT != endpoint) + { + if (USB_IN == direction) + { + if (endpoint < 8) + { + khciState->registerBase->STALL_IL_DIS |= (1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_IH_DIS |= (1 << (endpoint - 8)); + } +#endif + } + else + { + if (endpoint < 8) + { + khciState->registerBase->STALL_OL_DIS |= (1 << endpoint); + } +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH) && (FSL_FEATURE_USB_KHCI_HAS_STALL_HIGH > 0U) + else if ((endpoint >= 8) && (endpoint < 16)) + { + khciState->registerBase->STALL_OH_DIS |= (1 << (endpoint - 8)); + } +#endif + } + } +#endif + if ((USB_CONTROL_ENDPOINT != endpoint)) + { + /* Cancel the transfer of the endpoint */ + USB_DeviceKhciCancel(khciState, ep); + } + + /* 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 tansaction 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 transferred 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) + { + memcpy(transferBuffer, buffer, length); + } + 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)) +/*! + * @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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_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_ERROR_HANDLING */ + +/*! + * @brief Initialize the USB device KHCI instance. + * + * This function initializes 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 (((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)) + 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 + +#endif +#if defined(FSL_FEATURE_USB_KHCI_HAS_STALL_LOW) && (FSL_FEATURE_USB_KHCI_HAS_STALL_LOW > 0U) + khciState->registerBase->MISCCTRL |= USB_MISCCTRL_STL_ADJ_EN_MASK; +#endif + + /* Set KHCI device state to default value. */ + USB_DeviceKhciSetDefaultState(khciState); + + *khciHandle = khciState; + khciState->deviceHandle = (usb_device_struct_t *)handle; + + return kStatus_USB_Success; +} + +/*! + * @brief De-initialize the USB device KHCI instance. + * + * This function de-initializes 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 transfer 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 transfer 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; + uint8_t count; + +#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 (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_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + case kUSB_DeviceControlUpdateHwTick: + /*udpate 1ms time tick*/ + error = kStatus_USB_Success; + 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; + status &= khciState->registerBase->INTEN; +#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_ERROR_HANDLING) && (USB_DEVICE_CONFIG_ERROR_HANDLING > 0U) + /* Error interrupt */ + if (status & kUSB_KhciInterruptError) + { + USB_DeviceKhciInterruptError(khciState); + } +#endif /* USB_DEVICE_CONFIG_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); + } + + /* Check for Asynchronous Resume interrupt if it was enabled */ + if ((khciState->registerBase->USBTRC0 & USB_USBTRC0_USB_RESUME_INT_MASK) && + (khciState->registerBase->USBTRC0 & USB_USBTRC0_USBRESMEN_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 happened */ + 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 +} + +#endif /* USB_DEVICE_CONFIG_KHCI */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.h new file mode 100644 index 0000000000..f2c5c60b84 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_khci.h @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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) + +#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; + +/*! @brief Set BDT buffer address */ +#define USB_KHCI_BDT_SET_ADDRESS(bdt_base, ep, direction, odd, address) \ + *(((volatile uint32_t *)((uint8_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 *)((uint8_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 *)((uint8_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 *)((uint8_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/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.c new file mode 100644 index 0000000000..5f7bd12577 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.c @@ -0,0 +1,2213 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017,2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb_device_config.h" +#include "usb.h" +#include "usb_device.h" +#include "fsl_device_registers.h" +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + ((defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))) +#include "usb_hsdcd.h" +#endif +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) +#include "usb_phy.h" +#endif +#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_dci.h" +#include "usb_device_lpcip3511.h" + +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + +#define USB_LPC3511IP_INTSTAT_DEV_INT_MASK USBHSD_INTSTAT_DEV_INT_MASK +#define USB_LPC3511IP_INTSTAT_FRAME_INT_MASK USBHSD_INTSTAT_FRAME_INT_MASK + +#define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK USBHSD_DEVCMDSTAT_INTONNAK_AO_MASK +#define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK USBHSD_DEVCMDSTAT_INTONNAK_AI_MASK + +#define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK USBHSD_DEVCMDSTAT_LPM_REWP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT USBHSD_DEVCMDSTAT_LPM_REWP_SHIFT + +#define USB_LPC3511IP_DEVCMDSTAT_Speed_MASK USBHSD_DEVCMDSTAT_Speed_MASK + +#define USB_LPC3511IP_DEVCMDSTAT_DCON_MASK USBHSD_DEVCMDSTAT_DCON_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK USBHSD_DEVCMDSTAT_DEV_EN_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USBHSD_DEVCMDSTAT_LPM_SUP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK USBHSD_DEVCMDSTAT_FORCE_NEEDCLK_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK USBHSD_DEVCMDSTAT_LPM_SUS_MASK + +#define USB_LPC3511IP_USB_LPM_HIRD_SW USBHSD_LPM_HIRD_SW + +#define USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK USBHSD_DEVCMDSTAT_DEV_ADDR_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK USBHSD_DEVCMDSTAT_DSUS_MASK +#define USB_LPC3511IP_INFO_ERR_CODE_MASK USBHSD_INFO_ERR_CODE_MASK +#define USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK USBHSD_DEVCMDSTAT_SETUP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK USBHSD_DEVCMDSTAT_DRES_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK USBHSD_DEVCMDSTAT_DSUS_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DCON_C_MASK USBHSD_DEVCMDSTAT_DCON_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK USBHSD_DEVCMDSTAT_VBUS_DEBOUNCED_MASK +#else +#define USB_LPC3511IP_INTSTAT_DEV_INT_MASK USB_INTSTAT_DEV_INT_MASK +#define USB_LPC3511IP_INTSTAT_FRAME_INT_MASK USB_INTSTAT_FRAME_INT_MASK + +#define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK USB_DEVCMDSTAT_INTONNAK_AO_MASK +#define USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK USB_DEVCMDSTAT_INTONNAK_AI_MASK + +#define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK USB_DEVCMDSTAT_LPM_REWP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT USB_DEVCMDSTAT_LPM_REWP_SHIFT + +#define USB_LPC3511IP_DEVCMDSTAT_DCON_MASK USB_DEVCMDSTAT_DCON_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK USB_DEVCMDSTAT_DEV_EN_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USB_DEVCMDSTAT_LPM_SUP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK USB_DEVCMDSTAT_FORCE_NEEDCLK_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK USB_DEVCMDSTAT_LPM_SUP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK USB_DEVCMDSTAT_LPM_SUS_MASK + +#define USB_LPC3511IP_USB_LPM_HIRD_SW USB_LPM_HIRD_SW + +#define USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK USB_DEVCMDSTAT_DEV_ADDR_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK USB_DEVCMDSTAT_DSUS_MASK +#define USB_LPC3511IP_INFO_ERR_CODE_MASK USB_INFO_ERR_CODE_MASK +#define USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK USB_DEVCMDSTAT_SETUP_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK USB_DEVCMDSTAT_DRES_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK USB_DEVCMDSTAT_DSUS_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_DCON_C_MASK USB_DEVCMDSTAT_DCON_C_MASK +#define USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK USB_DEVCMDSTAT_VBUSDEBOUNCED_MASK +#endif + +#define USB_LPC3511IP_USB_LPM_ADPPROBE_MASK (0x00100000u) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* on Aruba IP3511 (USB0 FS), there are 8 physical EPs, on IP3511 HS (USB1 FS), there are 10 physical EPs. */ +#define USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK (0xFFFFu) + +/*! @brief endpoint command status, buffer address offset */ +#define USB_LPC3511IPHS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK (0x000007FFu) +#define USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT (11) +#define USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_MASK (0x03FFF800u) +#define USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK (0x0000FFFFu) +#define USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT (16) +#define USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_MASK (0x03FF0000u) + +#define USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK (0x01U << 26) +#define USB_LPC3511IP_ENDPOINT_RFTV_MASK (0x01U << 27) +#define USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK (0x01U << 28) +#define USB_LPC3511IP_ENDPOINT_STALL_MASK (0x01U << 29) +#define USB_LPC3511IP_ENDPOINT_STALL_SHIFT (29) +#define USB_LPC3511IP_ENDPOINT_DISABLE_MASK (0x01U << 30) +#define USB_LPC3511IP_ENDPOINT_ACTIVE_MASK (0x01U << 31) +#define USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT (26) + +#define USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK (0x0F000000u) + +#define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpcState, index, odd, value) \ + *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) | \ + (((uint32_t)(odd)&1U) << 2U))) &= (value) + +/*! @brief Set endpoint command/status value */ +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpcState, index, odd, value, NBytes, address) \ + \ + *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) | \ + (((uint32_t)(odd & 1U)) << 2U))) = \ + ((lpc3511IpState->controllerSpeed) ? \ + \ + ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT) | \ + (((uint32_t)(address) >> 6) & USB_LPC3511IPHS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK)) : \ + \ + ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT) | \ + (((uint32_t)(address) >> 6) & USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK))) +#else +#define USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpcState, index, odd, value, NBytes, address) \ + \ + *((volatile uint32_t *)(((uint32_t)(lpcState->epCommandStatusList)) | ((uint32_t)(index) << 3) | \ + (((uint32_t)(odd & 1U)) << 2U))) = \ + ((uint32_t)(value) | ((uint32_t)(NBytes) << USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT) | \ + (((uint32_t)(address) >> 6) & USB_LPC3511IPFS_ENDPOINT_BUFFER_ADDRESS_OFFSET_MASK)) +#endif + +#define USB_LPC3511IP_ENDPOINT_DES_INDEX(endpoint) \ + (((((uint32_t)endpoint) & 0x0F) << 1) + \ + ((((uint32_t)endpoint) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ? (1) : (0))) + +#define USB_LPC3511IP_GET_MULTIPLE_OF_64(n) ((n + 63U) & 0xFFFFFFC0U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +extern usb_status_t USB_DeviceNotificationTrigger(void *handle, void *msg); +static usb_status_t USB_DeviceLpc3511IpTransaction(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint8_t endpointIndex); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/* define the reserved buffer for endpoint max packet copy */ + +#define SETUP_TRANSFER_DATA_OFFSET (0u) +#define CONTROL_TRANSFER_DATA_OFFSET ((USB_DATA_ALIGN_SIZE_MULTIPLE(8U) >> 2)) +#define ZERO_TRANSFER_DATA_OFFSET ((USB_DATA_ALIGN_SIZE_MULTIPLE(8U) >> 2) + (USB_DATA_ALIGN_SIZE_MULTIPLE(64U) >> 2)) +#define RESERVED_EP_DATA_OFFSET \ + ((USB_DATA_ALIGN_SIZE_MULTIPLE(8U) >> 2) + (USB_DATA_ALIGN_SIZE_MULTIPLE(64U) >> 2) + \ + (USB_DATA_ALIGN_SIZE_MULTIPLE(4) >> 2)) + +#if defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint32_t + s_SetupAndEpReservedData[USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY] + [USB_DATA_ALIGN_SIZE_MULTIPLE((USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE >> 2)) + + RESERVED_EP_DATA_OFFSET]; +#else +USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static uint32_t + s_SetupAndEpReservedData[USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS][RESERVED_EP_DATA_OFFSET]; +#endif + +static usb_device_lpc3511ip_state_struct_t + s_UsbDeviceLpc3511IpState[USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS]; + +/* LPC3511IP controller driver instances and endpoint command/status list, EPLISTSTART's value is the buffer pointer. */ +#if ((USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) == 1U) +USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t + s_EpCommandStatusList1[((USB_DEVICE_IP3511_ENDPOINTS_NUM)) * 4]; +#define LPC_CONTROLLER_ENDPOINT_LIST_ARRAY \ + { \ + &s_EpCommandStatusList1[0] \ + } + +#elif ((USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) == 2U) +USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t + s_EpCommandStatusList1[(USB_DEVICE_IP3511_ENDPOINTS_NUM)*4]; +USB_CONTROLLER_DATA USB_RAM_ADDRESS_ALIGNMENT(256) static uint32_t + s_EpCommandStatusList2[(USB_DEVICE_IP3511_ENDPOINTS_NUM)*4]; +#define LPC_CONTROLLER_ENDPOINT_LIST_ARRAY \ + { \ + &s_EpCommandStatusList1[0], &s_EpCommandStatusList2[0] \ + } + +#else +#error "increase the instance count." +#endif + +#if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) +#if (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == (USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS)) +#define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u +#elif ((USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511FS) && \ + (!USB_DEVICE_CONFIG_LPCIP3511HS)) +#define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u +#elif ((USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511HS) && \ + (!USB_DEVICE_CONFIG_LPCIP3511FS)) +#define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 1u +#else +#define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 0u +#endif + +#else +#define USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER 0u + +#endif + +/******************************************************************************* + * Code + ******************************************************************************/ +#if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) + +static inline uint8_t USB_DeviceLpcIp3511MaxPacketNeedCopy(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ +#if (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == (USB_DEVICE_CONFIG_LPCIP3511HS + USB_DEVICE_CONFIG_LPCIP3511FS)) + return 1u; +#elif (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511HS) + return (lpc3511IpState->controllerSpeed); +#elif (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY == USB_DEVICE_CONFIG_LPCIP3511FS) +#if (defined USB_DEVICE_CONFIG_LPCIP3511HS) && (USB_DEVICE_CONFIG_LPCIP3511HS) + if (lpc3511IpState->controllerSpeed) + { + return 0u; + } + else + { + return 1u; + } +#else + return 1u; +#endif +#endif +} + +static uint8_t *USB_DeviceLpcIp3511MallocMaxPacketBuffer(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + uint32_t multile64) +{ + uint32_t bitsIndex; + uint8_t numIndex; + OSA_SR_ALLOC(); + + multile64 = ((multile64 + 63) / 64); + bitsIndex = 0; + OSA_ENTER_CRITICAL(); + do + { + numIndex = 0; + for (; numIndex < multile64; ++numIndex) + { + if (bitsIndex >= USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER) + { + OSA_EXIT_CRITICAL(); + return NULL; /* fail */ + } + if (lpc3511IpState->epReservedBufferBits[(bitsIndex / 8)] & + (uint8_t)(0x01u << (bitsIndex & 0x00000007u))) /* has allocated */ + { + bitsIndex++; + break; + } + bitsIndex++; + } + } while (numIndex < multile64); + + if (numIndex >= multile64) + { + /* set the bits */ + for (numIndex = 0; numIndex < multile64; ++numIndex) + { + lpc3511IpState->epReservedBufferBits[((bitsIndex - multile64 + numIndex) / 8)] |= + (uint8_t)(0x01u << ((bitsIndex - multile64 + numIndex) & 0x00000007u)); + } + OSA_EXIT_CRITICAL(); + return lpc3511IpState->epReservedBuffer + ((bitsIndex - multile64) * 64); + } + else + { + OSA_EXIT_CRITICAL(); + return NULL; + } +} + +static void USB_DeviceLpcIp3511ReleaseMaxPacketBuffer(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + uint8_t *buffer, + uint32_t bufferSize) +{ + uint32_t bitsIndex; + uint8_t bitsNum; + OSA_SR_ALLOC(); + + if ((buffer < lpc3511IpState->epReservedBuffer) || + (buffer >= (lpc3511IpState->epReservedBuffer + USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE))) + { + return; + } + bitsIndex = (buffer - lpc3511IpState->epReservedBuffer) / 64; + + OSA_ENTER_CRITICAL(); + for (bitsNum = 0; bitsNum < ((bufferSize + 63) / 64); ++bitsNum) + { + lpc3511IpState->epReservedBufferBits[((bitsIndex + bitsNum) / 8)] &= + (uint8_t)(~(0x01u << ((bitsIndex + bitsNum) & 0x00000007u))); /* clear the bit */ + } + OSA_EXIT_CRITICAL(); +} +#endif + +static usb_device_lpc3511ip_endpoint_state_struct_t *USB_DeviceLpc3511IpGetEndpointStateStruct( + usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t endpointIndex) +{ + if (endpointIndex <= (USB_DEVICE_IP3511_ENDPOINTS_NUM * 2)) + { + return &(lpc3511IpState->endpointState[endpointIndex]); + } + + return NULL; +} + +/*! + * @brief Write the command/status entry to start a transfer. + * + * The function is used to start a transfer by writing the command/status entry. + * + * @param lpc3511IpState Pointer of the controller 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_DeviceLpc3511IpEndpointPrime(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint8_t endpointIndex, + uint8_t *buffer, + uint32_t length) +{ + uint8_t odd; + + OSA_SR_ALLOC(); + + /* Enter critical */ + OSA_ENTER_CRITICAL(); + + /* Flag the endpoint is busy. */ + epState->stateUnion.stateBitField.transferring = 1U; + + /* update the endpoint status */ + epState->transferPrimedLength += length; +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if ((endpointIndex >> 1U) != USB_ENDPOINT_CONTROL) + { + odd = epState->stateUnion.stateBitField.producerOdd; + epState->stateUnion.stateBitField.doubleBufferBusy++; + epState->stateUnion.stateBitField.producerOdd ^= 1; + } + else +#endif + { + odd = 0U; + } + epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength = length; + + /* when receive the zero length packet, the controller will set 4 bytes buffer as 0x00 */ + if (buffer == NULL) + { + buffer = lpc3511IpState->zeroTransactionData; + } + + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT( + lpc3511IpState, endpointIndex, odd, + (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) | + USB_LPC3511IP_ENDPOINT_ACTIVE_MASK, + length, (uint32_t)buffer); + if (epState->stateUnion.stateBitField.epControlDefault & + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) + { + epState->stateUnion.stateBitField.epControlDefault &= + (~((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)); + } + /* Exit critical */ + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; +} + +#if 0 +/*! + * @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 lpc3511IpState Pointer of the controller state structure. + * + */ +static void USB_DeviceLpc3511IpPrimeNextSetup(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, 0, 1, 0, 8, lpc3511IpState->setupData); +} +#endif + +/*! + * @brief reset ip3511. + * + * @param lpc3511IpState Pointer of the controller state structure. + * + */ +static void USB_DeviceLpc3511IpSetDefaultState(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + uint32_t index = 0; + uint8_t usbAddress; + + /* zero the command/status list buffer and disable all endpoints */ + for (index = 0; index < 4; ++index) + { + lpc3511IpState->epCommandStatusList[index] = 0x00000000U; + } + for (index = 4; index < USB_DEVICE_IP3511_ENDPOINTS_NUM * 4; ++index) + { + lpc3511IpState->epCommandStatusList[index] = USB_LPC3511IP_ENDPOINT_DISABLE_MASK; + } + + /* set address as 0 */ + usbAddress = 0U; + USB_DeviceLpc3511IpControl(lpc3511IpState, kUSB_DeviceControlPreSetDeviceAddress, &usbAddress); + + lpc3511IpState->registerBase->EPLISTSTART = (uint32_t)lpc3511IpState->epCommandStatusList; +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + if (lpc3511IpState->controllerSpeed) + { + if ((USBHSD_DATABUFSTART_DA_BUF_MASK & (uint32_t)lpc3511IpState->setupData) != + lpc3511IpState->registerBase->DATABUFSTART) + { + /* please use the dedicated ram */ + } + } + else +#endif + { + /* all data buffer is in the same 4M range with this setup data buffer */ + lpc3511IpState->registerBase->DATABUFSTART = (uint32_t)lpc3511IpState->setupData; + } + /* reset registers */ + lpc3511IpState->registerBase->EPINUSE = 0x0; + lpc3511IpState->registerBase->EPSKIP = 0x0; +/* enable all double-buffer */ +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + lpc3511IpState->registerBase->EPBUFCFG = USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK; +#else + lpc3511IpState->registerBase->EPBUFCFG = 0x00000000u; +#endif + /* clear interrupts + * don't clear DEV_INT because the vbus valid interrupt may occurs with keeping usb connected and reseting device. + */ + lpc3511IpState->registerBase->INTSTAT = + (USB_LPC3511IP_INTSTAT_FRAME_INT_MASK | USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK); + /* enable interrupts */ + lpc3511IpState->registerBase->INTEN = USB_LPC3511IP_INTSTAT_DEV_INT_MASK | USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK; + + /* Clear reset flag */ + lpc3511IpState->isResetting = 0U; +} + +/* Config and Enable endpoint */ +static usb_status_t USB_DeviceLpc3511IpEndpointInit(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_endpoint_init_struct_t *epInit) +{ + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(epInit->endpointAddress); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + uint16_t maxPacketSize = epInit->maxPacketSize; + + /* clear the endpoint status bits */ + epState->stateUnion.state = 0x00000000u; + lpc3511IpState->registerBase->EPINUSE &= (~(0x01u << endpointIndex)); + /* Save the max packet size of the endpoint */ + epState->stateUnion.stateBitField.maxPacketSize = maxPacketSize; + /* Set the ZLT field */ + epState->stateUnion.stateBitField.zlt = epInit->zlt; + epState->stateUnion.stateBitField.endpointType = epInit->transferType; + + /* get the endpoint default control value */ + if (USB_ENDPOINT_ISOCHRONOUS == epInit->transferType) + { + epState->stateUnion.stateBitField.epControlDefault = + (USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); + } +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + else if ( +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + (!(lpc3511IpState->hsInterruptIssue)) && +#endif + (lpc3511IpState->controllerSpeed) && (USB_ENDPOINT_INTERRUPT == epInit->transferType)) + { + epState->stateUnion.stateBitField.epControlDefault = + ((USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK | USB_LPC3511IP_ENDPOINT_RFTV_MASK) >> + USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); + } +#endif +#endif + else + { + epState->stateUnion.stateBitField.epControlDefault = 0x00U; + } + /* set the command/status value */ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT( + lpc3511IpState, endpointIndex, 0, + (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT), 0, 0); + if ((epInit->endpointAddress & USB_ENDPOINT_NUMBER_MASK) == USB_CONTROL_ENDPOINT) + { + if (!(epInit->endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK)) + { + /* Prime setup packet when the endpoint is control out endpoint. */ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, 0, 1, 0, 0, (uint32_t)lpc3511IpState->setupData); + } + } + else + { + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT( + lpc3511IpState, endpointIndex, 1, + (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT), 0, 0); + } + if ((endpointIndex >> 1) != USB_CONTROL_ENDPOINT) + { + /* toggle reset for the toggle */ + epState->stateUnion.stateBitField.epControlDefault |= + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); + } + + epState->epPacketBuffer = NULL; + if ((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT) /* control endpoint */ + { + epState->epPacketBuffer = lpc3511IpState->controlData; + } +#if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) + else + { + if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState)) + { +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + uint8_t *maxPacketBuffer = USB_DeviceLpcIp3511MallocMaxPacketBuffer( + lpc3511IpState, USB_LPC3511IP_GET_MULTIPLE_OF_64(maxPacketSize) * 2); +#else + uint8_t *maxPacketBuffer = USB_DeviceLpcIp3511MallocMaxPacketBuffer(lpc3511IpState, maxPacketSize); +#endif + if (maxPacketBuffer == NULL) + { + return kStatus_USB_AllocFail; + } + epState->epPacketBuffer = maxPacketBuffer; + } + } +#endif + + 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 lpc3511IpState Pointer of the controller 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_DeviceLpc3511IpEndpointDeinit(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep) +{ + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + + /* Cancel the transfer of the endpoint */ + USB_DeviceLpc3511IpCancel(lpc3511IpState, ep); + +#if (defined USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY) + if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState)) + { + if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT) /* control endpoint */ + { +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + USB_DeviceLpcIp3511ReleaseMaxPacketBuffer( + lpc3511IpState, epState->epPacketBuffer, + USB_LPC3511IP_GET_MULTIPLE_OF_64(epState->stateUnion.stateBitField.maxPacketSize) * 2); +#else + USB_DeviceLpcIp3511ReleaseMaxPacketBuffer(lpc3511IpState, epState->epPacketBuffer, + epState->stateUnion.stateBitField.maxPacketSize); +#endif + } + epState->epPacketBuffer = NULL; + } +#endif + + /* reset the double buffer */ + lpc3511IpState->registerBase->EPINUSE &= ~(0x01U << endpointIndex); + /* Disable the endpoint */ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 0, USB_LPC3511IP_ENDPOINT_DISABLE_MASK, 0, 0); + /* Clear the max packet size */ + epState->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 lpc3511IpState Pointer of the controller 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_DeviceLpc3511IpEndpointStall(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep) +{ + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + + /* Set endpoint stall flag. */ + epState->stateUnion.stateBitField.stalled = 1U; + /* lpc3511IpState->registerBase->EPINUSE &= (~(0x01u << endpointIndex)); */ + /* stall the endpoint */ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 0, USB_LPC3511IP_ENDPOINT_STALL_MASK, 0, 0); + if ((ep & USB_ENDPOINT_NUMBER_MASK) != USB_CONTROL_ENDPOINT) + { + /* toggle reset for the toggle */ + epState->stateUnion.stateBitField.epControlDefault |= + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT(lpc3511IpState, endpointIndex, 1, USB_LPC3511IP_ENDPOINT_STALL_MASK, 0, 0); + } +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + if (lpc3511IpState->hsInterruptIssue) + { +#endif + if ((lpc3511IpState->controllerSpeed) && + (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType)) + { + lpc3511IpState->registerBase->DEVCMDSTAT |= + (USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK); + epState->stateUnion.stateBitField.epControlDefault &= + (~((USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK | USB_LPC3511IP_ENDPOINT_RFTV_MASK) >> + USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)); + } +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + } +#endif +#endif +#endif + + /* cancel the transfer in the endpoint */ + USB_DeviceLpc3511IpCancel(lpc3511IpState, ep); + 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 lpc3511IpState Pointer of the controller 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_DeviceLpc3511IpEndpointUnstall(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, uint8_t ep) +{ + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + + /* Clear the endpoint stall state, the hardware resets the endpoint + * toggle to one for both directions when a setup token is received */ + epState->stateUnion.stateBitField.stalled = 0U; + + /* unstall the endpoint for double buffers */ + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpc3511IpState, endpointIndex, 0, (~USB_LPC3511IP_ENDPOINT_STALL_MASK)); + if ((ep & USB_ENDPOINT_NUMBER_MASK) != USB_CONTROL_ENDPOINT) + { + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND(lpc3511IpState, endpointIndex, 1, (~USB_LPC3511IP_ENDPOINT_STALL_MASK)); + + /* toggle reset for the toggle */ + epState->stateUnion.stateBitField.epControlDefault |= + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + if (lpc3511IpState->hsInterruptIssue) + { +#endif + if ((lpc3511IpState->controllerSpeed) && + (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType)) + { + epState->stateUnion.stateBitField.epControlDefault &= + (~((USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK | USB_LPC3511IP_ENDPOINT_RFTV_MASK) >> + USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)); + } +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + } +#endif +#endif +#endif + } + + if (epState->stateUnion.stateBitField.stallPrimed) + { + epState->stateUnion.stateBitField.stallPrimed = 0u; + USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex); + } + /* cancel the transfer in the endpoint */ + USB_DeviceLpc3511IpCancel(lpc3511IpState, ep); + return kStatus_USB_Success; +} + +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +/*! + * @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 lpc3511IpState Pointer of the controller state structure. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceLpc3511IpInterruptSuspend(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + + 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(lpc3511IpState->deviceHandle, &message); + + 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 lpc3511IpState Pointer of the controller state structure. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceLpc3511IpInterruptResume(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyResume; + message.length = 0U; + message.isSetup = 0U; + + /* Notify up layer the USB suspend signal detected. */ + USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message); + + return kStatus_USB_Success; +} +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) +/*! + * @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 lpc3511IpState Pointer of the controller state structure. + * + * @return A USB error code or kStatus_USB_Success. + */ +static usb_status_t USB_DeviceLpc3511IpInterruptLPMSleep(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + uint8_t remotewakeup; + + message.buffer = (uint8_t *)NULL; + message.code = kUSB_DeviceNotifyLPMSleep; + message.length = 0U; + message.isSetup = 0U; + + remotewakeup = (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK) >> + USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_SHIFT; + USB_DeviceSetStatus(lpc3511IpState->deviceHandle, kUSB_DeviceStatusRemoteWakeup, &remotewakeup); + + /* Notify up layer the USB suspend signal detected. */ + USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message); + + return kStatus_USB_Success; +} + +#endif +#endif + +/* need copy the data before the trasaction buffer is used again */ +static void USB_DeviceLpc3511IpDoPreviousTransactionMemcpy(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint32_t length, + uint8_t endpointIndex, + uint8_t odd) +{ + uint8_t *destBuffer; + uint8_t *sourceBuffer; + +#if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U)) + /*control out doesn't support buffer toggle*/ + if (0U == endpointIndex) + { + odd = 0u; + } +#if USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER + if ((epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) && + ((endpointIndex & 0x01u) == 0U)) +#else + if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState) && + (epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) && + ((endpointIndex & 0x01u) == 0U)) +#endif +#else + /* control data buffer align is used */ + if (((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT) && + (epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed) && (length > 0U) && + ((endpointIndex & 0x01u) == 0U)) +#endif + { +#if ((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + destBuffer = &(epState->transferBuffer[epState->transferDone - length]); +#else + destBuffer = &(epState->transferBuffer[epState->transferDone]); +#endif +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + sourceBuffer = epState->epPacketBuffer + + odd * USB_LPC3511IP_GET_MULTIPLE_OF_64(epState->stateUnion.stateBitField.maxPacketSize); +#else + sourceBuffer = epState->epPacketBuffer; +#endif + memcpy(destBuffer, sourceBuffer, length); + } +} + +static uint32_t USB_DeviceLpc3511IpTokenUpdate(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint8_t endpointIndex, + uint8_t changedOdd) +{ + uint32_t length; + uint8_t odd; + +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if (changedOdd) + { + odd = epState->stateUnion.stateBitField.consumerOdd; + epState->stateUnion.stateBitField.consumerOdd ^= 1; + epState->stateUnion.stateBitField.doubleBufferBusy--; + } + else +#endif + { + odd = 0U; + } + +/* for OUT packet, compute the actual packet size. */ +#if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \ + (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U))) +#else + if ((endpointIndex & 0x01U) == 0x00u) /* OUT */ +#endif + { + /* get the transaction length */ + length = *(lpc3511IpState->epCommandStatusList + endpointIndex * 2 + odd); + +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + if (lpc3511IpState->controllerSpeed) + { + length = + (length & USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_MASK) >> USB_LPC3511IPHS_ENDPOINT_BUFFER_NBYTES_SHIFT; + } + else +#endif + { + length = + (length & USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_MASK) >> USB_LPC3511IPFS_ENDPOINT_BUFFER_NBYTES_SHIFT; + } + length = epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength - length; + } +#if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \ + (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U))) +#else + else /* for IN packet, if there is no error, the packet lenght is the primed length. */ + { + /* don't judge the actual packet size */ + length = epState->epBufferStatusUnion[odd].epBufferStatusField.transactionLength; + } +#endif + +#if !((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + USB_DeviceLpc3511IpDoPreviousTransactionMemcpy(lpc3511IpState, epState, length, endpointIndex, odd); +#endif + /* update the transferred length */ + epState->transferDone += length; + + return length; +} + +static void USB_DeviceLpc3511IpInterruptToken(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + uint8_t endpointIndex, + uint8_t isSetup, + uint32_t errorStatus) +{ + usb_device_callback_message_struct_t message; + uint32_t len = 0; + uint32_t length; + uint32_t remainLength; + usb_setup_struct_t *setupPacket; + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + if (lpc3511IpState->hsInterruptIssue) + { +#endif + if ((epState->stateUnion.stateBitField.epControlDefault & + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) && + (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType) && + (lpc3511IpState->controllerSpeed) && + (lpc3511IpState->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] & + USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK)) + { + if (!(lpc3511IpState->registerBase->EPTOGGLE & (0x01u << endpointIndex))) + { + uint32_t index; + length = 0; + for (index = 0; index < (USB_DEVICE_IP3511_ENDPOINTS_NUM)*4; ++index) + { + if ((lpc3511IpState->epCommandStatusList[index] & USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) && + (USB_ENDPOINT_INTERRUPT == + lpc3511IpState->endpointState[index / 2].stateUnion.stateBitField.endpointType)) + { + length++; + } + } + + if (length <= 1) + { + lpc3511IpState->registerBase->DEVCMDSTAT &= + ~(USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK); + } + epState->stateUnion.stateBitField.epControlDefault &= + (~((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)); +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + /* high-speed */ + epState->stateUnion.stateBitField.epControlDefault |= + ((USB_LPC3511IP_ENDPOINT_RFTV_MASK | USB_LPC3511IP_ENDPOINT_ENDPOINT_TYPE_MASK) >> + USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT); + USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex); +#endif + } + return; + } +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + } +#endif +#endif +#endif + + if ((!isSetup) && (0U == epState->stateUnion.stateBitField.transferring)) + { + return; + } + if (isSetup) + { + message.length = 8U; + message.buffer = (lpc3511IpState->setupData); + /* clear the primed control transactions */ + if (epState->stateUnion.stateBitField.transferring) + { + epState->stateUnion.stateBitField.transferring = 0U; + if (lpc3511IpState->epCommandStatusList[0] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK) + { + USB_DeviceLpc3511IpCancel(lpc3511IpState, USB_CONTROL_ENDPOINT); + } + } + if (lpc3511IpState->endpointState[1].stateUnion.stateBitField.transferring) + { + lpc3511IpState->endpointState[1].stateUnion.stateBitField.transferring = 0U; + if (lpc3511IpState->epCommandStatusList[2] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK) + { + USB_DeviceLpc3511IpCancel(lpc3511IpState, (0x80u | USB_CONTROL_ENDPOINT)); + } + } + + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND( + lpc3511IpState, 0, 0, (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK))); + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND( + lpc3511IpState, 1, 0, (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK))); + + lpc3511IpState->registerBase->INTSTAT = 0x03u; /* clear interrupt */ + /* W1 to clear the setup flag */ + lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK; + } + else + { + length = 0; +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if (lpc3511IpState->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] & + USB_LPC3511IP_ENDPOINT_ACTIVE_MASK) + { + return; + } +#else + if (lpc3511IpState->epCommandStatusList[endpointIndex * 2] & USB_LPC3511IP_ENDPOINT_ACTIVE_MASK) + { + return; + } +#endif + +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT) + { + len = USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 1U); + length += len; + + if ((epState->stateUnion.stateBitField.doubleBufferBusy > 0) && + (!(lpc3511IpState + ->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] & + USB_LPC3511IP_ENDPOINT_ACTIVE_MASK))) + { +#if ((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + USB_DeviceLpc3511IpDoPreviousTransactionMemcpy(lpc3511IpState, epState, len, endpointIndex, + epState->stateUnion.stateBitField.consumerOdd ^ 1); +#endif + len = USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 1U); + length += len; + } + } + else +#endif + { + length = USB_DeviceLpc3511IpTokenUpdate(lpc3511IpState, epState, endpointIndex, 0U); + len = length; + } + + /* update remaining length */ + remainLength = epState->transferLength - epState->transferDone; + + /* 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 tansaction is not the multiple of max packet size. + */ + if ((length > 0U) && (!(length % epState->stateUnion.stateBitField.maxPacketSize)) && (remainLength > 0U)) + { + (void)USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex); +#if ((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + USB_DeviceLpc3511IpDoPreviousTransactionMemcpy(lpc3511IpState, epState, len, endpointIndex, + epState->stateUnion.stateBitField.consumerOdd ^ 1); +#endif + return; + } + else + { + epState->stateUnion.stateBitField.transferring = 0U; + message.length = epState->transferDone; + message.buffer = epState->transferBuffer; + + /* process ZLT + * 1. IN endpoint; + * 2. transfer length is the multiple of max packet size. + */ + if ((endpointIndex & 0x01U) && (length) && (!(length % epState->stateUnion.stateBitField.maxPacketSize))) + { + if ((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT) + { + setupPacket = (usb_setup_struct_t *)(&(lpc3511IpState->setupData[0])); + /* + * Send ZLT transaction if setup transfer and the required length is longer than actual length + */ + if (USB_SHORT_FROM_LITTLE_ENDIAN(setupPacket->wLength) > epState->transferLength) + { + (void)USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, 1U, NULL, 0U); + return; + } + } + else if ((epState->stateUnion.stateBitField.zlt)) + { + (void)USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, endpointIndex, NULL, 0U); + return; + } + else + { + } + } + } + } + + message.isSetup = isSetup; + message.code = ((uint8_t)(endpointIndex >> 1) | (uint8_t)(((uint32_t)(endpointIndex & 0x01U) << 0x07U))); + +#if ((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + USB_DeviceLpc3511IpDoPreviousTransactionMemcpy(lpc3511IpState, epState, len, endpointIndex, + epState->stateUnion.stateBitField.consumerOdd ^ 1); +#endif + /* Notify the up layer the controller status changed. */ + USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message); +} + +/*! + * @brief Handle the USB bus reset interrupt. + * + * The function is used to handle the USB bus reset interrupt. + * + * @param lpc3511IpState Pointer of the controller state structure. + * + */ +static void USB_DeviceLpc3511IpInterruptReset(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + + /* Set reset flag */ + lpc3511IpState->isResetting = 1U; + +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + if (lpc3511IpState->controllerSpeed) + { + if (((lpc3511IpState->registerBase->DEVCMDSTAT & USBHSD_DEVCMDSTAT_Speed_MASK) >> + USBHSD_DEVCMDSTAT_Speed_SHIFT) == 0x02U) + { + lpc3511IpState->deviceSpeed = USB_SPEED_HIGH; + } + else if (((lpc3511IpState->registerBase->DEVCMDSTAT & USBHSD_DEVCMDSTAT_Speed_MASK) >> + USBHSD_DEVCMDSTAT_Speed_SHIFT) == 0x01U) + { + lpc3511IpState->deviceSpeed = USB_SPEED_FULL; + } + else + { + } + } + else +#endif + { + lpc3511IpState->deviceSpeed = USB_SPEED_FULL; + } + + 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(lpc3511IpState->deviceHandle, &message); +} + +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE)) +/*! + * @brief Handle detach interrupt. + * + * The function is used to handle the detach interrupt. + * + * @param lpc3511IpState Pointer of the controller state structure. + * + */ +static void USB_DeviceLpc3511IpInterruptDetach(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + + 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(lpc3511IpState->deviceHandle, &message); +} + +/*! + * @brief Handle Attach interrupt. + * + * The function is used to handle the attach interrupt. + * + * @param lpc3511IpState Pointer of the controller state structure. + * + */ +static void USB_DeviceLpc3511IpInterruptAttach(usb_device_lpc3511ip_state_struct_t *lpc3511IpState) +{ + usb_device_callback_message_struct_t message; + + 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(lpc3511IpState->deviceHandle, &message); +} +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) +/* The device dcd callback */ +static usb_hsdcd_status_t USB_DeviceLpcIp3511IsrHSDCDCallback(void *handle, uint32_t event, void *param) +{ + usb_hsdcd_status_t error = kStatus_hsdcd_Success; + usb_device_callback_message_struct_t message; + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)handle; + + if (lpc3511IpState == NULL) + { + return kStatus_hsdcd_Error; + } + + /*messsgae buffer contain event information*/ + message.buffer = (uint8_t *)param; + message.length = 0U; + message.isSetup = 0U; + message.code = kUSB_DeviceNotifyDcdDetectFinished; + USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message); + return error; +} + +void USB_DeviceLpcIp3511IsrDCDFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_lpc3511ip_state_struct_t *lpc3511IpState; + if (NULL == deviceHandle) + { + return; + } + lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)(handle->controllerHandle); + USB_HSDcdIsrFunction(lpc3511IpState->dcdHandle); +} +#endif +usb_status_t USB_DeviceLpc3511IpInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *controllerHandle) +{ + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = NULL; +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) + uint32_t ip3511FsBases[] = USB_BASE_ADDRS; +#endif + uint32_t *endpointListArray[] = LPC_CONTROLLER_ENDPOINT_LIST_ARRAY; + +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + uint32_t hsdcd_base[] = USBHSDCD_BASE_ADDRS; + USBHSDCD_Type *base; + usb_hsdcd_config_struct_t dcdParamConfig; + usb_hsdcd_status_t dcdError = kStatus_hsdcd_Success; +#endif + + uint32_t ip3511HsBases[] = USBHSD_BASE_ADDRS; + if ((controllerId >= kUSB_ControllerLpcIp3511Hs0) && (controllerId <= kUSB_ControllerLpcIp3511Hs1)) + { + if ((uint32_t)(controllerId - kUSB_ControllerLpcIp3511Hs0) >= (sizeof(ip3511HsBases) / sizeof(uint32_t))) + { + return kStatus_USB_ControllerNotFound; + } + lpc3511IpState = + &s_UsbDeviceLpc3511IpState[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS]; + lpc3511IpState->controlData = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Hs0 + + USB_DEVICE_CONFIG_LPCIP3511FS][CONTROL_TRANSFER_DATA_OFFSET]; + lpc3511IpState->setupData = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Hs0 + + USB_DEVICE_CONFIG_LPCIP3511FS][SETUP_TRANSFER_DATA_OFFSET]; + lpc3511IpState->zeroTransactionData = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Hs0 + + USB_DEVICE_CONFIG_LPCIP3511FS][ZERO_TRANSFER_DATA_OFFSET]; + /* set the endpoint list */ + lpc3511IpState->epCommandStatusList = + endpointListArray[controllerId - kUSB_ControllerLpcIp3511Hs0 + USB_DEVICE_CONFIG_LPCIP3511FS]; + /* get the ip base address */ + lpc3511IpState->registerBase = (USB_LPC3511IP_Type *)ip3511HsBases[controllerId - kUSB_ControllerLpcIp3511Hs0]; +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + base = (USBHSDCD_Type *)hsdcd_base[controllerId - kUSB_ControllerLpcIp3511Hs0]; + dcdParamConfig.dcdCallback = USB_DeviceLpcIp3511IsrHSDCDCallback; + dcdParamConfig.dcdCallbackParam = (void *)lpc3511IpState; + dcdError = USB_HSDCD_Init(base, &dcdParamConfig, &lpc3511IpState->dcdHandle); + if (kStatus_hsdcd_Success != dcdError) + { + return kStatus_USB_Error; + } +#endif + } + else +#endif +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511FS)) && (USB_DEVICE_CONFIG_LPCIP3511FS > 0U)) + { + /* get the controller instance */ + if ((controllerId < kUSB_ControllerLpcIp3511Fs0) || + ((controllerId - kUSB_ControllerLpcIp3511Fs0) >= (uint8_t)USB_DEVICE_CONFIG_LPCIP3511FS) || + ((uint32_t)(controllerId - kUSB_ControllerLpcIp3511Fs0) >= (sizeof(ip3511FsBases) / sizeof(uint32_t)))) + { + return kStatus_USB_ControllerNotFound; + } + lpc3511IpState = &s_UsbDeviceLpc3511IpState[controllerId - kUSB_ControllerLpcIp3511Fs0]; + lpc3511IpState->controlData = (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Fs0] + [CONTROL_TRANSFER_DATA_OFFSET]; + lpc3511IpState->setupData = (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Fs0] + [SETUP_TRANSFER_DATA_OFFSET]; + lpc3511IpState->zeroTransactionData = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Fs0][ZERO_TRANSFER_DATA_OFFSET]; + /* set the endpoint list */ + lpc3511IpState->epCommandStatusList = endpointListArray[controllerId - kUSB_ControllerLpcIp3511Fs0]; + /* get the ip base address */ + lpc3511IpState->registerBase = (USB_LPC3511IP_Type *)ip3511FsBases[controllerId - kUSB_ControllerLpcIp3511Fs0]; + } +#else + { + return kStatus_USB_ControllerNotFound; + } +#endif + + lpc3511IpState->controllerId = controllerId; +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + if ((lpc3511IpState->controllerId >= kUSB_ControllerLpcIp3511Hs0) && + (lpc3511IpState->controllerId <= kUSB_ControllerLpcIp3511Hs1)) + { + lpc3511IpState->controllerSpeed = 1U; +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + lpc3511IpState->hsInterruptIssue = ((Chip_GetVersion() == FSL_ROM_VERSION_1B) ? 0 : 1); +#endif + } + else + { + lpc3511IpState->controllerSpeed = 0U; + } +#endif + +#if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U)) + /* this controller need max packet buffer copy */ + if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState)) + { +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + if ((controllerId >= kUSB_ControllerLpcIp3511Hs0) && (controllerId <= kUSB_ControllerLpcIp3511Hs1)) + { +#if (USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER) + /* for allocating the max packet buffer */ + lpc3511IpState->epReservedBuffer = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Hs0 + + USB_DEVICE_CONFIG_LPCIP3511FS][RESERVED_EP_DATA_OFFSET]; +#else + lpc3511IpState->epReservedBuffer = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Hs0] + [RESERVED_EP_DATA_OFFSET]; +#endif + } + else +#endif + { + lpc3511IpState->epReservedBuffer = + (uint8_t *)&s_SetupAndEpReservedData[controllerId - kUSB_ControllerLpcIp3511Fs0] + [RESERVED_EP_DATA_OFFSET]; + } + } + for (controllerId = 0; controllerId < ((USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER + 7) / 8); ++controllerId) + { + lpc3511IpState->epReservedBufferBits[controllerId] = 0u; + } +#endif + + /* disable the controller */ + lpc3511IpState->registerBase->DEVCMDSTAT &= + (~(USB_LPC3511IP_DEVCMDSTAT_DCON_MASK | USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK | + USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK)); + /* reset and enalbe the controller */ + USB_DeviceLpc3511IpSetDefaultState(lpc3511IpState); + /* enable USB */ + lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) +#else + | USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK +#endif + ); +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK; + lpc3511IpState->registerBase->LPM |= USB_LPC3511IP_USB_LPM_HIRD_SW(4); + lpc3511IpState->registerBase->DEVCMDSTAT &= ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK); +#endif + lpc3511IpState->deviceHandle = handle; + *controllerHandle = lpc3511IpState; + + return kStatus_USB_Success; +} + +usb_status_t USB_DeviceLpc3511IpDeinit(usb_device_controller_handle controllerHandle) +{ + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle; + uint32_t usbAddress; + + if (controllerHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + /* Clear all interrupt flags. */ + lpc3511IpState->registerBase->INTSTAT = (USB_LPC3511IP_INTSTAT_DEV_INT_MASK | USB_LPC3511IP_INTSTAT_FRAME_INT_MASK | + USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK); + /* Disable all interrupts. */ + lpc3511IpState->registerBase->INTEN = 0U; + /* Clear device address. */ + usbAddress = 0U; + USB_DeviceLpc3511IpControl(lpc3511IpState, kUSB_DeviceControlPreSetDeviceAddress, &usbAddress); +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_LPM_SUP_MASK; +#endif + /* disable the controller */ + lpc3511IpState->registerBase->DEVCMDSTAT &= + (~(USB_LPC3511IP_DEVCMDSTAT_DCON_MASK | USB_LPC3511IP_DEVCMDSTAT_DEV_EN_MASK | + USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK)); +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + USB_HSDCD_Deinit(lpc3511IpState->dcdHandle); +#endif + + return kStatus_USB_Success; +} + +static usb_status_t USB_DeviceLpc3511IpGetActualBufferAndPrime(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint8_t endpointIndex, + uint8_t changedOdd) +{ + uint32_t index; + uint8_t *destBuffer; + uint8_t *actualBuffer; + uint32_t length; + uint8_t odd; + +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if (changedOdd) + { + odd = epState->stateUnion.stateBitField.producerOdd; + } + else +#endif + { + odd = 0; + } + actualBuffer = epState->transferBuffer + epState->transferPrimedLength; + length = epState->transferLength - epState->transferPrimedLength; + /* Data length needs to less than max packet size. */ + if (length > epState->stateUnion.stateBitField.maxPacketSize) + { + length = epState->stateUnion.stateBitField.maxPacketSize; + } + + epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed = 0; + + index = (endpointIndex & 0x01u); /* index mean IN endpoint here */ + if (length > 0U) + { +#if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U)) +/* if all the enabled IP support the reserved buffer, then don't need the judgement. */ +#if (!USB_DEVICE_IP3511_ALL_IP_SUPPORT_RESERVED_BUFFER) +#define USB_DEVICE_IP3511_NEED_CHECK_BUFFER (1u) + /* lengt > 0 && ((buffer not align with 64) || (buffer is not in the deticated ram))) */ + if (USB_DeviceLpcIp3511MaxPacketNeedCopy(lpc3511IpState)) +#endif +#else +#define USB_DEVICE_IP3511_NEED_CHECK_BUFFER (1u) + /* align the buffer for control transfer */ + if (((endpointIndex >> 1U) == USB_CONTROL_ENDPOINT)) +#endif + { + /* not 64 bytes align || not in the dedicated ram || ( OUT && not mutiple of 4 ) */ + if ((((uint32_t)actualBuffer & 0x0000003FU) != 0U) || + (((uint32_t)actualBuffer & 0xFFC00000U) != (lpc3511IpState->registerBase->DATABUFSTART & 0xFFC00000U)) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + || ((lpc3511IpState->controllerSpeed) && (!index) && + (length != epState->stateUnion.stateBitField.maxPacketSize))) +#else + ) +#endif + { + epState->epBufferStatusUnion[odd].epBufferStatusField.epPacketCopyed = 1U; +/* usb copy buffer for this packet */ +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + destBuffer = + (uint8_t *)(epState->epPacketBuffer + (odd * USB_LPC3511IP_GET_MULTIPLE_OF_64( + epState->stateUnion.stateBitField.maxPacketSize))); +#else + destBuffer = (uint8_t *)(epState->epPacketBuffer); +#endif + if (index) /* USB_IN */ + { + memcpy(destBuffer, actualBuffer, length); + } + else + { +#if ((defined(FSL_FEATURE_USB_VERSION) && (FSL_FEATURE_USB_VERSION >= 200U)) || \ + (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U))) +#else + length = epState->stateUnion.stateBitField.maxPacketSize; +#endif + } + actualBuffer = destBuffer; + } + } +#if (defined USB_DEVICE_IP3511_NEED_CHECK_BUFFER) && (USB_DEVICE_IP3511_NEED_CHECK_BUFFER) + else /* cannot do memory copy */ + { + /* not 64 bytes align || not in the dedicated ram || ( OUT && HS && not mutiple of 4 ) */ + if ((((uint32_t)actualBuffer & 0x0000003FU) != 0U) || + (((uint32_t)actualBuffer & 0xFFC00000U) != (lpc3511IpState->registerBase->DATABUFSTART & 0xFFC00000U)) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + || ((lpc3511IpState->controllerSpeed) && (!index) && ((length & 0x00000003u) != 0u))) +#else + ) +#endif + { + return kStatus_USB_Error; + } + } +#endif + } + + /* Send/Receive data when the device is not resetting. */ + if (0U == lpc3511IpState->isResetting) + { + return USB_DeviceLpc3511IpEndpointPrime(lpc3511IpState, epState, endpointIndex, actualBuffer, length); + } + else + { + return kStatus_USB_Error; + } +} +static usb_status_t USB_DeviceLpc3511IpTransaction(usb_device_lpc3511ip_state_struct_t *lpc3511IpState, + usb_device_lpc3511ip_endpoint_state_struct_t *epState, + uint8_t endpointIndex) +{ + usb_status_t status = kStatus_USB_Error; + OSA_SR_ALLOC(); + +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + if (lpc3511IpState->hsInterruptIssue) + { +#endif + /* high-speed */ + if ((epState->stateUnion.stateBitField.epControlDefault & + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) && + (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType) && + (lpc3511IpState->controllerSpeed)) + { + /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */ + OSA_ENTER_CRITICAL(); + + lpc3511IpState->registerBase->DEVCMDSTAT |= + (USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AO_MASK | USB_LPC3511IP_DEVCMDSTAT_INTONNAK_AI_MASK); + +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT( + lpc3511IpState, endpointIndex, epState->stateUnion.stateBitField.producerOdd, + (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) | + (epState->stateUnion.stateBitField.stalled << USB_LPC3511IP_ENDPOINT_STALL_SHIFT), + 0U, (uint32_t)lpc3511IpState->zeroTransactionData); +#else + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT( + lpc3511IpState, endpointIndex, 0, + (epState->stateUnion.stateBitField.epControlDefault << USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT) | + (epState->stateUnion.stateBitField.stalled << USB_LPC3511IP_ENDPOINT_STALL_SHIFT), + 0U, (uint32_t)lpc3511IpState->zeroTransactionData); +#endif + /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */ + OSA_EXIT_CRITICAL(); + return kStatus_USB_Success; + } +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + } +#endif +#endif +#endif + + /* Enter critical */ + OSA_ENTER_CRITICAL(); + if (epState->stateUnion.stateBitField.stalled) + { + if ((endpointIndex >> 1U) != USB_ENDPOINT_CONTROL) + { + epState->stateUnion.stateBitField.stallPrimed = 1u; + status = kStatus_USB_Success; + } + status = kStatus_USB_Error; + OSA_EXIT_CRITICAL(); + return status; + } + OSA_EXIT_CRITICAL(); + + /* 1. transfer size is 0; 2. All are primed */ + if ((epState->transferLength <= epState->transferPrimedLength) && (epState->transferLength != 0)) + { + return kStatus_USB_Success; + } +#if (defined USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) && (USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE) + if ((endpointIndex >> 1U) != USB_CONTROL_ENDPOINT) + { + /* disable endpoint interrupts, users can use NVIC to disable/enable the USB interrupt to improve the system + * performance */ + OSA_ENTER_CRITICAL(); + /* lpc3511IpState->registerBase->INTEN &= (uint32_t)(~(USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK)); */ +#if ((defined(USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER)) && (USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER > 0U)) + /* for out endpoint,only use buffer toggle, disable prime double buffer at the same time*/ + /*host send data less than maxpacket size and in endpoint prime length more more than maxpacketsize, there will + * be state mismtach*/ + if (0U == (endpointIndex & 0x1U)) + { + status = USB_DeviceLpc3511IpGetActualBufferAndPrime(lpc3511IpState, epState, endpointIndex, 1U); + } + else +#endif + { + do + { + status = USB_DeviceLpc3511IpGetActualBufferAndPrime(lpc3511IpState, epState, endpointIndex, 1U); + if (status != kStatus_USB_Success) + { + break; + } + } while ((epState->transferLength > epState->transferPrimedLength) && + (epState->stateUnion.stateBitField.doubleBufferBusy < 2)); + } + /* enable endpoint interrupt again, users can use NVIC to disable/enable the USB interrupt to improve the system + * performance */ + OSA_EXIT_CRITICAL(); + } + else +#endif + { + status = USB_DeviceLpc3511IpGetActualBufferAndPrime(lpc3511IpState, epState, endpointIndex, 0U); + } + return status; +} + +usb_status_t USB_DeviceLpc3511IpSend(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle; + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(endpointAddress); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + + if (1U == epState->stateUnion.stateBitField.transferring) + { + return kStatus_USB_Error; + } + + /* Save the transfer information */ + epState->transferDone = 0U; + epState->transferBuffer = buffer; + epState->transferLength = length; + epState->transferPrimedLength = 0U; + + return USB_DeviceLpc3511IpTransaction(lpc3511IpState, epState, endpointIndex); + +/* prime the control setup transfer if it is control in endpoint and data length is zero + * For IP3511 there is no need to prime, the buffer is always in the command/status list + */ +#if 0 + if ((0U == length) && (USB_CONTROL_ENDPOINT == (endpointAddress & USB_ENDPOINT_NUMBER_MASK))) + { + USB_DeviceLpc3511IpPrimeNextSetup(lpc3511IpState); + } +#endif +} + +usb_status_t USB_DeviceLpc3511IpRecv(usb_device_controller_handle controllerHandle, + uint8_t endpointAddress, + uint8_t *buffer, + uint32_t length) +{ + return USB_DeviceLpc3511IpSend(controllerHandle, endpointAddress, buffer, length); +} + +usb_status_t USB_DeviceLpc3511IpCancel(usb_device_controller_handle controllerHandle, uint8_t ep) +{ + /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */ + OSA_SR_ALLOC(); + + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle; + usb_device_callback_message_struct_t message; + uint8_t endpointIndex = USB_LPC3511IP_ENDPOINT_DES_INDEX(ep); + usb_device_lpc3511ip_endpoint_state_struct_t *epState = + USB_DeviceLpc3511IpGetEndpointStateStruct(lpc3511IpState, endpointIndex); + + /* Cancel the transfer and notify the up layer when the endpoint is busy. */ + if ((epState->stateUnion.stateBitField.transferring) +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + || ( +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + (lpc3511IpState->hsInterruptIssue) && +#endif + (epState->stateUnion.stateBitField.epControlDefault & + ((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)) && + (USB_ENDPOINT_INTERRUPT == epState->stateUnion.stateBitField.endpointType) && + (lpc3511IpState->controllerSpeed) && + (lpc3511IpState->epCommandStatusList[endpointIndex * 2 + epState->stateUnion.stateBitField.consumerOdd] & + USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) && + (!(lpc3511IpState->registerBase->EPTOGGLE & (0x01u << endpointIndex)))) +#endif +#endif + ) + { + /* disable endpoint interrupts, users can use NVIC to disable/enable the USB interrupt to improve the system + * performance */ + OSA_ENTER_CRITICAL(); +#if (defined(FSL_FEATURE_USBHSD_VERSION) && (FSL_FEATURE_USBHSD_VERSION >= 300U)) && \ + (!(defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK))) +#else +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + if (lpc3511IpState->hsInterruptIssue) + { +#endif + epState->stateUnion.stateBitField.epControlDefault &= + (~((USB_LPC3511IP_ENDPOINT_TOGGLE_RESET_MASK) >> USB_LPC3511IP_ENDPOINT_CONFIGURE_BITS_SHIFT)); +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + } +#endif +#endif +#endif + do + { + if (epState->stateUnion.stateBitField.doubleBufferBusy == 2) + { + epState->stateUnion.stateBitField.doubleBufferBusy = 1; + } + else + { + epState->stateUnion.stateBitField.doubleBufferBusy = 0; + } + /* cancel the transfer in the endpoint command/status */ + lpc3511IpState->registerBase->EPSKIP |= (0x01U << endpointIndex); + while (lpc3511IpState->registerBase->EPSKIP & (0x01U << endpointIndex)) + { + } + if (epState->stateUnion.stateBitField.doubleBufferBusy) + { + epState->stateUnion.stateBitField.producerOdd = + ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex); + epState->stateUnion.stateBitField.producerOdd ^= 1; + lpc3511IpState->registerBase->EPINUSE |= + (uint32_t)(epState->stateUnion.stateBitField.producerOdd << endpointIndex); + } + } while (epState->stateUnion.stateBitField.doubleBufferBusy); + + /* clear interrupt status, enable endpoint interrupt again */ + lpc3511IpState->registerBase->INTSTAT = (0x01U << endpointIndex); + + /* users can use NVIC to disable/enable the USB interrupt to improve the system performance */ + OSA_EXIT_CRITICAL(); + + message.length = USB_UNINITIALIZED_VAL_32; + message.buffer = epState->transferBuffer; + message.code = ep; + message.isSetup = 0U; + epState->stateUnion.stateBitField.transferring = 0U; + epState->stateUnion.stateBitField.producerOdd = + ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex); + epState->stateUnion.stateBitField.consumerOdd = + ((lpc3511IpState->registerBase->EPINUSE & ((uint32_t)(0x01 << endpointIndex))) >> endpointIndex); + USB_DeviceNotificationTrigger(lpc3511IpState->deviceHandle, &message); + } + return kStatus_USB_Success; +} + +usb_status_t USB_DeviceLpc3511IpControl(usb_device_controller_handle controllerHandle, + usb_device_control_type_t type, + void *param) +{ + usb_device_lpc3511ip_state_struct_t *lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)controllerHandle; + usb_status_t error = kStatus_USB_Error; + uint32_t tmp32Value; + uint8_t tmp8Value; +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + usb_device_struct_t *deviceHandle; +#endif + usb_device_lpc3511ip_endpoint_state_struct_t *epState; + + if (controllerHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + +#if ((defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP)) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U)) + deviceHandle = (usb_device_struct_t *)lpc3511IpState->deviceHandle; +#endif + + switch (type) + { + case kUSB_DeviceControlRun: + lpc3511IpState->registerBase->DEVCMDSTAT |= (USB_LPC3511IP_DEVCMDSTAT_DCON_MASK); + lpc3511IpState->registerBase->DEVCMDSTAT &= ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK); + break; + + case kUSB_DeviceControlStop: + lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK; + lpc3511IpState->registerBase->DEVCMDSTAT &= (~USB_LPC3511IP_DEVCMDSTAT_DCON_MASK); + break; + + case kUSB_DeviceControlEndpointInit: + if (param) + { + error = USB_DeviceLpc3511IpEndpointInit(lpc3511IpState, (usb_device_endpoint_init_struct_t *)param); + } + break; + + case kUSB_DeviceControlEndpointDeinit: + if (param) + { + tmp8Value = *((uint8_t *)param); + error = USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, tmp8Value); + } + break; + + case kUSB_DeviceControlEndpointStall: + if (param) + { + tmp8Value = *((uint8_t *)param); + error = USB_DeviceLpc3511IpEndpointStall(lpc3511IpState, tmp8Value); + } + break; + + case kUSB_DeviceControlEndpointUnstall: + if (param) + { + tmp8Value = *((uint8_t *)param); + error = USB_DeviceLpc3511IpEndpointUnstall(lpc3511IpState, tmp8Value); + } + break; + + case kUSB_DeviceControlGetDeviceStatus: + if (param) + { + *((uint16_t *)param) = + (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_IP3511_ENDPOINTS_NUM) + { + epState = USB_DeviceLpc3511IpGetEndpointStateStruct( + lpc3511IpState, USB_LPC3511IP_ENDPOINT_DES_INDEX(endpointStatus->endpointAddress)); + endpointStatus->endpointStatus = (uint16_t)(epState->stateUnion.stateBitField.stalled == 1U) ? + kUSB_DeviceEndpointStateStalled : + kUSB_DeviceEndpointStateIdle; + error = kStatus_USB_Success; + } + } + break; + + case kUSB_DeviceControlPreSetDeviceAddress: + if (param) + { + tmp8Value = *((uint8_t *)param); + tmp32Value = lpc3511IpState->registerBase->DEVCMDSTAT; + tmp32Value &= (~USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK); + tmp32Value |= (tmp8Value & USB_LPC3511IP_DEVCMDSTAT_DEV_ADDR_MASK); + lpc3511IpState->registerBase->DEVCMDSTAT = tmp32Value; + error = kStatus_USB_Success; + } + break; + + case kUSB_DeviceControlSetDeviceAddress: + error = kStatus_USB_Success; + break; + + case kUSB_DeviceControlGetSynchFrame: + break; + +#if defined(USB_DEVICE_CONFIG_REMOTE_WAKEUP) && (USB_DEVICE_CONFIG_REMOTE_WAKEUP > 0U) + case kUSB_DeviceControlResume: + /* todo: turn on USB clock and enable the USB clock source */ + lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK; + lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK; + while (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK) + { + } + /* the W1C bits */ + lpc3511IpState->registerBase->DEVCMDSTAT &= + ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK); + error = kStatus_USB_Success; + break; +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + case kUSB_DeviceControlSleepResume: + /* todo: turn on USB clock and enable the USB clock source */ + lpc3511IpState->registerBase->DEVCMDSTAT |= USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK; + lpc3511IpState->registerBase->DEVCMDSTAT &= ~USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK; + while (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK) + { + __NOP(); + } + /* the W1C bits */ + lpc3511IpState->registerBase->DEVCMDSTAT &= + ~(USB_LPC3511IP_DEVCMDSTAT_FORCE_NEEDCLK_MASK | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK); + error = kStatus_USB_Success; + break; +#endif + case kUSB_DeviceControlGetRemoteWakeUp: + *((uint8_t *)param) = !!(lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_REWP_MASK); + break; +#endif /* USB_DEVICE_CONFIG_REMOTE_WAKEUP */ + + case kUSB_DeviceControlSetDefaultStatus: + for (tmp32Value = 0U; tmp32Value < USB_DEVICE_IP3511_ENDPOINTS_NUM; tmp32Value++) + { + USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, (tmp32Value | (USB_IN << 0x07U))); + USB_DeviceLpc3511IpEndpointDeinit(lpc3511IpState, (tmp32Value | (USB_OUT << 0x07U))); + } + USB_DeviceLpc3511IpSetDefaultState(lpc3511IpState); + error = kStatus_USB_Success; + break; + + case kUSB_DeviceControlGetSpeed: + if (param) + { + *((uint8_t *)param) = lpc3511IpState->deviceSpeed; + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlGetOtgStatus: + break; + case kUSB_DeviceControlSetOtgStatus: + break; +#if (defined(USB_DEVICE_CONFIG_USB20_TEST_MODE) && (USB_DEVICE_CONFIG_USB20_TEST_MODE > 0U)) + case kUSB_DeviceControlSetTestMode: + if (param) + { + tmp8Value = *((uint8_t *)param); +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + lpc3511IpState->registerBase->DEVCMDSTAT |= + ((uint32_t)(tmp8Value) << USBHSD_DEVCMDSTAT_PHY_TEST_MODE_SHIFT); +#endif + error = kStatus_USB_Success; + } + break; +#endif +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + case kUSB_DeviceControlDcdEnable: + if (kStatus_hsdcd_Success == USB_HSDCD_Control(lpc3511IpState->dcdHandle, kUSB_DeviceHSDcdEnable, NULL)) + { + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlDcdDisable: + if (kStatus_hsdcd_Success == USB_HSDCD_Control(lpc3511IpState->dcdHandle, kUSB_DeviceHSDcdDisable, NULL)) + { + error = kStatus_USB_Success; + } + break; + case kUSB_DeviceControlUpdateHwTick: + /*udpate 1ms time tick*/ + error = kStatus_USB_Success; + break; + +#endif + default: + break; + } + + return error; +} + +void USB_DeviceLpcIp3511IsrFunction(void *deviceHandle) +{ + usb_device_struct_t *handle = (usb_device_struct_t *)deviceHandle; + usb_device_lpc3511ip_state_struct_t *lpc3511IpState; + uint32_t interruptStatus; + uint32_t usbErrorCode; + uint32_t devState; + + if (NULL == deviceHandle) + { + return; + } + + lpc3511IpState = (usb_device_lpc3511ip_state_struct_t *)(handle->controllerHandle); + /* get and clear interrupt status */ + interruptStatus = lpc3511IpState->registerBase->INTSTAT; + lpc3511IpState->registerBase->INTSTAT = interruptStatus; + interruptStatus &= lpc3511IpState->registerBase->INTEN; + + usbErrorCode = (lpc3511IpState->registerBase->INFO & USB_LPC3511IP_INFO_ERR_CODE_MASK); + + /* device status change interrupt */ + if (interruptStatus & USB_LPC3511IP_INTSTAT_DEV_INT_MASK) + { + /* get and clear device state change status */ + devState = lpc3511IpState->registerBase->DEVCMDSTAT; + devState &= ~(USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK); + lpc3511IpState->registerBase->DEVCMDSTAT = (devState | USB_LPC3511IP_DEVCMDSTAT_INTERRUPT_WC_MASK); + + /* For HS: there is interrupt with DEV_INT=1, OTG_C=1 and ADPPROBE=1 when vbus rising. + * For FS: there is no interrupt when vbus rising. The only way is: check the VBUS_DEBOUNCED in the DRES_C + * interrupt with DCON set. + */ +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE)) + if ((0U == lpc3511IpState->deviceState) && + ((devState & USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + || ((lpc3511IpState->registerBase->LPM & USB_LPC3511IP_USB_LPM_ADPPROBE_MASK) && + (1U == lpc3511IpState->controllerSpeed)) +#endif + )) + { +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if ((defined(USB_DEVICE_IP3511HS_LPM_ADPPROBE_ATTACH_DEBOUNCE_COUNT)) && \ + (USB_DEVICE_IP3511HS_LPM_ADPPROBE_ATTACH_DEBOUNCE_COUNT > 0U)) + /* add one little debounce for HS's attach detection because ADPPROBE is undebounced value */ + uint32_t debounceCount = USB_DEVICE_IP3511HS_LPM_ADPPROBE_ATTACH_DEBOUNCE_COUNT; + if (1U == lpc3511IpState->controllerSpeed) + { + while ((debounceCount) && (!(devState & USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK))) + { + if (!(lpc3511IpState->registerBase->LPM & USB_LPC3511IP_USB_LPM_ADPPROBE_MASK)) + { + break; + } + debounceCount--; + } + } + + if ((debounceCount == 0) || (devState & USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK)) +#endif +#endif + { + lpc3511IpState->deviceState = 1U; +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) + USB_PhyDeviceForceEnterFSMode(lpc3511IpState->controllerId, 0); +#endif +#endif + USB_DeviceLpc3511IpInterruptAttach(lpc3511IpState); +#if (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) && \ + (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) + USB_HSDCD_Control(lpc3511IpState->dcdHandle, kUSB_DeviceHSDcdRun, NULL); +#endif + } + } + /* For HS: there is interrupt with DEV_INT=1, OTG_C=1 and ADPPROBE=0 when vbus falling. + * For HS and FS: there is interrupt when vbus falling if DCON is set. + */ + else if ((1U == lpc3511IpState->deviceState) && + (((lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DCON_MASK) && + (!(devState & USB_LPC3511IP_DEVCMDSTAT_VBUS_DEBOUNCED_MASK))) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + || ((!(lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DCON_MASK)) && + (!(lpc3511IpState->registerBase->LPM & USB_LPC3511IP_USB_LPM_ADPPROBE_MASK)) && + (1U == lpc3511IpState->controllerSpeed)) +#endif + )) + { + lpc3511IpState->deviceState = 0U; +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) + USB_PhyDeviceForceEnterFSMode(lpc3511IpState->controllerId, 1); +#endif +#endif + USB_DeviceLpc3511IpInterruptDetach(lpc3511IpState); + } +#endif + + /* reset change */ + if (devState & USB_LPC3511IP_DEVCMDSTAT_DRES_C_MASK) + { + USB_DeviceLpc3511IpInterruptReset(lpc3511IpState); + } + +/* Suspend/Resume */ +#if ((defined(USB_DEVICE_CONFIG_LOW_POWER_MODE)) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U)) + if (devState & USB_LPC3511IP_DEVCMDSTAT_DSUS_C_MASK) + { + if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_DSUS_MASK) + { + USB_DeviceLpc3511IpInterruptSuspend(lpc3511IpState); + } +#if (defined(USB_DEVICE_CONFIG_LPM_L1) && (USB_DEVICE_CONFIG_LPM_L1 > 0U)) + else if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_LPM_SUS_MASK) + { + USB_DeviceLpc3511IpInterruptLPMSleep(lpc3511IpState); + } +#endif + else + { + USB_DeviceLpc3511IpInterruptResume(lpc3511IpState); + } + } + +#endif + +#if 0U /* some soc don't support this bit, need check according to the feature macro */ + /* OTG Status change */ + if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_OTG_C_MASK) + { + } +#endif + } + + /* endpoint transfers interrupt */ + if (interruptStatus & USB_LPC3511IP_MAX_PHY_ENDPOINT_MASK) + { + devState = 0; /* devState means index here */ + if (interruptStatus & 0x01u) /* control OUT */ + { + if (lpc3511IpState->registerBase->DEVCMDSTAT & USB_LPC3511IP_DEVCMDSTAT_SETUP_MASK) + { + devState = 2; + if ((lpc3511IpState->endpointState[0].stateUnion.stateBitField.stalled == 1U) || + (lpc3511IpState->endpointState[1].stateUnion.stateBitField.stalled == 1U)) + { + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND( + lpc3511IpState, 0, 0, + (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK))); + USB_LPC3511IP_ENDPOINT_SET_ENDPOINT_AND( + lpc3511IpState, 1, 0, + (~(USB_LPC3511IP_ENDPOINT_STALL_MASK | USB_LPC3511IP_ENDPOINT_ACTIVE_MASK))); + lpc3511IpState->endpointState[0].stateUnion.stateBitField.stalled = 0U; + lpc3511IpState->endpointState[1].stateUnion.stateBitField.stalled = 0U; + } + + /* todo: setup token interrupt */ + USB_DeviceLpc3511IpInterruptToken(lpc3511IpState, 0U, 1, usbErrorCode); + } + } + + for (; devState < (USB_DEVICE_IP3511_ENDPOINTS_NUM * 2); ++devState) + { + /* check the endpoint interrupt */ + if (interruptStatus & (0x01U << devState)) + { + USB_DeviceLpc3511IpInterruptToken(lpc3511IpState, devState, 0, usbErrorCode); + } + } + } + +#if 0U + if (interruptStatus & USB_LPC3511IP_INTSTAT_FRAME_INT_MASK) + { + } +#endif +} + +#endif diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.h new file mode 100644 index 0000000000..5b56a2041b --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/device/usb_device_lpcip3511.h @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_DEVICE_LPC3511IP_H__ +#define __USB_DEVICE_LPC3511IP_H__ + +#include "fsl_device_registers.h" + +/*! + * @addtogroup usb_device_controller_lpcip3511_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief The reserved buffer size, the buffer is for the memory copy if the application transfer buffer is + ((not 64 bytes alignment) || (not in the same 64K ram) || (HS && OUT && not multiple of 4)) */ +#define USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE (5 * 1024) +/*! @brief Use one bit to represent one reserved 64 bytes to allocate the buffer by uint of 64 bytes. */ +#define USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER ((USB_DEVICE_IP3511_ENDPOINT_RESERVED_BUFFER_SIZE + 63) / 64) +/*! @brief How many IPs support the reserved buffer */ +#define USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY (USB_DEVICE_CONFIG_LPCIP3511FS + USB_DEVICE_CONFIG_LPCIP3511HS) +/*! @brief Prime all the double endpoint buffer at the same time, if the transfer length is larger than max packet size. + */ +#define USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE (1u) +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#define USB_LPC3511IP_Type USBHSD_Type +#define USB_DEVICE_IP3511_ENDPOINTS_NUM FSL_FEATURE_USBHSD_EP_NUM +#else +#define USB_LPC3511IP_Type USB_Type +#define USB_DEVICE_IP3511_ENDPOINTS_NUM FSL_FEATURE_USB_EP_NUM +#endif + +/* for out endpoint,only use buffer toggle, disable prime double buffer at the same time*/ +/*host send data less than maxpacket size and in endpoint prime length more more than maxpacketsize, there will be state + * mismtach*/ +#if USB_DEVICE_IP3511_DOUBLE_BUFFER_ENABLE +#define USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER (1u) +#else +#define USB_DEVICE_IP3511_DISABLE_OUT_DOUBLE_BUFFER (0u) +#endif + +#define USB_DEVICE_IP3511HS_LPM_ADPPROBE_ATTACH_DEBOUNCE_COUNT (3) + +/*! @brief Endpoint state structure */ +typedef struct _usb_device_lpc3511ip_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*/ + uint32_t transferPrimedLength; /*!< it may larger than transferLength, because the primed length may larger than the + transaction length. */ + uint8_t *epPacketBuffer; /*!< The max packet buffer for copying*/ + union + { + uint32_t state; /*!< The state of the endpoint */ + struct + { + uint32_t maxPacketSize : 11U; /*!< The maximum packet size of the endpoint */ + uint32_t stalled : 1U; /*!< The endpoint is stalled or not */ + uint32_t transferring : 1U; /*!< The endpoint is transferring */ + uint32_t zlt : 1U; /*!< zlt flag */ + uint32_t stallPrimed : 1U; + uint32_t epPacketCopyed : 1U; /*!< whether use the copy buffer */ + uint32_t epControlDefault : 5u; /*!< The EP command/status 26~30 bits */ + uint32_t doubleBufferBusy : 2U; /*!< How many buffers are primed, for control endpoint it is not used */ + uint32_t producerOdd : 1U; /*!< When priming one transaction, prime to this endpoint buffer */ + uint32_t consumerOdd : 1U; /*!< When transaction is done, read result from this endpoint buffer */ + uint32_t endpointType : 2U; + uint32_t reserved1 : 5U; + } stateBitField; + } stateUnion; + union + { + uint16_t epBufferStatus; + /* If double buff is disable, only epBufferStatusUnion[0] is used; + For control endpoint, only epBufferStatusUnion[0] is used. */ + struct + { + uint16_t transactionLength : 11U; + uint16_t epPacketCopyed : 1U; + } epBufferStatusField; + } epBufferStatusUnion[2]; +} usb_device_lpc3511ip_endpoint_state_struct_t; + +/*! @brief LPC USB controller (IP3511) state structure */ +typedef struct _usb_device_lpc3511ip_state_struct +{ + /*!< control data buffer, must align with 64 */ + uint8_t *controlData; + /*!< 8 bytes' setup data, must align with 64 */ + uint8_t *setupData; + /*!< 4 bytes for zero length transaction, must align with 64 */ + uint8_t *zeroTransactionData; + /* Endpoint state structures */ + usb_device_lpc3511ip_endpoint_state_struct_t endpointState[(USB_DEVICE_IP3511_ENDPOINTS_NUM * 2)]; + usb_device_handle deviceHandle; /*!< (4 bytes) Device handle used to identify the device object belongs to */ + USB_LPC3511IP_Type *registerBase; /*!< (4 bytes) ip base address */ + volatile uint32_t *epCommandStatusList; /* endpoint list */ +#if (defined(USB_DEVICE_CONFIG_CHARGER_DETECT) && (USB_DEVICE_CONFIG_CHARGER_DETECT > 0U)) && \ + (defined(FSL_FEATURE_SOC_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U)) + void *dcdHandle; /*!< Dcd handle used to identify the device object belongs to */ +#endif + uint8_t controllerId; /*!< Controller ID */ + uint8_t isResetting; /*!< Is doing device reset or not */ + uint8_t deviceSpeed; /*!< some controller support the HS */ +#if ((defined(USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY)) && (USB_DEVICE_IP3511_RESERVED_BUFFER_FOR_COPY > 0U)) + uint8_t *epReservedBuffer; + uint8_t epReservedBufferBits[(USB_DEVICE_IP3511_BITS_FOR_RESERVED_BUFFER + 7) / 8]; +#endif +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) + uint8_t controllerSpeed; +#endif +#if (defined(USB_DEVICE_CONFIG_DETACH_ENABLE) && (USB_DEVICE_CONFIG_DETACH_ENABLE)) + uint8_t deviceState; /*!< Is device attached,1 attached,0 detached */ +#endif +#if ((defined(USB_DEVICE_CONFIG_LPCIP3511HS)) && (USB_DEVICE_CONFIG_LPCIP3511HS > 0U)) +#if (defined(FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK) && \ + (FSL_FEATURE_USBHSD_INTERRUPT_DATAX_ISSUE_VERSION_CHECK)) + uint8_t hsInterruptIssue; +#endif +#endif +} usb_device_lpc3511ip_state_struct_t; + +/*! + * @name USB device controller (IP3511) functions + * @{ + */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Initializes the USB device controller instance. + * + * This function initializes the USB device controller 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] controllerHandle An out parameter used to return the pointer of the device controller handle to the + * caller. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceLpc3511IpInit(uint8_t controllerId, + usb_device_handle handle, + usb_device_controller_handle *controllerHandle); + +/*! + * @brief Deinitializes the USB device controller instance. + * + * This function deinitializes the USB device controller module. + * + * @param[in] controllerHandle Pointer of the device controller handle. + * + * @return A USB error code or kStatus_USB_Success. + */ +usb_status_t USB_DeviceLpc3511IpDeinit(usb_device_controller_handle controllerHandle); + +/*! + * @brief Sends data through a specified endpoint. + * + * This function sends data through a specified endpoint. + * + * @param[in] controllerHandle Pointer of the device controller 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_DeviceLpc3511IpSend(usb_device_controller_handle controllerHandle, + 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] controllerHandle Pointer of the device controller 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_DeviceLpc3511IpRecv(usb_device_controller_handle controllerHandle, + 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] controllerHandle ointer of the device controller 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_DeviceLpc3511IpCancel(usb_device_controller_handle controllerHandle, 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] controllerHandle Pointer of the device controller handle. + * @param[in] type The selected item. Please refer to 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_DeviceLpc3511IpControl(usb_device_controller_handle controllerHandle, + usb_device_control_type_t type, + void *param); + +/*! @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @} */ + +#endif /* __USB_DEVICE_LPC3511IP_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb.h new file mode 100644 index 0000000000..fad418e642 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_H__ +#define __USB_H__ + +#include +#include +#include "fsl_common.h" +#include "fsl_os_abstraction.h" +#include "usb_misc.h" +#include "usb_spec.h" + +/*! + * @addtogroup usb_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/*! @brief Defines USB stack major version */ +#define USB_STACK_VERSION_MAJOR (2U) +/*! @brief Defines USB stack minor version */ +#define USB_STACK_VERSION_MINOR (5U) +/*! @brief Defines USB stack bugfix version */ +#define USB_STACK_VERSION_BUGFIX (0U) + +/*! @brief USB stack version definition */ +#define USB_MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +#define MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) + +/*! @brief USB stack component version definition, changed with component in yaml together */ +#define USB_STACK_COMPONENT_VERSION MAKE_VERSION(2, 5, 0) + +/* + * Component ID used by tools + * + * FSL_COMPONENT_ID "middleware.usb.stack_common" + */ + +/*! @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, + kStatus_USB_DataOverRun, /*!< The amount of data returned by the endpoint exceeded + either the size of the maximum data packet allowed + from the endpoint or the remaining buffer size. */ +} 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. */ + kUSB_ControllerDwc30 = 12U, /*!< DWC3 0U */ + kUSB_ControllerDwc31 = + 13U, /*!< DWC3 1U Currently, there are no platforms which have two Dwc 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/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_misc.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_misc.h new file mode 100644 index 0000000000..716b954c26 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_misc.h @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016, 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __USB_MISC_H__ +#define __USB_MISC_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Define big endian */ +#define USB_BIG_ENDIAN (0U) +/*! @brief Define little endian */ +#define USB_LITTLE_ENDIAN (1U) + +/*! @brief Define current endian */ +#ifndef ENDIANNESS +#define ENDIANNESS USB_LITTLE_ENDIAN +#endif +/*! @brief Define default timeout value */ +#if (defined(USE_RTOS) && (USE_RTOS > 0)) +#define USB_OSA_WAIT_TIMEOUT (osaWaitForever_c) +#else +#define USB_OSA_WAIT_TIMEOUT (0U) +#endif /* (defined(USE_RTOS) && (USE_RTOS > 0)) */ + +/*! @brief Define USB printf */ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +extern int DbgConsole_Printf(const char *fmt_s, ...); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#ifndef __DSC__ +#if defined(SDK_DEBUGCONSOLE) && (SDK_DEBUGCONSOLE < 1) +#define usb_echo printf +#else +#define usb_echo DbgConsole_Printf +#endif +#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) || (defined(__ARMCC_VERSION)) + +#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[3] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[3]) << 24U) | (((uint8_t)n[2]) << 16U) | (((uint8_t)n[1]) << 8U) | \ + (((uint8_t)n[0]) << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[3] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[0]) << 24U) | (((uint8_t)n[1]) << 16U) | (((uint8_t)n[2]) << 8U) | \ + (((uint8_t)n[3]) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[1]) << 8U) | (((uint8_t)n[0]) << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[1] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[0]) << 8U) | (((uint8_t)n[1]) << 0U))) + +#define USB_LONG_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 3) = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + *((uint8_t *)&(m) + 2) = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + *((uint8_t *)&(m) + 1) = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m) + 0) = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_DATA(n) \ + ((uint32_t)(((*((uint8_t *)&(n) + 3)) << 24U) | ((*((uint8_t *)&(n) + 2)) << 16U) | \ + ((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n))) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 1) = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m)) = ((((uint16_t)(n))) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_DATA(n) ((uint32_t)(((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n)))))) + +#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] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[3]) << 24U) | (((uint8_t)n[2]) << 16U) | (((uint8_t)n[1]) << 8U) | \ + (((uint8_t)n[0]) << 0U))) + +#define USB_LONG_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + m[1] = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + m[2] = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + m[3] = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_BIG_ENDIAN_ADDRESS(n) \ + ((uint32_t)((((uint8_t)n[0]) << 24U) | (((uint8_t)n[1]) << 16U) | (((uint8_t)n[2]) << 8U) | \ + (((uint8_t)n[3]) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_ADDRESS(n, m) \ + { \ + m[1] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[0] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[1]) << 8U) | (((uint8_t)n[0]) << 0U))) + +#define USB_SHORT_TO_BIG_ENDIAN_ADDRESS(n, m) \ + { \ + m[0] = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + m[1] = (((uint16_t)(n)) & 0xFFU); \ + } + +#define USB_SHORT_FROM_BIG_ENDIAN_ADDRESS(n) ((uint32_t)((((uint8_t)n[0]) << 8U) | (((uint8_t)n[1]) << 0U))) + +#define USB_LONG_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 3) = ((((uint32_t)(n)) >> 24U) & 0xFFU); \ + *((uint8_t *)&(m) + 2) = ((((uint32_t)(n)) >> 16U) & 0xFFU); \ + *((uint8_t *)&(m) + 1) = ((((uint32_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m) + 0) = (((uint32_t)(n)) & 0xFFU); \ + } + +#define USB_LONG_FROM_LITTLE_ENDIAN_DATA(n) \ + ((uint32_t)(((*((uint8_t *)&(n) + 3)) << 24U) | ((*((uint8_t *)&(n) + 2)) << 16U) | \ + ((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n))) << 0U))) + +#define USB_SHORT_TO_LITTLE_ENDIAN_DATA(n, m) \ + { \ + *((uint8_t *)&(m) + 1) = ((((uint16_t)(n)) >> 8U) & 0xFFU); \ + *((uint8_t *)&(m)) = ((((uint16_t)(n))) & 0xFFU); \ + } + +#define USB_SHORT_FROM_LITTLE_ENDIAN_DATA(n) ((uint32_t)(((*((uint8_t *)&(n) + 1)) << 8U) | ((*((uint8_t *)&(n)))))) + +#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 + * 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 macro 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(__ICCARM__) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +/* 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) + _Pragma("diag_suppress=Pm120") +#define USB_LINK_SECTION_PART(str) _Pragma(#str) +#define USB_LINK_DMA_INIT_DATA(sec) USB_LINK_SECTION_PART(location = #sec) +#define USB_LINK_USB_GLOBAL _Pragma("location = \"m_usb_global\"") +#define USB_LINK_USB_BDT _Pragma("location = \"m_usb_bdt\"") +#define USB_LINK_USB_GLOBAL_BSS +#define USB_LINK_USB_BDT_BSS + _Pragma("diag_default=Pm120") +#define USB_LINK_DMA_NONINIT_DATA _Pragma("location = \"m_usb_dma_noninit_data\"") +#define USB_LINK_NONCACHE_NONINIT_DATA _Pragma("location = \"NonCacheable\"") +#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION)) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) +#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec))) +#if defined(__CC_ARM) +#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global"))) __attribute__((zero_init)) +#else +#define USB_LINK_USB_GLOBAL __attribute__((section(".bss.m_usb_global"))) +#endif +#if defined(__CC_ARM) +#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt"))) __attribute__((zero_init)) +#else +#define USB_LINK_USB_BDT __attribute__((section(".bss.m_usb_bdt"))) +#endif +#define USB_LINK_USB_GLOBAL_BSS +#define USB_LINK_USB_BDT_BSS +#if defined(__CC_ARM) +#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data"))) __attribute__((zero_init)) +#else +#define USB_LINK_DMA_NONINIT_DATA __attribute__((section(".bss.m_usb_dma_noninit_data"))) +#endif +#if defined(__CC_ARM) +#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable"))) __attribute__((zero_init)) +#else +#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section(".bss.NonCacheable"))) +#endif + +#elif defined(__GNUC__) + +#define USB_WEAK_VAR __attribute__((weak)) +#define USB_WEAK_FUN __attribute__((weak)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) __attribute__((aligned(n))) +#define USB_LINK_DMA_INIT_DATA(sec) __attribute__((section(#sec))) +#define USB_LINK_USB_GLOBAL __attribute__((section("m_usb_global, \"aw\", %nobits @"))) +#define USB_LINK_USB_BDT __attribute__((section("m_usb_bdt, \"aw\", %nobits @"))) +#define USB_LINK_USB_GLOBAL_BSS +#define USB_LINK_USB_BDT_BSS +#define USB_LINK_DMA_NONINIT_DATA __attribute__((section("m_usb_dma_noninit_data, \"aw\", %nobits @"))) +#define USB_LINK_NONCACHE_NONINIT_DATA __attribute__((section("NonCacheable, \"aw\", %nobits @"))) + +#elif defined(__DSC__) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define USB_RAM_ADDRESS_ALIGNMENT(n) +#define USB_LINK_USB_BDT_BSS +#define USB_LINK_USB_GLOBAL_BSS +#else +#error The tool-chain is not supported. +#endif + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + +#if ((defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)) && (defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE))) +#define USB_CACHE_LINESIZE MAX(FSL_FEATURE_L2CACHE_LINESIZE_BYTE, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#elif (defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE)) +#define USB_CACHE_LINESIZE MAX(FSL_FEATURE_L2CACHE_LINESIZE_BYTE, 0) +#elif (defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE)) +#define USB_CACHE_LINESIZE MAX(0, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) +#else +#define USB_CACHE_LINESIZE 4 +#endif + +#else +#define USB_CACHE_LINESIZE 4 +#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_ALIGN 64 +#else +#define USB_DATA_ALIGN 4 +#endif + +#define USB_DATA_ALIGN_SIZE MAX(USB_CACHE_LINESIZE, USB_DATA_ALIGN) + +#define USB_DATA_ALIGN_SIZE_MULTIPLE(n) ((n + USB_DATA_ALIGN_SIZE - 1U) & (~(USB_DATA_ALIGN_SIZE - 1U))) + +#if defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT_GLOBAL) + +#define USB_GLOBAL USB_LINK_USB_GLOBAL +#define USB_BDT USB_LINK_USB_BDT + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#if (defined(DATA_SECTION_IS_CACHEABLE) && (DATA_SECTION_IS_CACHEABLE)) +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(NonCacheable.init) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA USB_LINK_USB_GLOBAL +#endif +#endif + +#elif defined(USB_STACK_USE_DEDICATED_RAM) && (USB_STACK_USE_DEDICATED_RAM == USB_STACK_DEDICATED_RAM_TYPE_BDT) + +#define USB_BDT USB_LINK_USB_BDT + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_GLOBAL USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#if (defined(DATA_SECTION_IS_CACHEABLE) && (DATA_SECTION_IS_CACHEABLE)) +#define USB_GLOBAL USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(NonCacheable.init) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#define USB_GLOBAL USB_LINK_USB_GLOBAL_BSS +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA +#endif +#endif + +#else + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) + +#define USB_GLOBAL USB_LINK_DMA_NONINIT_DATA +#define USB_BDT USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_DMA_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(m_usb_dma_init_data) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA + +#else + +#if (defined(DATA_SECTION_IS_CACHEABLE) && (DATA_SECTION_IS_CACHEABLE)) +#define USB_GLOBAL USB_LINK_NONCACHE_NONINIT_DATA +#define USB_BDT USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_NONINIT_SUB USB_LINK_NONCACHE_NONINIT_DATA +#define USB_DMA_DATA_INIT_SUB USB_LINK_DMA_INIT_DATA(NonCacheable.init) +#define USB_CONTROLLER_DATA USB_LINK_NONCACHE_NONINIT_DATA +#else +#define USB_GLOBAL USB_LINK_USB_GLOBAL_BSS +#define USB_BDT USB_LINK_USB_BDT_BSS +#define USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_DATA_INIT_SUB +#define USB_CONTROLLER_DATA +#endif + +#endif + +#endif + +#define USB_DMA_NONINIT_DATA_ALIGN(n) USB_RAM_ADDRESS_ALIGNMENT(n) USB_DMA_DATA_NONINIT_SUB +#define USB_DMA_INIT_DATA_ALIGN(n) USB_RAM_ADDRESS_ALIGNMENT(n) USB_DMA_DATA_INIT_SUB + +#if (defined(USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_DEVICE_CONFIG_BUFFER_PROPERTY_CACHEABLE)) || \ + (defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) +#define USB_DMA_DATA_NONCACHEABLE USB_LINK_NONCACHE_NONINIT_DATA + +#else +#define USB_DMA_DATA_NONCACHEABLE +#endif + +#define USB_GLOBAL_DEDICATED_RAM USB_LINK_USB_GLOBAL + +/* #define USB_RAM_ADDRESS_NONCACHEREG_ALIGNMENT(n, var) AT_NONCACHEABLE_SECTION_ALIGN(var, n) */ +/* #define USB_RAM_ADDRESS_NONCACHEREG(var) AT_NONCACHEABLE_SECTION(var) */ + +#endif /* __USB_MISC_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_spec.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_spec.h new file mode 100644 index 0000000000..f9f33a6aba --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/include/usb_spec.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#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) +#define USB_SPEED_SUPER (0x04U) + +/* 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_ENDPOINT_COMPANION (0x06U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_QUALITIER (0x0AU) +#define USB_DESCRIPTOR_LENGTH_OTG_DESCRIPTOR (5U) +#define USB_DESCRIPTOR_LENGTH_BOS_DESCRIPTOR (5U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_CAPABILITY_USB20_EXTENSION (0x07U) +#define USB_DESCRIPTOR_LENGTH_DEVICE_CAPABILITY_SUPERSPEED (0x0AU) + +/* 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) + +#define USB_DESCRIPTOR_TYPE_ENDPOINT_COMPANION (0x30U) + +/* 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_endpoint_companion +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint8_t wBytesPerInterval[2]; +} usb_descriptor_endpoint_companion_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 struct _usb_descriptor_super_speed_device_capability +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bmAttributes; + uint8_t wSpeedsSupported[2]; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint8_t wU2DevExitLat[2]; +} usb_bos_device_capability_susperspeed_desc_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_endpoint_companion_t endpointCompanion; /* Endpoint companion descriptor */ +} usb_descriptor_union_t; + +#endif /* __USB_SPEC_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.c new file mode 100644 index 0000000000..a1e04c89b9 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "usb.h" +#include "fsl_device_registers.h" + +#include "usb_phy.h" + +void *USB_EhciPhyGetBase(uint8_t controllerId) +{ + void *usbPhyBase = NULL; +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + uint32_t instance; + uint32_t newinstance = 0; + uint32_t usbphy_base_temp[] = USBPHY_BASE_ADDRS; + uint32_t usbphy_base[] = USBPHY_BASE_ADDRS; + + if (controllerId < kUSB_ControllerEhci0) + { + return NULL; + } + + if ((controllerId == kUSB_ControllerEhci0) || (controllerId == kUSB_ControllerEhci1)) + { + controllerId = controllerId - kUSB_ControllerEhci0; + } + else if ((controllerId == kUSB_ControllerLpcIp3511Hs0) || (controllerId == kUSB_ControllerLpcIp3511Hs1)) + { + controllerId = controllerId - kUSB_ControllerLpcIp3511Hs0; + } + else if ((controllerId == kUSB_ControllerIp3516Hs0) || (controllerId == kUSB_ControllerIp3516Hs1)) + { + controllerId = controllerId - kUSB_ControllerIp3516Hs0; + } + else + { + } + + for (instance = 0; instance < (sizeof(usbphy_base_temp) / sizeof(usbphy_base_temp[0])); instance++) + { + if (usbphy_base_temp[instance]) + { + usbphy_base[newinstance++] = usbphy_base_temp[instance]; + } + } + if (controllerId > newinstance) + { + return NULL; + } + + usbPhyBase = (void *)usbphy_base[controllerId]; +#endif + return usbPhyBase; +} + +/*! + * @brief ehci phy initialization. + * + * This function initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return kStatus_USB_Error; + } + +#if ((defined FSL_FEATURE_SOC_ANATOP_COUNT) && (FSL_FEATURE_SOC_ANATOP_COUNT > 0U)) + ANATOP->HW_ANADIG_REG_3P0.RW = + (ANATOP->HW_ANADIG_REG_3P0.RW & + (~(ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x1F) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_ILIMIT_MASK))) | + ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x17) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_LINREG_MASK; + ANATOP->HW_ANADIG_USB2_CHRG_DETECT.SET = + ANATOP_HW_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B_MASK | ANATOP_HW_ANADIG_USB2_CHRG_DETECT_EN_B_MASK; +#endif + +#if (defined USB_ANALOG) + USB_ANALOG->INSTANCE[controllerId - kUSB_ControllerEhci0].CHRG_DETECT_SET = + USB_ANALOG_CHRG_DETECT_CHK_CHRG_B(1) | USB_ANALOG_CHRG_DETECT_EN_B(1); +#endif + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; + if ((kUSB_ControllerIp3516Hs0 == controllerId) || (kUSB_ControllerIp3516Hs1 == controllerId) || + (kUSB_ControllerLpcIp3511Hs0 == controllerId) || (kUSB_ControllerLpcIp3511Hs0 == controllerId)) + { + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_CLKGATE_MASK; + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_PHY_PWD_MASK; + } + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return kStatus_USB_Success; +} + +/*! + * @brief ehci phy initialization for suspend and resume. + * + * This function initialize ehci phy IP for suspend and resume. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return kStatus_USB_Error; + } + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + +#if ((defined USBPHY_CTRL_AUTORESUME_EN_MASK) && (USBPHY_CTRL_AUTORESUME_EN_MASK > 0U)) + usbPhyBase->CTRL |= USBPHY_CTRL_AUTORESUME_EN_MASK; +#else + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTO_PWRON_PLL_MASK; +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK; + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; +#if (defined USBPHY_ANACTRL_PFD_CLKGATE_MASK) + /* now the 480MHz USB clock is up, then configure fractional divider after PLL with PFD + * pfd clock = 480MHz*18/N, where N=18~35 + * Please note that USB1PFDCLK has to be less than 180MHz for RUN or HSRUN mode + */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_FRAC(24); /* N=24 */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_CLK_SEL(1); /* div by 4 */ + + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_DEV_PULLDOWN_MASK; + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_PFD_CLKGATE_MASK; + while (!(usbPhyBase->ANACTRL & USBPHY_ANACTRL_PFD_STABLE_MASK)) + { + } +#endif + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return kStatus_USB_Success; +} + +/*! + * @brief ehci phy de-initialization. + * + * This function de-initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + */ +void USB_EhciPhyDeinit(uint8_t controllerId) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_POWER_MASK; /* power down PLL */ + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_EN_USB_CLKS_MASK; /* disable USB clock output from USB PHY PLL */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* set to 1U to gate clocks */ +#endif +} + +/*! + * @brief ehci phy disconnect detection enable or disable. + * + * This function enable/disable host ehci disconnect detection. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } + + if (enable) + { + usbPhyBase->CTRL |= USBPHY_CTRL_ENHOSTDISCONDETECT_MASK; + } + else + { + usbPhyBase->CTRL &= (~USBPHY_CTRL_ENHOSTDISCONDETECT_MASK); + } +#endif +} + +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) +void USB_PhyDeviceForceEnterFSMode(uint8_t controllerId, uint8_t enable) +{ + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } + + if (enable) + { + uint32_t delay = 1000000; + usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK; + while ((usbPhyBase->USB1_VBUS_DET_STAT & USBPHY_USB1_VBUS_DET_STAT_VBUS_VALID_3V_MASK) && (delay)) + { + delay--; + } + usbPhyBase->USB1_LOOPBACK_SET = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK; + } + else + { + usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK; + usbPhyBase->USB1_LOOPBACK_CLR = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK; + } +} +#endif +#endif diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.h new file mode 100644 index 0000000000..e31653010a --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/TARGET_USB/phy/usb_phy.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016 - 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __USB_PHY_H__ +#define __USB_PHY_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +typedef struct _usb_phy_config_struct +{ + uint8_t D_CAL; /* Decode to trim the nominal 17.78mA current source */ + uint8_t TXCAL45DP; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DP output pin */ + uint8_t TXCAL45DM; /* Decode to trim the nominal 45-Ohm series termination resistance to the USB_DM output pin */ +} usb_phy_config_struct_t; + +#if defined(__cplusplus) +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ +/*! + * @brief EHCI PHY get USB phy bass address. + * + * This function is used to get USB phy bass address. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * + * @retval USB phy bass address. + */ +extern void *USB_EhciPhyGetBase(uint8_t controllerId); + +/*! + * @brief EHCI PHY initialization. + * + * This function initializes the EHCI PHY IP. + * + * @param[in] controllerId EHCI controller ID; See the #usb_controller_index_t. + * @param[in] freq The external input clock. + * + * @retval kStatus_USB_Success Cancel successfully. + * @retval kStatus_USB_Error The freq value is incorrect. + */ +extern uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig); + +/*! + * @brief ehci phy initialization for suspend and resume. + * + * This function initialize ehci phy IP for suspend and resume. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +extern uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig); + +/*! + * @brief EHCI PHY deinitialization. + * + * This function deinitializes the EHCI PHY IP. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + */ +extern void USB_EhciPhyDeinit(uint8_t controllerId); + +/*! + * @brief EHCI PHY disconnect detection enable or disable. + * + * This function enable/disable the host EHCI disconnect detection. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +extern void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable); + +/*! + * @brief Force the PHY enter FS Mode + * + * on RT500 and RT600, the device doesn't enter FS Mode after vbus is invalide and the controller works as HS. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +extern void USB_PhyDeviceForceEnterFSMode(uint8_t controllerId, uint8_t enable); + +#if defined(__cplusplus) +} +#endif + +#endif /* __USB_PHY_H__ */ diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction.h new file mode 100644 index 0000000000..84789b2739 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_OS_ABSTRACTION_H_ +#define _FSL_OS_ABSTRACTION_H_ + +/*! + * @addtogroup osa_adapter + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "fsl_os_abstraction_mbed.h" + +/* + * alloc the temporary memory to store the status + */ +#define OSA_SR_ALLOC() uint32_t osaCurrentSr; +/* + * Enter critical mode + */ +#define OSA_ENTER_CRITICAL() OSA_EnterCritical(&osaCurrentSr) +/* + * Exit critical mode and retore the previous mode + */ +#define OSA_EXIT_CRITICAL() OSA_ExitCritical(osaCurrentSr) + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief Enter critical with nesting mode. + * + * @param sr Store current status and return to caller. + */ +void OSA_EnterCritical(uint32_t *sr); + +/*! + * @brief Exit critical with nesting mode. + * + * @param sr Previous status to restore. + */ +void OSA_ExitCritical(uint32_t sr); + +/*! @}*/ +#ifdef __cplusplus +} +#endif +/*! @}*/ +#endif diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.c new file mode 100644 index 0000000000..34bce65b66 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.c @@ -0,0 +1,29 @@ +/*! ********************************************************************************* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2020 NXP + * All rights reserved. + * + * + * This is the source file for the OS Abstraction layer for freertos. + * + * SPDX-License-Identifier: BSD-3-Clause + ********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "fsl_common.h" +#include "fsl_os_abstraction_mbed.h" + +void OSA_EnterCritical(uint32_t *sr) +{ + core_util_critical_section_enter(); +} + +void OSA_ExitCritical(uint32_t sr) +{ + core_util_critical_section_exit(); +} + diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.h b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.h new file mode 100644 index 0000000000..9c27732336 --- /dev/null +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/middleware/osa/fsl_os_abstraction_mbed.h @@ -0,0 +1,26 @@ +/*! ********************************************************************************* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + ********************************************************************************** */ +#if !defined(__FSL_OS_ABSTRACTION_MBED_H__) +#define __FSL_OS_ABSTRACTION_MBED_H__ + +#include "mbed_critical.h" + +/*! + * @addtogroup os_abstraction_free_rtos + * @{ + */ + +/******************************************************************************* + * Declarations + ******************************************************************************/ +/*! @brief Constant to pass as timeout value in order to wait indefinitely. */ +#define OSA_WAIT_FOREVER 0xFFFFFFFFU + +/*! @brief OSA's time range in millisecond, OSA time wraps if exceeds this value. */ +#define FSL_OSA_TIME_RANGE 0xFFFFFFFFU + +#endif // __FSL_OS_ABSTRACTION_MBED_H__ \ No newline at end of file diff --git a/targets/targets.json b/targets/targets.json index bc7ba4cb4f..d7caa8e39e 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4153,7 +4153,8 @@ "EVK", "MIMXRT1050", "IMX", - "NXP_EMAC" + "NXP_EMAC", + "USB" ], "is_disk_virtual": true, "macros": [ @@ -4169,7 +4170,8 @@ "__STARTUP_INITIALIZE_RAMFUNCTION", "__STARTUP_INITIALIZE_NONCACHEDATA", "MBED_MPU_CUSTOM", - "MBED_TICKLESS" + "MBED_TICKLESS", + "DATA_SECTION_IS_CACHEABLE=1" ], "components_add": [ "FLASHIAP" @@ -4201,7 +4203,8 @@ "STDIO_MESSAGES", "TRNG", "WATCHDOG", - "FLASH" + "FLASH", + "USBDEVICE" ], "release_versions": [ "5"