1976 lines
81 KiB
C
1976 lines
81 KiB
C
/*
|
|
* Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
|
|
* Copyright 2016 - 2017,2019 - 2020 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"
|
|
#elif (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);
|
|
|
|
/*******************************************************************************
|
|
* 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))
|
|
static 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 < (uint8_t)kUSB_ControllerEhci0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
controllerId = controllerId - (uint8_t)kUSB_ControllerEhci0;
|
|
|
|
for (instance = 0; instance < (sizeof(usbnc_base_temp) / sizeof(usbnc_base_temp[0])); instance++)
|
|
{
|
|
if (usbnc_base_temp[instance] != 0U)
|
|
{
|
|
usbnc_base[newinstance++] = usbnc_base_temp[instance];
|
|
}
|
|
}
|
|
if (controllerId > newinstance)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
usbNCBase = (void *)(uint8_t *)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 & 0x0000FFFFU;
|
|
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
|
|
| USBHS_USBINTR_SRE_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 = 1UL << ((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 */
|
|
(void)USB_DeviceEhciCancel(ehciState, epInit->endpointAddress);
|
|
|
|
if ((0U != (ehciState->registerBase->EPPRIME & primeBit)) || (0U != (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 =
|
|
1UL + ((((uint32_t)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 =
|
|
((0U == epInit->zlt) ? 1U : 0U);
|
|
}
|
|
|
|
/* Enable the endpoint. */
|
|
if ((USB_CONTROL_ENDPOINT == endpoint))
|
|
{
|
|
ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios = 1U;
|
|
ehciState->registerBase->EPCR0 |=
|
|
((0U != 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] |=
|
|
((0U != 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 =
|
|
1UL << ((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 */
|
|
(void)USB_DeviceEhciCancel(ehciState, ep);
|
|
if ((0U != (ehciState->registerBase->EPPRIME & primeBit)) || (0U != (ehciState->registerBase->EPSR & primeBit)))
|
|
{
|
|
return kStatus_USB_Busy;
|
|
}
|
|
|
|
/* Clear endpoint state */
|
|
ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristics = 0U;
|
|
/* Disable the endpoint */
|
|
if (0U == endpoint)
|
|
{
|
|
ehciState->registerBase->EPCR0 &=
|
|
~((0U != direction) ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK | USBHS_EPCR_TXS_MASK) :
|
|
(USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK | USBHS_EPCR_RXS_MASK));
|
|
}
|
|
else
|
|
{
|
|
ehciState->registerBase->EPCR[endpoint - 1U] &=
|
|
~((0U != direction) ? (USBHS_EPCR_TXE_MASK | USBHS_EPCR_TXT_MASK | USBHS_EPCR_TXS_MASK) :
|
|
(USBHS_EPCR_RXE_MASK | USBHS_EPCR_RXT_MASK | USBHS_EPCR_RXS_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 */
|
|
(void)USB_DeviceEhciCancel(ehciState, ep);
|
|
|
|
/* Set endpoint stall flag. */
|
|
if (0U != ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.ios)
|
|
{
|
|
if (0U == 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 (0U == endpoint)
|
|
{
|
|
ehciState->registerBase->EPCR0 |= ((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
|
|
}
|
|
else
|
|
{
|
|
ehciState->registerBase->EPCR[endpoint - 1U] |=
|
|
((0U != 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 (0U == endpoint)
|
|
{
|
|
ehciState->registerBase->EPCR0 &= ~((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
|
|
}
|
|
else
|
|
{
|
|
ehciState->registerBase->EPCR[endpoint - 1U] &=
|
|
~((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK);
|
|
ehciState->registerBase->EPCR[endpoint - 1U] |= ((0U != direction) ? USBHS_EPCR_TXR_MASK : USBHS_EPCR_RXR_MASK);
|
|
}
|
|
/* Cancel the transfer of the endpoint */
|
|
(void)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 = 1UL << ep;
|
|
|
|
while (0U != 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 (0U != (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 (NULL != 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_CANCELLED_TRANSFER_LENGTH. Or set the length by using
|
|
* finished length. */
|
|
if (0U != (currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE))
|
|
{
|
|
message.length = USB_CANCELLED_TRANSFER_LENGTH;
|
|
}
|
|
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 ((0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) ||
|
|
(0U == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK)))
|
|
{
|
|
message.code = endpoint | (uint8_t)((uint32_t)direction << 0x07U);
|
|
message.isSetup = 0U;
|
|
(void)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;
|
|
void *temp;
|
|
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 (0U != status)
|
|
{
|
|
for (endpoint = 0U; endpoint < USB_DEVICE_CONFIG_ENDPOINTS; endpoint++)
|
|
{
|
|
/* Check the endpoint receive the setup packet. */
|
|
if (0U != (status & (1UL << endpoint)))
|
|
{
|
|
/* Get last setup packet */
|
|
temp = (void *)&ehciState->qh[(uint8_t)((uint32_t)endpoint << 1U) + USB_OUT].setupBufferBack;
|
|
usb_setup_struct_t *deviceSetup = (usb_setup_struct_t *)temp;
|
|
|
|
/* 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. */
|
|
(void)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 (0U != status)
|
|
{
|
|
for (count = 0U; count < 32U; count++)
|
|
{
|
|
/* Check the transfer is done or not in the specified endpoint. */
|
|
if (0U != (status & (1UL << 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 (0U ==
|
|
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 (NULL != 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 (NULL != currentDtd)
|
|
{
|
|
/* Don't handle the active dtd. */
|
|
if ((0U !=
|
|
(currentDtd->dtdTokenUnion.dtdTokenBitmap.status & USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) ||
|
|
(0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc))
|
|
{
|
|
if ((0U == (currentDtd->dtdTokenUnion.dtdTokenBitmap.status &
|
|
USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)) &&
|
|
(0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc))
|
|
{
|
|
isTokenDone = 1U;
|
|
}
|
|
break;
|
|
}
|
|
currentDtd = (usb_device_ehci_dtd_struct_t *)(currentDtd->nextDtdPointer &
|
|
USB_DEVICE_ECHI_DTD_POINTER_MASK);
|
|
}
|
|
|
|
if ((0U == isTokenDone) && (NULL != 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 (NULL != currentDtd)
|
|
{
|
|
/* Don't handle the active dtd. */
|
|
if (0U != (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 ((0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) ||
|
|
(0U == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK)))
|
|
{
|
|
message.code = endpoint | (uint8_t)((uint32_t)direction << 0x07U);
|
|
message.isSetup = 0U;
|
|
(void)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) && (0U != (currentDtd->dtdTokenUnion.dtdTokenBitmap.status &
|
|
USB_DEVICE_ECHI_DTD_STATUS_ACTIVE)))
|
|
{
|
|
primeBit = 1UL << (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 (0U == (ehciState->registerBase->EPSR & primeBit))
|
|
{
|
|
/* Wait for the endpoint prime bit cleared by HW */
|
|
while (0U != (ehciState->registerBase->EPPRIME & primeBit))
|
|
{
|
|
}
|
|
|
|
/* If the endpoint transmit/receive buffer is not ready */
|
|
if (0U == (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 (0U == (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_PR_MASK))
|
|
{
|
|
/* If not, update the USB speed. */
|
|
if (0U != (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 (0U != ehciState->isResetting)
|
|
{
|
|
message.code = (uint8_t)kUSB_DeviceNotifyBusReset;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
ehciState->isResetting = 0U;
|
|
}
|
|
}
|
|
|
|
#if (defined(USB_DEVICE_CONFIG_LOW_POWER_MODE) && (USB_DEVICE_CONFIG_LOW_POWER_MODE > 0U))
|
|
if ((0U != ehciState->isSuspending) && (0U == (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_SUSP_MASK)))
|
|
{
|
|
/* Set the resume flag */
|
|
ehciState->isSuspending = 0U;
|
|
|
|
message.code = (uint8_t)kUSB_DeviceNotifyResume;
|
|
(void)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 (0U != (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 (0U != (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 = (uint8_t)kUSB_DeviceNotifyBusReset;
|
|
message.length = 0U;
|
|
message.isSetup = 0U;
|
|
|
|
(void)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 (0U != (ehciState->registerBase->PORTSC1 & USBHS_PORTSC1_SUSP_MASK))
|
|
{
|
|
#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
|
|
#else
|
|
if (0U != (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 = (uint8_t)kUSB_DeviceNotifySuspend;
|
|
(void)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 = (((uint32_t)endpointAddress & USB_ENDPOINT_NUMBER_MASK) << 1U) |
|
|
(((uint32_t)endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
|
|
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
|
|
uint32_t primeBit = 1UL << ((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;
|
|
void *temp;
|
|
OSA_SR_ALLOC();
|
|
|
|
if (NULL == 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 (0U != ehciState->isResetting)
|
|
{
|
|
return kStatus_USB_Error;
|
|
}
|
|
|
|
if (0U == 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 (0U == 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 (0U == 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 (NULL != (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 (0U != length);
|
|
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 */
|
|
temp = (void *)&ehciState->qh[setupindex].setupBufferBack[0];
|
|
usb_setup_struct_t *deviceSetup = (usb_setup_struct_t *)temp;
|
|
if (1U == ehciState->qh[index].endpointStatusUnion.endpointStatusBitmap.zlt)
|
|
{
|
|
if ((0U != sendLength) && (sendLength < deviceSetup->wLength) &&
|
|
(0U ==
|
|
(sendLength % ehciState->qh[index]
|
|
.capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.maxPacketSize)))
|
|
{
|
|
/* enable ZLT. */
|
|
ehciState->qh[index].capabilttiesCharacteristicsUnion.capabilttiesCharacteristicsBitmap.zlt = 0U;
|
|
}
|
|
}
|
|
}
|
|
/* If the QH is not empty */
|
|
if (0U == qhIdle)
|
|
{
|
|
/* If the prime bit is set, nothing need to do. */
|
|
if (0U != (ehciState->registerBase->EPPRIME & primeBit))
|
|
{
|
|
OSA_EXIT_CRITICAL();
|
|
return kStatus_USB_Success;
|
|
}
|
|
|
|
/* To safely a dtd */
|
|
while (0U != 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 (0U != (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 ((0U != qhIdle) || (0U == (epStatus & primeBit)))
|
|
{
|
|
ehciState->qh[index].nextDtdPointer = (uint32_t)dtdHard;
|
|
ehciState->qh[index].dtdTokenUnion.dtdToken = 0U;
|
|
/*make sure dtd is linked to dqh*/
|
|
__DSB();
|
|
ehciState->registerBase->EPPRIME = primeBit;
|
|
while (0U == (ehciState->registerBase->EPSR & primeBit))
|
|
{
|
|
primeTimesCount++;
|
|
if (primeTimesCount == USB_DEVICE_MAX_TRANSFER_PRIME_TIMES)
|
|
{
|
|
OSA_EXIT_CRITICAL();
|
|
return kStatus_USB_Error;
|
|
}
|
|
if (0U != (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.
|
|
*/
|
|
static void *USB_EhciGetValidEhciState(uint8_t *instanceIndex)
|
|
{
|
|
for (uint8_t instance = 0; instance < USB_DEVICE_CONFIG_EHCI; instance++)
|
|
{
|
|
if (0U == g_UsbDeviceEhciStateStatus[instance])
|
|
{
|
|
g_UsbDeviceEhciStateStatus[instance] = 1U;
|
|
*instanceIndex = instance;
|
|
return (void *)(&g_UsbDeviceEhciState[instance]);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#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 = (uint8_t)kUSB_DeviceNotifyDcdDetectFinished;
|
|
(void)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);
|
|
}
|
|
#elif (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 = (uint8_t)kUSB_DeviceNotifyDcdDetectFinished;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
|
|
return error;
|
|
}
|
|
#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 = NULL;
|
|
uint32_t ehci_base[] = USBHS_BASE_ADDRS;
|
|
uint8_t intanceIndex;
|
|
void *temp;
|
|
#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_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;
|
|
#elif (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 ((controllerId < (uint8_t)kUSB_ControllerEhci0) ||
|
|
((uint32_t)((uint32_t)controllerId - (uint32_t)kUSB_ControllerEhci0) >= (sizeof(ehci_base) / sizeof(uint32_t))))
|
|
{
|
|
return kStatus_USB_ControllerNotFound;
|
|
}
|
|
|
|
ehciState = USB_EhciGetValidEhciState(&intanceIndex);
|
|
if (NULL == ehciState)
|
|
{
|
|
return kStatus_USB_InvalidHandle;
|
|
}
|
|
ehciState->dtd = s_UsbDeviceEhciDtd[intanceIndex];
|
|
temp = (void *)&qh_buffer[intanceIndex * 2048U];
|
|
ehciState->qh = (usb_device_ehci_qh_struct_t *)temp;
|
|
|
|
ehciState->controllerId = controllerId;
|
|
|
|
ehciState->registerBase = (USBHS_Type *)ehci_base[controllerId - (uint8_t)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
|
|
/* Reset the controller. */
|
|
ehciState->registerBase->USBCMD |= USBHS_USBCMD_RST_MASK;
|
|
while (0U != (ehciState->registerBase->USBCMD & USBHS_USBCMD_RST_MASK))
|
|
{
|
|
}
|
|
|
|
/* 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_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))
|
|
base = (USBHSDCD_Type *)hsdcd_base[controllerId - (uint8_t)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 (0U != (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK))
|
|
{
|
|
/* Device is connected to a host. */
|
|
message.code = (uint8_t)kUSB_DeviceNotifyAttach;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
(void)USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdRun, NULL);
|
|
}
|
|
#elif (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 - (uint8_t)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 (0U != (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK))
|
|
{
|
|
/* Device is connected to a host. */
|
|
message.code = (uint8_t)kUSB_DeviceNotifyAttach;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
|
|
(void)USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdRun, 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 (NULL == 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_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))
|
|
(void)USB_HSDCD_Deinit(ehciState->dcdHandle);
|
|
#elif (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))
|
|
(void)USB_PHYDCD_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 =
|
|
1UL << ((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);
|
|
uint8_t flag = 0;
|
|
|
|
OSA_SR_ALLOC();
|
|
|
|
if (NULL == ehciHandle)
|
|
{
|
|
return kStatus_USB_InvalidHandle;
|
|
}
|
|
|
|
OSA_ENTER_CRITICAL();
|
|
|
|
message.buffer = NULL;
|
|
message.length = USB_CANCELLED_TRANSFER_LENGTH;
|
|
|
|
/* 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 (NULL != 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 (NULL != currentDtd)
|
|
{
|
|
/* this if statement is used with the previous while loop to avoid the endless loop */
|
|
if (0U == currentDtd->reservedUnion.originalBufferInfo.dtdInvalid)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (0U != (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 (0U != (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 (0U != (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 ((0U != currentDtd->dtdTokenUnion.dtdTokenBitmap.ioc) ||
|
|
(0U == ((uint32_t)ehciState->dtdHard[index] & USB_DEVICE_ECHI_DTD_POINTER_MASK)))
|
|
{
|
|
flag = 1;
|
|
}
|
|
/* 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 (NULL == 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();
|
|
|
|
if (0U != flag)
|
|
{
|
|
message.code = ep;
|
|
message.isSetup = 0U;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
message.buffer = NULL;
|
|
}
|
|
|
|
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;
|
|
#if defined(USB_DEVICE_CONFIG_GET_SOF_COUNT) && (USB_DEVICE_CONFIG_GET_SOF_COUNT > 0U)
|
|
uint32_t *temp32;
|
|
#endif
|
|
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 (NULL == 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 (NULL != param)
|
|
{
|
|
error = USB_DeviceEhciEndpointInit(ehciState, (usb_device_endpoint_init_struct_t *)param);
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlEndpointDeinit:
|
|
if (NULL != param)
|
|
{
|
|
temp8 = (uint8_t *)param;
|
|
error = USB_DeviceEhciEndpointDeinit(ehciState, *temp8);
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlEndpointStall:
|
|
if (NULL != param)
|
|
{
|
|
temp8 = (uint8_t *)param;
|
|
error = USB_DeviceEhciEndpointStall(ehciState, *temp8);
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlEndpointUnstall:
|
|
if (NULL != param)
|
|
{
|
|
temp8 = (uint8_t *)param;
|
|
error = USB_DeviceEhciEndpointUnstall(ehciState, *temp8);
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlGetDeviceStatus:
|
|
if (NULL != param)
|
|
{
|
|
temp16 = (uint16_t *)param;
|
|
*temp16 = ((uint16_t)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)deviceHandle->remotewakeup
|
|
<< (USB_REQUEST_STANDARD_GET_STATUS_DEVICE_REMOTE_WARKUP_SHIFT))
|
|
#endif
|
|
;
|
|
error = kStatus_USB_Success;
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlGetEndpointStatus:
|
|
if (NULL != 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 (0U != ep)
|
|
{
|
|
endpointStatus->endpointStatus =
|
|
(0U != (ehciState->registerBase->EPCR[ep - 1U] &
|
|
((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK))) ?
|
|
(uint16_t)kUSB_DeviceEndpointStateStalled :
|
|
(uint16_t)kUSB_DeviceEndpointStateIdle;
|
|
}
|
|
else
|
|
{
|
|
endpointStatus->endpointStatus =
|
|
(0U != (ehciState->registerBase->EPCR0 &
|
|
((0U != direction) ? USBHS_EPCR_TXS_MASK : USBHS_EPCR_RXS_MASK))) ?
|
|
(uint16_t)kUSB_DeviceEndpointStateStalled :
|
|
(uint16_t)kUSB_DeviceEndpointStateIdle;
|
|
}
|
|
error = kStatus_USB_Success;
|
|
}
|
|
}
|
|
break;
|
|
case kUSB_DeviceControlPreSetDeviceAddress:
|
|
if (NULL != 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) < 10U)
|
|
{
|
|
__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 = 0xFFFFFFFFU;
|
|
/* ehciState->registerBase->OTGCTL |= ((1U<<10) | (1U<<17) | (1U<<16)); */
|
|
while (0U != (ehciState->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK)))
|
|
{
|
|
__NOP();
|
|
}
|
|
/* ehciState->registerPhyBase->CTRL |= ((1U << 21) | (1U << 22) | (1U << 23)); */
|
|
ehciState->registerBase->USBSTS |= USBHS_USBSTS_SRI_MASK;
|
|
#if (defined(FSL_FEATURE_USBPHY_28FDSOI) && (FSL_FEATURE_USBPHY_28FDSOI > 0U))
|
|
ehciState->registerPhyBase->USB1_VBUS_DETECT_SET |= USBPHY_USB1_VBUS_DETECT_VBUSVALID_TO_SESSVALID_MASK;
|
|
#endif
|
|
ehciState->registerBase->PORTSC1 |= USBHS_PORTSC1_PHCD_MASK;
|
|
#if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U))
|
|
#if (defined(USBPHY_CTRL_ENVBUSCHG_WKUP_MASK))
|
|
ehciState->registerPhyBase->CTRL |= USBPHY_CTRL_ENVBUSCHG_WKUP_MASK | USBPHY_CTRL_ENIDCHG_WKUP_MASK |
|
|
USBPHY_CTRL_ENDPDMCHG_WKUP_MASK | USBPHY_CTRL_ENIRQRESUMEDETECT_MASK;
|
|
#endif
|
|
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++)
|
|
{
|
|
(void)USB_DeviceEhciEndpointDeinit(ehciState, (count | (USB_IN << 0x07U)));
|
|
(void)USB_DeviceEhciEndpointDeinit(ehciState, (count | (USB_OUT << 0x07U)));
|
|
}
|
|
USB_DeviceEhciSetDefaultState(ehciState);
|
|
error = kStatus_USB_Success;
|
|
break;
|
|
case kUSB_DeviceControlGetSpeed:
|
|
if (NULL != 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_USBHSDCD_COUNT) && (FSL_FEATURE_SOC_USBHSDCD_COUNT > 0U))
|
|
#ifndef USBHSDCD_IRQS
|
|
USB_HSDcdIsrFunction(ehciState->dcdHandle);
|
|
#endif
|
|
#elif (defined(FSL_FEATURE_SOC_USB_ANALOG_COUNT) && (FSL_FEATURE_SOC_USB_ANALOG_COUNT > 0U))
|
|
(void)USB_PHYDCD_TimerIsrFunction(ehciState->dcdHandle);
|
|
#endif
|
|
|
|
error = kStatus_USB_Success;
|
|
break;
|
|
case kUSB_DeviceControlDcdEnable:
|
|
|
|
#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;
|
|
}
|
|
#elif (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
|
|
|
|
break;
|
|
case kUSB_DeviceControlDcdDisable:
|
|
|
|
#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;
|
|
}
|
|
#elif (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
|
|
|
|
break;
|
|
#endif
|
|
#if defined(USB_DEVICE_CONFIG_GET_SOF_COUNT) && (USB_DEVICE_CONFIG_GET_SOF_COUNT > 0U)
|
|
case kUSB_DeviceControlGetCurrentFrameCount:
|
|
if (NULL != param)
|
|
{
|
|
temp32 = (uint32_t *)param;
|
|
if (USB_SPEED_HIGH == ehciState->speed)
|
|
{
|
|
*temp32 = ehciState->registerBase->FRINDEX & (USB_DEVICE_MAX_FRAME_COUNT);
|
|
}
|
|
else /* if not high speed, change to use frame count */
|
|
{
|
|
*temp32 = (ehciState->registerBase->FRINDEX & (USB_DEVICE_MAX_FRAME_COUNT)) / 8U;
|
|
}
|
|
error = kStatus_USB_Success;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
/*no action*/
|
|
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 (0U != (ehciState->registerNcBase->USB_OTGn_CTRL & USBNC_USB_OTGn_CTRL_WIE_MASK))
|
|
{
|
|
if (0U != (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 (0U != (ehciState->registerBase->USBGENCTRL & USBHS_USBGENCTRL_WU_IE_MASK))
|
|
{
|
|
if (0U != (ehciState->registerBase->USBGENCTRL & (1UL << 8)))
|
|
{
|
|
ehciState->registerBase->USBGENCTRL &= ~(1UL << 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) != 0U)
|
|
{
|
|
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 (0U != (ehciState->registerBase->OTGSC & USBHS_OTGSC_BSV_MASK))
|
|
{
|
|
/* Device is connected to a host. */
|
|
message.code = (uint8_t)kUSB_DeviceNotifyAttach;
|
|
(void)USB_DeviceNotificationTrigger(ehciState->deviceHandle, &message);
|
|
|
|
#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))
|
|
|
|
(void)USB_HSDCD_Control(ehciState->dcdHandle, kUSB_DeviceHSDcdRun, NULL);
|
|
#elif (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))
|
|
(void)USB_PHYDCD_Control(ehciState->dcdHandle, kUSB_DevicePHYDcdRun, NULL);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* Device is disconnected from a host. */
|
|
message.code = (uint8_t)kUSB_DeviceNotifyDetach;
|
|
(void)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 (0U != (status & USBHS_USBSTS_UEI_MASK))
|
|
{
|
|
/* Error interrupt */
|
|
USB_DeviceEhciInterruptError(ehciState);
|
|
}
|
|
#endif /* USB_DEVICE_CONFIG_ERROR_HANDLING */
|
|
|
|
if (0U != (status & USBHS_USBSTS_URI_MASK))
|
|
{
|
|
/* Reset interrupt */
|
|
USB_DeviceEhciInterruptReset(ehciState);
|
|
}
|
|
|
|
if (0U != (status & USBHS_USBSTS_UI_MASK))
|
|
{
|
|
/* Token done interrupt */
|
|
USB_DeviceEhciInterruptTokenDone(ehciState);
|
|
}
|
|
|
|
if (0U != (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 (0U != (status & USBHS_USBSTS_SLI_MASK))
|
|
{
|
|
/* Suspend interrupt */
|
|
USB_DeviceEhciInterruptSuspend(ehciState);
|
|
}
|
|
#endif /* USB_DEVICE_CONFIG_LOW_POWER_MODE */
|
|
|
|
if (0U != (status & USBHS_USBSTS_SRI_MASK))
|
|
{
|
|
/* Sof interrupt */
|
|
USB_DeviceEhciInterruptSof(ehciState);
|
|
}
|
|
}
|
|
|
|
#endif /* USB_DEVICE_CONFIG_EHCI */
|