blob: 9641c491fb81a006c1173a19298d9ef760e511ad [file] [log] [blame]
/* ----------------------------------------------------------------------------
* ATMEL Microcontroller Software Support
* ----------------------------------------------------------------------------
* Copyright (c) 2008, Atmel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Atmel's name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ----------------------------------------------------------------------------
*/
/** \file
* \addtogroup usbd_interface
*@{
*/
/*------------------------------------------------------------------------------
* Headers
*------------------------------------------------------------------------------*/
#include <USBLib_Trace.h>
#include "USBDDriver.h"
#include "USBD.h"
#include "USBD_HAL.h"
#include <string.h>
/*------------------------------------------------------------------------------
* Local variables
*------------------------------------------------------------------------------*/
/** Default device driver instance, for all class drivers in USB Lib. */
static USBDDriver usbdDriver;
/*------------------------------------------------------------------------------
* Local functions
*------------------------------------------------------------------------------*/
/**
* Send a NULL packet
*/
static void TerminateCtrlInWithNull(void *pArg,
uint8_t status,
uint32_t transferred,
uint32_t remaining)
{
pArg = pArg; status = status;
transferred = transferred; remaining = remaining;
USBD_Write(0, /* Endpoint #0 */
0, /* No data buffer */
0, /* No data buffer */
(TransferCallback) 0,
(void *) 0);
}
/**
* Configures the device by setting it into the Configured state and
* initializing all endpoints.
* \param pDriver Pointer to a USBDDriver instance.
* \param cfgnum Configuration number to set.
*/
static void SetConfiguration(USBDDriver *pDriver, uint8_t cfgnum)
{
USBEndpointDescriptor *pEndpoints[17];
const USBConfigurationDescriptor *pConfiguration;
/* Use different descriptor depending on device speed */
if ( USBD_HAL_IsHighSpeed()
&& pDriver->pDescriptors->pHsConfiguration) {
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
}
else {
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
}
/* Set & save the desired configuration */
USBD_SetConfiguration(cfgnum);
pDriver->cfgnum = cfgnum;
pDriver->isRemoteWakeUpEnabled =
((pConfiguration->bmAttributes & 0x20) > 0);
/* If the configuration is not 0, configure endpoints */
if (cfgnum != 0) {
/* Parse configuration to get endpoint descriptors */
USBConfigurationDescriptor_Parse(pConfiguration, 0, pEndpoints, 0);
/* Configure endpoints */
int i = 0;
while (pEndpoints[i] != 0) {
USBD_ConfigureEndpoint(pEndpoints[i]);
i++;
}
}
/* Should be done before send the ZLP */
if (NULL != USBDDriverCallbacks_ConfigurationChanged)
USBDDriverCallbacks_ConfigurationChanged(cfgnum);
/* Acknowledge the request */
USBD_Write(0, /* Endpoint #0 */
0, /* No data buffer */
0, /* No data buffer */
(TransferCallback) 0,
(void *) 0);
}
/**
* Sends the current configuration number to the host.
* \param pDriver Pointer to a USBDDriver instance.
*/
static void GetConfiguration(const USBDDriver *pDriver)
{
unsigned long tmp; // Coud be unsigned char : unsigned long has been chose to avoid any potential alignment issue with DMA
if( USBD_GetState() < USBD_STATE_CONFIGURED)
tmp = 0; // If device is unconfigured, returned configuration must be 0
else
tmp = pDriver->cfgnum;
USBD_Write(0, &tmp, 1, 0, 0);
}
/**
* Sends the current status of the device to the host.
* \param pDriver Pointer to a USBDDriver instance.
*/
static void GetDeviceStatus(const USBDDriver *pDriver)
{
static unsigned short data;
const USBConfigurationDescriptor *pConfiguration;
data = 0;
/* Use different configuration depending on device speed */
if (USBD_IsHighSpeed()) {
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
}
else {
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
}
/* Check current configuration for power mode (if device is configured) */
if (pDriver->cfgnum != 0) {
if (USBConfigurationDescriptor_IsSelfPowered(pConfiguration)) {
data |= 1;
}
}
/* Check if remote wake-up is enabled */
if (pDriver->isRemoteWakeUpEnabled) {
data |= 2;
}
/* Send the device status */
USBD_Write(0, &data, 2, 0, 0);
}
/**
* Sends the current status of an endpoints to the USB host.
* \param bEndpoint Endpoint number.
*/
static void GetEndpointStatus(uint8_t bEndpoint)
{
static unsigned short data;
data = 0;
switch (USBD_HAL_Halt(bEndpoint, 0xFF)) {
case USBD_STATUS_INVALID_PARAMETER: /* the endpoint not exists */
USBD_Stall(0);
break;
case 1:
data = 1;
case 0:
/* Send the endpoint status */
USBD_Write(0, &data, 2, 0, 0);
break;
}
}
/**
* Sends the requested USB descriptor to the host if available, or STALLs the
* request.
* \param pDriver Pointer to a USBDDriver instance.
* \param type Type of the requested descriptor
* \param index Index of the requested descriptor.
* \param length Maximum number of bytes to return.
*/
static void GetDescriptor(
const USBDDriver *pDriver,
uint8_t type,
uint8_t indexRDesc,
uint32_t length)
{
const USBDeviceDescriptor *pDevice;
const USBConfigurationDescriptor *pConfiguration;
const USBDeviceQualifierDescriptor *pQualifier;
const USBConfigurationDescriptor *pOtherSpeed;
const USBGenericDescriptor **pStrings =
(const USBGenericDescriptor **) pDriver->pDescriptors->pStrings;
const USBGenericDescriptor *pString;
uint8_t numStrings = pDriver->pDescriptors->numStrings;
uint8_t terminateWithNull = 0;
/* Use different set of descriptors depending on device speed */
/* By default, we uses full speed values */
pDevice = pDriver->pDescriptors->pFsDevice;
pConfiguration = pDriver->pDescriptors->pFsConfiguration;
/* HS, we try HS values */
if (USBD_HAL_IsHighSpeed()) {
TRACE_DEBUG_WP("HS ");
if (pDriver->pDescriptors->pHsDevice)
pDevice = pDriver->pDescriptors->pHsDevice;
if (pDriver->pDescriptors->pHsConfiguration)
pConfiguration = pDriver->pDescriptors->pHsConfiguration;
pQualifier = pDriver->pDescriptors->pHsQualifier;
pOtherSpeed = pDriver->pDescriptors->pHsOtherSpeed;
}
else {
TRACE_DEBUG_WP("FS ");
pQualifier = pDriver->pDescriptors->pFsQualifier;
pOtherSpeed = pDriver->pDescriptors->pFsOtherSpeed;
}
/* Check the descriptor type */
switch (type) {
case USBGenericDescriptor_DEVICE:
TRACE_INFO_WP("Dev ");
/* Adjust length and send descriptor */
if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice)) {
length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pDevice);
}
USBD_Write(0, pDevice, length, 0, 0);
break;
case USBGenericDescriptor_CONFIGURATION:
TRACE_INFO_WP("Cfg ");
/* Adjust length and send descriptor */
if (length > USBConfigurationDescriptor_GetTotalLength(pConfiguration)) {
length = USBConfigurationDescriptor_GetTotalLength(pConfiguration);
terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
}
USBD_Write(0,
pConfiguration,
length,
terminateWithNull ? TerminateCtrlInWithNull : 0,
0);
break;
case USBGenericDescriptor_DEVICEQUALIFIER:
TRACE_INFO_WP("Qua ");
/* Check if descriptor exists */
if (!pQualifier) {
USBD_Stall(0);
}
else {
/* Adjust length and send descriptor */
if (length > USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier)) {
length = USBGenericDescriptor_GetLength((USBGenericDescriptor *) pQualifier);
}
USBD_Write(0, pQualifier, length, 0, 0);
}
break;
case USBGenericDescriptor_OTHERSPEEDCONFIGURATION:
TRACE_INFO_WP("OSC ");
/* Check if descriptor exists */
if (!pOtherSpeed) {
USBD_Stall(0);
}
else {
/* Adjust length and send descriptor */
if (length > USBConfigurationDescriptor_GetTotalLength(pOtherSpeed)) {
length = USBConfigurationDescriptor_GetTotalLength(pOtherSpeed);
terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
}
USBD_Write(0,
pOtherSpeed,
length,
terminateWithNull ? TerminateCtrlInWithNull : 0,
0);
}
break;
case USBGenericDescriptor_STRING:
TRACE_INFO_WP("Str%d ", indexRDesc);
/* Check if descriptor exists */
if (indexRDesc >= numStrings) {
USBD_Stall(0);
}
else {
pString = pStrings[indexRDesc];
/* Adjust length and send descriptor */
if (length > USBGenericDescriptor_GetLength(pString)) {
length = USBGenericDescriptor_GetLength(pString);
terminateWithNull = ((length % pDevice->bMaxPacketSize0) == 0);
}
USBD_Write(0,
pString,
length,
terminateWithNull ? TerminateCtrlInWithNull : 0,
0);
}
break;
default:
TRACE_WARNING(
"USBDDriver_GetDescriptor: Unknown descriptor type (%d)\n\r",
type);
USBD_Stall(0);
}
}
/**
* Sets the active setting of the given interface if the configuration supports
* it; otherwise, the control pipe is STALLed. If the setting of an interface
* changes.
* \parma pDriver Pointer to a USBDDriver instance.
* \parma infnum Interface number.
* \parma setting New active setting for the interface.
*/
static void SetInterface(
USBDDriver *pDriver,
uint8_t infnum,
uint8_t setting)
{
/* Make sure alternate settings are supported */
if (!pDriver->pInterfaces) {
USBD_Stall(0);
}
else {
/* Change the current setting of the interface and trigger the callback */
/* if necessary */
if (pDriver->pInterfaces[infnum] != setting) {
pDriver->pInterfaces[infnum] = setting;
if (NULL != USBDDriverCallbacks_InterfaceSettingChanged)
USBDDriverCallbacks_InterfaceSettingChanged(infnum, setting);
}
/* Acknowledge the request */
USBD_Write(0, 0, 0, 0, 0);
}
}
/**
* Sends the currently active setting of the given interface to the USB
* host. If alternate settings are not supported, this function STALLs the
* control pipe.
* \param pDriver Pointer to a USBDDriver instance.
* \param infnum Interface number.
*/
static void GetInterface(
const USBDDriver *pDriver,
uint8_t infnum)
{
/* Make sure alternate settings are supported, or STALL the control pipe */
if (!pDriver->pInterfaces) {
USBD_Stall(0);
}
else {
/* Sends the current interface setting to the host */
USBD_Write(0, &(pDriver->pInterfaces[infnum]), 1, 0, 0);
}
}
/**
* Performs the selected test on the USB device (high-speed only).
* \param test Test selector value.
*/
static void USBDDriver_Test(const USBDDriver *pDriver, uint8_t test)
{
pDriver = pDriver;
TRACE_DEBUG("UDPHS_Test\n\r");
/* the lower byte of wIndex must be zero
the most significant byte of wIndex is used to specify the specific test mode */
switch (test) {
case USBFeatureRequest_TESTPACKET:
/*Test mode Test_Packet: */
/*Upon command, a port must repetitively transmit the following test packet until */
/*the exit action is taken. This enables the testing of rise and fall times, eye */
/*patterns, jitter, and any other dynamic waveform specifications. */
/*The test packet is made up by concatenating the following strings. */
/*(Note: For J/K NRZI data, and for NRZ data, the bit on the left is the first one */
/*transmitted. “S?indicates that a bit stuff occurs, which inserts an “extra?NRZI data bit. */
/*? N?is used to indicate N occurrences of a string of bits or symbols.) */
/*A port in Test_Packet mode must send this packet repetitively. The inter-packet timing */
/*must be no less than the minimum allowable inter-packet gap as defined in Section 7.1.18 and */
/*no greater than 125 us. */
/* Send ZLP */
USBD_Test(USBFeatureRequest_TESTSENDZLP);
/* Tst PACKET */
USBD_Test(USBFeatureRequest_TESTPACKET);
while (1);
/*break; not reached */
case USBFeatureRequest_TESTJ:
/*Test mode Test_J: */
/*Upon command, a portÂ’s transceiver must enter the high-speed J state and remain in that */
/*state until the exit action is taken. This enables the testing of the high output drive */
/*level on the D+ line. */
/* Send ZLP */
USBD_Test(USBFeatureRequest_TESTSENDZLP);
/* Tst J */
USBD_Test(USBFeatureRequest_TESTJ);
while (1);
/*break; not reached */
case USBFeatureRequest_TESTK:
/*Test mode Test_K: */
/*Upon command, a portÂ’s transceiver must enter the high-speed K state and remain in */
/*that state until the exit action is taken. This enables the testing of the high output drive */
/*level on the D- line. */
/* Send a ZLP */
USBD_Test(USBFeatureRequest_TESTSENDZLP);
USBD_Test(USBFeatureRequest_TESTK);
while (1);
/*break; not reached */
case USBFeatureRequest_TESTSE0NAK:
/*Test mode Test_SE0_NAK: */
/*Upon command, a portÂ’s transceiver must enter the high-speed receive mode */
/*and remain in that mode until the exit action is taken. This enables the testing */
/*of output impedance, low level output voltage, and loading characteristics. */
/*In addition, while in this mode, upstream facing ports (and only upstream facing ports) */
/*must respond to any IN token packet with a NAK handshake (only if the packet CRC is */
/*determined to be correct) within the normal allowed device response time. This enables testing of */
/*the device squelch level circuitry and, additionally, provides a general purpose stimulus/response */
/*test for basic functional testing. */
/* Send a ZLP */
USBD_Test(USBFeatureRequest_TESTSENDZLP);
/* Test SE0_NAK */
USBD_Test(USBFeatureRequest_TESTSE0NAK);
while (1);
/*break; not reached */
default:
USBD_Stall(0);
break;
}
/* The exit action is to power cycle the device. */
/* The device must be disconnected from the host */
}
/*------------------------------------------------------------------------------
* Exported functions
*------------------------------------------------------------------------------*/
/**
* Return USBDDriver instance pointer for global usage.
*/
USBDDriver *USBD_GetDriver(void)
{
return &usbdDriver;
}
/**
* Initializes a USBDDriver instance with a list of descriptors. If
* interfaces can have multiple alternate settings, an array to store the
* current setting for each interface must be provided.
* \param pDriver Pointer to a USBDDriver instance.
* \param pDescriptors Pointer to a USBDDriverDescriptors instance.
* \param pInterfaces Pointer to an array for storing the current alternate
* setting of each interface (optional).
*/
void USBDDriver_Initialize(
USBDDriver *pDriver,
const USBDDriverDescriptors *pDescriptors,
uint8_t *pInterfaces)
{
pDriver->cfgnum = 0;
pDriver->isRemoteWakeUpEnabled = 0;
pDriver->pDescriptors = pDescriptors;
pDriver->pInterfaces = pInterfaces;
/* Initialize interfaces array if not null */
if (pInterfaces != 0) {
memset(pInterfaces, sizeof(pInterfaces), 0);
}
}
/**
* Returns configuration descriptor list.
* \param pDriver Pointer to a USBDDriver instance.
* \param cfgNum Reserved.
*/
USBConfigurationDescriptor *USBDDriver_GetCfgDescriptors(
USBDDriver *pDriver, uint8_t cfgNum)
{
USBDDriverDescriptors *pDescList = (USBDDriverDescriptors *)pDriver->pDescriptors;
USBConfigurationDescriptor *pCfg;
cfgNum = cfgNum;
if (USBD_HAL_IsHighSpeed() && pDescList->pHsConfiguration)
pCfg = (USBConfigurationDescriptor *)pDescList->pHsConfiguration;
else
pCfg = (USBConfigurationDescriptor *)pDescList->pFsConfiguration;
return pCfg;
}
/**
* Handles the given request if it is standard, otherwise STALLs it.
* \param pDriver Pointer to a USBDDriver instance.
* \param pRequest Pointer to a USBGenericRequest instance.
*/
void USBDDriver_RequestHandler(
USBDDriver *pDriver,
const USBGenericRequest *pRequest)
{
uint8_t cfgnum;
uint8_t infnum;
uint8_t eptnum;
uint8_t setting;
uint8_t type;
uint8_t indexDesc;
uint32_t length;
uint32_t address;
TRACE_INFO_WP("Std ");
/* Check request code */
switch (USBGenericRequest_GetRequest(pRequest)) {
case USBGenericRequest_GETDESCRIPTOR:
TRACE_INFO_WP("gDesc ");
/* Send the requested descriptor */
type = USBGetDescriptorRequest_GetDescriptorType(pRequest);
indexDesc = USBGetDescriptorRequest_GetDescriptorIndex(pRequest);
length = USBGenericRequest_GetLength(pRequest);
GetDescriptor(pDriver, type, indexDesc, length);
break;
case USBGenericRequest_SETADDRESS:
TRACE_INFO_WP("sAddr ");
/* Sends a zero-length packet and then set the device address */
address = USBSetAddressRequest_GetAddress(pRequest);
USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address);
break;
case USBGenericRequest_SETCONFIGURATION:
TRACE_INFO_WP("sCfg ");
/* Set the requested configuration */
cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest);
SetConfiguration(pDriver, cfgnum);
break;
case USBGenericRequest_GETCONFIGURATION:
TRACE_INFO_WP("gCfg ");
/* Send the current configuration number */
GetConfiguration(pDriver);
break;
case USBGenericRequest_GETSTATUS:
TRACE_INFO_WP("gSta ");
/* Check who is the recipient */
switch (USBGenericRequest_GetRecipient(pRequest)) {
case USBGenericRequest_DEVICE:
TRACE_INFO_WP("Dev ");
/* Send the device status */
GetDeviceStatus(pDriver);
break;
case USBGenericRequest_ENDPOINT:
TRACE_INFO_WP("Ept ");
/* Send the endpoint status */
eptnum = USBGenericRequest_GetEndpointNumber(pRequest);
GetEndpointStatus(eptnum);
break;
default:
TRACE_WARNING(
"USBDDriver_RequestHandler: Unknown recipient (%d)\n\r",
USBGenericRequest_GetRecipient(pRequest));
USBD_Stall(0);
}
break;
case USBGenericRequest_CLEARFEATURE:
TRACE_INFO_WP("cFeat ");
/* Check which is the requested feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Hlt ");
/* Unhalt endpoint and send a zero-length packet */
USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest));
USBD_Write(0, 0, 0, 0, 0);
break;
case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU ");
/* Disable remote wake-up and send a zero-length packet */
pDriver->isRemoteWakeUpEnabled = 0;
USBD_Write(0, 0, 0, 0, 0);
break;
default:
TRACE_WARNING(
"USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r",
USBFeatureRequest_GetFeatureSelector(pRequest));
USBD_Stall(0);
}
break;
case USBGenericRequest_SETFEATURE:
TRACE_INFO_WP("sFeat ");
/* Check which is the selected feature */
switch (USBFeatureRequest_GetFeatureSelector(pRequest)) {
case USBFeatureRequest_DEVICEREMOTEWAKEUP:
TRACE_INFO_WP("RmWU ");
/* Enable remote wake-up and send a ZLP */
pDriver->isRemoteWakeUpEnabled = 1;
USBD_Write(0, 0, 0, 0, 0);
break;
case USBFeatureRequest_ENDPOINTHALT:
TRACE_INFO_WP("Halt ");
/* Halt endpoint */
USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest));
USBD_Write(0, 0, 0, 0, 0);
break;
case USBFeatureRequest_TESTMODE:
/* 7.1.20 Test Mode Support, 9.4.9 Set Feature */
if ((USBGenericRequest_GetRecipient(pRequest) == USBGenericRequest_DEVICE)
&& ((USBGenericRequest_GetIndex(pRequest) & 0x000F) == 0)) {
/* Handle test request */
USBDDriver_Test(pDriver,
USBFeatureRequest_GetTestSelector(pRequest));
}
else {
USBD_Stall(0);
}
break;
#if 0
case USBFeatureRequest_OTG_B_HNP_ENABLE:
TRACE_INFO_WP("OTG_B_HNP_ENABLE ");
pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_B_HNP_ENABLE;
USBD_Write(0, 0, 0, 0, 0);
break;
case USBFeatureRequest_OTG_A_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_HNP_SUPPORT ");
pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0);
break;
case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT:
TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT ");
pDriver->otg_features_supported |=
1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT;
USBD_Write(0, 0, 0, 0, 0);
break;
#endif
default:
TRACE_WARNING(
"USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r",
USBFeatureRequest_GetFeatureSelector(pRequest));
USBD_Stall(0);
}
break;
case USBGenericRequest_SETINTERFACE:
TRACE_INFO_WP("sInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest);
setting = USBInterfaceRequest_GetAlternateSetting(pRequest);
SetInterface(pDriver, infnum, setting);
break;
case USBGenericRequest_GETINTERFACE:
TRACE_INFO_WP("gInterface ");
infnum = USBInterfaceRequest_GetInterface(pRequest);
GetInterface(pDriver, infnum);
break;
default:
TRACE_WARNING(
"USBDDriver_RequestHandler: Unknown request code (%d)\n\r",
USBGenericRequest_GetRequest(pRequest));
USBD_Stall(0);
}
}
/**
* Test if RemoteWakeUP feature is enabled
* \param pDriver Pointer to an USBDDriver instance.
* \return 1 if remote wake up has been enabled by the host; otherwise, returns
* 0
*/
uint8_t USBDDriver_IsRemoteWakeUpEnabled(const USBDDriver *pDriver)
{
return pDriver->isRemoteWakeUpEnabled;
}
/**
* Return OTG features supported
* \param pDriver Pointer to an USBDDriver instance.
* \return the OTG features
*/
uint8_t USBDDriver_returnOTGFeatures(const USBDDriver *pDriver)
{
return pDriver->otg_features_supported;
}
/**
* Clear OTG features supported
* \param pDriver Pointer to an USBDDriver instance.
* \return none
*/
void USBDDriver_clearOTGFeatures(USBDDriver *pDriver)
{
pDriver->otg_features_supported = 0;
}
/**@}*/