/**
******************************************************************************
* @file usbh_audio.c
* @author MCD Application Team
* @brief This file is the AC Layer Handlers for USB Host AC class.
*
* @verbatim
*
* ===================================================================
* AUDIO Class Description
* ===================================================================
* This driver manages the Audio Class 1.0 following the "USB Device
* Class Definition for Audio Devices V1.0 Mar 18, 98".
*
* @endverbatim
*
******************************************************************************
* @attention
*
*
© Copyright (c) 2015 STMicroelectronics.
* All rights reserved.
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* BSPDependencies
- "stm32xxxxx_{eval}{discovery}{nucleo_144}.c"
- "stm32xxxxx_{eval}{discovery}_io.c"
- "stm32xxxxx_{eval}{discovery}{adafruit}_sd.c"
- "stm32xxxxx_{eval}{discovery}{adafruit}_lcd.c"
- "stm32xxxxx_{eval}{discovery}_sdram.c"
EndBSPDependencies */
/* Includes ------------------------------------------------------------------*/
#include "usbh_audio.h"
/** @addtogroup USBH_LIB
* @{
*/
/** @addtogroup USBH_CLASS
* @{
*/
/** @addtogroup USBH_AUDIO_CLASS
* @{
*/
/** @defgroup USBH_AUDIO_CORE
* @brief This file includes HID Layer Handlers for USB Host HID class.
* @{
*/
/** @defgroup USBH_AUDIO_CORE_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @defgroup USBH_AUDIO_CORE_Private_Defines
* @{
*/
/**
* @}
*/
/** @defgroup USBH_AUDIO_CORE_Private_Macros
* @{
*/
/**
* @}
*/
/** @defgroup USBH_AUDIO_CORE_Private_Variables
* @{
*/
/**
* @}
*/
/** @defgroup USBH_AUDIO_CORE_Private_FunctionPrototypes
* @{
*/
static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_Process(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_SOFProcess(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost,
uint8_t feature,
uint8_t channel);
static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc,
uint8_t ac_subclass,
uint8_t *pdesc);
static USBH_StatusTypeDef USBH_AUDIO_Transmit(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length);
static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length);
static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length);
static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length);
static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length);
static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost,
uint8_t Ep,
uint8_t *buff);
static USBH_StatusTypeDef AUDIO_SetVolume(USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume);
static USBH_StatusTypeDef USBH_AUDIO_InputStream(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_OutputStream(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_Control(USBH_HandleTypeDef *phost);
static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute(USBH_HandleTypeDef *phost, uint8_t attrib);
static uint32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID);
USBH_ClassTypeDef AUDIO_Class =
{
"AUDIO",
AC_CLASS,
USBH_AUDIO_InterfaceInit,
USBH_AUDIO_InterfaceDeInit,
USBH_AUDIO_ClassRequest,
USBH_AUDIO_Process,
USBH_AUDIO_SOFProcess,
NULL,
};
/**
* @}
*/
/** @defgroup USBH_AUDIO_CORE_Private_Functions
* @{
*/
/**
* @brief USBH_AUDIO_InterfaceInit
* The function init the Audio class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_InterfaceInit(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef out_status, in_status;
AUDIO_HandleTypeDef *AUDIO_Handle;
uint8_t interface, index;
uint16_t ep_size_out = 0U;
uint16_t ep_size_in = 0U;
interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0x00U);
if (interface == 0xFFU) /* Not Valid Interface */
{
USBH_DbgLog("Cannot Find the interface for %s class.", phost->pActiveClass->Name);
return USBH_FAIL;
}
phost->pActiveClass->pData = (AUDIO_HandleTypeDef *)USBH_malloc(sizeof(AUDIO_HandleTypeDef));
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle == NULL)
{
USBH_DbgLog("Cannot allocate memory for AUDIO Handle");
return USBH_FAIL;
}
/* Initialize audio handler */
USBH_memset(AUDIO_Handle, 0, sizeof(AUDIO_HandleTypeDef));
/* 1st Step: Find Audio Interfaces */
out_status = USBH_AUDIO_FindAudioStreamingIN(phost);
in_status = USBH_AUDIO_FindAudioStreamingOUT(phost);
if ((out_status == USBH_FAIL) && (in_status == USBH_FAIL))
{
USBH_DbgLog("%s class configuration not supported.", phost->pActiveClass->Name);
return USBH_FAIL;
}
/* 2nd Step: Select Audio Streaming Interfaces with largest endpoint size : default behavior */
for (index = 0U; index < AUDIO_MAX_AUDIO_STD_INTERFACE; index ++)
{
if (AUDIO_Handle->stream_out[index].valid == 1U)
{
if (ep_size_out < AUDIO_Handle->stream_out[index].EpSize)
{
ep_size_out = AUDIO_Handle->stream_out[index].EpSize;
AUDIO_Handle->headphone.interface = AUDIO_Handle->stream_out[index].interface;
AUDIO_Handle->headphone.AltSettings = AUDIO_Handle->stream_out[index].AltSettings;
AUDIO_Handle->headphone.Ep = AUDIO_Handle->stream_out[index].Ep;
AUDIO_Handle->headphone.EpSize = AUDIO_Handle->stream_out[index].EpSize;
AUDIO_Handle->headphone.Poll = (uint8_t)AUDIO_Handle->stream_out[index].Poll;
AUDIO_Handle->headphone.supported = 1U;
}
}
if (AUDIO_Handle->stream_in[index].valid == 1U)
{
if (ep_size_in < AUDIO_Handle->stream_in[index].EpSize)
{
ep_size_in = AUDIO_Handle->stream_in[index].EpSize;
AUDIO_Handle->microphone.interface = AUDIO_Handle->stream_in[index].interface;
AUDIO_Handle->microphone.AltSettings = AUDIO_Handle->stream_in[index].AltSettings;
AUDIO_Handle->microphone.Ep = AUDIO_Handle->stream_in[index].Ep;
AUDIO_Handle->microphone.EpSize = AUDIO_Handle->stream_in[index].EpSize;
AUDIO_Handle->microphone.Poll = (uint8_t)AUDIO_Handle->stream_out[index].Poll;
AUDIO_Handle->microphone.supported = 1U;
}
}
}
if (USBH_AUDIO_FindHIDControl(phost) == USBH_OK)
{
AUDIO_Handle->control.supported = 1U;
}
/* 3rd Step: Find and Parse Audio interfaces */
USBH_AUDIO_ParseCSDescriptors(phost);
/* 4th Step: Open the Audio streaming pipes*/
if (AUDIO_Handle->headphone.supported == 1U)
{
USBH_AUDIO_BuildHeadphonePath(phost);
AUDIO_Handle->headphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->headphone.Ep);
/* Open pipe for IN endpoint */
USBH_OpenPipe(phost,
AUDIO_Handle->headphone.Pipe,
AUDIO_Handle->headphone.Ep,
phost->device.address,
phost->device.speed,
USB_EP_TYPE_ISOC,
AUDIO_Handle->headphone.EpSize);
USBH_LL_SetToggle(phost, AUDIO_Handle->headphone.Pipe, 0U);
}
if (AUDIO_Handle->microphone.supported == 1U)
{
USBH_AUDIO_BuildMicrophonePath(phost);
AUDIO_Handle->microphone.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->microphone.Ep);
/* Open pipe for IN endpoint */
USBH_OpenPipe(phost,
AUDIO_Handle->microphone.Pipe,
AUDIO_Handle->microphone.Ep,
phost->device.address,
phost->device.speed,
USB_EP_TYPE_ISOC,
AUDIO_Handle->microphone.EpSize);
USBH_LL_SetToggle(phost, AUDIO_Handle->microphone.Pipe, 0U);
}
if (AUDIO_Handle->control.supported == 1U)
{
AUDIO_Handle->control.Pipe = USBH_AllocPipe(phost, AUDIO_Handle->control.Ep);
/* Open pipe for IN endpoint */
USBH_OpenPipe(phost,
AUDIO_Handle->control.Pipe,
AUDIO_Handle->control.Ep,
phost->device.address,
phost->device.speed,
USB_EP_TYPE_INTR,
AUDIO_Handle->control.EpSize);
USBH_LL_SetToggle(phost, AUDIO_Handle->control.Pipe, 0U);
}
AUDIO_Handle->req_state = AUDIO_REQ_INIT;
AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
return USBH_OK;
}
/**
* @brief USBH_AUDIO_InterfaceDeInit
* The function DeInit the Pipes used for the Audio class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_InterfaceDeInit(USBH_HandleTypeDef *phost)
{
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->microphone.Pipe != 0x00U)
{
USBH_ClosePipe(phost, AUDIO_Handle->microphone.Pipe);
USBH_FreePipe(phost, AUDIO_Handle->microphone.Pipe);
AUDIO_Handle->microphone.Pipe = 0U; /* Reset the pipe as Free */
}
if (AUDIO_Handle->headphone.Pipe != 0x00U)
{
USBH_ClosePipe(phost, AUDIO_Handle->headphone.Pipe);
USBH_FreePipe(phost, AUDIO_Handle->headphone.Pipe);
AUDIO_Handle->headphone.Pipe = 0U; /* Reset the pipe as Free */
}
if (AUDIO_Handle->control.Pipe != 0x00U)
{
USBH_ClosePipe(phost, AUDIO_Handle->control.Pipe);
USBH_FreePipe(phost, AUDIO_Handle->control.Pipe);
AUDIO_Handle->control.Pipe = 0U; /* Reset the pipe as Free */
}
if (phost->pActiveClass->pData)
{
USBH_free(phost->pActiveClass->pData);
phost->pActiveClass->pData = 0U;
}
return USBH_OK ;
}
/**
* @brief USBH_AUDIO_ClassRequest
* The function is responsible for handling Standard requests
* for Audio class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_ClassRequest(USBH_HandleTypeDef *phost)
{
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef status = USBH_BUSY;
USBH_StatusTypeDef req_status = USBH_BUSY;
/* Switch AUDIO REQ state machine */
switch (AUDIO_Handle->req_state)
{
case AUDIO_REQ_INIT:
case AUDIO_REQ_SET_DEFAULT_IN_INTERFACE:
if (AUDIO_Handle->microphone.supported == 1U)
{
req_status = USBH_SetInterface(phost,
AUDIO_Handle->microphone.interface,
0U);
if (req_status == USBH_OK)
{
AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE;
}
else if (req_status == USBH_NOT_SUPPORTED)
{
USBH_ErrLog("Control error: AUDIO: Device Set interface request failed");
status = USBH_FAIL;
}
else
{
/* .. */
}
}
else
{
AUDIO_Handle->req_state = AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
break;
case AUDIO_REQ_SET_DEFAULT_OUT_INTERFACE:
if (AUDIO_Handle->headphone.supported == 1U)
{
req_status = USBH_SetInterface(phost,
AUDIO_Handle->headphone.interface,
0U);
if (req_status == USBH_OK)
{
AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS;
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
}
else if (req_status == USBH_NOT_SUPPORTED)
{
USBH_ErrLog("Control error: AUDIO: Device Set interface request failed");
status = USBH_FAIL;
}
else
{
/* .. */
}
}
else
{
AUDIO_Handle->req_state = AUDIO_REQ_CS_REQUESTS;
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
break;
case AUDIO_REQ_CS_REQUESTS:
if (USBH_AUDIO_HandleCSRequest(phost) == USBH_OK)
{
AUDIO_Handle->req_state = AUDIO_REQ_SET_IN_INTERFACE;
}
break;
case AUDIO_REQ_SET_IN_INTERFACE:
if (AUDIO_Handle->microphone.supported == 1U)
{
req_status = USBH_SetInterface(phost,
AUDIO_Handle->microphone.interface,
AUDIO_Handle->microphone.AltSettings);
if (req_status == USBH_OK)
{
AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE;
}
else if (req_status == USBH_NOT_SUPPORTED)
{
USBH_ErrLog("Control error: AUDIO: Device Set interface request failed");
status = USBH_FAIL;
}
else
{
/* .. */
}
}
else
{
AUDIO_Handle->req_state = AUDIO_REQ_SET_OUT_INTERFACE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
break;
case AUDIO_REQ_SET_OUT_INTERFACE:
if (AUDIO_Handle->headphone.supported == 1U)
{
req_status = USBH_SetInterface(phost,
AUDIO_Handle->headphone.interface,
AUDIO_Handle->headphone.AltSettings);
if (req_status == USBH_OK)
{
AUDIO_Handle->req_state = AUDIO_REQ_IDLE;
}
else if (req_status == USBH_NOT_SUPPORTED)
{
USBH_ErrLog("Control error: AUDIO: Device Set interface request failed");
status = USBH_FAIL;
}
else
{
/* .. */
}
}
else
{
AUDIO_Handle->req_state = AUDIO_REQ_IDLE;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
break;
case AUDIO_REQ_IDLE:
AUDIO_Handle->play_state = AUDIO_PLAYBACK_INIT;
phost->pUser(phost, HOST_USER_CLASS_ACTIVE);
status = USBH_OK;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
default:
break;
}
return status;
}
/**
* @brief USBH_AUDIO_CSRequest
* The function is responsible for handling AC Specific requests for a specific feature and channel
* for Audio class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_CSRequest(USBH_HandleTypeDef *phost,
uint8_t feature, uint8_t channel)
{
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef status = USBH_BUSY;
USBH_StatusTypeDef req_status = USBH_BUSY;
uint16_t VolumeCtl, ResolutionCtl;
/* Switch AUDIO REQ state machine */
switch (AUDIO_Handle->cs_req_state)
{
case AUDIO_REQ_GET_VOLUME:
req_status = USBH_AC_GetCur(phost,
UAC_FEATURE_UNIT, /* subtype */
feature, /* feature */
VOLUME_CONTROL, /* Selector */
channel, /* channel */
0x02U); /* length */
if (req_status != USBH_BUSY)
{
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MIN_VOLUME;
VolumeCtl = LE16(&(AUDIO_Handle->mem[0]));
AUDIO_Handle->headphone.attribute.volume = (uint32_t)VolumeCtl;
}
break;
case AUDIO_REQ_GET_MIN_VOLUME:
req_status = USBH_AC_GetMin(phost,
UAC_FEATURE_UNIT, /* subtype */
feature, /* feature */
VOLUME_CONTROL, /* Selector */
channel, /* channel */
0x02U); /* length */
if (req_status != USBH_BUSY)
{
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_MAX_VOLUME;
VolumeCtl = LE16(&(AUDIO_Handle->mem[0]));
AUDIO_Handle->headphone.attribute.volumeMin = (uint32_t)VolumeCtl;
}
break;
case AUDIO_REQ_GET_MAX_VOLUME:
req_status = USBH_AC_GetMax(phost,
UAC_FEATURE_UNIT, /* subtype */
feature, /* feature */
VOLUME_CONTROL, /* Selector */
channel, /* channel */
0x02U); /* length */
if (req_status != USBH_BUSY)
{
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_RESOLUTION;
VolumeCtl = LE16(&(AUDIO_Handle->mem[0]));
AUDIO_Handle->headphone.attribute.volumeMax = (uint32_t)VolumeCtl;
if (AUDIO_Handle->headphone.attribute.volumeMax < AUDIO_Handle->headphone.attribute.volumeMin)
{
AUDIO_Handle->headphone.attribute.volumeMax = 0xFF00U;
}
}
break;
case AUDIO_REQ_GET_RESOLUTION:
req_status = USBH_AC_GetRes(phost,
UAC_FEATURE_UNIT, /* subtype */
feature, /* feature */
VOLUME_CONTROL, /* Selector */
channel, /* channel */
0x02U); /* length */
if (req_status != USBH_BUSY)
{
AUDIO_Handle->cs_req_state = AUDIO_REQ_CS_IDLE;
ResolutionCtl = LE16(&AUDIO_Handle->mem[0]);
AUDIO_Handle->headphone.attribute.resolution = (uint32_t)ResolutionCtl;
}
break;
case AUDIO_REQ_CS_IDLE:
status = USBH_OK;
break;
default:
break;
}
return status;
}
/**
* @brief USBH_AUDIO_HandleCSRequest
* The function is responsible for handling AC Specific requests for a all features
* and associated channels for Audio class.
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_HandleCSRequest(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY;
USBH_StatusTypeDef cs_status = USBH_BUSY;
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
cs_status = USBH_AUDIO_CSRequest(phost,
AUDIO_Handle->temp_feature,
AUDIO_Handle->temp_channels);
if (cs_status != USBH_BUSY)
{
if (AUDIO_Handle->temp_channels == 1U)
{
AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
AUDIO_Handle->temp_channels = 0U;
status = USBH_OK;
}
else
{
AUDIO_Handle->temp_channels--;
}
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
return status;
}
/**
* @brief USBH_AUDIO_Process
* The function is for managing state machine for Audio data transfers
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_Process(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY;
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->headphone.supported == 1U)
{
USBH_AUDIO_OutputStream(phost);
}
if (AUDIO_Handle->microphone.supported == 1U)
{
USBH_AUDIO_InputStream(phost);
}
return status;
}
/**
* @brief USBH_AUDIO_SOFProcess
* The function is for managing the SOF callback
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_SOFProcess(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
return USBH_OK;
}
/**
* @brief Find IN Audio Streaming interfaces
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingIN(USBH_HandleTypeDef *phost)
{
uint8_t interface, alt_settings;
USBH_StatusTypeDef status = USBH_FAIL ;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/* Look For AUDIOSTREAMING IN interface */
alt_settings = 0U;
for (interface = 0U; interface < USBH_MAX_NUM_INTERFACES; interface++)
{
if ((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS) &&
(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING))
{
if ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U) &&
(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0U))
{
AUDIO_Handle->stream_in[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
AUDIO_Handle->stream_in[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
AUDIO_Handle->stream_in[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
AUDIO_Handle->stream_in[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting;
AUDIO_Handle->stream_in[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
AUDIO_Handle->stream_in[alt_settings].valid = 1U;
alt_settings++;
}
}
}
if (alt_settings > 0U)
{
status = USBH_OK;
}
return status;
}
/**
* @brief Find OUT Audio Streaming interfaces
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_FindAudioStreamingOUT(USBH_HandleTypeDef *phost)
{
uint8_t interface, alt_settings;
USBH_StatusTypeDef status = USBH_FAIL ;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/* Look For AUDIOSTREAMING IN interface */
alt_settings = 0U;
for (interface = 0U; interface < USBH_MAX_NUM_INTERFACES; interface++)
{
if ((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == AC_CLASS) &&
(phost->device.CfgDesc.Itf_Desc[interface].bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING))
{
if (((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U) == 0x00U) &&
(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0U))
{
AUDIO_Handle->stream_out[alt_settings].Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
AUDIO_Handle->stream_out[alt_settings].EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
AUDIO_Handle->stream_out[alt_settings].interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
AUDIO_Handle->stream_out[alt_settings].AltSettings = phost->device.CfgDesc.Itf_Desc[interface].bAlternateSetting;
AUDIO_Handle->stream_out[alt_settings].Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
AUDIO_Handle->stream_out[alt_settings].valid = 1U;
alt_settings++;
}
}
}
if (alt_settings > 0U)
{
status = USBH_OK;
}
return status;
}
/**
* @brief Find HID Control interfaces
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_FindHIDControl(USBH_HandleTypeDef *phost)
{
uint8_t interface;
USBH_StatusTypeDef status = USBH_FAIL;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/* Look For AUDIOCONTROL interface */
interface = USBH_FindInterface(phost, AC_CLASS, USB_SUBCLASS_AUDIOCONTROL, 0xFFU);
if ((interface == 0xFFU) || (interface >= USBH_MAX_NUM_INTERFACES))
{
return USBH_FAIL;
}
for (interface = 0U; interface < USBH_MAX_NUM_INTERFACES; interface++)
{
if ((phost->device.CfgDesc.Itf_Desc[interface].bInterfaceClass == 0x03U) && /*HID*/
(phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize > 0U))
{
if ((phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress & 0x80U) == 0x80U)
{
AUDIO_Handle->control.Ep = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bEndpointAddress;
AUDIO_Handle->control.EpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].wMaxPacketSize;
AUDIO_Handle->control.interface = phost->device.CfgDesc.Itf_Desc[interface].bInterfaceNumber;
AUDIO_Handle->control.Poll = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[0].bInterval;
AUDIO_Handle->control.supported = 1U;
status = USBH_OK;
break;
}
}
}
return status;
}
/**
* @brief Parse AC and interfaces Descriptors
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_ParseCSDescriptors(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_OK;
USBH_DescHeader_t *pdesc;
uint16_t ptr;
uint8_t itf_index = 0U;
uint8_t itf_number = 0U;
uint8_t alt_setting;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
pdesc = (USBH_DescHeader_t *)(void *)(phost->device.CfgDesc_Raw);
ptr = USB_LEN_CFG_DESC;
AUDIO_Handle->class_desc.FeatureUnitNum = 0U;
AUDIO_Handle->class_desc.InputTerminalNum = 0U;
AUDIO_Handle->class_desc.OutputTerminalNum = 0U;
AUDIO_Handle->class_desc.ASNum = 0U;
while (ptr < phost->device.CfgDesc.wTotalLength)
{
pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
switch (pdesc->bDescriptorType)
{
case USB_DESC_TYPE_INTERFACE:
itf_number = *((uint8_t *)(void *)pdesc + 2U);
alt_setting = *((uint8_t *)(void *)pdesc + 3U);
itf_index = USBH_FindInterfaceIndex(phost, itf_number, alt_setting);
break;
case USB_DESC_TYPE_CS_INTERFACE:
if (itf_number <= phost->device.CfgDesc.bNumInterfaces)
{
if ((itf_index == 0xFFU) || (itf_index >= USBH_MAX_NUM_INTERFACES)) /* No Valid Interface */
{
USBH_DbgLog("Cannot Find the audio interface index for %s class.", phost->pActiveClass->Name);
status = USBH_FAIL;
}
else
{
ParseCSDescriptors(&AUDIO_Handle->class_desc,
phost->device.CfgDesc.Itf_Desc[itf_index].bInterfaceSubClass,
(uint8_t *)pdesc);
}
}
break;
default:
break;
}
}
return status;
}
/**
* @brief Parse AC interfaces
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef ParseCSDescriptors(AUDIO_ClassSpecificDescTypedef *class_desc,
uint8_t ac_subclass,
uint8_t *pdesc)
{
if (ac_subclass == USB_SUBCLASS_AUDIOCONTROL)
{
switch (pdesc[2])
{
case UAC_HEADER:
class_desc->cs_desc.HeaderDesc = (AUDIO_HeaderDescTypeDef *)(void *)pdesc;
break;
case UAC_INPUT_TERMINAL:
class_desc->cs_desc.InputTerminalDesc[class_desc->InputTerminalNum++] = (AUDIO_ITDescTypeDef *)(void *)pdesc;
break;
case UAC_OUTPUT_TERMINAL:
class_desc->cs_desc.OutputTerminalDesc[class_desc->OutputTerminalNum++] = (AUDIO_OTDescTypeDef *)(void *)pdesc;
break;
case UAC_FEATURE_UNIT:
class_desc->cs_desc.FeatureUnitDesc[class_desc->FeatureUnitNum++] = (AUDIO_FeatureDescTypeDef *)(void *)pdesc;
break;
case UAC_SELECTOR_UNIT:
class_desc->cs_desc.SelectorUnitDesc[class_desc->SelectorUnitNum++] = (AUDIO_SelectorDescTypeDef *)(void *)pdesc;
break;
case UAC_MIXER_UNIT:
class_desc->cs_desc.MixerUnitDesc[class_desc->MixerUnitNum++] = (AUDIO_MixerDescTypeDef *)(void *)pdesc;
break;
default:
break;
}
}
else
{
if (ac_subclass == USB_SUBCLASS_AUDIOSTREAMING)
{
switch (pdesc[2])
{
case UAC_AS_GENERAL:
class_desc->as_desc[class_desc->ASNum].GeneralDesc = (AUDIO_ASGeneralDescTypeDef *)(void *)pdesc;
break;
case UAC_FORMAT_TYPE:
class_desc->as_desc[class_desc->ASNum++].FormatTypeDesc = (AUDIO_ASFormatTypeDescTypeDef *)(void *)pdesc;
break;
default:
break;
}
}
}
return USBH_OK;
}
/**
* @brief Link a Unit to next associated one
* @param phost: Host handle
* @param UnitID: Unit identifer
* @retval UnitID, Index and Type of the associated Unit
*/
static uint32_t USBH_AUDIO_FindLinkedUnit(USBH_HandleTypeDef *phost, uint8_t UnitID)
{
uint8_t Index;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/* Find Feature Unit */
for (Index = 0U; Index < AUDIO_Handle->class_desc.FeatureUnitNum; Index ++)
{
if (AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bSourceID == UnitID)
{
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[Index]->bUnitID;
return (((uint32_t)UnitID << 16U) | (UAC_FEATURE_UNIT << 8U) | (uint32_t)Index);
}
}
/* Find Mixer Unit */
for (Index = 0U; Index < AUDIO_Handle->class_desc.MixerUnitNum; Index ++)
{
if ((AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID0 == UnitID) ||
(AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bSourceID1 == UnitID))
{
UnitID = AUDIO_Handle->class_desc.cs_desc.MixerUnitDesc[Index]->bUnitID;
return ((UnitID << 16U) | (UAC_MIXER_UNIT << 8U) | Index);
}
}
/* Find Selector Unit */
for (Index = 0U; Index < AUDIO_Handle->class_desc.SelectorUnitNum; Index ++)
{
if (AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bSourceID0 == UnitID)
{
UnitID = AUDIO_Handle->class_desc.cs_desc.SelectorUnitDesc[Index]->bUnitID;
return ((UnitID << 16U) | (UAC_SELECTOR_UNIT << 8U) | Index);
}
}
/* Find OT Unit */
for (Index = 0U; Index < AUDIO_Handle->class_desc.OutputTerminalNum; Index ++)
{
if (AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bSourceID == UnitID)
{
UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->bTerminalID;
return ((UnitID << 16U) | (UAC_OUTPUT_TERMINAL << 8U) | Index);
}
}
/* No associated Unit found return undefined ID 0x00*/
return 0U;
}
/**
* @brief Build full path for Microphone device
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_BuildMicrophonePath(USBH_HandleTypeDef *phost)
{
uint8_t UnitID = 0U, Type, Index;
uint32_t value;
uint8_t terminalIndex;
AUDIO_HandleTypeDef *AUDIO_Handle;
USBH_StatusTypeDef ret = USBH_OK;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/*Find microphone IT*/
for (terminalIndex = 0U; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++)
{
if (LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x201)
{
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID;
AUDIO_Handle->microphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels;
break;
}
}
do
{
value = USBH_AUDIO_FindLinkedUnit(phost, UnitID);
if (!value)
{
return USBH_FAIL;
}
Index = (uint8_t)(value & 0xFFU);
Type = (uint8_t)((value >> 8U) & 0xFFU);
UnitID = (uint8_t)((value >> 16U) & 0xFFU);
switch (Type)
{
case UAC_FEATURE_UNIT:
AUDIO_Handle->microphone.asociated_feature = Index;
break;
case UAC_MIXER_UNIT:
AUDIO_Handle->microphone.asociated_mixer = Index;
break;
case UAC_SELECTOR_UNIT:
AUDIO_Handle->microphone.asociated_selector = Index;
break;
case UAC_OUTPUT_TERMINAL:
AUDIO_Handle->microphone.asociated_terminal = Index;
break;
default:
ret = USBH_FAIL;
break;
}
}
while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0U));
return ret;
}
/**
* @brief Build full path for Headphone device
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_BuildHeadphonePath(USBH_HandleTypeDef *phost)
{
uint8_t UnitID = 0U, Type, Index;
uint32_t value;
uint8_t terminalIndex;
AUDIO_HandleTypeDef *AUDIO_Handle;
USBH_StatusTypeDef ret = USBH_OK;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
/* Find association between audio streaming and microphone */
for (terminalIndex = 0U; terminalIndex < AUDIO_Handle->class_desc.InputTerminalNum; terminalIndex++)
{
if (LE16(AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->wTerminalType) == 0x101)
{
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bTerminalID;
AUDIO_Handle->headphone.asociated_channels = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[terminalIndex]->bNrChannels;
break;
}
}
for (Index = 0U; Index < AUDIO_Handle->class_desc.ASNum; Index++)
{
if (AUDIO_Handle->class_desc.as_desc[Index].GeneralDesc->bTerminalLink == UnitID)
{
AUDIO_Handle->headphone.asociated_as = Index;
break;
}
}
do
{
value = USBH_AUDIO_FindLinkedUnit(phost, UnitID);
if (!value)
{
return USBH_FAIL;
}
Index = (uint8_t)(value & 0xFFU);
Type = (uint8_t)((value >> 8U) & 0xFFU);
UnitID = (uint8_t)((value >> 16U) & 0xFFU);
switch (Type)
{
case UAC_FEATURE_UNIT:
AUDIO_Handle->headphone.asociated_feature = Index;
break;
case UAC_MIXER_UNIT:
AUDIO_Handle->headphone.asociated_mixer = Index;
break;
case UAC_SELECTOR_UNIT:
AUDIO_Handle->headphone.asociated_selector = Index;
break;
case UAC_OUTPUT_TERMINAL:
AUDIO_Handle->headphone.asociated_terminal = Index;
if (Index < AUDIO_MAX_NUM_OUT_TERMINAL)
{
if (LE16(AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[Index]->wTerminalType) != 0x103)
{
return USBH_OK;
}
}
else
{
ret = USBH_FAIL;
}
break;
default:
ret = USBH_FAIL;
break;
}
}
while ((Type != UAC_OUTPUT_TERMINAL) && (value > 0U));
return ret;
}
/**
* @brief Handle Set Cur request
* @param phost: Host handle
* @param subtype: subtype index
* @param feature: feature index
* @param controlSelector: control code
* @param channel: channel index
* @param length: Command length
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AC_SetCur(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length)
{
uint16_t wValue = 0U, wIndex = 0U, wLength = 0U;
uint8_t UnitID, InterfaceNum;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef ret = USBH_OK;
switch (subtype)
{
case UAC_INPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
AUDIO_Handle->mem[0] = 0x00U;
wLength = 1U;
break;
case UAC_FEATURE_UNIT:
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum ;
/*holds the CS(control selector ) and CN (channel number)*/
wValue = (uint16_t)((uint32_t)controlSelector << 8U) | (uint16_t)channel;
wLength = length;
break;
default:
ret = USBH_FAIL;
break;
}
if (ret != USBH_OK)
{
return ret;
}
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE
| USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_SET_CUR;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)(void *)(AUDIO_Handle->mem), wLength));
}
/**
* @brief Handle Get Cur request
* @param phost: Host handle
* @param subtype: subtype index
* @param feature: feature index
* @param controlSelector: control code
* @param channel: channel index
* @param length: Command length
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AC_GetCur(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length)
{
uint16_t wValue = 0U, wIndex = 0U, wLength = 0U;
uint8_t UnitID = 0U, InterfaceNum = 0U;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef ret = USBH_OK;
switch (subtype)
{
case UAC_INPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
AUDIO_Handle->mem[0] = 0x00U;
wLength = 1U;
break;
case UAC_FEATURE_UNIT:
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
/*holds the CS(control selector ) and CN (channel number)*/
wValue = (uint16_t)((uint32_t)controlSelector << 8U) | (uint16_t)channel;
wLength = length;
break;
case UAC_OUTPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
wLength = 1U;
break;
default:
ret = USBH_FAIL;
break;
}
if (ret != USBH_OK)
{
return ret;
}
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_GET_CUR;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)(void *)(AUDIO_Handle->mem), wLength));
}
/**
* @brief Handle Get Max request
* @param phost: Host handle
* @param subtype: subtype index
* @param feature: feature index
* @param controlSelector: control code
* @param channel: channel index
* @param length: Command length
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AC_GetMax(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length)
{
uint16_t wValue = 0U, wIndex = 0U, wLength = 0U;
uint8_t UnitID = 0U, InterfaceNum = 0U;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef ret = USBH_OK;
switch (subtype)
{
case UAC_INPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
AUDIO_Handle->mem[0] = 0x00U;
wLength = 1U;
break;
case UAC_FEATURE_UNIT:
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum ;
/*holds the CS(control selector ) and CN (channel number)*/
wValue = (uint16_t)((uint32_t)controlSelector << 8U) | (uint16_t)channel;
wLength = length;
break;
case UAC_OUTPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum ;
wValue = (COPY_PROTECT_CONTROL << 8U) ;
wLength = 1U;
break;
default:
ret = USBH_FAIL;
break;
}
if (ret != USBH_OK)
{
return ret;
}
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_GET_MAX;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)(void *)(AUDIO_Handle->mem), wLength));
}
/**
* @brief Handle Get Res request
* @param phost: Host handle
* @param subtype: subtype index
* @param feature: feature index
* @param controlSelector: control code
* @param channel: channel index
* @param length: Command length
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AC_GetRes(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length)
{
uint16_t wValue = 0U, wIndex = 0U, wLength = 0U;
uint8_t UnitID = 0U, InterfaceNum = 0U;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef ret = USBH_OK;
switch (subtype)
{
case UAC_INPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U) ;
AUDIO_Handle->mem[0] = 0x00U;
wLength = 1U;
break;
case UAC_FEATURE_UNIT:
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
/*holds the CS(control selector ) and CN (channel number)*/
wValue = (uint16_t)((uint32_t)controlSelector << 8U) | (uint16_t)channel;
wLength = length;
break;
case UAC_OUTPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U) ;
wLength = 1U;
break;
default:
ret = USBH_FAIL;
break;
}
if (ret != USBH_OK)
{
return ret;
}
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE
| USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_GET_RES;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)(void *)(AUDIO_Handle->mem), wLength));
}
/**
* @brief Handle Get Min request
* @param phost: Host handle
* @param subtype: subtype index
* @param feature: feature index
* @param controlSelector: control code
* @param channel: channel index
* @param length: Command length
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AC_GetMin(USBH_HandleTypeDef *phost,
uint8_t subtype,
uint8_t feature,
uint8_t controlSelector,
uint8_t channel,
uint16_t length)
{
uint16_t wValue = 0U, wIndex = 0U, wLength = 0U;
uint8_t UnitID = 0U, InterfaceNum = 0U;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
USBH_StatusTypeDef ret = USBH_OK;
switch (subtype)
{
case UAC_INPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.InputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
AUDIO_Handle->mem[0] = 0x00U;
wLength = 1U;
break;
case UAC_FEATURE_UNIT:
UnitID = AUDIO_Handle->class_desc.cs_desc.FeatureUnitDesc[feature]->bUnitID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
/*holds the CS(control selector ) and CN (channel number)*/
wValue = (uint16_t)((uint32_t)controlSelector << 8U) | (uint16_t)channel;
wLength = length;
break;
case UAC_OUTPUT_TERMINAL:
UnitID = AUDIO_Handle->class_desc.cs_desc.OutputTerminalDesc[0]->bTerminalID;
InterfaceNum = 0U; /*Always zero Control Interface */
wIndex = (uint16_t)((uint32_t)UnitID << 8U) | (uint16_t)InterfaceNum;
wValue = (COPY_PROTECT_CONTROL << 8U);
wLength = 1U;
break;
default:
ret = USBH_FAIL;
break;
}
if (ret != USBH_OK)
{
return ret;
}
phost->Control.setup.b.bmRequestType = USB_D2H | USB_REQ_RECIPIENT_INTERFACE | \
USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_GET_MIN;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)(void *)(AUDIO_Handle->mem), wLength));
}
/**
* @brief Handle Set Endpoint Controls Request
* @param phost: Host handle
* @param Ep: Endpoint address
* @param buf: pointer to data
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_SetEndpointControls(USBH_HandleTypeDef *phost,
uint8_t Ep,
uint8_t *buff)
{
uint16_t wValue, wIndex, wLength;
wValue = SAMPLING_FREQ_CONTROL << 8U;
wIndex = Ep;
wLength = 3U; /*length of the frequency parameter*/
phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | \
USB_REQ_TYPE_CLASS;
phost->Control.setup.b.bRequest = UAC_SET_CUR;
phost->Control.setup.b.wValue.w = wValue;
phost->Control.setup.b.wIndex.w = wIndex;
phost->Control.setup.b.wLength.w = wLength;
return (USBH_CtlReq(phost, (uint8_t *)buff, wLength));
}
/**
* @brief Handle Input stream process
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_InputStream(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
USBH_StatusTypeDef status = USBH_BUSY;
return status;
}
/**
* @brief Handle HID Control process
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_Control(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY ;
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
uint16_t attribute = 0U;
switch (AUDIO_Handle->control_state)
{
case AUDIO_CONTROL_INIT:
if ((phost->Timer & 1U) == 0U)
{
AUDIO_Handle->control.timer = phost->Timer;
USBH_InterruptReceiveData(phost,
(uint8_t *)(void *)(AUDIO_Handle->mem),
(uint8_t)AUDIO_Handle->control.EpSize,
AUDIO_Handle->control.Pipe);
AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
AUDIO_Handle->control_state = AUDIO_CONTROL_CHANGE ;
}
break;
case AUDIO_CONTROL_CHANGE:
if (USBH_LL_GetURBState(phost, AUDIO_Handle->control.Pipe) == USBH_URB_DONE)
{
attribute = LE16(&AUDIO_Handle->mem[0]);
if (USBH_AUDIO_SetControlAttribute(phost, (uint8_t)attribute) == USBH_BUSY)
{
break;
}
}
if ((phost->Timer - AUDIO_Handle->control.timer) >= AUDIO_Handle->control.Poll)
{
AUDIO_Handle->control.timer = phost->Timer;
USBH_InterruptReceiveData(phost,
(uint8_t *)(void *)(AUDIO_Handle->mem),
(uint8_t)AUDIO_Handle->control.EpSize,
AUDIO_Handle->control.Pipe);
}
break;
case AUDIO_CONTROL_VOLUME_UP:
if (USBH_AUDIO_SetControlAttribute(phost, 1U) == USBH_OK)
{
AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
status = USBH_OK;
}
break;
case AUDIO_CONTROL_VOLUME_DOWN:
if (USBH_AUDIO_SetControlAttribute(phost, 2U) == USBH_OK)
{
AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
status = USBH_OK;
}
break;
case AUDIO_CONTROL_IDLE:
default:
break;
}
return status;
}
/**
* @brief Handle Output stream process
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_OutputStream(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY ;
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
uint8_t *buff;
switch (AUDIO_Handle->play_state)
{
case AUDIO_PLAYBACK_INIT:
if (AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0U)
{
AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP_FREQ;
}
else
{
AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP;
}
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_URB_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case AUDIO_PLAYBACK_SET_EP_FREQ:
buff = (uint8_t *)AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0];
status = USBH_AUDIO_SetEndpointControls(phost, AUDIO_Handle->headphone.Ep, buff);
if (status == USBH_OK)
{
AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
}
break;
case AUDIO_PLAYBACK_SET_EP:
buff = (uint8_t *)(void *)&AUDIO_Handle->headphone.frequency;
status = USBH_AUDIO_SetEndpointControls(phost, AUDIO_Handle->headphone.Ep, buff);
if (status == USBH_OK)
{
AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
USBH_AUDIO_FrequencySet(phost);
}
break;
case AUDIO_PLAYBACK_IDLE:
status = USBH_OK;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
break;
case AUDIO_PLAYBACK_PLAY:
USBH_AUDIO_Transmit(phost);
status = USBH_OK;
break;
default:
break;
}
return status;
}
/**
* @brief Handle Transmission process
* @param phost: Host handle
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_Transmit(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef status = USBH_BUSY ;
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
switch (AUDIO_Handle->processing_state)
{
case AUDIO_DATA_START_OUT:
/* Sync with start of Even Frame */
if ((phost->Timer & 1U) == 0U)
{
AUDIO_Handle->headphone.timer = phost->Timer;
AUDIO_Handle->processing_state = AUDIO_DATA_OUT;
USBH_IsocSendData(phost,
AUDIO_Handle->headphone.buf,
(uint32_t)AUDIO_Handle->headphone.frame_length,
AUDIO_Handle->headphone.Pipe);
AUDIO_Handle->headphone.partial_ptr = AUDIO_Handle->headphone.frame_length;
AUDIO_Handle->headphone.global_ptr = AUDIO_Handle->headphone.frame_length;
AUDIO_Handle->headphone.cbuf = AUDIO_Handle->headphone.buf;
}
else
{
#if (USBH_USE_OS == 1U)
osDelay(1);
phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
break;
case AUDIO_DATA_OUT:
if ((USBH_LL_GetURBState(phost, AUDIO_Handle->headphone.Pipe) == USBH_URB_DONE) &&
((phost->Timer - AUDIO_Handle->headphone.timer) >= AUDIO_Handle->headphone.Poll))
{
AUDIO_Handle->headphone.timer = phost->Timer;
if (AUDIO_Handle->control.supported == 1U)
{
USBH_AUDIO_Control(phost);
}
if (AUDIO_Handle->headphone.global_ptr <= AUDIO_Handle->headphone.total_length)
{
USBH_IsocSendData(phost,
AUDIO_Handle->headphone.cbuf,
(uint32_t)AUDIO_Handle->headphone.frame_length,
AUDIO_Handle->headphone.Pipe);
AUDIO_Handle->headphone.cbuf += AUDIO_Handle->headphone.frame_length;
AUDIO_Handle->headphone.partial_ptr += AUDIO_Handle->headphone.frame_length;
AUDIO_Handle->headphone.global_ptr += AUDIO_Handle->headphone.frame_length;
}
else
{
AUDIO_Handle->headphone.partial_ptr = 0xFFFFFFFFU;
AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
USBH_AUDIO_BufferEmptyCallback(phost);
}
}
break;
default:
status = USBH_FAIL;
break;
}
return status;
}
/**
* @brief USBH_AUDIO_SetFrequency
* Set Audio sampling parameters
* @param phost: Host handle
* @param SampleRate: Sample Rate
* @param NbrChannels: Number of Channels
* @param BitPerSample: Bit Per Sample
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_SetFrequency(USBH_HandleTypeDef *phost,
uint16_t SampleRate,
uint8_t NbrChannels,
uint8_t BitPerSample)
{
USBH_StatusTypeDef Status = USBH_BUSY;
AUDIO_HandleTypeDef *AUDIO_Handle;
uint8_t index;
uint8_t change_freq = FALSE;
uint32_t freq_min, freq_max;
uint8_t num_supported_freq;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
{
if (AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bSamFreqType == 0U)
{
freq_min = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[0]);
freq_max = LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[1]);
if ((SampleRate >= freq_min) && (SampleRate <= freq_max))
{
change_freq = TRUE;
}
}
else
{
num_supported_freq = (AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->bLength - 8U) / 3U;
for (index = 0U; index < num_supported_freq; index++)
{
if (SampleRate == LE24(AUDIO_Handle->class_desc.as_desc[AUDIO_Handle->headphone.asociated_as].FormatTypeDesc->tSamFreq[index]))
{
change_freq = TRUE;
break;
}
}
}
if (change_freq == TRUE)
{
AUDIO_Handle->headphone.frequency = SampleRate;
AUDIO_Handle->headphone.frame_length = (SampleRate * BitPerSample * NbrChannels) / 8000U;
AUDIO_Handle->play_state = AUDIO_PLAYBACK_SET_EP;
Status = USBH_OK;
}
}
}
return Status;
}
/**
* @brief USBH_AUDIO_Play
* Start playback process
* @param phost: Host handle
* @param buf: pointer to raw audio data
* @param length: total length of the audio data
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_Play(USBH_HandleTypeDef *phost, uint8_t *buf, uint32_t length)
{
USBH_StatusTypeDef Status = USBH_FAIL;
AUDIO_HandleTypeDef *AUDIO_Handle;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
{
AUDIO_Handle->headphone.buf = buf;
AUDIO_Handle->headphone.total_length = length;
AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY;
AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
AUDIO_Handle->processing_state = AUDIO_DATA_START_OUT;
Status = USBH_OK;
#if (USBH_USE_OS == 1U)
phost->os_msg = (uint32_t)USBH_CLASS_EVENT;
#if (osCMSIS < 0x20000U)
(void)osMessagePut(phost->os_event, phost->os_msg, 0U);
#else
(void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
#endif
#endif
}
}
return Status;
}
/**
* @brief USBH_AUDIO_Pause
* Stop the playback process
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_Stop(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef Status = USBH_FAIL;
Status = USBH_AUDIO_Suspend(phost);
return Status;
}
/**
* @brief USBH_AUDIO_Suspend
* Suspend the playback process
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_Suspend(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef Status = USBH_FAIL;
AUDIO_HandleTypeDef *AUDIO_Handle;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
{
AUDIO_Handle->control_state = AUDIO_CONTROL_IDLE;
AUDIO_Handle->play_state = AUDIO_PLAYBACK_IDLE;
Status = USBH_OK;
}
}
return Status;
}
/**
* @brief USBH_AUDIO_Resume
* Resume the playback process
* @param phost: Host handle
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_Resume(USBH_HandleTypeDef *phost)
{
USBH_StatusTypeDef Status = USBH_FAIL;
AUDIO_HandleTypeDef *AUDIO_Handle;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_IDLE)
{
AUDIO_Handle->control_state = AUDIO_CONTROL_INIT;
AUDIO_Handle->play_state = AUDIO_PLAYBACK_PLAY;
}
}
return Status;
}
/**
* @brief USBH_AUDIO_GetOutOffset
* return the current buffer pointer for OUT process
* @param phost: Host handle
* @retval USBH Status
*/
int32_t USBH_AUDIO_GetOutOffset(USBH_HandleTypeDef *phost)
{
AUDIO_HandleTypeDef *AUDIO_Handle;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
{
return (int32_t)AUDIO_Handle->headphone.partial_ptr;
}
}
return -1;
}
/**
* @brief USBH_AUDIO_ChangeOutBuffer
* Change audio data buffer address
* @param phost: Host handle
* @param buf: buffer address
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_ChangeOutBuffer(USBH_HandleTypeDef *phost, uint8_t *buf)
{
USBH_StatusTypeDef Status = USBH_FAIL;
AUDIO_HandleTypeDef *AUDIO_Handle;
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
{
if (AUDIO_Handle->headphone.buf <= buf)
{
AUDIO_Handle->headphone.cbuf = buf;
if (AUDIO_Handle->headphone.buf == buf)
{
AUDIO_Handle->headphone.partial_ptr = 0U;
}
Status = USBH_OK;
}
}
}
return Status;
}
/**
* @brief USBH_AUDIO_SetControlAttribute
* Set Control Attribute
* @param phost: Host handle
* @param attrib: control attribute
* @retval USBH Status
*/
static USBH_StatusTypeDef USBH_AUDIO_SetControlAttribute(USBH_HandleTypeDef *phost, uint8_t attrib)
{
USBH_StatusTypeDef status = USBH_BUSY;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
switch (attrib)
{
case 0x01:
AUDIO_Handle->headphone.attribute.volume += AUDIO_Handle->headphone.attribute.resolution;
break;
case 0x02:
AUDIO_Handle->headphone.attribute.volume -= AUDIO_Handle->headphone.attribute.resolution;
break;
default :
status = USBH_FAIL;
break;
}
if (AUDIO_Handle->headphone.attribute.volume > AUDIO_Handle->headphone.attribute.volumeMax)
{
AUDIO_Handle->headphone.attribute.volume = AUDIO_Handle->headphone.attribute.volumeMax;
}
if (AUDIO_Handle->headphone.attribute.volume < AUDIO_Handle->headphone.attribute.volumeMin)
{
AUDIO_Handle->headphone.attribute.volume = AUDIO_Handle->headphone.attribute.volumeMin;
}
if (AUDIO_SetVolume(phost,
AUDIO_Handle->temp_feature,
(uint8_t)AUDIO_Handle->temp_channels,
(uint16_t)AUDIO_Handle->headphone.attribute.volume) != USBH_BUSY)
{
if (AUDIO_Handle->temp_channels == 1U)
{
AUDIO_Handle->temp_feature = AUDIO_Handle->headphone.asociated_feature;
AUDIO_Handle->temp_channels = AUDIO_Handle->headphone.asociated_channels;
status = USBH_OK;
}
else
{
AUDIO_Handle->temp_channels--;
}
AUDIO_Handle->cs_req_state = AUDIO_REQ_GET_VOLUME;
}
return status;
}
/**
* @brief USBH_AUDIO_SetVolume
* Set Volume
* @param phost: Host handle
* @param volume: VOLUME_UP/ VOLUME_DOWN
* @retval USBH Status
*/
USBH_StatusTypeDef USBH_AUDIO_SetVolume(USBH_HandleTypeDef *phost, AUDIO_VolumeCtrlTypeDef volume_ctl)
{
AUDIO_HandleTypeDef *AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if ((volume_ctl == VOLUME_UP) || (volume_ctl == VOLUME_DOWN))
{
if (phost->gState == HOST_CLASS)
{
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
if (AUDIO_Handle->play_state == AUDIO_PLAYBACK_PLAY)
{
AUDIO_Handle->control_state = (volume_ctl == VOLUME_UP) ? AUDIO_CONTROL_VOLUME_UP : AUDIO_CONTROL_VOLUME_DOWN;
return USBH_OK;
}
}
}
return USBH_FAIL;
}
/**
* @brief AUDIO_SetVolume
* Set Volume
* @param phost: Host handle
* @param feature: feature Unit index
* @param channel: channel index
* @param volume: new volume
* @retval USBH Status
*/
static USBH_StatusTypeDef AUDIO_SetVolume(USBH_HandleTypeDef *phost, uint8_t feature, uint8_t channel, uint16_t volume)
{
USBH_StatusTypeDef status = USBH_BUSY ;
AUDIO_HandleTypeDef *AUDIO_Handle;
AUDIO_Handle = (AUDIO_HandleTypeDef *) phost->pActiveClass->pData;
AUDIO_Handle->mem[0] = volume;
status = USBH_AC_SetCur(phost, UAC_FEATURE_UNIT, feature,
VOLUME_CONTROL, channel, 2U);
return status;
}
/**
* @brief The function informs user that Settings have been changed
* @param phost: Selected device
* @retval None
*/
__weak void USBH_AUDIO_FrequencySet(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
}
/**
* @brief The function informs user that User data are processed
* @param phost: Selected device
* @retval None
*/
__weak void USBH_AUDIO_BufferEmptyCallback(USBH_HandleTypeDef *phost)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(phost);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/