mirror of
https://gitea.osmocom.org/sim-card/simtrace2.git
synced 2026-03-17 21:58:33 +03:00
771 lines
24 KiB
C
771 lines
24 KiB
C
/* ----------------------------------------------------------------------------
|
|
* 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
|
|
* USB Audio Device Streaming interface with controls.
|
|
* (3 channels supported).
|
|
*/
|
|
|
|
/** \addtogroup usbd_audio_speakerphone
|
|
*@{
|
|
*/
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Headers
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
#include <AUDDSpeakerPhone.h>
|
|
|
|
#include <USBDescriptors.h>
|
|
#include <USBRequests.h>
|
|
#include <AUDDescriptors.h>
|
|
#include <AUDRequests.h>
|
|
|
|
#include <USBD_HAL.h>
|
|
|
|
#include <USBLib_Trace.h>
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Types
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/** Parse data extention for descriptor parsing */
|
|
typedef struct _AUDDParseData {
|
|
/** Pointer to AUDDSpeakerPhone instance */
|
|
AUDDSpeakerPhone * pAudf;
|
|
/** Pointer to found interface descriptor */
|
|
USBInterfaceDescriptor * pIfDesc;
|
|
|
|
} AUDDParseData;
|
|
|
|
/** Transfer callback extention */
|
|
typedef struct _AUDDXfrExt {
|
|
/** Pointer to AUDDStream instance */
|
|
AUDDStream *pStream;
|
|
/** Buffer for USB device to get data from host */
|
|
uint16_t usbBuffer;
|
|
/** Additional information: Entity */
|
|
uint8_t bEntity;
|
|
/** Additional information: Channel */
|
|
uint8_t bCh;
|
|
} AUDDXfrExt;
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Internal Variable
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/** Transfer data extension */
|
|
static AUDDXfrExt auddXfrData;
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Internal Functions
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Parse descriptors: Interface, ISO IN/OUT, Feature Unit IDs.
|
|
* \param desc Pointer to descriptor list.
|
|
* \param arg Argument, pointer to AUDDParseData instance.
|
|
*/
|
|
static uint32_t AUDDSpeakerPhone_Parse(USBGenericDescriptor *pDesc,
|
|
AUDDParseData * pArg)
|
|
{
|
|
AUDDStream *pSpeaker = pArg->pAudf->pSpeaker;
|
|
AUDDStream *pMic = pArg->pAudf->pMicrophone;
|
|
USBEndpointDescriptor* pEp = (USBEndpointDescriptor*)pDesc;
|
|
uint8_t bSpeakerDone = 0, bMicDone = 0;
|
|
|
|
/* Validate descriptor */
|
|
if (pDesc->bLength == 0)
|
|
return USBRC_PARAM_ERR;
|
|
|
|
/* Log current interface */
|
|
if (pDesc->bDescriptorType == USBGenericDescriptor_INTERFACE) {
|
|
USBInterfaceDescriptor* pIf = (USBInterfaceDescriptor*)pDesc;
|
|
/* AudioControl interface */
|
|
if (pIf->bInterfaceClass ==
|
|
AUDControlInterfaceDescriptor_CLASS
|
|
&& pIf->bInterfaceSubClass ==
|
|
AUDControlInterfaceDescriptor_SUBCLASS) {
|
|
pArg->pIfDesc = pIf;
|
|
|
|
if (pSpeaker) pSpeaker->bAcInterface = pIf->bInterfaceNumber;
|
|
if (pMic) pMic->bAcInterface = pIf->bInterfaceNumber;
|
|
}
|
|
/* AudioStreaming interface with endpoint */
|
|
else if (pIf->bInterfaceClass ==
|
|
AUDStreamingInterfaceDescriptor_CLASS
|
|
&& pIf->bInterfaceSubClass ==
|
|
AUDStreamingInterfaceDescriptor_SUBCLASS) {
|
|
pArg->pIfDesc = pIf;
|
|
}
|
|
/* Not Audio interface, force end */
|
|
else if (pArg->pIfDesc){
|
|
return USBRC_PARTIAL_DONE;
|
|
}
|
|
}
|
|
|
|
if (pArg->pIfDesc) {
|
|
/* Find Control Interface */
|
|
/* Find Entities */
|
|
/* Find Streaming Interface & Endpoints */
|
|
if (pDesc->bDescriptorType == USBGenericDescriptor_ENDPOINT
|
|
&& (pEp->bmAttributes & 0x3) == USBEndpointDescriptor_ISOCHRONOUS) {
|
|
if (pEp->bEndpointAddress & 0x80
|
|
&& pMic) {
|
|
pMic->bEndpointIn = pEp->bEndpointAddress & 0x7F;
|
|
pMic->bAsInterface = pArg->pIfDesc->bInterfaceNumber;
|
|
/* Fixed FU */
|
|
pMic->bFeatureUnitIn = AUDD_ID_MicrophoneFU;
|
|
}
|
|
else if (pSpeaker) {
|
|
pSpeaker->bEndpointOut = pEp->bEndpointAddress;
|
|
pSpeaker->bAsInterface = pArg->pIfDesc->bInterfaceNumber;
|
|
/* Fixed FU */
|
|
pSpeaker->bFeatureUnitOut = AUDD_ID_SpeakerFU;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pSpeaker) {
|
|
if (pSpeaker->bAcInterface != 0xFF
|
|
&& pSpeaker->bAsInterface != 0xFF
|
|
&& pSpeaker->bFeatureUnitOut != 0xFF
|
|
&& pSpeaker->bEndpointOut != 0) {
|
|
bSpeakerDone = 1;
|
|
}
|
|
}
|
|
else bSpeakerDone = 1;
|
|
|
|
if (pMic) {
|
|
if (pMic->bAcInterface != 0xFF
|
|
&& pMic->bAsInterface != 0xFF
|
|
&& pMic->bFeatureUnitIn != 0xFF
|
|
&& pMic->bEndpointIn != 0) {
|
|
bMicDone = 1;
|
|
}
|
|
}
|
|
else bMicDone = 1;
|
|
|
|
if (bSpeakerDone && bMicDone)
|
|
return USBRC_FINISHED;
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Callback triggered after the new mute status of a channel has been read.
|
|
* Changes the mute status of the given channel accordingly.
|
|
* \param pData Pointer to AUDDXfrExt (transfer extension data).
|
|
*/
|
|
static void AUDD_MuteReceived(AUDDXfrExt *pData)
|
|
{
|
|
AUDDStream_ChangeMute(pData->pStream,
|
|
pData->bCh,
|
|
(uint8_t)pData->usbBuffer);
|
|
USBD_Write(0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Callback triggered after the new volume status of a channel has been read.
|
|
* Changes the volume status of the given channel accordingly.
|
|
* \param pData Pointer to AUDDXfrExt (transfer extension data).
|
|
*/
|
|
static void AUDD_VolumeReceived(AUDDXfrExt *pData)
|
|
{
|
|
AUDDStream_SetVolume(pData->pStream,
|
|
pData->bCh,
|
|
pData->usbBuffer);
|
|
USBD_Write(0, 0, 0, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Get Target AUDDStream for control
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param bAcInterface Interface number
|
|
* \param bEntity Entity ID
|
|
* \param bChannel Channel number
|
|
* \return Pointer to AUDDStream instance
|
|
*/
|
|
static AUDDStream *AUDD_GetCtlStream(
|
|
AUDDSpeakerPhone *pAudf,
|
|
uint8_t bAcInterface,
|
|
uint8_t bEntity,
|
|
uint8_t bChannel)
|
|
{
|
|
AUDDStream *pAuds = 0;
|
|
|
|
if (bEntity == pAudf->pSpeaker->bFeatureUnitOut
|
|
|| bEntity == pAudf->pSpeaker->bFeatureUnitIn)
|
|
pAuds = pAudf->pSpeaker;
|
|
else if (bEntity == pAudf->pMicrophone->bFeatureUnitIn
|
|
|| bEntity == pAudf->pMicrophone->bFeatureUnitOut)
|
|
pAuds = pAudf->pMicrophone;
|
|
|
|
if (pAuds != 0
|
|
&& bAcInterface == pAuds->bAcInterface
|
|
&& bChannel <= pAuds->bNumChannels) {
|
|
return pAuds;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Handle the SET_CUR request.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pReq Pointer to USBGenericRequest instance.
|
|
*/
|
|
static void AUDD_SetCUR(
|
|
AUDDSpeakerPhone *pAudf,
|
|
const USBGenericRequest* pReq)
|
|
{
|
|
uint8_t bIf = AUDGenericRequest_GetInterface(pReq);
|
|
uint8_t bEntity = AUDGenericRequest_GetEntity(pReq);
|
|
uint8_t bLength = USBGenericRequest_GetLength(pReq);
|
|
uint8_t bCh = AUDFeatureUnitRequest_GetChannel(pReq);
|
|
uint8_t bCtrl = AUDFeatureUnitRequest_GetControl(pReq);
|
|
uint8_t bSet = 1;
|
|
AUDDStream *pAuds = AUDD_GetCtlStream(pAudf, bIf, bEntity, bCh);
|
|
TransferCallback fCallback;
|
|
|
|
TRACE_INFO_WP("sCUR ");
|
|
TRACE_DEBUG("\b(E%d, CtlS%d, Ch%d, L%d) ", bEntity, bCtrl, bCh, bLength);
|
|
|
|
/* Set Mute to AC, 1 byte */
|
|
if (bCtrl == AUDFeatureUnitRequest_MUTE
|
|
&& bLength == 1
|
|
&& pAuds) {
|
|
fCallback = (TransferCallback) AUDD_MuteReceived;
|
|
}
|
|
else if (bCtrl == AUDFeatureUnitRequest_VOLUME
|
|
&& bLength == 2
|
|
&& pAuds && pAuds->pwVolumes) {
|
|
fCallback = (TransferCallback) AUDD_VolumeReceived;
|
|
}
|
|
else
|
|
bSet = 0;
|
|
|
|
if (bSet) {
|
|
|
|
auddXfrData.pStream = pAuds;
|
|
auddXfrData.bEntity = bEntity;
|
|
auddXfrData.bCh = bCh;
|
|
USBD_Read(0,
|
|
&auddXfrData.usbBuffer,
|
|
bLength,
|
|
fCallback,
|
|
(void *) &auddXfrData);
|
|
}
|
|
else {
|
|
|
|
USBD_Stall(0);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Handle the GET_CUR request.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pReq Pointer to USBGenericRequest instance.
|
|
*/
|
|
static void AUDD_GetCUR(
|
|
AUDDSpeakerPhone *pAudf,
|
|
const USBGenericRequest *pReq)
|
|
{
|
|
uint8_t bIf = AUDGenericRequest_GetInterface(pReq);
|
|
uint8_t bEntity = AUDGenericRequest_GetEntity(pReq);
|
|
uint8_t bLength = USBGenericRequest_GetLength(pReq);
|
|
uint8_t bCh = AUDFeatureUnitRequest_GetChannel(pReq);
|
|
uint8_t bCtrl = AUDFeatureUnitRequest_GetControl(pReq);
|
|
uint8_t bGet = 1;
|
|
AUDDStream *pAuds = AUDD_GetCtlStream(pAudf, bIf, bEntity, bCh);
|
|
|
|
TRACE_INFO_WP("gCUR ");
|
|
TRACE_DEBUG("\b(E%d, CtlS%d, Ch%d, L%d) ", bEntity, bCtrl, bCh, bLength);
|
|
|
|
/* Get Mute 1 byte */
|
|
if (bCtrl == AUDFeatureUnitRequest_MUTE
|
|
&& bLength == 1
|
|
&& pAuds) {
|
|
auddXfrData.usbBuffer = ((pAuds->bmMute & (1<<bCh)) > 0);
|
|
}
|
|
else if (bCtrl == AUDFeatureUnitRequest_VOLUME
|
|
&& bLength == 2
|
|
&& pAuds && pAuds->pwVolumes) {
|
|
auddXfrData.usbBuffer = pAuds->pwVolumes[bCh];
|
|
}
|
|
else
|
|
bGet = 0;
|
|
|
|
if (bGet) {
|
|
|
|
USBD_Write(0, &auddXfrData.usbBuffer, bLength, 0, 0);
|
|
}
|
|
else {
|
|
|
|
USBD_Stall(0);
|
|
}
|
|
}
|
|
|
|
/*------------------------------------------------------------------------------
|
|
* Exported Functions
|
|
*------------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Initialize AUDDStream instance.
|
|
* Note the number of channels excludes the master control, so
|
|
* actual volume array size should be (1 + numChannels).
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param numChannels Number of channels in the stream (<31).
|
|
* \param wChannelVolumes Data array for channel volume values.
|
|
* \param fCallback Callback function for stream events.
|
|
* \param pArg Pointer to event handler arguments.
|
|
*/
|
|
void AUDDStream_Initialize(AUDDStream *pAuds,
|
|
uint8_t numChannels,
|
|
uint16_t wChannelVolumes[],
|
|
AUDDStreamEventCallback fCallback,
|
|
void* pArg)
|
|
{
|
|
pAuds->bAcInterface = 0xFF;
|
|
pAuds->bFeatureUnitOut = 0xFF;
|
|
pAuds->bFeatureUnitIn = 0xFF;
|
|
pAuds->bAsInterface = 0xFF;
|
|
pAuds->bEndpointOut = 0;
|
|
pAuds->bEndpointIn = 0;
|
|
|
|
pAuds->bNumChannels = numChannels;
|
|
pAuds->bmMute = 0;
|
|
pAuds->pwVolumes = wChannelVolumes;
|
|
|
|
pAuds->fCallback = fCallback;
|
|
pAuds->pArg = pArg;
|
|
}
|
|
|
|
/**
|
|
* Check if the request is accepted.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param pReq Pointer to a USBGenericRequest instance.
|
|
* \return 1 if accepted.
|
|
*/
|
|
uint32_t AUDDStream_IsRequestAccepted(
|
|
AUDDStream *pAuds,
|
|
const USBGenericRequest *pReq)
|
|
{
|
|
uint8_t bIf = AUDGenericRequest_GetInterface(pReq);
|
|
uint8_t bEntity = AUDGenericRequest_GetEntity(pReq);
|
|
uint8_t bCh = AUDFeatureUnitRequest_GetChannel(pReq);
|
|
/* AudioControl Interface */
|
|
if (bIf == pAuds->bAcInterface) {
|
|
if (bCh > pAuds->bNumChannels)
|
|
return 0;
|
|
if (bEntity != pAuds->bFeatureUnitIn
|
|
&& bEntity != pAuds->bFeatureUnitOut)
|
|
return 0;
|
|
}
|
|
/* AudioStream Interface not handled */
|
|
else {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Change Stream Mute status.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param bChannel Channel number.
|
|
* \param bmMute 1 to mute, 0 to unmute.
|
|
*/
|
|
uint32_t AUDDStream_ChangeMute(AUDDStream *pAuds,
|
|
uint8_t bChannel,
|
|
uint8_t bMute)
|
|
{
|
|
uint8_t bmMute = (bMute << bChannel);
|
|
|
|
if (pAuds->bNumChannels < bChannel)
|
|
return USBRC_PARAM_ERR;
|
|
|
|
if (bMute)
|
|
pAuds->bmMute |= bmMute;
|
|
else
|
|
pAuds->bmMute &= ~bmMute;
|
|
|
|
if (pAuds->fCallback)
|
|
pAuds->fCallback(AUDD_EC_MuteChanged,
|
|
bChannel,
|
|
pAuds->pArg);
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Set Stream Volume status.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param bChannel Channel number.
|
|
* \param wVolume New volume value.
|
|
*/
|
|
uint32_t AUDDStream_SetVolume(AUDDStream *pAuds,
|
|
uint8_t bChannel,
|
|
uint16_t wVolume)
|
|
{
|
|
if (pAuds->pwVolumes == 0)
|
|
return USBRC_PARAM_ERR;
|
|
if (bChannel > pAuds->bNumChannels)
|
|
return USBRC_PARAM_ERR;
|
|
|
|
pAuds->pwVolumes[bChannel] = wVolume;
|
|
if (pAuds->fCallback) {
|
|
pAuds->fCallback(AUDD_EC_VolumeChanged,
|
|
bChannel,
|
|
pAuds->pArg);
|
|
}
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Receives data from the host through the audio function (as speaker).
|
|
* This function behaves like USBD_Read.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param pData Pointer to the data buffer to put received data.
|
|
* \param dwSize Size of the data buffer in bytes.
|
|
* \param fCallback Optional callback function to invoke when the transfer
|
|
* finishes.
|
|
* \param pArg Optional argument to the callback function.
|
|
* \return USBD_STATUS_SUCCESS if the read operation has been started normally;
|
|
* otherwise, the corresponding error code.
|
|
*/
|
|
uint32_t AUDDStream_Read(
|
|
AUDDStream *pAuds,
|
|
void * pData,uint32_t dwSize,
|
|
TransferCallback fCallback,void * pArg)
|
|
{
|
|
if (pAuds->bEndpointOut == 0)
|
|
return USBRC_PARAM_ERR;
|
|
return USBD_Read(pAuds->bEndpointOut,
|
|
pData, dwSize,
|
|
fCallback, pArg);
|
|
}
|
|
|
|
/**
|
|
* Initialize Frame List for sending audio data.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param pListInit Pointer to the allocated list for audio write.
|
|
* \param pDmaInit Pointer to the allocated DMA descriptors for autio write
|
|
* (if DMA supported).
|
|
* \param listSize Circular list size.
|
|
* \param delaySize Start transfer after delaySize frames filled in.
|
|
* \param callback Optional callback function for transfer.
|
|
* \param argument Optional callback argument.
|
|
* \return USBD_STATUS_SUCCESS if setup successfully; otherwise an error code.
|
|
*/
|
|
uint32_t AUDDStream_SetupWrite(
|
|
AUDDStream *pAuds,
|
|
void * pListInit,
|
|
void * pDmaInit,
|
|
uint16_t listSize,
|
|
uint16_t delaySize,
|
|
TransferCallback callback,
|
|
void * argument)
|
|
{
|
|
uint32_t error;
|
|
|
|
if (pAuds->bEndpointIn == 0)
|
|
return USBRC_STATE_ERR;
|
|
|
|
error = USBD_HAL_SetupMblTransfer(pAuds->bEndpointIn,
|
|
pListInit,
|
|
listSize,
|
|
delaySize);
|
|
if (error) return error;
|
|
|
|
error = USBD_HAL_SetTransferCallback(pAuds->bEndpointIn,
|
|
callback, argument);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add frame buffer to audio sending list.
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param pBuffer Pointer to data frame to send.
|
|
* \param wLength Frame size in bytes.
|
|
* \return USBD_STATUS_SUCCESS if the transfer is started successfully;
|
|
* otherwise an error code.
|
|
*/
|
|
uint32_t AUDDStream_Write(AUDDStream *pAuds, void* pBuffer, uint16_t wLength)
|
|
{
|
|
if (pAuds->bEndpointIn == 0)
|
|
return USBRC_STATE_ERR;
|
|
|
|
return USBD_HAL_Write(pAuds->bEndpointIn,
|
|
pBuffer, wLength);
|
|
}
|
|
|
|
/**
|
|
* Close the stream. All pending transfers are canceled.
|
|
* \param pStream Pointer to AUDDStream instance.
|
|
*/
|
|
uint32_t AUDDStream_Close(AUDDStream *pStream)
|
|
{
|
|
uint32_t bmEPs = 0;
|
|
|
|
/* Close output stream */
|
|
if (pStream->bEndpointIn) {
|
|
bmEPs |= 1 << pStream->bEndpointIn;
|
|
}
|
|
/* Close input stream */
|
|
if (pStream->bEndpointOut) {
|
|
bmEPs |= 1 << pStream->bEndpointOut;
|
|
}
|
|
USBD_HAL_ResetEPs(bmEPs, USBRC_CANCELED, 1);
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Audio Speakerphone functions
|
|
*/
|
|
|
|
/**
|
|
* Initialize AUDDStream instance.
|
|
* Note the number of channels excludes the master control, so
|
|
* actual volume array size should be (1 + numChannels).
|
|
* \param pAuds Pointer to AUDDStream instance.
|
|
* \param numChannels Number of channels in the stream (excluding master,<31).
|
|
* \param wChannelVolumes Data array for channel volume values,
|
|
* must include master (1 + numChannels).
|
|
* \param fCallback Callback function for stream control events.
|
|
* \param pArg Pointer to event handler arguments.
|
|
*/
|
|
void AUDDSpeakerPhone_InitializeStream(
|
|
AUDDStream *pAuds,
|
|
uint8_t numChannels,
|
|
uint16_t wChannelVolumes[],
|
|
AUDDStreamEventCallback fCallback,
|
|
void* pArg)
|
|
{
|
|
pAuds->bAcInterface = 0xFF;
|
|
pAuds->bFeatureUnitOut = 0xFF;
|
|
pAuds->bFeatureUnitIn = 0xFF;
|
|
pAuds->bAsInterface = 0xFF;
|
|
pAuds->bEndpointOut = 0;
|
|
pAuds->bEndpointIn = 0;
|
|
|
|
pAuds->bNumChannels = numChannels;
|
|
pAuds->bmMute = 0;
|
|
pAuds->pwVolumes = wChannelVolumes;
|
|
|
|
pAuds->fCallback = fCallback;
|
|
pAuds->pArg = pArg;
|
|
}
|
|
|
|
/**
|
|
* Initialize AUDDSpeakerPhone instance.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pUsbd Pointer to USBDDriver instance.
|
|
* \param pSpeaker Pointer to speaker streaming interface.
|
|
* \param pMicrophone Pointer to microphone streaming interface.
|
|
*/
|
|
void AUDDSpeakerPhone_Initialize(
|
|
AUDDSpeakerPhone *pAudf,
|
|
USBDDriver *pUsbd,
|
|
AUDDStream *pSpeaker,
|
|
AUDDStream *pMicrophone)
|
|
{
|
|
pAudf->pUsbd = pUsbd;
|
|
pAudf->pSpeaker = pSpeaker;
|
|
pAudf->pMicrophone = pMicrophone;
|
|
}
|
|
|
|
/**
|
|
* Parse USB Audio streaming information for AUDDStream instance.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pDescriptors Pointer to descriptor list.
|
|
* \param dwLength Descriptor list size in bytes.
|
|
*/
|
|
USBGenericDescriptor *AUDDSpeakerPhone_ParseInterfaces(
|
|
AUDDSpeakerPhone *pAudf,
|
|
USBGenericDescriptor *pDescriptors,
|
|
uint32_t dwLength)
|
|
{
|
|
AUDDParseData data;
|
|
|
|
data.pAudf = pAudf;
|
|
data.pIfDesc = 0;
|
|
|
|
return USBGenericDescriptor_Parse(pDescriptors,
|
|
dwLength,
|
|
(USBDescriptorParseFunction)AUDDSpeakerPhone_Parse,
|
|
(void*)&data);
|
|
}
|
|
|
|
/**
|
|
* Close the stream. All pending transfers are canceled.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param bInterface Stream interface number
|
|
*/
|
|
uint32_t AUDDSpeakerPhone_CloseStream(
|
|
AUDDSpeakerPhone *pAudf,
|
|
uint32_t bInterface)
|
|
{
|
|
if (pAudf->pSpeaker->bAsInterface == bInterface) {
|
|
USBD_HAL_ResetEPs(1 << pAudf->pSpeaker->bEndpointOut,
|
|
USBRC_CANCELED,
|
|
1);
|
|
}
|
|
else if (pAudf->pMicrophone->bAsInterface == bInterface) {
|
|
USBD_HAL_ResetEPs(1 << pAudf->pMicrophone->bEndpointIn,
|
|
USBRC_CANCELED,
|
|
1);
|
|
}
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Handles audio-specific USB requests sent by the host
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pRequest Pointer to a USBGenericRequest instance.
|
|
* \return USBRC_PARAM_ERR if not handled.
|
|
*/
|
|
uint32_t AUDDSpeakerPhone_RequestHandler(
|
|
AUDDSpeakerPhone *pAudf,
|
|
const USBGenericRequest* pRequest)
|
|
{
|
|
//USBDDriver *pUsbd = pAudf->pUsbd;
|
|
|
|
if (USBGenericRequest_GetType(pRequest) != USBGenericRequest_CLASS)
|
|
return USBRC_PARAM_ERR;
|
|
|
|
TRACE_INFO_WP("Aud ");
|
|
switch (USBGenericRequest_GetRequest(pRequest)) {
|
|
case AUDGenericRequest_SETCUR:
|
|
AUDD_SetCUR(pAudf, pRequest);
|
|
break;
|
|
case AUDGenericRequest_GETCUR:
|
|
AUDD_GetCUR(pAudf, pRequest);
|
|
break;
|
|
|
|
default:
|
|
return USBRC_PARAM_ERR;
|
|
}
|
|
|
|
return USBRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Receives data from the host through the audio function (as speaker).
|
|
* This function behaves like USBD_Read.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pData Pointer to the data buffer to put received data.
|
|
* \param dwSize Size of the data buffer in bytes.
|
|
* \param fCallback Optional callback function to invoke when the transfer
|
|
* finishes.
|
|
* \param pArg Optional argument to the callback function.
|
|
* \return USBD_STATUS_SUCCESS if the read operation has been started normally;
|
|
* otherwise, the corresponding error code.
|
|
*/
|
|
uint32_t AUDDSpeakerPhone_Read(
|
|
AUDDSpeakerPhone *pAudf,
|
|
void * pData,uint32_t dwSize,
|
|
TransferCallback fCallback,void * pArg)
|
|
{
|
|
if (pAudf->pSpeaker == 0)
|
|
return USBRC_PARAM_ERR;
|
|
if (pAudf->pSpeaker->bEndpointOut == 0)
|
|
return USBRC_PARAM_ERR;
|
|
return USBD_Read(pAudf->pSpeaker->bEndpointOut,
|
|
pData, dwSize,
|
|
fCallback, pArg);
|
|
}
|
|
|
|
/**
|
|
* Initialize Frame List for sending audio data.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pListInit Pointer to the allocated list for audio write.
|
|
* \param pDmaInit Pointer to the allocated DMA descriptors for autio write
|
|
* (if DMA supported).
|
|
* \param listSize Circular list size.
|
|
* \param delaySize Start transfer after delaySize frames filled in.
|
|
* \param callback Optional callback function for transfer.
|
|
* \param argument Optional callback argument.
|
|
* \return USBD_STATUS_SUCCESS if setup successfully; otherwise an error code.
|
|
*/
|
|
uint32_t AUDDSpeakerPhone_SetupWrite(
|
|
AUDDSpeakerPhone *pAudf,
|
|
void * pListInit,
|
|
void * pDmaInit,
|
|
uint16_t listSize,
|
|
uint16_t delaySize,
|
|
TransferCallback callback,
|
|
void * argument)
|
|
{
|
|
uint32_t error;
|
|
|
|
if (pAudf->pMicrophone == 0)
|
|
return USBRC_PARAM_ERR;
|
|
if (pAudf->pMicrophone->bEndpointIn == 0)
|
|
return USBRC_STATE_ERR;
|
|
|
|
error = USBD_HAL_SetupMblTransfer(pAudf->pMicrophone->bEndpointIn,
|
|
pListInit,
|
|
listSize,
|
|
delaySize);
|
|
if (error) return error;
|
|
|
|
error = USBD_HAL_SetTransferCallback(
|
|
pAudf->pMicrophone->bEndpointIn,
|
|
callback, argument);
|
|
return error;
|
|
}
|
|
|
|
|
|
/**
|
|
* Add frame buffer to audio sending list.
|
|
* \param pAudf Pointer to AUDDSpeakerPhone instance.
|
|
* \param pBuffer Pointer to data frame to send.
|
|
* \param wLength Frame size in bytes.
|
|
* \return USBD_STATUS_SUCCESS if the transfer is started successfully;
|
|
* otherwise an error code.
|
|
*/
|
|
uint32_t AUDDSpeakerPhone_Write(AUDDSpeakerPhone *pAudf, void* pBuffer, uint16_t wLength)
|
|
{
|
|
if (pAudf->pSpeaker == 0)
|
|
return USBRC_PARAM_ERR;
|
|
if (pAudf->pSpeaker->bEndpointIn == 0)
|
|
return USBRC_STATE_ERR;
|
|
|
|
return USBD_HAL_Write(pAudf->pSpeaker->bEndpointIn,
|
|
pBuffer, wLength);
|
|
}
|
|
|
|
/**@}*/
|
|
|