4127 lines
186 KiB
C
4127 lines
186 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/USB-Device
|
|
* The Embedded USB Device Stack
|
|
*
|
|
* Copyright 2004-2021 Silicon Laboratories Inc. www.silabs.com
|
|
*
|
|
* SPDX-License-Identifier: APACHE-2.0
|
|
*
|
|
* This software is subject to an open source license and is distributed by
|
|
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
|
|
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* NOTICE
|
|
*
|
|
* Semidrive modified this file to adapt it for ssdk platform.
|
|
* The modifications are only intended for use with Semidrive chips.
|
|
* Copyright of all the modifications belongs to Semidrive Semiconductor.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* USB DEVICE AUDIO CLASS
|
|
*
|
|
* Filename : usbd_audio.c
|
|
* Version : V4.06.01
|
|
*********************************************************************************************************
|
|
* Note(s) : (1) This Audio class complies with the following specifications:
|
|
*
|
|
* (a) 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998'
|
|
* (b) 'USB Device Class Definition for Terminal Types, Release 1.0, March 18, 1998'
|
|
* (c) 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18,
|
|
* 1998'
|
|
* (d) 'USB Audio Device Class Specification for Basic Audio Devices, Release 1.0,
|
|
* November 24, 2009'
|
|
*
|
|
* (2) This Audio class does NOT support:
|
|
*
|
|
* (a) Processor Unit
|
|
* (b) Extension Unit
|
|
* (c) Data format Type II
|
|
* (d) Data format Type III
|
|
* (e) Associated interfaces
|
|
* (f) Class-specific requests: GET_STAT, GET_MEM, SET_MEM
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define MICRIUM_SOURCE
|
|
#define USBD_AUDIO_MODULE
|
|
#include "usbd_audio.h"
|
|
#include "usbd_audio_os.h"
|
|
#include "usbd_audio_processing.h"
|
|
#include "usbd_audio_internal.h"
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL DEFINES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_DBG_AUDIO_MSG(msg) USBD_DBG_GENERIC ((msg), \
|
|
USBD_EP_ADDR_NONE, \
|
|
USBD_IF_NBR_NONE)
|
|
|
|
#define USBD_DBG_AUDIO_ERR(msg, err) USBD_DBG_GENERIC_ERR((msg), \
|
|
USBD_EP_ADDR_NONE, \
|
|
USBD_IF_NBR_NONE, \
|
|
(err))
|
|
|
|
#define USBD_AUDIO_CTRL_REQ_TIMEOUT_mS 5000u
|
|
|
|
#define USBD_AUDIO_REQ_ENTITY_ID_MASK 0xFF00u
|
|
#define USBD_AUDIO_REQ_IF_MASK 0x00FFu
|
|
|
|
#define USBD_AUDIO_TYPE_IT 1u /* Input Terminal Type. */
|
|
#define USBD_AUDIO_TYPE_OT 2u /* Output Terminal Type. */
|
|
#define USBD_AUDIO_TYPE_FU 3u /* Function Unit Type. */
|
|
#define USBD_AUDIO_TYPE_MU 4u /* Mixer Unit Type. */
|
|
#define USBD_AUDIO_TYPE_SU 5u /* Selector Unit Type. */
|
|
#define USBD_AUDIO_TYPE_PU 6u /* Processor Unit Type. */
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO CLASS DESC
|
|
*
|
|
* Note(s): (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 3.2 and appendix A.2 for more details about audio subclass.
|
|
*
|
|
* (2) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* appendix A.4 for more details about Audio class-specific descriptor type.
|
|
*
|
|
* (3) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3 for more details about AudioControl interface descriptors length.
|
|
*
|
|
* (a) See Table 4-2, 'bLength' field description for more details.
|
|
*
|
|
* (b) See Table 4-3, 'bLength' field description for more details.
|
|
*
|
|
* (c) See Table 4-4, 'bLength' field description for more details.
|
|
*
|
|
* (d) See Table 4-5, 'bLength' field description for more details.
|
|
*
|
|
* (e) See Table 4-6, 'bLength' field description for more details.
|
|
*
|
|
* (f) See Table 4-7, 'bLength' field description for more details.
|
|
*
|
|
* (g) See Table 4-8, 'bLength' field description for more details.
|
|
*
|
|
* (h) See Table 4-19, 'bLength' field description for more details.
|
|
*
|
|
* (g) See Table 4-21, 'bLength' field description for more details.
|
|
*
|
|
* (4) See 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18, 1998',
|
|
* Table 2-1, 'bLength' field description for more details.
|
|
*********************************************************************************************************
|
|
*/
|
|
/* Audio IF subclass (see Note #1). */
|
|
#define USBD_AUDIO_SUBCLASS_AUDIO_CTRL 0x01u
|
|
#define USBD_AUDIO_SUBCLASS_AUDIO_STREAMING 0x02u
|
|
#define USBD_AUDIO_SUBCLASS_MIDI_STREAMING 0x03u
|
|
|
|
/* Audio class-specific desc type (see Note #2). */
|
|
#define USBD_AUDIO_DESC_TYPE_CS_IF 0x24u
|
|
#define USBD_AUDIO_DESC_TYPE_CS_EP 0x25u
|
|
|
|
/* class-specific desc len (see Note #3). */
|
|
#define USBD_AUDIO_DESC_LEN_AC_HEADER_MIN 8u /* See Note #3a. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_IT 12u /* See Note #3b. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_OT 9u /* See Note #3c. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_MU_MIN 10u /* See Note #3d. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_SU_MIN 6u /* See Note #3e. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_FU_MIN 7u /* See Note #3f. */
|
|
#define USBD_AUDIO_DESC_LEN_AC_PU_MIN 13u /* See Note #3g. */
|
|
#define USBD_AUDIO_DESC_LEN_AS_GENERAL 7u /* See Note #3h. */
|
|
#define USBD_AUDIO_DESC_LEN_EP_GENERAL 7u /* See Note #3g. */
|
|
#define USBD_AUDIO_DESC_LEN_TYPE_I_FMT_MIN 8u /* See Note #4. */
|
|
#define USBD_AUDIO_DESC_LEN_TYPE_I_SAM_FREQ 3u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO CTRL IF
|
|
* Note(s): (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* appendix A.5 for more details about AudioControl class-specific interface descriptor
|
|
* subtype.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* Desc subtype (see Note #1). */
|
|
#define USBD_AUDIO_DESC_SUBTYPE_AC_HEADER 0x01u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_IT 0x02u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_OT 0x03u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_MU 0x04u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_SU 0x05u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_FU 0x06u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_PU 0x07u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_XU 0x08u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO STREAMING IF
|
|
*
|
|
* Note(s): (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* appendix A.6 for more details about AudioStreaming class-specific interface descriptor
|
|
* subtype.
|
|
*
|
|
* (2) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* appendix A.8 for more details about AudioStreaming class-specific endpoint descriptor
|
|
* subtype.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* AS IF desc subtype (see Note #1). */
|
|
#define USBD_AUDIO_DESC_SUBTYPE_AS_GENERAL 0x01u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_FMT_TYPE 0x02u
|
|
#define USBD_AUDIO_DESC_SUBTYPE_FMT_SPECIFIC 0x03u
|
|
|
|
/* Audio EP desc subtype (see Note #2). */
|
|
#define USBD_AUDIO_DESC_SUBTYPE_EP_GENERAL 0x01u
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO DATA FMT
|
|
*
|
|
* Note(s): (1) See 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18, 1998',
|
|
* Appendix A.2 for more details about audio data format Type codes.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* See Note #1. */
|
|
#define USBD_AUDIO_FMT_TYPE_UNDEFINED 0x00u
|
|
#define USBD_AUDIO_FMT_TYPE_I 0x01u
|
|
#define USBD_AUDIO_FMT_TYPE_II 0x02u
|
|
#define USBD_AUDIO_FMT_TYPE_III 0x03u
|
|
|
|
#define USBD_AUDIO_FMT_TYPE_I_CONT_FREQ_NBR 2u /* Continuous freq has a lower and upper freq. */
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO DATA STREAM
|
|
*
|
|
* Note(s): (1) The maximum throughput for Audio 1.0 is determined by the maximum packet size for
|
|
* an isochronous endpoint at full-speed, that is 1023 bytes/ms.
|
|
*
|
|
* (2) With stream correction enabled, it is required to allocate a certain number of buffers
|
|
* that takes into account the underrun and overrun boundaries around the pre-buffering
|
|
* value.
|
|
*
|
|
* (3) Without any stream correction enabled, it is required to allocate at least
|
|
* USBD_AUDIO_STREAM_BUF_QTY_MIN buffers per stream to ensure the proper functioning of the
|
|
* audio stream given a pre-buffering equal to half of the maximum number of buffers.
|
|
* The minimum pre-buffering is 2 buffers, that is 2 ms worth of audio data.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#define USBD_AUDIO_MAX_THROUGHPUT 1023u /* Max throughput in bytes/ms for Audio 1.0... */
|
|
/* ...(see Note #1). */
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_FEEDBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
#define USBD_AUDIO_STREAM_BUF_QTY_MIN 6u /* See Note #2. */
|
|
#else
|
|
#define USBD_AUDIO_STREAM_BUF_QTY_MIN 4u /* See Note #3. */
|
|
#endif
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL CONSTANTS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL DATA TYPES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL TABLES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL GLOBAL VARIABLES
|
|
*
|
|
* Note(s): (1) This table contains one AIC (Audio Interface Collection) per element. The first element
|
|
* (index 0) corresponds to class number 0 and so on.
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* Audio class instances tbl (see Note #1). */
|
|
static USBD_AUDIO_CTRL USBD_Audio_CtrlTbl[USBD_AUDIO_CFG_MAX_NBR_AIC];
|
|
static CPU_INT08U USBD_Audio_CtrlNbrNext;
|
|
/* Audio class comm tbl. */
|
|
static USBD_AUDIO_COMM USBD_Audio_CommTbl[USBD_AUDIO_MAX_NBR_COMM];
|
|
static CPU_INT08U USBD_Audio_CommNbrNext;
|
|
/* Input Terminal tbl. */
|
|
static USBD_AUDIO_IT USBD_Audio_IT_Tbl[USBD_AUDIO_CFG_MAX_NBR_IT];
|
|
static CPU_INT08U USBD_Audio_IT_NbrNext;
|
|
/* Output Terminal tbl. */
|
|
static USBD_AUDIO_OT USBD_Audio_OT_Tbl[USBD_AUDIO_CFG_MAX_NBR_OT];
|
|
static CPU_INT08U USBD_Audio_OT_NbrNext;
|
|
/* Feature Unit tbl. */
|
|
static USBD_AUDIO_FU USBD_Audio_FU_Tbl[USBD_AUDIO_CFG_MAX_NBR_FU];
|
|
static CPU_INT08U USBD_Audio_FU_NbrNext;
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
/* Mixer Unit tbl. */
|
|
static USBD_AUDIO_MU USBD_Audio_MU_Tbl[USBD_AUDIO_CFG_MAX_NBR_MU];
|
|
static CPU_INT08U USBD_Audio_MU_NbrNext;
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_SU > 0u)
|
|
/* Selector Unit tbl. */
|
|
static USBD_AUDIO_SU USBD_Audio_SU_Tbl[USBD_AUDIO_CFG_MAX_NBR_SU];
|
|
static CPU_INT08U USBD_Audio_SU_NbrNext;
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
/* Alternate Setting tbl. */
|
|
static USBD_AUDIO_AS_IF_ALT USBD_Audio_AS_IF_AltTbl[USBD_AUDIO_MAX_NBR_IF_ALT];
|
|
static CPU_INT08U USBD_Audio_AS_IF_AltNbrNext;
|
|
/* AS IF settings tbl. */
|
|
static USBD_AUDIO_AS_IF_SETTINGS USBD_Audio_AS_IF_SettingsTbl[USBD_AUDIO_MAX_NBR_AS_IF_SETTINGS];
|
|
static CPU_INT08U USBD_Audio_AS_IF_SettingsNbrNext;
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/* AudioControl IF Class callbacks. */
|
|
static void USBD_Audio_AC_Conn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_Audio_AC_Disconn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_Audio_AC_IF_Desc ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_INT16U USBD_Audio_AC_IF_DescSizeGet ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_BOOLEAN USBD_Audio_AC_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg);
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
/* AudioStreaming IF Class callbacks. */
|
|
static void USBD_Audio_AS_Conn ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg);
|
|
|
|
static void USBD_Audio_AS_AltSettingUpdate( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static void USBD_Audio_AS_IF_Desc ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_INT16U USBD_Audio_AS_IF_DescSizeGet ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static void USBD_Audio_AS_EP_Desc ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_INT16U USBD_Audio_AS_EP_DescSizeGet ( CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg);
|
|
|
|
static CPU_BOOLEAN USBD_Audio_AS_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg);
|
|
#endif
|
|
|
|
static void *USBD_Audio_AC_RecipientGet (const USBD_AUDIO_CTRL *p_ctrl,
|
|
CPU_INT08U entity_id,
|
|
USBD_AUDIO_ENTITY_TYPE *p_recipient_type);
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED) || \
|
|
(USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
static USBD_AUDIO_COMM *USBD_Audio_CommGet (const USBD_AUDIO_CTRL *p_ctrl,
|
|
CPU_INT08U cfg_nbr);
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static CPU_INT16U USBD_Audio_MaxPktLenGet ( USBD_AUDIO_AS_ALT_CFG *p_as_cfg,
|
|
USBD_ERR *p_err);
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* AUDIO CLASS DRIVER
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static USBD_CLASS_DRV USBD_Audio_AC_Drv = { /* AudioControl IF class driver. */
|
|
USBD_Audio_AC_Conn,
|
|
USBD_Audio_AC_Disconn,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
USBD_Audio_AC_IF_Desc,
|
|
USBD_Audio_AC_IF_DescSizeGet,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
DEF_NULL,
|
|
USBD_Audio_AC_ClassReq,
|
|
DEF_NULL,
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
DEF_NULL,
|
|
DEF_NULL
|
|
#endif
|
|
};
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static USBD_CLASS_DRV USBD_Audio_AS_Drv = { /* AudioStreaming IF class driver. */
|
|
USBD_Audio_AS_Conn,
|
|
DEF_NULL,
|
|
USBD_Audio_AS_AltSettingUpdate,
|
|
DEF_NULL,
|
|
USBD_Audio_AS_IF_Desc,
|
|
USBD_Audio_AS_IF_DescSizeGet,
|
|
USBD_Audio_AS_EP_Desc,
|
|
USBD_Audio_AS_EP_DescSizeGet,
|
|
DEF_NULL,
|
|
USBD_Audio_AS_ClassReq,
|
|
DEF_NULL,
|
|
|
|
#if (USBD_CFG_MS_OS_DESC_EN == DEF_ENABLED)
|
|
DEF_NULL,
|
|
DEF_NULL
|
|
#endif
|
|
};
|
|
#endif
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL CONFIGURATION ERRORS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* GLOBAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_Init()
|
|
*
|
|
* Description : Initialize Audio class.
|
|
*
|
|
* Argument(s) : msg_qty Maximum quantity of messages for playback and record tasks' queues.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function:
|
|
*
|
|
* USBD_ERR_NONE Audio class successfully initialized.
|
|
*
|
|
* -RETURNED BY USBD_Audio_ProcessingInit()-
|
|
* See USBD_Audio_ProcessingInit() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_Audio_Init (CPU_INT16U msg_qty,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT08U ix;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
if (msg_qty == 0u) { /* Validate msg qty. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
/* ------------ INITIALIZE CLASS STRUCTURES ----------- */
|
|
for (ix = 0u; ix < USBD_AUDIO_CFG_MAX_NBR_AIC; ix++) { /* Init audio class instances tbl. */
|
|
|
|
Mem_Clr((void *)&USBD_Audio_CtrlTbl[ix],
|
|
sizeof(USBD_AUDIO_CTRL));
|
|
|
|
USBD_Audio_CtrlTbl[ix].DevNbr = USBD_DEV_NBR_NONE;
|
|
}
|
|
|
|
Mem_Clr((void *)&USBD_Audio_CommTbl[0u], /* Init Audio class comm tbl. */
|
|
(USBD_AUDIO_MAX_NBR_COMM * sizeof(USBD_AUDIO_COMM)));
|
|
|
|
Mem_Clr((void *)&USBD_Audio_IT_Tbl[0u], /* Init Input Terminal tbl. */
|
|
(USBD_AUDIO_CFG_MAX_NBR_IT * sizeof(USBD_AUDIO_IT)));
|
|
|
|
Mem_Clr((void *)&USBD_Audio_OT_Tbl[0u], /* Init Output Terminal tbl. */
|
|
(USBD_AUDIO_CFG_MAX_NBR_OT * sizeof(USBD_AUDIO_OT)));
|
|
|
|
Mem_Clr((void *)&USBD_Audio_FU_Tbl[0u], /* Init Feature Unit tbl. */
|
|
(USBD_AUDIO_CFG_MAX_NBR_FU * sizeof(USBD_AUDIO_FU)));
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
Mem_Clr((void *)&USBD_Audio_MU_Tbl[0u], /* Init Mixer Unit tbl. */
|
|
(USBD_AUDIO_CFG_MAX_NBR_MU * sizeof(USBD_AUDIO_MU)));
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_SU > 0u)
|
|
Mem_Clr((void *)&USBD_Audio_SU_Tbl[0u], /* Init Selector Unit tbl. */
|
|
(USBD_AUDIO_CFG_MAX_NBR_SU * sizeof(USBD_AUDIO_SU)));
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
{
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
|
|
|
|
for (ix = 0u; ix < USBD_AUDIO_MAX_NBR_IF_ALT; ix++) { /* Init alternate setting tbl. */
|
|
p_as_if_alt = &USBD_Audio_AS_IF_AltTbl[ix];
|
|
p_as_if_alt->AS_CfgPtr = DEF_NULL;
|
|
p_as_if_alt->DataIsocAddr = USBD_EP_ADDR_NONE;
|
|
p_as_if_alt->SynchIsocAddr = USBD_EP_ADDR_NONE;
|
|
p_as_if_alt->MaxPktLen = 0u;
|
|
}
|
|
|
|
Mem_Clr((void *)&USBD_Audio_AS_IF_SettingsTbl[0u], /* Init AS IF settings tbl. */
|
|
(USBD_AUDIO_MAX_NBR_AS_IF_SETTINGS * sizeof(USBD_AUDIO_AS_IF_SETTINGS)));
|
|
|
|
USBD_Audio_AS_IF_AltNbrNext = 0u;
|
|
}
|
|
#endif
|
|
|
|
USBD_Audio_CtrlNbrNext = 0u;
|
|
USBD_Audio_CommNbrNext = 0u;
|
|
USBD_Audio_IT_NbrNext = 0u;
|
|
USBD_Audio_OT_NbrNext = 0u;
|
|
USBD_Audio_FU_NbrNext = 0u;
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
USBD_Audio_MU_NbrNext = 0u;
|
|
#endif
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_SU > 0u)
|
|
USBD_Audio_SU_NbrNext = 0u;
|
|
#endif
|
|
|
|
USBD_Audio_ProcessingInit(msg_qty, p_err); /* Init Audio Processing layer. */
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_Add()
|
|
*
|
|
* Description : Create a new instance of the audio class (see Note #1).
|
|
*
|
|
* Argument(s) : entity_cnt Number of entities within the audio function.
|
|
*
|
|
* p_audio_drv_common_api Pointer to common audio codec driver API.
|
|
*
|
|
* p_audio_event_fnct Pointer to audio event callbacks.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Audio class instance successfully added.
|
|
* USBD_ERR_NULL_PTR Argument 'p_audio_drv_common_api' passed a
|
|
* NULL pointer.
|
|
* USBD_ERR_AUDIO_INSTANCE_ALLOC Audio class instances NOT available.
|
|
* USBD_ERR_ALLOC Cannot allocate request buffer from heap.
|
|
*
|
|
* -RETURNED BY p_audio_drv_common_api->Init()-
|
|
* See Audio Peripheral Driver Init() function for additional return error codes.
|
|
*
|
|
* Return(s) : Class instance number, if NO error(s).
|
|
*
|
|
* USBD_CLASS_NBR_NONE, otherwise.
|
|
*
|
|
* Note(s) : (1) One audio class instance = one audio function = one Audio Interface Collection (AIC).
|
|
*
|
|
* (2) In this version of the audio class, only the 1st form of data parameter is
|
|
* considered. Size of the request buffer should be therefore limited.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 5-20, for an example of the first form request.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_Audio_Add ( CPU_INT08U entity_cnt,
|
|
const USBD_AUDIO_DRV_COMMON_API *p_audio_drv_common_api,
|
|
const USBD_AUDIO_EVENT_FNCTS *p_audio_event_fnct,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
CPU_INT08U class_nbr;
|
|
LIB_ERR err_lib;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(USBD_CLASS_NBR_NONE);
|
|
}
|
|
|
|
if ((p_audio_drv_common_api == DEF_NULL) ||
|
|
(p_audio_drv_common_api->Init == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
#endif
|
|
/* ---------------- ADD CLASS INSTANCE ---------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
class_nbr = USBD_Audio_CtrlNbrNext; /* Alloc new audio class instance. */
|
|
|
|
if (class_nbr >= USBD_AUDIO_CFG_MAX_NBR_AIC) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_INSTANCE_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
|
|
USBD_Audio_CtrlNbrNext++; /* Next avail audio class instance nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
/* ------------- STORE CLASS INSTANCE INFO ------------ */
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
p_ctrl->ClassNbr = class_nbr;
|
|
/* See Note #2. */
|
|
p_ctrl->ReqBufPtr = (CPU_INT08U *)Mem_HeapAlloc(USBD_AUDIO_CFG_CLASS_REQ_MAX_LEN,
|
|
USBD_CFG_BUF_ALIGN_OCTETS,
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
|
|
p_ctrl->EventFnctPtr = p_audio_event_fnct;
|
|
p_ctrl->EntityID_Nxt = 0u;
|
|
|
|
p_ctrl->EntityCnt = entity_cnt;
|
|
/* Alloc ptr to entity struct for ID management. */
|
|
p_ctrl->EntityID_TblPtr = (USBD_AUDIO_ENTITY **)Mem_HeapAlloc((entity_cnt * sizeof(USBD_AUDIO_ENTITY *)),
|
|
sizeof(CPU_ALIGN),
|
|
NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
/* Init the audio driver associated to this AIC. */
|
|
p_audio_drv_common_api->Init(&p_ctrl->DrvInfo,
|
|
p_err);
|
|
|
|
return (class_nbr);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_CfgAdd()
|
|
*
|
|
* Description : Add an audio class instance into the specified configuration (see Note #1).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration index to add Audio class instance to.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Audio class configuration successfully added.
|
|
* USBD_ERR_CFG_INVALID_NBR Invalid configuration number.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_INVALID_ARG Class number associated with a different device number.
|
|
* USBD_ERR_AUDIO_INSTANCE_ALLOC Audio class communication instances NOT available.
|
|
*
|
|
* -RETURNED BY USBD_IF_Add()-
|
|
* See USBD_IF_Add() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) Called several times, it allows to create multiple instances and multiple configurations.
|
|
* For instance, the following architecture could be created :
|
|
*
|
|
* Audio Class 0 (device number 0)
|
|
* |-- Configuration 0
|
|
* |-- Configuration 1
|
|
*
|
|
* Audio Class 1 (device number 1)
|
|
* |-- Configuration 0
|
|
* |-- Configuration 1
|
|
*
|
|
* (2) Configuration Descriptor corresponding to an audio device has the following format:
|
|
*
|
|
* Configuration Descriptor
|
|
* |-- Interface Descriptor (AudioControl) [standard]
|
|
* |-- Header Descriptor [class-specific]
|
|
* |-- Unit Descriptor(s) [class-specific]
|
|
* |-- Terminal Descriptor(s) [class-specific]
|
|
* |-- Endpoint Descriptor (Interrupt IN) - optional [standard]
|
|
* |-- Interface Descriptor (AudioStreaming) [standard]
|
|
* |-- AS Interface Descriptor [class-specific]
|
|
* |-- AS Format Type Descriptor [class-specific]
|
|
* |-- AS Format-Specific Descriptor(s) [class-specific]
|
|
* |-- Endpoint Descriptor (Isochronous IN or OUT Data) [standard]
|
|
* |-- AS Isochronous Audio Data Endpoint Descriptor [class-specific]
|
|
* |-- Endpoint Descriptor (Isochronous OUT or IN Synch endpoint) [standard]
|
|
* |-- Interface Descriptor (AudioStreaming) [standard]
|
|
* |-- ...
|
|
* |-- Interface Descriptor (AudioStreaming) [standard]
|
|
* |-- ...
|
|
*
|
|
* The function USBD_Audio_CfgAdd() only adds the Interface Descriptor (AudioControl).
|
|
* Other standard and class-specific descriptors are added by functions:
|
|
* USBD_Audio_IT_Add()
|
|
* USBD_Audio_OT_Add()
|
|
* USBD_Audio_FU_Add()
|
|
* USBD_Audio_MU_Add()
|
|
* USBD_Audio_SU_Add()
|
|
* USBD_Audio_AS_IF_Add()
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_Audio_CfgAdd (CPU_INT08U class_nbr,
|
|
CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_COMM *p_comm;
|
|
CPU_INT16U comm_ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
if (cfg_nbr == USBD_CFG_NBR_NONE) { /* Check that config number is valid */
|
|
*p_err = USBD_ERR_CFG_INVALID_NBR;
|
|
return;
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check that class number is valid */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if ((p_ctrl->DevNbr != USBD_DEV_NBR_NONE) && /* Chk if class is associated with a different dev. */
|
|
(p_ctrl->DevNbr != dev_nbr)) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
p_comm = USBD_Audio_CommGet(p_ctrl, cfg_nbr);
|
|
if(p_comm != DEF_NULL) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
#endif
|
|
/* --------------- ALLOC NEW COMM INFO ---------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
comm_ix = USBD_Audio_CommNbrNext;
|
|
|
|
if (comm_ix >= USBD_AUDIO_MAX_NBR_COMM) { /* Check that comm index is within max range. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_INSTANCE_ALLOC;
|
|
return;
|
|
}
|
|
|
|
USBD_Audio_CommNbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_comm = &USBD_Audio_CommTbl[comm_ix];
|
|
p_comm->CfgNbr = cfg_nbr;
|
|
/* ------- CFG DESC CONSTRUCTION (see Note #2) -------- */
|
|
(void)USBD_IF_Add( dev_nbr, /* Add AudioControl IF to cfg. */
|
|
cfg_nbr,
|
|
&USBD_Audio_AC_Drv,
|
|
(void *)p_comm,
|
|
DEF_NULL,
|
|
USBD_CLASS_CODE_AUDIO,
|
|
USBD_AUDIO_SUBCLASS_AUDIO_CTRL,
|
|
USBD_PROTOCOL_CODE_USE_IF_DESC,
|
|
"Audio Control Interface",
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* ---------- STORE AUDIO CLASS INSTANCE INFO ----------*/
|
|
p_ctrl->DevNbr = dev_nbr; /* Save device number */
|
|
p_comm->CtrlPtr = p_ctrl; /* Save pointer to control struct */
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->State = USBD_AUDIO_STATE_INIT;
|
|
CPU_CRITICAL_EXIT();
|
|
/* Add class instance info to audio comm list. */
|
|
if (p_ctrl->CommHeadPtr == DEF_NULL) { /* First element of list. */
|
|
p_ctrl->CommHeadPtr = p_comm;
|
|
} else {
|
|
p_ctrl->CommTailPtr->NextPtr = p_comm; /* Element at the end of list. */
|
|
}
|
|
p_ctrl->CommTailPtr = p_comm;
|
|
p_ctrl->CommCnt++; /* Increment nbr of audio comm info struct. */
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_IsConn()
|
|
*
|
|
* Description : Get the audio class connection state.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* Return(s) : DEF_YES, if Audio class is connected.
|
|
*
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_BOOLEAN USBD_Audio_IsConn (CPU_INT08U class_nbr)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_DEV_STATE state;
|
|
USBD_ERR err;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check audio class instance nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
return (DEF_NO);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr];
|
|
state = USBD_DevStateGet(p_ctrl->DevNbr, &err); /* Get dev state. */
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if ((err == USBD_ERR_NONE ) &&
|
|
(state == USBD_DEV_STATE_CONFIGURED) &&
|
|
(p_ctrl->State == USBD_AUDIO_STATE_CFG )) {
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
return (DEF_YES);
|
|
} else {
|
|
CPU_CRITICAL_EXIT();
|
|
return (DEF_NO);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_IT_Add()
|
|
*
|
|
* Description : Add an Input Terminal to the specified class instance (i.e. audio function).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_it_cfg Pointer to the Input Terminal configuration structure.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Input Terminal successfully added.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_it_cfg'.
|
|
* USBD_ERR_INVALID_ARG Wrong copy protection level OR
|
|
* invalid spatial locations.
|
|
* USBD_ERR_AUDIO_IT_ALLOC No Input Terminal structure available OR
|
|
* no entity structure available.
|
|
*
|
|
* -RETURNED BY USBD_StrAdd()-
|
|
* See USBD_StrAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : Terminal ID assigned by audio class, if NO error(s).
|
|
*
|
|
* 0, otherwise (see Note #1).
|
|
*
|
|
* Note(s) : (1) Audio 1.0 specification indicates that ID #0 is reserved for undefined ID. Thus it
|
|
* indicates an error.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_Audio_IT_Add ( CPU_INT08U class_nbr,
|
|
const USBD_AUDIO_IT_CFG *p_it_cfg,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_IT *p_it;
|
|
CPU_INT08U it_nbr;
|
|
CPU_INT08U ix;
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
CPU_INT08U log_ch_cnt;
|
|
#endif
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0u);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_it_cfg == DEF_NULL) { /* Check if IT config is null */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
|
|
switch (p_it_cfg->CopyProtLevel) { /* Check copy protection level. */
|
|
case USBD_AUDIO_CPL_NONE:
|
|
case USBD_AUDIO_CPL0:
|
|
case USBD_AUDIO_CPL1:
|
|
case USBD_AUDIO_CPL2:
|
|
break;
|
|
|
|
default:
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
if (p_it_cfg->LogChCfg == 0x00u) { /* Non-predefined spatial positions. */
|
|
|
|
if (p_it_cfg->LogChNbr > USBD_AUDIO_LOG_CH_NBR_MAX) { /* Check if nbr of log ch exceeds max allowed. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
|
|
switch (p_it_cfg->LogChNbr) {
|
|
/* Default spatial location supported. */
|
|
case USBD_AUDIO_MONO:
|
|
case USBD_AUDIO_STEREO:
|
|
case 3u:
|
|
case 4u:
|
|
case USBD_AUDIO_5_1:
|
|
case USBD_AUDIO_7_1:
|
|
break;
|
|
|
|
default:
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
} else { /* Predefined spatial positions. */
|
|
/* Cnt nbr of log ch from spatial locations bitmap. */
|
|
USBD_AUDIO_BIT_SET_CNT(log_ch_cnt, p_it_cfg->LogChCfg);
|
|
/* Check if nbr of log ch deduced from spatial... */
|
|
/* ...locations matches nbr of log ch declared. */
|
|
if ((p_it_cfg->LogChNbr != log_ch_cnt) ||
|
|
(p_it_cfg->LogChNbr > USBD_AUDIO_LOG_CH_NBR_MAX) ) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return (0u);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
|
|
/* ------------ GET INPUT TERMINAL STRUCT ------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
it_nbr = USBD_Audio_IT_NbrNext;
|
|
|
|
if (it_nbr >= USBD_AUDIO_CFG_MAX_NBR_IT) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_IT_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
USBD_Audio_IT_NbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_it = &USBD_Audio_IT_Tbl[it_nbr];
|
|
|
|
/* ---------- ADD NEW IT TO CLASS CTRL INFO ----------- */
|
|
p_it->IT_CfgPtr = p_it_cfg; /* Save configuration for later use */
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_ctrl->EntityID_Nxt > p_ctrl->EntityCnt) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_IT_ALLOC;
|
|
return (0u);
|
|
}
|
|
p_it->ID = p_ctrl->EntityID_Nxt + 1u; /* ID #0 reserved. Assigned ID needs +1 (see Note #1). */
|
|
ix = p_ctrl->EntityID_Nxt; /* ID used as a 0-index. */
|
|
p_ctrl->EntityID_Nxt++; /* Nxt avail ID. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_it->EntityType = USBD_AUDIO_ENTITY_IT;
|
|
p_ctrl->EntityID_TblPtr[ix] = (USBD_AUDIO_ENTITY *)p_it;
|
|
|
|
USBD_StrAdd(p_ctrl->DevNbr, /* Add string describing this IT. */
|
|
p_it_cfg->StrPtr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (p_it->ID);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_OT_Add()
|
|
*
|
|
* Description : Add an Output Terminal to the specified class instance (i.e. audio function).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_ot_cfg Pointer to the Output Terminal configuration structure.
|
|
*
|
|
* p_ot_api Pointer to the audio codec API associated to this Output Terminal.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Output Terminal successfully added.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_ot_cfg'/'p_ot_api'.
|
|
* USBD_ERR_AUDIO_OT_ALLOC No Output Terminal structure available OR
|
|
* no entity structure available.
|
|
*
|
|
* -RETURNED BY USBD_StrAdd()-
|
|
* See USBD_StrAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : Terminal ID assigned by audio class, if NO error(s).
|
|
*
|
|
* 0, otherwise (see Note #1).
|
|
*
|
|
* Note(s) : (1) Audio 1.0 specification indicates that ID #0 is reserved for undefined ID. Thus it
|
|
* indicates an error.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_Audio_OT_Add ( CPU_INT08U class_nbr,
|
|
const USBD_AUDIO_OT_CFG *p_ot_cfg,
|
|
const USBD_AUDIO_DRV_AC_OT_API *p_ot_api,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_OT *p_ot;
|
|
CPU_INT08U ot_nbr;
|
|
CPU_INT08U ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0u);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_ot_cfg == DEF_NULL) { /* Check pointer to OT configuration. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
/* If Copy Prot ctrl enabled, check if OT API present. */
|
|
if ((p_ot_cfg->CopyProtEn == DEF_ENABLED) &&
|
|
((p_ot_api == DEF_NULL) ||
|
|
(p_ot_api->OT_CopyProtSet == DEF_NULL))) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
|
|
/* ------------ GET OUTPUT TERMINAL STRUCT ------------ */
|
|
CPU_CRITICAL_ENTER();
|
|
ot_nbr = USBD_Audio_OT_NbrNext;
|
|
|
|
if (ot_nbr >= USBD_AUDIO_CFG_MAX_NBR_OT) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_OT_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
USBD_Audio_OT_NbrNext++;
|
|
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_ot = &USBD_Audio_OT_Tbl[ot_nbr];
|
|
|
|
/* ---------- ADD NEW OT TO CLASS CTRL INFO ----------- */
|
|
p_ot->OT_CfgPtr = p_ot_cfg; /* Save configuration for later use */
|
|
p_ot->OT_API_Ptr = p_ot_api;
|
|
p_ot->DrvInfoPtr = &p_ctrl->DrvInfo;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_ctrl->EntityID_Nxt > p_ctrl->EntityCnt) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_OT_ALLOC;
|
|
return (0u);
|
|
}
|
|
p_ot->ID = p_ctrl->EntityID_Nxt + 1u; /* ID #0 reserved. Assigned ID needs +1 (see Note #1). */
|
|
ix = p_ctrl->EntityID_Nxt; /* ID used as a 0-index. */
|
|
p_ctrl->EntityID_Nxt++; /* Nxt avail ID. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_ot->EntityType = USBD_AUDIO_ENTITY_OT;
|
|
p_ctrl->EntityID_TblPtr[ix] = (USBD_AUDIO_ENTITY *)p_ot;
|
|
|
|
USBD_StrAdd(p_ctrl->DevNbr, /* Add string describing this OT. */
|
|
p_ot_cfg->StrPtr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (p_ot->ID);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_FU_Add()
|
|
*
|
|
* Description : Add a Feature Unit to the specified class instance (i.e. audio function).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_fu_cfg Pointer to the Feature Unit configuration structure.
|
|
*
|
|
* p_fu_api Pointer to the audio codec API associated to this Feature Unit.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Feature Unit successfully added.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_fu_cfg'/'p_fu_api'.
|
|
* USBD_ERR_AUDIO_FU_ALLOC No Feature Unit structure available OR
|
|
* no entity structure available.
|
|
*
|
|
* -RETURNED BY USBD_StrAdd()-
|
|
* See USBD_StrAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : Unit ID assigned by audio class, if NO error(s).
|
|
*
|
|
* 0, otherwise (see Note #1).
|
|
*
|
|
* Note(s) : (1) Audio 1.0 specification indicates that ID #0 is reserved for undefined ID. Thus it
|
|
* indicates an error.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_INT08U USBD_Audio_FU_Add ( CPU_INT08U class_nbr,
|
|
const USBD_AUDIO_FU_CFG *p_fu_cfg,
|
|
const USBD_AUDIO_DRV_AC_FU_API *p_fu_api,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_FU *p_fu;
|
|
CPU_INT08U fu_nbr;
|
|
CPU_INT08U ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0u);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_fu_cfg == DEF_NULL) { /* Check Pointer to FU configuration */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
/* Any FU should supports minimally mute and vol ctrl. */
|
|
if ((p_fu_api == DEF_NULL) ||
|
|
(p_fu_api->FU_MuteManage == DEF_NULL) ||
|
|
(p_fu_api->FU_VolManage == DEF_NULL)) {
|
|
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (USBD_CLASS_NBR_NONE);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
|
|
/* ------------- GET FEATURE UNIT STRUCT -------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
fu_nbr = USBD_Audio_FU_NbrNext;
|
|
|
|
if (fu_nbr >= USBD_AUDIO_CFG_MAX_NBR_FU) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_FU_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
USBD_Audio_FU_NbrNext++;
|
|
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_fu = &USBD_Audio_FU_Tbl[fu_nbr];
|
|
|
|
/* ---------- ADD NEW FU TO CLASS CTRL INFO ----------- */
|
|
p_fu->FU_CfgPtr = p_fu_cfg; /* Save configuration for later use */
|
|
p_fu->FU_API_Ptr = p_fu_api;
|
|
p_fu->DrvInfoPtr = &p_ctrl->DrvInfo;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_ctrl->EntityID_Nxt > p_ctrl->EntityCnt) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_FU_ALLOC;
|
|
return (0u);
|
|
}
|
|
p_fu->ID = p_ctrl->EntityID_Nxt + 1u; /* ID #0 reserved. Assigned ID needs +1 (see Note #1). */
|
|
ix = p_ctrl->EntityID_Nxt; /* ID used as a 0-index. */
|
|
p_ctrl->EntityID_Nxt++; /* Nxt avail ID. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_fu->EntityType = USBD_AUDIO_ENTITY_FU;
|
|
p_ctrl->EntityID_TblPtr[ix] = (USBD_AUDIO_ENTITY *)p_fu;
|
|
|
|
USBD_StrAdd(p_ctrl->DevNbr, /* Add string describing this FU. */
|
|
p_fu_cfg->StrPtr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (p_fu->ID);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_MU_Add()
|
|
*
|
|
* Description : Add a Mixer Unit to the specified class instance (i.e. audio function).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number
|
|
*
|
|
* p_mu_cfg Pointer to the Mixer Unit configuration structure.
|
|
*
|
|
* p_mu_api Pointer to the audio codec API associated to this Mixer Unit.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Mixer Unit successfully added.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_mu_cfg'.
|
|
* USBD_ERR_AUDIO_MU_ALLOC No Mixer Unit structure available OR
|
|
* no entity structure available.
|
|
* USBD_ERR_ALLOC No space on heap to allocate mixing controls bitmap.
|
|
*
|
|
* -RETURNED BY USBD_StrAdd()-
|
|
* See USBD_StrAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : Unit ID assigned by audio class, if NO error(s).
|
|
*
|
|
* 0, otherwise (see Note #1).
|
|
*
|
|
* Note(s) : (1) Audio 1.0 specification indicates that ID #0 is reserved for undefined ID. Thus it
|
|
* indicates an error.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
CPU_INT08U USBD_Audio_MU_Add ( CPU_INT08U class_nbr,
|
|
const USBD_AUDIO_MU_CFG *p_mu_cfg,
|
|
const USBD_AUDIO_DRV_AC_MU_API *p_mu_api,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_MU *p_mu;
|
|
CPU_INT08U mu_nbr;
|
|
CPU_INT32U nbr_mixing_ctrl;
|
|
LIB_ERR err_lib;
|
|
CPU_INT08U ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0u);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_mu_cfg == DEF_NULL) { /* Check Pointer to MU configuration */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
|
|
/* -------------- GET MIXER UNIT STRUCT --------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
mu_nbr = USBD_Audio_MU_NbrNext;
|
|
|
|
if (mu_nbr >= USBD_AUDIO_CFG_MAX_NBR_MU) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_MU_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
USBD_Audio_MU_NbrNext++;
|
|
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_mu = &USBD_Audio_MU_Tbl[mu_nbr];
|
|
|
|
/* ---------- ADD NEW MU TO CLASS COMM INFO ----------- */
|
|
/* Alloc programmable ctrl bitmap tbl. */
|
|
nbr_mixing_ctrl = p_mu_cfg->LogInChNbr * p_mu_cfg->LogOutChNbr;
|
|
if ((nbr_mixing_ctrl % DEF_OCTET_NBR_BITS) == 0) {
|
|
p_mu->ControlsSize = nbr_mixing_ctrl / DEF_OCTET_NBR_BITS;
|
|
} else {
|
|
p_mu->ControlsSize = (nbr_mixing_ctrl / DEF_OCTET_NBR_BITS) + 1u;
|
|
}
|
|
|
|
p_mu->ControlsTblPtr = (CPU_INT08U *)Mem_HeapAlloc(p_mu->ControlsSize,
|
|
sizeof(CPU_ALIGN),
|
|
NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
Mem_Clr((void *)p_mu->ControlsTblPtr,
|
|
p_mu->ControlsSize);
|
|
|
|
p_mu->MU_CfgPtr = p_mu_cfg; /* Save configuration for later use */
|
|
p_mu->MU_API_Ptr = p_mu_api;
|
|
p_mu->DrvInfoPtr = &p_ctrl->DrvInfo;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_ctrl->EntityID_Nxt > p_ctrl->EntityCnt) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_MU_ALLOC;
|
|
return (0u);
|
|
}
|
|
p_mu->ID = p_ctrl->EntityID_Nxt + 1u; /* ID #0 reserved. Assigned ID needs +1 (see Note #1). */
|
|
ix = p_ctrl->EntityID_Nxt; /* ID used as a 0-index. */
|
|
p_ctrl->EntityID_Nxt++; /* Nxt avail ID. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_mu->EntityType = USBD_AUDIO_ENTITY_MU;
|
|
p_ctrl->EntityID_TblPtr[ix] = (USBD_AUDIO_ENTITY *)p_mu;
|
|
|
|
USBD_StrAdd(p_ctrl->DevNbr, /* Add string describing this MU. */
|
|
p_mu_cfg->StrPtr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (p_mu->ID);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_SU_Add()
|
|
*
|
|
* Description : Add a Selector Unit to the specified class instance (i.e. audio function).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* p_su_cfg Pointer to the Selector Unit configuration structure.
|
|
*
|
|
* p_su_api Pointer to the audio codec API associated to this Selector Unit.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Selector Unit successfully added.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_su_cfg'/'p_su_api'.
|
|
* USBD_ERR_AUDIO_SU_ALLOC No Selector Unit structure available OR
|
|
* no entity structure available.
|
|
*
|
|
* -RETURNED BY USBD_StrAdd()-
|
|
* See USBD_StrAdd() for additional return error codes.
|
|
*
|
|
* Return(s) : Unit ID assigned by audio class, if NO error(s).
|
|
*
|
|
* 0, otherwise (see Note #1).
|
|
*
|
|
* Note(s) : (1) Audio 1.0 specification indicates that ID #0 is reserved for undefined ID. Thus it
|
|
* indicates an error.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_SU > 0u)
|
|
CPU_INT08U USBD_Audio_SU_Add ( CPU_INT08U class_nbr,
|
|
const USBD_AUDIO_SU_CFG *p_su_cfg,
|
|
const USBD_AUDIO_DRV_AC_SU_API *p_su_api,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_SU *p_su;
|
|
CPU_INT08U su_nbr;
|
|
CPU_INT08U ix;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(0u);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return (0u);
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_su_cfg == DEF_NULL) { /* Check Pointer to SU configuration */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
/* Check if SU API provided. */
|
|
if ((p_su_api == DEF_NULL) ||
|
|
(p_su_api->SU_InPinManage == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return (0u);
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
|
|
/* ------------- GET SELECTOR UNIT STRUCT ------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
su_nbr = USBD_Audio_SU_NbrNext;
|
|
|
|
if (su_nbr >= USBD_AUDIO_CFG_MAX_NBR_SU) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_SU_ALLOC;
|
|
return (0u);
|
|
}
|
|
|
|
USBD_Audio_SU_NbrNext++;
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_su = &USBD_Audio_SU_Tbl[su_nbr];
|
|
|
|
/* ---------- ADD NEW MU TO CLASS COMM INFO ----------- */
|
|
p_su->SU_CfgPtr = p_su_cfg; /* Save configuration for later use */
|
|
p_su->SU_API_Ptr = p_su_api;
|
|
p_su->DrvInfoPtr = &p_ctrl->DrvInfo;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (p_ctrl->EntityID_Nxt > p_ctrl->EntityCnt) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_SU_ALLOC;
|
|
return (0u);
|
|
}
|
|
p_su->ID = p_ctrl->EntityID_Nxt + 1u; /* ID #0 reserved. Assigned ID needs +1 (see Note #1). */
|
|
ix = p_ctrl->EntityID_Nxt; /* ID used as a 0-index. */
|
|
p_ctrl->EntityID_Nxt++; /* Nxt avail ID. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_su->EntityType = USBD_AUDIO_ENTITY_SU;
|
|
p_ctrl->EntityID_TblPtr[ix] = (USBD_AUDIO_ENTITY *)p_su;
|
|
|
|
USBD_StrAdd(p_ctrl->DevNbr, /* Add string describing this SU. */
|
|
p_su_cfg->StrPtr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return (0u);
|
|
}
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (p_su->ID);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_IT_Assoc()
|
|
*
|
|
* Description : Associate the Input Terminal to an Output Terminal (see Note #1).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* it_id Input Terminal ID.
|
|
*
|
|
* assoc_terminal_id Output Terminal ID associated (see Note #2).
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Input Terminal successfully associated.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : (1) The Input Terminal descriptor has the field 'bAssocTerminal'. It associates an
|
|
* Output Terminal to this Input Terminal, effectively implementing a bi-directional
|
|
* Terminal pair.
|
|
*
|
|
* (2) If there is no associated Output Terminal, you can specify
|
|
* USBD_AUDIO_TERMINAL_NO_ASSOCIATION.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_Audio_IT_Assoc (CPU_INT08U class_nbr,
|
|
CPU_INT08U it_id,
|
|
CPU_INT08U assoc_terminal_id,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_IT *p_it;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_it = (USBD_AUDIO_IT *)p_ctrl->EntityID_TblPtr[(it_id - 1u)];
|
|
|
|
p_it->AssociatedOT_ID = assoc_terminal_id; /* Save associated OT ID. */
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_OT_Assoc()
|
|
*
|
|
* Description : Specify the entity ID connected to this Output Terminal and associate the Output Terminal
|
|
* to an Input Terminal (see Note #1).
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* ot_id Output Terminal ID.
|
|
*
|
|
* src_entity_id ID of the Unit or Terminal to which this Terminal is connected.
|
|
*
|
|
* assoc_terminal_id Input Terminal ID associated (see Note #2).
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Output Terminal successfully associated.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : (1) The Output Terminal descriptor has the field 'bAssocTerminal'. It associates an
|
|
* Input Terminal to this Output Terminal, effectively implementing a bi-directional
|
|
* Terminal pair.
|
|
*
|
|
* (2) If there is no associated Input Terminal, you can specify
|
|
* USBD_AUDIO_TERMINAL_NO_ASSOCIATION.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_Audio_OT_Assoc (CPU_INT08U class_nbr,
|
|
CPU_INT08U ot_id,
|
|
CPU_INT08U src_entity_id,
|
|
CPU_INT08U assoc_terminal_id,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_OT *p_ot;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_ot = (USBD_AUDIO_OT *)p_ctrl->EntityID_TblPtr[(ot_id - 1u)];
|
|
|
|
p_ot->AssociatedIT_ID = assoc_terminal_id; /* Save associated IT ID. */
|
|
p_ot->SourceID = src_entity_id; /* Save unit or terminal ID. */
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_FU_Assoc()
|
|
*
|
|
* Description : Specify the entity ID connected to this Feature Unit.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* fu_id Feature Unit ID.
|
|
*
|
|
* entity_id_src ID of the Unit or Terminal to which this Unit is connected.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Feature Unit successfully associated.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_INVALID_ARG Output Terminal cannot be connected as input of
|
|
* a Feature Unit.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void USBD_Audio_FU_Assoc (CPU_INT08U class_nbr,
|
|
CPU_INT08U fu_id,
|
|
CPU_INT08U src_entity_id,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_FU *p_fu;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_fu = (USBD_AUDIO_FU *)p_ctrl->EntityID_TblPtr[(fu_id - 1u)];
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
USBD_AUDIO_ENTITY *p_entity_src;
|
|
|
|
|
|
p_entity_src = p_ctrl->EntityID_TblPtr[(src_entity_id - 1u)];
|
|
if (p_entity_src->EntityType == USBD_AUDIO_ENTITY_OT) { /* No OT can be connected as an input of FU. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_fu->SourceID = src_entity_id; /* Save unit or terminal ID. */
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_MU_Assoc()
|
|
*
|
|
* Description : Specify the entities ID connected to this Mixer Unit.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* mu_id Mixer Unit ID.
|
|
*
|
|
* p_src_entity_id Pointer to table containing IDs of Units and/or Terminals to which
|
|
* Input Pins of this Mixer Unit are connected.
|
|
*
|
|
* nbr_input_pins Number of input pins.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Mixer Unit successfully associated.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_src_entity_id'.
|
|
* USBD_ERR_INVALID_ARG Output Terminal cannot be connected as input of
|
|
* a Mixer Unit.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
void USBD_Audio_MU_Assoc (CPU_INT08U class_nbr,
|
|
CPU_INT08U mu_id,
|
|
CPU_INT08U *p_src_entity_id,
|
|
CPU_INT08U nbr_input_pins,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_MU *p_mu;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_src_entity_id == DEF_NULL) { /* Check src IDs ptr. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_mu = (USBD_AUDIO_MU *)p_ctrl->EntityID_TblPtr[(mu_id - 1u)];
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_INT08U ix;
|
|
CPU_INT08U entity_id_src;
|
|
USBD_AUDIO_ENTITY *p_entity_src;
|
|
|
|
for (ix = 0; ix < nbr_input_pins; ix++) {
|
|
entity_id_src = p_src_entity_id[ix];
|
|
p_entity_src = p_ctrl->EntityID_TblPtr[(entity_id_src - 1u)];
|
|
/* No OT can be connected as an input of MU. */
|
|
if (p_entity_src->EntityType == USBD_AUDIO_ENTITY_OT) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
(void)nbr_input_pins;
|
|
#endif
|
|
|
|
p_mu->SourceID_TblPtr = p_src_entity_id; /* Save unit and/or terminal IDs. */
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_SU_Assoc()
|
|
*
|
|
* Description : Specify the entities ID connected to this Selector Unit.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* su_id Selector Unit ID.
|
|
*
|
|
* p_src_entity_id Pointer to table containing IDs of Units and/or Terminals to which
|
|
* Input Pins of this Selector Unit are connected.
|
|
*
|
|
* nbr_input_pins Number of input pins.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Selector Unit successfully associated.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Null pointer passed to 'p_src_entity_id'.
|
|
* USBD_ERR_INVALID_ARG Output Terminal cannot be connected as input of
|
|
* a Selector Unit.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : none.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_SU > 0u)
|
|
void USBD_Audio_SU_Assoc (CPU_INT08U class_nbr,
|
|
CPU_INT08U su_id,
|
|
CPU_INT08U *p_src_entity_id,
|
|
CPU_INT08U nbr_input_pins,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_SU *p_su;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_src_entity_id == DEF_NULL) { /* Check src IDs ptr. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_su = (USBD_AUDIO_SU *)p_ctrl->EntityID_TblPtr[(su_id - 1u)];
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_INT08U ix;
|
|
CPU_INT08U entity_id_src;
|
|
USBD_AUDIO_ENTITY *p_entity_src;
|
|
|
|
for (ix = 0; ix < nbr_input_pins; ix++) {
|
|
entity_id_src = p_src_entity_id[ix];
|
|
p_entity_src = p_ctrl->EntityID_TblPtr[(entity_id_src - 1u)];
|
|
/* No OT can be connected as an input of SU. */
|
|
if (p_entity_src->EntityType == USBD_AUDIO_ENTITY_OT) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
(void)nbr_input_pins;
|
|
#endif
|
|
|
|
p_su->SourceID_TblPtr = p_src_entity_id; /* Save unit and/or terminal IDs. */
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_MU_MixingCtrlSet()
|
|
*
|
|
* Description : Set programmable mixing control.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* mu_id Mixer Unit ID.
|
|
*
|
|
* log_in_ch_nbr Logical input channel number.
|
|
*
|
|
* log_out_ch_nbr Logical output channel number.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Mixing control successfully set.
|
|
* USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR Mixer Unit API not provided.
|
|
*
|
|
* Return(s) : none.
|
|
*
|
|
* Note(s) : (1) See function USBD_Audio_AC_UnitCtrl() note #3.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_MAX_NBR_MU > 0u)
|
|
void USBD_Audio_MU_MixingCtrlSet (CPU_INT08U class_nbr,
|
|
CPU_INT08U mu_id,
|
|
CPU_INT08U log_in_ch_nbr,
|
|
CPU_INT08U log_out_ch_nbr,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_MU *p_mu;
|
|
CPU_INT08U byte_ix;
|
|
CPU_INT08U bit_shift;
|
|
CPU_INT32U bit_nbr;
|
|
|
|
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
{
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
/* ID used as a 0-index. */
|
|
p_mu = (USBD_AUDIO_MU *)p_ctrl->EntityID_TblPtr[(mu_id - 1u)];
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
/* If MU has programmable ctrls, API must be provided. */
|
|
if ((p_mu->MU_API_Ptr == DEF_NULL) &&
|
|
(p_mu->MU_API_Ptr->MU_CtrlManage == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
#endif
|
|
/* Set this mixing ctrl as programmable within... */
|
|
/* ...bitmap (see Note #1). */
|
|
bit_nbr = ((log_in_ch_nbr - 1u) * p_mu->MU_CfgPtr->LogOutChNbr) + (log_out_ch_nbr - 1u);
|
|
byte_ix = bit_nbr / DEF_OCTET_NBR_BITS;
|
|
bit_shift = bit_nbr % DEF_OCTET_NBR_BITS;
|
|
|
|
DEF_BIT_SET(p_mu->ControlsTblPtr[byte_ix], ((DEF_BIT_07) >> bit_shift));
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_IF_Cfg()
|
|
*
|
|
* Description : Configure AudioStreaming interface settings by:
|
|
*
|
|
* 1) Allocating an AudioStreaming Settings structure.
|
|
* 2) Initializing this structure with the stream information.
|
|
* 3) Allocating buffers that will be used by the given AudioStreaming interface.
|
|
*
|
|
* Argument(s) : p_stream_cfg Pointer to general stream configuration.
|
|
*
|
|
* p_as_if_cfg Pointer to AudioStreaming interface configuration structure.
|
|
*
|
|
* p_as_api Pointer to AudioStreaming interface API.
|
|
*
|
|
* p_seg Pointer to memory segment used for buffers allocation. If null pointer,
|
|
* buffers are allocated from the heap. Otherwise, buffers are allocated
|
|
* from a memory region created by the application.
|
|
*
|
|
* terminal_ID Terminal ID associated to this AudioStreaming interface.
|
|
*
|
|
* corr_callback Application callback for user-defined correction algorithm.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Buffers successfully allocated.
|
|
* USBD_ERR_NULL_PTR NULL pointer passed to 'p_as_if_cfg'/'p_as_api'/
|
|
* 'p_stream_cfg'.
|
|
* USBD_ERR_INVALID_ARG Invalid 'p_stream_cfg' or 'p_as_if_cfg' field.
|
|
* USBD_ERR_ALLOC AS IF Settings structure, buffers, events or audio
|
|
* statistics structure allocation failed.
|
|
*
|
|
* -RETURNED BY USBD_Audio_MaxPktLenGet()-
|
|
* See USBD_Audio_MaxPktLenGet() for additional return error codes.
|
|
*
|
|
* Return(s) : Handle to AudioStreaming interface, if NO error(s).
|
|
*
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : (1) Streams can be corrected using the following corrections: built-in (for playback
|
|
* and record) and feedback (for playback only).
|
|
* Playback and record streams correction rely on a buffers difference monitoring.
|
|
* The difference involves the rate at which the buffers are produced (by USB or codec)
|
|
* versus the rate at which they are consumed (by codec or USB). The buffers total
|
|
* number allocated for a stream is divided by 6. The quotient of this division
|
|
* represents an interval used to set different boundaries used for the stream
|
|
* correction. The following figure illustrates what the boundaries are depending
|
|
* of the correction method:
|
|
*
|
|
* Buffers Number 0 1 2 3 4 5 6 7 8 9 10 11 12
|
|
* Buffers Diff -6 -5 -4 -3 -2 -1 0 +1 +2 +3 +4 +5 +6
|
|
* | | | | | | |
|
|
* Boundary | heavy light light heavy |
|
|
* Built-In Corr | corr | safe zone | corr |
|
|
* Feedback Corr | correction | safe zone | correction |
|
|
*
|
|
* In the figure, the stream has 12 buffers. Thus, the quotient is 2. The heavy
|
|
* boundaries will be -4 and +4 for built-in and feedback corrections. The feedback
|
|
* correction uses two more light boundaries (here -2 and +2) to apply a progressive
|
|
* correction.
|
|
*
|
|
* (2) Allocation of audio buffers is done from a memory segment. This memory segment
|
|
* will be organized when the stream is open. When allocating the memory segment
|
|
* for the stream's audio buffers, the buffer's alignment must take into account
|
|
* any alignment to DMA and cache. The user must properly configure the constant
|
|
* USBD_AUDIO_CFG_BUF_ALIGN_OCTETS given any DMA and cache alignment requirements.
|
|
*
|
|
* (3) Pre-buffering is equal to half of buffers total number allocated for this stream.
|
|
* This pre-bufferring value eases the stream safe zone monitoring for the correction.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
USBD_AUDIO_AS_IF_HANDLE USBD_Audio_AS_IF_Cfg (const USBD_AUDIO_STREAM_CFG *p_stream_cfg,
|
|
const USBD_AUDIO_AS_IF_CFG *p_as_if_cfg,
|
|
const USBD_AUDIO_DRV_AS_API *p_as_api,
|
|
MEM_SEG *p_seg,
|
|
CPU_INT08U terminal_ID,
|
|
USBD_AUDIO_PLAYBACK_CORR_FNCT corr_callback,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_AS_IF_SETTINGS *p_as_if_settings;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
USBD_AUDIO_AS_IF_HANDLE as_if_handle;
|
|
USBD_AUDIO_STREAM_DIR stream_dir;
|
|
CPU_INT08U as_if_settings_ix;
|
|
CPU_INT16U mem_blk_len;
|
|
CPU_INT16U max_mem_blk_len;
|
|
CPU_INT16U mem_blk_len_worst;
|
|
CPU_INT08U as_alt_ix;
|
|
CPU_INT16U max_pkt_len;
|
|
LIB_ERR err_lib;
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
CPU_INT08U audio_frame_len;
|
|
#endif
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
CPU_INT32U max_sam_freq;
|
|
CPU_INT08U sam_freq_ix;
|
|
CPU_INT16U cur_max_throughput;
|
|
#endif
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_DISABLED)
|
|
(void)corr_callback;
|
|
#endif
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(DEF_NULL);
|
|
}
|
|
|
|
if (p_as_if_cfg == DEF_NULL) { /* Check ptr to AS IF cfg. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
if (p_as_api == DEF_NULL) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
if ((p_as_api->AS_SamplingFreqManage == DEF_NULL) || /* Any AS must provide minimally these fnct. */
|
|
(p_as_api->StreamStart == DEF_NULL) ||
|
|
(p_as_api->StreamStop == DEF_NULL)) {
|
|
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
#endif
|
|
|
|
if ((USBD_AUDIO_CFG_BUF_ALIGN_OCTETS < USBD_CFG_BUF_ALIGN_OCTETS) ||
|
|
((USBD_AUDIO_CFG_BUF_ALIGN_OCTETS % USBD_CFG_BUF_ALIGN_OCTETS) != 0u)) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
p_as_cfg = p_as_if_cfg->AS_CfgPtrTbl[0u];
|
|
stream_dir = (p_as_cfg->EP_DirIn == DEF_YES) ? USBD_AUDIO_STREAM_IN : USBD_AUDIO_STREAM_OUT;
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
/* If playback stream, associated fnct must be provided.*/
|
|
if ((stream_dir == USBD_AUDIO_STREAM_OUT) &&
|
|
(p_as_api->StreamPlaybackTx == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* If record stream, associated fnct must be provided. */
|
|
if ((stream_dir == USBD_AUDIO_STREAM_IN) &&
|
|
(p_as_api->StreamRecordRx == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* General stream cfg content check. */
|
|
if (p_stream_cfg == DEF_NULL) { /* Check ptr to general stream cfg struct. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* Ensure a min of buf w/o or w/ stream corr. */
|
|
if (p_stream_cfg->MaxBufNbr < USBD_AUDIO_STREAM_BUF_QTY_MIN) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
if (p_stream_cfg->CorrPeriodMs < 1u) { /* Corr period must be at least 1 ms. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* When stream corr en, max buf nbr must be multiple... */
|
|
/* ...of 6 to ensure proper corr oper (see Note #1). */
|
|
if ((p_stream_cfg->MaxBufNbr % USBD_AUDIO_STREAM_CORR_BOUNDARY_INTERVAL) != 0u) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
#endif
|
|
/* AS IF cfg content check. */
|
|
if (p_as_if_cfg->AS_CfgAltSettingNbr > USBD_AUDIO_CFG_MAX_NBR_IF_ALT) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* Check nbr of alt settings */
|
|
for (as_alt_ix = 0u; as_alt_ix < p_as_if_cfg->AS_CfgAltSettingNbr; as_alt_ix++) {
|
|
|
|
p_as_cfg = p_as_if_cfg->AS_CfgPtrTbl[as_alt_ix];
|
|
if (p_as_cfg == DEF_NULL) { /* Check ptr to AudioStreaming alt setting cfg. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
if ((p_as_cfg->NbrSamplingFreq != 0u) &&
|
|
(p_as_cfg->SamplingFreqTblPtr == DEF_NULL)) {
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
}
|
|
/* Verify that among all alt setting for given AS IF,...*/
|
|
/* ...max allowed Audio 1.0 throughput not exceeded. */
|
|
cur_max_throughput = 0u;
|
|
for (as_alt_ix = 0u; as_alt_ix < p_as_if_cfg->AS_CfgAltSettingNbr; as_alt_ix++) {
|
|
|
|
p_as_cfg = p_as_if_cfg->AS_CfgPtrTbl[as_alt_ix];
|
|
|
|
if (p_as_cfg->NbrSamplingFreq == 0u) {
|
|
max_sam_freq = p_as_cfg->UpperSamplingFreq;
|
|
} else {
|
|
max_sam_freq = 0u;
|
|
for(sam_freq_ix = 0u; sam_freq_ix < p_as_cfg->NbrSamplingFreq; sam_freq_ix++) {
|
|
if(p_as_cfg->SamplingFreqTblPtr[sam_freq_ix] > max_sam_freq) {
|
|
max_sam_freq = p_as_cfg->SamplingFreqTblPtr[sam_freq_ix];
|
|
}
|
|
}
|
|
}
|
|
|
|
cur_max_throughput = (max_sam_freq / DEF_TIME_NBR_mS_PER_SEC) * (p_as_cfg->BitRes / DEF_OCTET_NBR_BITS) * p_as_cfg->NbrCh;
|
|
|
|
if (cur_max_throughput > USBD_AUDIO_MAX_THROUGHPUT) {
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
}
|
|
#endif
|
|
/* --------------- AS IF SETTINGS ALLOC --------------- */
|
|
CPU_CRITICAL_ENTER();
|
|
as_if_settings_ix = USBD_Audio_AS_IF_SettingsNbrNext; /* Alloc new AS IF settings. */
|
|
if (as_if_settings_ix >= USBD_AUDIO_MAX_NBR_IF_ALT) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
USBD_Audio_AS_IF_SettingsNbrNext++; /* Next avail AS IF settings nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_as_if_settings = &USBD_Audio_AS_IF_SettingsTbl[as_if_settings_ix];
|
|
/* Returned to app for later use by audio class. */
|
|
as_if_handle = (USBD_AUDIO_AS_IF_HANDLE)p_as_if_settings;
|
|
|
|
/* ------------------ BUF POOL ALLOC ------------------ */
|
|
max_mem_blk_len = 0u;
|
|
/* Find largest buffer among all alt settings. */
|
|
for (as_alt_ix = 0u; as_alt_ix < p_as_if_cfg->AS_CfgAltSettingNbr; as_alt_ix++) {
|
|
|
|
p_as_cfg = p_as_if_cfg->AS_CfgPtrTbl[as_alt_ix];
|
|
max_pkt_len = USBD_Audio_MaxPktLenGet(p_as_cfg, /* Max pkt size. */
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* Max buf len. */
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
audio_frame_len = p_as_cfg->SubframeSize * p_as_cfg->NbrCh;
|
|
mem_blk_len = max_pkt_len + audio_frame_len;
|
|
#else
|
|
mem_blk_len = max_pkt_len;
|
|
#endif
|
|
|
|
if (mem_blk_len > max_mem_blk_len) { /* Keep largest buffer size among all alt settings. */
|
|
max_mem_blk_len = mem_blk_len;
|
|
}
|
|
}
|
|
|
|
/* See Note #2. */
|
|
mem_blk_len_worst = MATH_ROUND_INC_UP(max_mem_blk_len * (p_stream_cfg->ExtraPktTx + 1),
|
|
USBD_AUDIO_CFG_BUF_ALIGN_OCTETS);
|
|
p_as_if_settings->BufMemPtr = (CPU_INT08U *)Mem_HeapAlloc((mem_blk_len_worst * p_stream_cfg->MaxBufNbr),
|
|
USBD_AUDIO_CFG_BUF_ALIGN_OCTETS,
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* Alloc buf desc from heap. */
|
|
p_as_if_settings->StreamRingBufQ.BufDescTblPtr = (USBD_AUDIO_BUF_DESC *)Mem_HeapAlloc((sizeof(USBD_AUDIO_BUF_DESC) * p_stream_cfg->MaxBufNbr),
|
|
sizeof(CPU_ALIGN),
|
|
DEF_NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
/* --------------- AS IF SETTINGS INIT ---------------- */
|
|
p_as_if_settings->AS_API_Ptr = p_as_api;
|
|
p_as_if_settings->Ix = as_if_settings_ix;
|
|
p_as_if_settings->TerminalID = terminal_ID;
|
|
p_as_if_settings->BufTotalNbr = p_stream_cfg->MaxBufNbr;
|
|
p_as_if_settings->BufTotalLen = max_mem_blk_len * (p_stream_cfg->ExtraPktTx + 1);
|
|
p_as_if_settings->StreamDir = stream_dir;
|
|
p_as_if_settings->StreamStarted = DEF_NO;
|
|
/* See Note #3. */
|
|
p_as_if_settings->StreamPreBufMax = p_stream_cfg->MaxBufNbr / 2u;
|
|
p_as_if_settings->StreamPrimingDone = DEF_NO;
|
|
|
|
USBD_Audio_OS_RingBufQLockCreate(as_if_settings_ix, p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
p_as_if_settings->CorrPeriod = p_stream_cfg->CorrPeriodMs;
|
|
#endif
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_FEEDBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_CORR_EN == DEF_ENABLED)
|
|
p_as_if_settings->CorrBoundaryHeavyPos = (p_stream_cfg->MaxBufNbr / USBD_AUDIO_STREAM_CORR_BOUNDARY_INTERVAL) * 2u;
|
|
p_as_if_settings->CorrBoundaryHeavyNeg = p_as_if_settings->CorrBoundaryHeavyPos * -1;
|
|
#endif
|
|
|
|
if (stream_dir == USBD_AUDIO_STREAM_OUT) {
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED)
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_FEEDBACK_EN == DEF_ENABLED)
|
|
p_as_if_settings->PlaybackSynch.FeedbackValUpdate = DEF_NO;
|
|
|
|
/* Alloc synch buffs for AS IF. */
|
|
if ((((p_as_cfg->EP_SynchType & USBD_EP_TYPE_SYNC_MASK) == USBD_EP_TYPE_SYNC_ASYNC ) &&
|
|
( stream_dir == USBD_AUDIO_STREAM_OUT )) ||
|
|
(((p_as_cfg->EP_SynchType & USBD_EP_TYPE_SYNC_MASK) == USBD_EP_TYPE_SYNC_ADAPTIVE) &&
|
|
( stream_dir == USBD_AUDIO_STREAM_IN) )) {
|
|
|
|
p_as_if_settings->PlaybackSynch.SynchBufFree = DEF_YES;
|
|
p_as_if_settings->PlaybackSynch.SynchBufPtr = (CPU_INT32U *)Mem_HeapAlloc(sizeof(CPU_INT32U),
|
|
USBD_AUDIO_CFG_BUF_ALIGN_OCTETS,
|
|
DEF_NULL,
|
|
&err_lib);
|
|
|
|
p_as_if_settings->PlaybackSynch.SynchBoundaryLightPos = p_stream_cfg->MaxBufNbr / USBD_AUDIO_STREAM_CORR_BOUNDARY_INTERVAL;
|
|
p_as_if_settings->PlaybackSynch.SynchBoundaryLightNeg = p_as_if_settings->PlaybackSynch.SynchBoundaryLightPos * -1;
|
|
}
|
|
#endif
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_CORR_EN == DEF_ENABLED)
|
|
p_as_if_settings->CorrCallbackPtr = corr_callback;
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
#if (USBD_AUDIO_CFG_STAT_EN == DEF_ENABLED)
|
|
/* Alloc a stat struct from the heap. */
|
|
p_as_if_settings->StatPtr = (USBD_AUDIO_STAT *)Mem_HeapAlloc(sizeof(USBD_AUDIO_STAT),
|
|
sizeof(CPU_ALIGN),
|
|
NULL,
|
|
&err_lib);
|
|
if (err_lib != LIB_MEM_ERR_NONE) {
|
|
*p_err = USBD_ERR_ALLOC;
|
|
return ((USBD_AUDIO_AS_IF_HANDLE)0);
|
|
}
|
|
#endif
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
return (as_if_handle);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_IF_Add()
|
|
*
|
|
* Description : Add the AudioStreaming interface to the given configuration.
|
|
*
|
|
* Argument(s) : class_nbr Class instance number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* as_if_handle Handle to AudioStreaming interface.
|
|
*
|
|
* p_as_if_cfg Pointer to AudioStreaming interface configuration.
|
|
*
|
|
* p_as_cfg_name Pointer to AudioStreaming interface name.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE AudioStreaming interface successfully added.
|
|
USBD_ERR_CLASS_INVALID_NBR Invalid class number.
|
|
* USBD_ERR_NULL_PTR NULL pointer passed to 'p_as_if_cfg'.
|
|
* USBD_ERR_INVALID_ARG Invalid 'p_comm' retrieved from 'class_nbr'
|
|
* USBD_ERR_AUDIO_AS_IF_ALLOC No more AudioStreaming interface alternate
|
|
* setting available.
|
|
*
|
|
* -RETURNED BY USBD_Audio_AS_IF_Alloc()-
|
|
* See USBD_Audio_AS_IF_Alloc() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_IF_Add()-
|
|
* See USBD_IF_Add() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_IF_AltAdd()-
|
|
* See USBD_IF_AltAdd() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_Audio_MaxPktLenGet()-
|
|
* See USBD_Audio_MaxPktLenGet() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_IsocAdd()-
|
|
* See USBD_IsocAdd() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_IsocSyncAddrSet()-
|
|
* See USBD_IsocSyncAddrSet() for additional return error codes.
|
|
*
|
|
* -RETURNED BY USBD_IsocSyncRefreshSet()-
|
|
* See USBD_IsocSyncRefreshSet() for additional return error codes.
|
|
**
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 3.7.2 for more details about AudioStreaming Interface.
|
|
*
|
|
* (2) For FS, 1 ms = 1 frame. For HS, 1 ms = 8 microframes = 1 frame.
|
|
*
|
|
* (3) Regardless of the isochronous endpoint speed (full- or high-speed), the polling
|
|
* interval is always 1 ms with Audio 1.0. Hence, the number of transactions per frame
|
|
* will always be 1.
|
|
*
|
|
* (4) Feedback is restricted to Adaptive Source endpoint or Asynchronous Sink endpoint.
|
|
* If explicit synchronization mechanism is needed to maintain synchronization during
|
|
* transfers, the information carried over the synchronization path must be available
|
|
* every 2 ^ (10 - P) frames, with P ranging from 1 to 9 (512 ms down to 2 ms).
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 3.7.2.2 for more details about Isochronous Synch Endpoint.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
void USBD_Audio_AS_IF_Add ( CPU_INT08U class_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
USBD_AUDIO_AS_IF_HANDLE as_if_handle,
|
|
const USBD_AUDIO_AS_IF_CFG *p_as_if_cfg,
|
|
const CPU_CHAR *p_as_cfg_name,
|
|
USBD_ERR *p_err)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
CPU_INT08U if_nbr;
|
|
CPU_INT08U if_alt_nbr;
|
|
CPU_INT08U data_ep_addr;
|
|
CPU_INT08U as_alt_ix;
|
|
CPU_INT08U as_alt_ix_global;
|
|
CPU_INT16U interval;
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_FEEDBACK_EN == DEF_ENABLED)
|
|
USBD_AUDIO_STREAM_DIR stream_dir;
|
|
CPU_BOOLEAN synch_dir_in;
|
|
CPU_INT08U synch_ep_addr;
|
|
CPU_INT08U synch_ep_xfer_len;
|
|
#endif
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
#if (USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
/* ------------------- VALIDATE ARG ------------------- */
|
|
if (p_err == DEF_NULL) { /* Validate error ptr. */
|
|
CPU_SW_EXCEPTION(;);
|
|
}
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
if (class_nbr >= USBD_Audio_CtrlNbrNext) { /* Check Audio Class nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_CLASS_INVALID_NBR;
|
|
return;
|
|
}
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
if (p_as_if_cfg == DEF_NULL) { /* Check ptr to AS IF cfg. */
|
|
*p_err = USBD_ERR_NULL_PTR;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
p_ctrl = &USBD_Audio_CtrlTbl[class_nbr]; /* Get audio class instance. */
|
|
p_comm = USBD_Audio_CommGet(p_ctrl, cfg_nbr); /* Get comm struct. */
|
|
if (p_comm == DEF_NULL) { /* Check if the cfg exist. */
|
|
*p_err = USBD_ERR_INVALID_ARG;
|
|
return;
|
|
}
|
|
|
|
p_as_if = USBD_Audio_AS_IF_Alloc(p_err); /* Get AS IF struct. */
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* ---------------- AUDIO STREAMING IF ---------------- */
|
|
/* See Note #1. */
|
|
/* Add default AudioStreaming IF 0 to cfg. */
|
|
if_nbr = USBD_IF_Add( p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
&USBD_Audio_AS_Drv,
|
|
(void *)p_as_if,
|
|
DEF_NULL,
|
|
USBD_CLASS_CODE_AUDIO,
|
|
USBD_AUDIO_SUBCLASS_AUDIO_STREAMING,
|
|
0u,
|
|
"0-Bandwidth AudioStreaming Interface",
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* Store the required info for internal use. */
|
|
p_as_if->CommPtr = (USBD_AUDIO_COMM *)p_comm;
|
|
p_as_if->DevNbr = p_ctrl->DevNbr; /* Store dev nbr assigned by the core. */
|
|
p_as_if->ClassNbr = p_ctrl->ClassNbr; /* Store class instance nbr. */
|
|
p_as_if->AS_IF_Nbr = if_nbr; /* Store AudioStreaming IF nbr given by the core. */
|
|
p_as_if->AS_IF_SettingsPtr = (USBD_AUDIO_AS_IF_SETTINGS *)as_if_handle;
|
|
|
|
p_as_if->AS_IF_SettingsPtr->DrvInfoPtr = &p_ctrl->DrvInfo; /* Store audio drv info. */
|
|
|
|
/* Create a lock for this AudioStreaming IF. */
|
|
USBD_Audio_OS_AS_IF_LockCreate(USBD_AUDIO_AS_IF_HANDLE_IX_GET(p_as_if->Handle), p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* For Audio 1.0, isoc EP interval always 1 ms... */
|
|
/* ...(see Note #2). */
|
|
if (DEF_BIT_IS_CLR(cfg_nbr, USBD_CFG_NBR_SPD_BIT) == DEF_YES) {
|
|
interval = 1u; /* In FS, bInterval in frames. */
|
|
} else {
|
|
interval = 8u; /* In HS, bInterval in microframes. */
|
|
}
|
|
|
|
for (as_alt_ix = 0u; as_alt_ix < p_as_if_cfg->AS_CfgAltSettingNbr; as_alt_ix++) {
|
|
/* ------ AUDIO STREAMING IF ALTERNATIVE SETTING ------ */
|
|
/* Add operational alternate if to cfg. */
|
|
CPU_CRITICAL_ENTER();
|
|
as_alt_ix_global = USBD_Audio_AS_IF_AltNbrNext; /* Alloc new alt setting. */
|
|
|
|
if (as_alt_ix_global >= USBD_AUDIO_MAX_NBR_IF_ALT) {
|
|
CPU_CRITICAL_EXIT();
|
|
*p_err = USBD_ERR_AUDIO_AS_IF_ALLOC;
|
|
return;
|
|
}
|
|
|
|
USBD_Audio_AS_IF_AltNbrNext++; /* Next avail alt setting nbr. */
|
|
CPU_CRITICAL_EXIT();
|
|
|
|
p_as_if_alt = &USBD_Audio_AS_IF_AltTbl[as_alt_ix_global];
|
|
p_as_cfg = p_as_if_cfg->AS_CfgPtrTbl[as_alt_ix];
|
|
p_as_if_alt->AS_CfgPtr = p_as_cfg;
|
|
|
|
if_alt_nbr = USBD_IF_AltAdd( p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
(void *)p_as_if_alt,
|
|
p_as_cfg_name,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* -------------- MAXIMUM PACKET LENGTH --------------- */
|
|
p_as_if_alt->MaxPktLen = USBD_Audio_MaxPktLenGet(p_as_cfg,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* ----------- ISOCHRONOUS ENDPOINT ADDRESS ----------- */
|
|
/* Add Isoc EP to alternate IF 1. */
|
|
data_ep_addr = USBD_IsocAdd(p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
p_as_cfg->EP_DirIn,
|
|
p_as_cfg->EP_SynchType,
|
|
p_as_if_alt->MaxPktLen,
|
|
USBD_EP_TRANSACTION_PER_UFRAME_1, /* See Note #3. */
|
|
interval,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
p_as_if_alt->DataIsocAddr = data_ep_addr;
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_FEEDBACK_EN == DEF_ENABLED)
|
|
stream_dir = (p_as_cfg->EP_DirIn == DEF_YES) ? USBD_AUDIO_STREAM_IN : USBD_AUDIO_STREAM_OUT;
|
|
/* See Note #4. */
|
|
if ((((p_as_cfg->EP_SynchType & USBD_EP_TYPE_SYNC_MASK) == USBD_EP_TYPE_SYNC_ASYNC ) &&
|
|
( stream_dir == USBD_AUDIO_STREAM_OUT )) ||
|
|
(((p_as_cfg->EP_SynchType & USBD_EP_TYPE_SYNC_MASK) == USBD_EP_TYPE_SYNC_ADAPTIVE) &&
|
|
( stream_dir == USBD_AUDIO_STREAM_IN) )) {
|
|
|
|
/* Dir of Synch EP is the opposite of Data EP. */
|
|
synch_dir_in = (stream_dir == USBD_AUDIO_STREAM_IN) ? DEF_NO : DEF_YES;
|
|
|
|
/* Add Synch EP to alternate IF 1. */
|
|
if (DEF_BIT_IS_CLR(cfg_nbr, USBD_CFG_NBR_SPD_BIT) == DEF_YES) {
|
|
synch_ep_xfer_len = USBD_AUDIO_FS_SYNCH_EP_XFER_LEN;
|
|
} else {
|
|
synch_ep_xfer_len = USBD_AUDIO_HS_SYNCH_EP_XFER_LEN;
|
|
}
|
|
|
|
synch_ep_addr = USBD_IsocAdd(p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
synch_dir_in,
|
|
USBD_EP_TYPE_SYNC_NONE | USBD_EP_TYPE_USAGE_FEEDBACK,
|
|
synch_ep_xfer_len,
|
|
USBD_EP_TRANSACTION_PER_UFRAME_1, /* See Note #3. */
|
|
interval,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
/* Addr of Synch EP associated to Data EP. */
|
|
USBD_IsocSyncAddrSet(p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
data_ep_addr,
|
|
synch_ep_addr,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
|
|
p_as_if_alt->SynchIsocAddr = synch_ep_addr;
|
|
/* Indicate synch feedback data rate. */
|
|
USBD_IsocSyncRefreshSet(p_ctrl->DevNbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
synch_ep_addr,
|
|
p_as_cfg->EP_SynchRefresh,
|
|
p_err);
|
|
if (*p_err != USBD_ERR_NONE) {
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
/* ----------- SAVE AS IF STRUCT IN A LIST ------------ */
|
|
if (p_comm->AS_IF_HeadPtr == DEF_NULL) { /* First element of list. */
|
|
p_comm->AS_IF_HeadPtr = p_as_if;
|
|
} else {
|
|
p_comm->AS_IF_TailPtr->NextPtr = p_as_if; /* Element at the end of list. */
|
|
}
|
|
|
|
p_comm->AS_IF_TailPtr = p_as_if;
|
|
p_comm->AS_IF_Cnt++; /* Increment nbr of AudioStreaming IF. */
|
|
|
|
*p_err = USBD_ERR_NONE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_IF_StatGet()
|
|
*
|
|
* Description : Get the statistics structure associated to a given AudioStreaming interface.
|
|
*
|
|
* Argument(s) : as_handle AudioStreaming interface handle.
|
|
*
|
|
* Return(s) : Pointer to the audio stream statistics.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (USBD_AUDIO_CFG_STAT_EN == DEF_ENABLED)
|
|
USBD_AUDIO_STAT *USBD_Audio_AS_IF_StatGet (USBD_AUDIO_AS_HANDLE as_handle)
|
|
{
|
|
USBD_AUDIO_STAT *p_as_if_stat;
|
|
|
|
|
|
p_as_if_stat = USBD_Audio_StatGet(as_handle);
|
|
|
|
return (p_as_if_stat);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_Conn()
|
|
*
|
|
* Description : Notify class that configuration is active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_Audio_AC_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
|
|
p_comm = (USBD_AUDIO_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->CommPtr = p_comm;
|
|
p_ctrl->State = USBD_AUDIO_STATE_CFG;
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_Disconn()
|
|
*
|
|
* Description : Notify class that configuration is not active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_Audio_AC_Disconn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
CPU_SR_ALLOC();
|
|
|
|
|
|
p_comm = (USBD_AUDIO_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
{
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_IF_SETTINGS *p_as_if_settings;
|
|
CPU_INT08U i;
|
|
USBD_ERR err_usbd;
|
|
|
|
|
|
p_as_if = p_comm->AS_IF_HeadPtr;
|
|
p_as_if_settings = p_as_if->AS_IF_SettingsPtr;
|
|
|
|
for (i = 0u; i < p_comm->AS_IF_Cnt; i++) {
|
|
|
|
USBD_Audio_AS_IF_Stop(p_as_if,
|
|
&err_usbd);
|
|
if (err_usbd != USBD_ERR_NONE) {
|
|
USBD_DBG_AUDIO_ERR("AC_Disconn(): cannot stop stream on AS IF w/ err = %d\n", err_usbd);
|
|
}
|
|
|
|
p_as_if = p_as_if->NextPtr;
|
|
|
|
if (p_ctrl->EventFnctPtr->Disconn != DEF_NULL) { /* Notify app about cfg deactivation by host. */
|
|
p_ctrl->EventFnctPtr->Disconn(dev_nbr,
|
|
cfg_nbr,
|
|
p_as_if_settings->TerminalID,
|
|
p_as_if->Handle);
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
#endif
|
|
|
|
CPU_CRITICAL_ENTER();
|
|
p_ctrl->CommPtr = DEF_NULL;
|
|
p_ctrl->State = USBD_AUDIO_STATE_INIT;
|
|
CPU_CRITICAL_EXIT();
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_IF_Desc()
|
|
*
|
|
* Description : Class interface control descriptor callback for AudioControl interface.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2 for more details about Class-Specific AC Interface Descriptor.
|
|
*
|
|
* (2) Total number of bytes returned for the class-specific AudioControl interface
|
|
* descriptor. It includes the combined length of this descriptor header and all Unit
|
|
* and Terminal descriptors.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 4-2, 'wTotalLength' field description for more details.
|
|
*
|
|
* (3) Audio 1.0 specification does NOT define a specific order for the class-specific
|
|
* descriptors following the AudioControl interface.
|
|
*
|
|
* (4) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2.1 for more details about Input Terminal Descriptor.
|
|
*
|
|
* (5) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2.2 for more details about Output Terminal Descriptor.
|
|
*
|
|
* (6) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2.5 for more details about Feature Unit Descriptor.
|
|
*
|
|
* (a) The size of the Feature Unit Descriptor corresponds to 7+(ch+1)*n where ch is
|
|
* number of logical channels and n is the size in bytes of each bmaControls.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 4-7, 'bLength' field description for more details.
|
|
*
|
|
* (7) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2.3 for more details about Mixer Unit Descriptor.
|
|
*
|
|
* (a) The size of the Mixer Unit Descriptor corresponds to 10+p+N where p is the number
|
|
* of Input Pins and N is the number of bytes to use to store the bit Array.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 4-5, 'bLength' field description for more details.
|
|
*
|
|
* (8) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.3.2.4 for more details about Selector Unit Descriptor.
|
|
*
|
|
* (a) The size of the Selector Unit Descriptor corresponds to 6+p where p is number of
|
|
* Input Pins.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 4-6, 'bLength' field description for more details.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void USBD_Audio_AC_IF_Desc (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_IT *p_it;
|
|
USBD_AUDIO_OT *p_ot;
|
|
USBD_AUDIO_FU *p_fu;
|
|
USBD_AUDIO_MU *p_mu;
|
|
USBD_AUDIO_SU *p_su;
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_IT_CFG *p_it_cfg;
|
|
USBD_AUDIO_OT_CFG *p_ot_cfg;
|
|
USBD_AUDIO_FU_CFG *p_fu_cfg;
|
|
USBD_AUDIO_MU_CFG *p_mu_cfg;
|
|
USBD_AUDIO_SU_CFG *p_su_cfg;
|
|
CPU_INT08U desc_size;
|
|
CPU_INT16U total_len;
|
|
CPU_INT08U ix;
|
|
CPU_INT08U ctrl_ix;
|
|
CPU_INT08U src_ix;
|
|
CPU_INT08U str_ix;
|
|
USBD_AUDIO_ENTITY_TYPE entity_type;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)if_alt_nbr;
|
|
(void)p_if_alt_class_arg;
|
|
|
|
p_comm = (USBD_AUDIO_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
/* ----------------- AC IF HEADER DESC ---------------- */
|
|
/* See Note #1. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_AC_HEADER_MIN + p_comm->AS_IF_Cnt;
|
|
USBD_DescWr08(p_ctrl->DevNbr, desc_size);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_AC_HEADER);
|
|
USBD_DescWr16(p_ctrl->DevNbr, 0x0100u);
|
|
|
|
total_len = USBD_Audio_AC_IF_DescSizeGet(dev_nbr,
|
|
cfg_nbr,
|
|
if_nbr,
|
|
if_alt_nbr,
|
|
p_if_class_arg,
|
|
p_if_alt_class_arg);
|
|
USBD_DescWr16(p_ctrl->DevNbr, total_len); /* See Note #2. */
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_comm->AS_IF_Cnt);
|
|
p_as_if = p_comm->AS_IF_HeadPtr;
|
|
for (ix = 0u; ix < p_comm->AS_IF_Cnt; ix++) {
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_as_if->AS_IF_Nbr);
|
|
p_as_if = p_as_if->NextPtr;
|
|
}
|
|
|
|
for (ix = 0u; ix < p_ctrl->EntityCnt; ix++) {
|
|
|
|
entity_type = p_ctrl->EntityID_TblPtr[ix]->EntityType;
|
|
|
|
switch (entity_type) { /* See Note #3. */
|
|
case USBD_AUDIO_ENTITY_IT: /* ---------------- INPUT TERMINAL DESC --------------- */
|
|
/* See Note #4. */
|
|
p_it = (USBD_AUDIO_IT *)p_ctrl->EntityID_TblPtr[ix];
|
|
p_it_cfg = p_it->IT_CfgPtr;
|
|
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_LEN_AC_IT);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_IT);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_it->ID);
|
|
USBD_DescWr16(p_ctrl->DevNbr, p_it_cfg->TerminalType);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_it->AssociatedOT_ID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_it_cfg->LogChNbr);
|
|
USBD_DescWr16(p_ctrl->DevNbr, p_it_cfg->LogChCfg);
|
|
USBD_DescWr08(p_ctrl->DevNbr, 0u);
|
|
str_ix = USBD_StrIxGet(p_ctrl->DevNbr, p_it_cfg->StrPtr);
|
|
USBD_DescWr08(p_ctrl->DevNbr, str_ix);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_OT: /* ---------------- OUTPUT TERMINAL DESC -------------- */
|
|
/* See Note #5. */
|
|
p_ot = (USBD_AUDIO_OT *)p_ctrl->EntityID_TblPtr[ix];
|
|
p_ot_cfg = p_ot->OT_CfgPtr;
|
|
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_LEN_AC_OT);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_OT);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_ot->ID);
|
|
USBD_DescWr16(p_ctrl->DevNbr, p_ot_cfg->TerminalType);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_ot->AssociatedIT_ID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_ot->SourceID);
|
|
str_ix = USBD_StrIxGet(p_ctrl->DevNbr, p_ot_cfg->StrPtr);
|
|
USBD_DescWr08(p_ctrl->DevNbr, str_ix);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_FU: /* ---------------- FEATURE UNIT DESC ----------------- */
|
|
/* See Note #6. */
|
|
p_fu = (USBD_AUDIO_FU *)p_ctrl->EntityID_TblPtr[ix];
|
|
p_fu_cfg = p_fu->FU_CfgPtr;
|
|
/* See Note #6a. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_AC_FU_MIN + (p_fu_cfg->LogChNbr + 1) * 2u;
|
|
USBD_DescWr08(p_ctrl->DevNbr, desc_size);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_FU);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_fu->ID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_fu->SourceID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, 2u);
|
|
for (ctrl_ix = 0; ctrl_ix < (p_fu_cfg->LogChNbr + 1); ctrl_ix++) {
|
|
USBD_DescWr16(p_ctrl->DevNbr, p_fu_cfg->LogChCtrlPtr[ctrl_ix]);
|
|
}
|
|
str_ix = USBD_StrIxGet(p_ctrl->DevNbr, p_fu_cfg->StrPtr);
|
|
USBD_DescWr08(p_ctrl->DevNbr, str_ix);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_MU: /* ----------------- MIXER UNIT DESC ------------------ */
|
|
/* See Note #7. */
|
|
p_mu = (USBD_AUDIO_MU *)p_ctrl->EntityID_TblPtr[ix];
|
|
p_mu_cfg = p_mu->MU_CfgPtr;
|
|
|
|
/* See Note #7a. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_AC_MU_MIN + p_mu_cfg->NbrInPins + p_mu->ControlsSize;
|
|
USBD_DescWr08(p_ctrl->DevNbr, desc_size);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_MU);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_mu->ID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_mu_cfg->NbrInPins);
|
|
for (src_ix = 0u; src_ix < p_mu_cfg->NbrInPins; src_ix++) {
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_mu->SourceID_TblPtr[src_ix]);
|
|
}
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_mu_cfg->LogOutChNbr);
|
|
USBD_DescWr16(p_ctrl->DevNbr, p_mu_cfg->LogOutChCfg);
|
|
USBD_DescWr08(p_ctrl->DevNbr, 0u);
|
|
for (ctrl_ix = 0u; ctrl_ix < p_mu->ControlsSize; ctrl_ix++) {
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_mu->ControlsTblPtr[ctrl_ix]);
|
|
}
|
|
str_ix = USBD_StrIxGet(p_ctrl->DevNbr, p_mu_cfg->StrPtr);
|
|
USBD_DescWr08(p_ctrl->DevNbr, str_ix);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_SU: /* ---------------- SELECTOR UNIT DESC ---------------- */
|
|
/* See Note #8. */
|
|
p_su = (USBD_AUDIO_SU *)p_ctrl->EntityID_TblPtr[ix];
|
|
p_su_cfg = p_su->SU_CfgPtr;
|
|
|
|
/* See Note #8a. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_AC_SU_MIN + p_su_cfg->NbrInPins;
|
|
USBD_DescWr08(p_ctrl->DevNbr, desc_size);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_ctrl->DevNbr, USBD_AUDIO_DESC_SUBTYPE_SU);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_su->ID);
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_su_cfg->NbrInPins);
|
|
for (src_ix = 0u; src_ix < p_su_cfg->NbrInPins; src_ix++) {
|
|
USBD_DescWr08(p_ctrl->DevNbr, p_su->SourceID_TblPtr[src_ix]);
|
|
}
|
|
str_ix = USBD_StrIxGet(p_ctrl->DevNbr, p_su_cfg->StrPtr);
|
|
USBD_DescWr08(p_ctrl->DevNbr, str_ix);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_IF_DescSizeGet()
|
|
*
|
|
* Description : Retrieve the size of the class interface descriptor for AudioControl interface.
|
|
* (See Note #1.)
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
|
|
*
|
|
* Return(s) : Size of the class interface descriptor.
|
|
*
|
|
* Note(s) : (1) Total number of bytes returned for the class-specific AudioControl interface
|
|
* descriptor. It includes the combined length of this descriptor header and all Unit
|
|
* and Terminal descriptors.
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* Table 4-2, 'wTotalLength' field description for more details.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_INT16U USBD_Audio_AC_IF_DescSizeGet (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_FU *p_fu;
|
|
USBD_AUDIO_MU *p_mu;
|
|
USBD_AUDIO_SU *p_su;
|
|
CPU_INT16U desc_size;
|
|
CPU_INT08U ix;
|
|
USBD_AUDIO_ENTITY_TYPE entity_type;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)if_alt_nbr;
|
|
(void)p_if_alt_class_arg;
|
|
|
|
p_comm = (USBD_AUDIO_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
|
|
desc_size = USBD_AUDIO_DESC_LEN_AC_HEADER_MIN + p_comm->AS_IF_Cnt;
|
|
|
|
for (ix = 0u; ix < p_ctrl->EntityCnt; ix++) {
|
|
|
|
entity_type = p_ctrl->EntityID_TblPtr[ix]->EntityType;
|
|
|
|
switch (entity_type) {
|
|
case USBD_AUDIO_ENTITY_IT:
|
|
desc_size += USBD_AUDIO_DESC_LEN_AC_IT;
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_OT:
|
|
desc_size += USBD_AUDIO_DESC_LEN_AC_OT;
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_FU:
|
|
p_fu = (USBD_AUDIO_FU *)p_ctrl->EntityID_TblPtr[ix];
|
|
desc_size += (USBD_AUDIO_DESC_LEN_AC_FU_MIN + (p_fu->FU_CfgPtr->LogChNbr + 1u) * 2u);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_MU:
|
|
p_mu = (USBD_AUDIO_MU *)p_ctrl->EntityID_TblPtr[ix];
|
|
desc_size += (USBD_AUDIO_DESC_LEN_AC_MU_MIN + p_mu->MU_CfgPtr->NbrInPins + p_mu->ControlsSize);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_SU:
|
|
p_su = (USBD_AUDIO_SU *)p_ctrl->EntityID_TblPtr[ix];
|
|
desc_size += (USBD_AUDIO_DESC_LEN_AC_SU_MIN + p_su->SU_CfgPtr->NbrInPins);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (desc_size);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_ClassReq()
|
|
*
|
|
* Description : Process class-specific requests for AudioControl interface. (see Note #1)
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* p_setup_req Pointer to setup request structure.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : DEF_OK, if NO error(s) occurred and request is supported.
|
|
*
|
|
* DEF_FAIL, otherwise.
|
|
*
|
|
* Note(s) : (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.2 for more details about AudioControl Requests.
|
|
*
|
|
* (2) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.1.1 for more details about Set Request.
|
|
*
|
|
* (3) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.1.2 for more details about Get Request.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static CPU_BOOLEAN USBD_Audio_AC_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_ERR err;
|
|
USBD_AUDIO_ENTITY_TYPE recipient;
|
|
void *p_recipient_info;
|
|
CPU_INT08U entity_id;
|
|
CPU_INT16U req_len;
|
|
CPU_BOOLEAN dev_to_host;
|
|
|
|
|
|
switch (p_setup_req->bRequest) { /* Discard class req not supported by this class. */
|
|
case USBD_AUDIO_REQ_GET_CUR:
|
|
case USBD_AUDIO_REQ_GET_MIN:
|
|
case USBD_AUDIO_REQ_GET_MAX:
|
|
case USBD_AUDIO_REQ_GET_RES:
|
|
case USBD_AUDIO_REQ_SET_CUR:
|
|
case USBD_AUDIO_REQ_SET_MIN:
|
|
case USBD_AUDIO_REQ_SET_MAX:
|
|
case USBD_AUDIO_REQ_SET_RES:
|
|
break;
|
|
|
|
case USBD_AUDIO_REQ_GET_STAT:
|
|
case USBD_AUDIO_REQ_GET_MEM:
|
|
case USBD_AUDIO_REQ_SET_MEM:
|
|
default:
|
|
return (DEF_FAIL); /* Class req not supported. Ctrl EP will be stalled. */
|
|
}
|
|
|
|
req_len = p_setup_req->wLength; /* Length of param block. */
|
|
if (req_len > USBD_AUDIO_CFG_CLASS_REQ_MAX_LEN) { /* Check if enough room to process class req data. */
|
|
return (DEF_FAIL);
|
|
}
|
|
|
|
p_comm = (USBD_AUDIO_COMM *)p_if_class_arg;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
dev_to_host = DEF_BIT_IS_SET(p_setup_req->bmRequestType, USBD_REQ_DIR_BIT);
|
|
entity_id = (p_setup_req->wIndex & USBD_AUDIO_REQ_ENTITY_ID_MASK) >> 8u;
|
|
p_recipient_info = USBD_Audio_AC_RecipientGet(p_ctrl, entity_id, &recipient);
|
|
|
|
if (recipient == USBD_AUDIO_ENTITY_UNKNOWN) {
|
|
return (DEF_FAIL);
|
|
}
|
|
/* -------------------- SET REQUEST ------------------- */
|
|
/* See Note #2. */
|
|
if (dev_to_host == DEF_NO) {
|
|
USBD_CtrlRx( dev_nbr, /* Receive param block from host. */
|
|
(void *)p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
USBD_AUDIO_CTRL_REQ_TIMEOUT_mS,
|
|
&err);
|
|
if (err != USBD_ERR_NONE) {
|
|
USBD_DBG_AUDIO_ERR("AC (SET req): Ctrl Rx fails w/ err = %d\n", err);
|
|
return (DEF_FAIL);
|
|
}
|
|
}
|
|
/* ------------------ REQ EXECUTION ------------------- */
|
|
switch (recipient) {
|
|
case USBD_AUDIO_ENTITY_IT:
|
|
case USBD_AUDIO_ENTITY_OT:
|
|
USBD_Audio_AC_TerminalCtrl(entity_id,
|
|
recipient,
|
|
p_recipient_info,
|
|
p_setup_req->bRequest,
|
|
p_setup_req->wValue,
|
|
p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
&err);
|
|
break;
|
|
|
|
|
|
case USBD_AUDIO_ENTITY_FU:
|
|
case USBD_AUDIO_ENTITY_MU:
|
|
case USBD_AUDIO_ENTITY_SU:
|
|
USBD_Audio_AC_UnitCtrl(entity_id,
|
|
recipient,
|
|
p_recipient_info,
|
|
p_setup_req->bRequest,
|
|
p_setup_req->wValue,
|
|
p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
&err);
|
|
break;
|
|
|
|
|
|
default:
|
|
err = USBD_ERR_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_FAIL);
|
|
}
|
|
/* -------------------- GET REQUESTS ------------------ */
|
|
/* See Note #3. */
|
|
if (dev_to_host == DEF_YES) {
|
|
USBD_CtrlTx( dev_nbr, /* Send param block to host. */
|
|
(void *)p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
USBD_AUDIO_CTRL_REQ_TIMEOUT_mS,
|
|
DEF_NO,
|
|
&err);
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_FAIL);
|
|
}
|
|
}
|
|
|
|
return (DEF_OK);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_Conn()
|
|
*
|
|
* Description : Notify class that configuration is active.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static void USBD_Audio_AS_Conn (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
|
|
|
|
p_as_if = (USBD_AUDIO_AS_IF *)p_if_class_arg;
|
|
p_ctrl = p_as_if->CommPtr->CtrlPtr;
|
|
/* Notify app about cfg activation by host. */
|
|
if (p_ctrl->EventFnctPtr->Conn != DEF_NULL) {
|
|
p_ctrl->EventFnctPtr->Conn(dev_nbr,
|
|
cfg_nbr,
|
|
p_as_if->AS_IF_SettingsPtr->TerminalID,
|
|
p_as_if->Handle);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_AltSettingUpdate()
|
|
*
|
|
* Description : Notify class that interface alternate setting has been updated.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static void USBD_Audio_AS_AltSettingUpdate (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
USBD_AUDIO_AS_IF_SETTINGS *p_as_if_settings;
|
|
USBD_ERR err_usbd;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
|
|
p_as_if = (USBD_AUDIO_AS_IF *)p_if_class_arg;
|
|
p_as_if_alt = (USBD_AUDIO_AS_IF_ALT *)p_if_alt_class_arg;
|
|
p_as_if_settings = p_as_if->AS_IF_SettingsPtr;
|
|
|
|
if (p_as_if->AS_IF_Nbr == 0u) { /* Should not be an AudioControl interface. */
|
|
return;
|
|
}
|
|
/* Stop current streaming on specified IF nbr if a ... */
|
|
/* ...previous one was already started. */
|
|
if (p_as_if->AS_IF_AltCurPtr != DEF_NULL) {
|
|
|
|
USBD_Audio_AS_IF_Stop(p_as_if,
|
|
&err_usbd);
|
|
if (err_usbd != USBD_ERR_NONE) {
|
|
USBD_DBG_AUDIO_ERR("AS_UpdateAltSetting(): cannot stop stream on AS IF w/ err = %d\n", err_usbd);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (if_alt_nbr == 0u) { /* Default IF has NO EP. */
|
|
p_as_if->AS_IF_AltCurPtr = DEF_NULL; /* Reset the current alt setting. */
|
|
|
|
} else { /* Operational IF. */
|
|
p_as_if->AS_IF_AltCurPtr = p_as_if_alt; /* Select Isoc EP associated with specified alt nbr. */
|
|
/* Start streaming on new alt setting. */
|
|
if (p_as_if_settings->StreamDir == USBD_AUDIO_STREAM_OUT) {
|
|
|
|
USBD_Audio_AS_IF_Start(p_as_if,
|
|
&err_usbd);
|
|
if (err_usbd != USBD_ERR_NONE) {
|
|
USBD_DBG_AUDIO_ERR("AS_UpdateAltSetting(): cannot start stream on AS IF w/ err = %d\n", err_usbd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_IF_Desc()
|
|
*
|
|
* Description : Class interface descriptor callback for AudioStreaming interface.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) AudioStreaming interface alternate setting 0 is a zero-bandwidth interface. It is not
|
|
* followed by class-specific descriptors.
|
|
* See 'USB Audio Device Class Specification for Basic Audio Devices, Release 1.0,
|
|
* November 24, 2009', section 5.3.3.3.1 for more details.
|
|
*
|
|
* (2) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.5.2 for more details about Class-Specific AS Interface Descriptor.
|
|
*
|
|
* (3) See 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18, 1998',
|
|
* section 2.2.5 for more details about Type I Format Type Descriptor.
|
|
*
|
|
* (a) Size of the descriptor correspond to 8+(ns*3) where ns is the number of sampling
|
|
* frequencies.
|
|
* See 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18, 1998',
|
|
* Table 2-1, 'bLength' field description for more details.
|
|
*
|
|
* (4) A sampling frequency value holds on 3 bytes according to Audio 1.0 specification.
|
|
* The use of a temporary buffer ensures to correctly write the sampling frequency value
|
|
* into the descriptor Type I Format descriptor regardless of the CPU endianness.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static void USBD_Audio_AS_IF_Desc (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
CPU_INT08U desc_size;
|
|
CPU_INT08U sam_freq_ix;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
|
|
if (if_alt_nbr == 0u) {
|
|
return; /* See Note #1. */
|
|
}
|
|
|
|
p_as_if = (USBD_AUDIO_AS_IF *)p_if_class_arg;
|
|
p_as_if_alt = (USBD_AUDIO_AS_IF_ALT *)p_if_alt_class_arg;
|
|
p_as_cfg = p_as_if_alt->AS_CfgPtr;
|
|
|
|
/* ----------------- AS IF GENERAL DESC --------------- */
|
|
/* See Note #2. */
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_LEN_AS_GENERAL);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_SUBTYPE_AS_GENERAL);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_if->AS_IF_SettingsPtr->TerminalID);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->Dly);
|
|
USBD_DescWr16(p_as_if->DevNbr, p_as_cfg->FmtTag);
|
|
/* ------------------ TYPE I FMT DESC ----------------- */
|
|
/* See Note #3 & 3a. */
|
|
if (p_as_cfg->NbrSamplingFreq == 0u) { /* Continuous sampling freq. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_TYPE_I_FMT_MIN + (USBD_AUDIO_FMT_TYPE_I_CONT_FREQ_NBR * USBD_AUDIO_DESC_LEN_TYPE_I_SAM_FREQ);
|
|
} else { /* Discrete sampling frequencies. */
|
|
desc_size = USBD_AUDIO_DESC_LEN_TYPE_I_FMT_MIN + (p_as_cfg->NbrSamplingFreq * USBD_AUDIO_DESC_LEN_TYPE_I_SAM_FREQ);
|
|
}
|
|
|
|
USBD_DescWr08(p_as_if->DevNbr, desc_size);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_TYPE_CS_IF);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_SUBTYPE_FMT_TYPE);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_FMT_TYPE_I);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->NbrCh);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->SubframeSize);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->BitRes);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->NbrSamplingFreq);
|
|
|
|
if (p_as_cfg->NbrSamplingFreq == 0u) { /* Continuous sampling freq (see Note #4). */
|
|
|
|
USBD_DescWr24(p_as_if->DevNbr, p_as_cfg->LowerSamplingFreq);
|
|
USBD_DescWr24(p_as_if->DevNbr, p_as_cfg->UpperSamplingFreq);
|
|
|
|
} else { /* Discrete sampling frequencies (see Note #4). */
|
|
for (sam_freq_ix = 0u; sam_freq_ix < p_as_cfg->NbrSamplingFreq; sam_freq_ix++) {
|
|
|
|
USBD_DescWr24(p_as_if->DevNbr, p_as_cfg->SamplingFreqTblPtr[sam_freq_ix]);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_IF_DescSizeGet()
|
|
*
|
|
* Description : Retrieve the size of the class interface descriptor for AudioStreaming interface.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : Size of the class interface descriptor.
|
|
*
|
|
* Note(s) : (1) See 'USB Device Class Definition for Audio Data Formats, Release 1.0, March 18, 1998',
|
|
* section 2.2.5 for more details about Type I Format Type Descriptor.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static CPU_INT16U USBD_Audio_AS_IF_DescSizeGet (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
CPU_INT16U desc_size;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)p_if_class_arg;
|
|
|
|
if (if_alt_nbr == 0u) { /* Alt setting 0 has no class-specific desc. */
|
|
return (0u);
|
|
}
|
|
|
|
p_as_if_alt = (USBD_AUDIO_AS_IF_ALT *)p_if_alt_class_arg;
|
|
p_as_cfg = p_as_if_alt->AS_CfgPtr;
|
|
desc_size = USBD_AUDIO_DESC_LEN_AS_GENERAL;
|
|
|
|
if (p_as_cfg->NbrSamplingFreq == 0u) { /* Continuous sampling freq. */
|
|
desc_size += (USBD_AUDIO_DESC_LEN_TYPE_I_FMT_MIN + (USBD_AUDIO_FMT_TYPE_I_CONT_FREQ_NBR * USBD_AUDIO_DESC_LEN_TYPE_I_SAM_FREQ));
|
|
} else { /* Discrete sampling frequencies. */
|
|
/* See Note #1. */
|
|
desc_size += (USBD_AUDIO_DESC_LEN_TYPE_I_FMT_MIN + (p_as_cfg->NbrSamplingFreq * USBD_AUDIO_DESC_LEN_TYPE_I_SAM_FREQ));
|
|
}
|
|
|
|
return (desc_size);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* USBD_Audio_AS_EP_Desc()
|
|
*
|
|
* Description : Write class-specific endpoint descriptor for AudioStreaming interface.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* ep_addr Endpoint address.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Note(s) : (1) AudioStreaming interface alternate setting 0 has NO endpoints.
|
|
* See 'USB Audio Device Class Specification for Basic Audio Devices, Release 1.0,
|
|
* November 24, 2009', section 5.3.3.3.1 for more details.
|
|
*
|
|
* (2) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 4.6.1.2 for more details about Class-Specific AS Isochronous Audio Data
|
|
* Endpoint Descriptor.
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static void USBD_Audio_AS_EP_Desc (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
|
|
if (if_alt_nbr == 0u) {
|
|
return; /* See Note #1. */
|
|
}
|
|
|
|
p_as_if = (USBD_AUDIO_AS_IF *)p_if_class_arg;
|
|
p_as_if_alt = (USBD_AUDIO_AS_IF_ALT *)p_if_alt_class_arg;
|
|
|
|
if (p_as_if_alt->SynchIsocAddr == ep_addr) { /* Synch EP does NOT have class-specific desc. */
|
|
return;
|
|
}
|
|
|
|
p_as_cfg = p_as_if_alt->AS_CfgPtr;
|
|
/* -------------- DATA EP GENERAL DESC ---------------- */
|
|
/* See Note #2. */
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_LEN_EP_GENERAL);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_TYPE_CS_EP);
|
|
USBD_DescWr08(p_as_if->DevNbr, USBD_AUDIO_DESC_SUBTYPE_EP_GENERAL);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->EP_Attrib);
|
|
USBD_DescWr08(p_as_if->DevNbr, p_as_cfg->EP_LockDlyUnits);
|
|
USBD_DescWr16(p_as_if->DevNbr, p_as_cfg->EP_LockDly);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
**********************************************************************************************************
|
|
* USBD_Audio_AS_EP_DescSizeGet()
|
|
*
|
|
* Description : Return size of class-specific endpoint descriptor for AudioStreaming interface.
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* cfg_nbr Configuration number.
|
|
*
|
|
* if_nbr Interface number.
|
|
*
|
|
* if_alt_nbr Interface alternate setting number.
|
|
*
|
|
* ep_addr Endpoint address.
|
|
*
|
|
* p_if_class_arg Pointer to class argument specific to interface.
|
|
*
|
|
* p_if_alt_class_arg Pointer to class argument specific to alternate interface.
|
|
*
|
|
* Return(s) : Size of class-specific endpoint descriptor in octets.
|
|
*
|
|
* Note(s) : None.
|
|
**********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static CPU_INT16U USBD_Audio_AS_EP_DescSizeGet (CPU_INT08U dev_nbr,
|
|
CPU_INT08U cfg_nbr,
|
|
CPU_INT08U if_nbr,
|
|
CPU_INT08U if_alt_nbr,
|
|
CPU_INT08U ep_addr,
|
|
void *p_if_class_arg,
|
|
void *p_if_alt_class_arg)
|
|
{
|
|
CPU_INT16U desc_size;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_if_alt;
|
|
|
|
|
|
(void)dev_nbr;
|
|
(void)cfg_nbr;
|
|
(void)if_nbr;
|
|
(void)p_if_class_arg;
|
|
|
|
if (if_alt_nbr == 0u) { /* Alt setting 0 has no class-specific desc. */
|
|
return (0u);
|
|
}
|
|
|
|
p_as_if_alt = (USBD_AUDIO_AS_IF_ALT *)p_if_alt_class_arg;
|
|
|
|
if (p_as_if_alt->SynchIsocAddr == ep_addr) { /* Synch EP does NOT have class-specific desc. */
|
|
return (0u);
|
|
}
|
|
|
|
desc_size = USBD_AUDIO_DESC_LEN_EP_GENERAL;
|
|
|
|
return (desc_size);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AS_ClassReq()
|
|
*
|
|
* Description : Process class-specific requests for AudioStreaming interface (see Note #1).
|
|
*
|
|
* Argument(s) : dev_nbr Device number.
|
|
*
|
|
* p_setup_req Pointer to setup request structure.
|
|
*
|
|
* p_if_class_arg Pointer to class argument.
|
|
*
|
|
* Return(s) : DEF_OK, if NO error(s) occurred and request is supported.
|
|
*
|
|
* DEF_FAIL, otherwise.
|
|
*
|
|
* Note(s) : (1) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.1.1 for more details about Set Request.
|
|
*
|
|
* (2) Requests intended for the AudioStreaming interface deals ONLY with audio data format-
|
|
* specific requests. Depending on the Audio Data Format used by the interface
|
|
* (reflected in the wFormatTag field of the class-specific AS interface descriptor),
|
|
* the set of requests to control the interface may vary.
|
|
* According to 'USB Device Class Definition for Audio Data Formats, Release 1.0,
|
|
* March 18, 1998' specification, Type I data format does not define any AudioStreaming
|
|
* interface requests. Since the current Audio class implementation supports only Type I
|
|
* data format , all the requests will be stalled.
|
|
*
|
|
* See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.3.1 for more details about AudioStreaming interface Control requests.
|
|
*
|
|
* (3) See 'USB Device Class Definition for Audio Devices, Release 1.0, March 18, 1998',
|
|
* section 5.2.1.2 for more details about Get Request.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static CPU_BOOLEAN USBD_Audio_AS_ClassReq ( CPU_INT08U dev_nbr,
|
|
const USBD_SETUP_REQ *p_setup_req,
|
|
void *p_if_class_arg)
|
|
{
|
|
USBD_AUDIO_COMM *p_comm;
|
|
USBD_AUDIO_CTRL *p_ctrl;
|
|
USBD_AUDIO_AS_ALT_CFG *p_as_cfg;
|
|
USBD_AUDIO_AS_IF *p_as_if;
|
|
USBD_AUDIO_AS_IF_ALT *p_as_alt;
|
|
USBD_ERR err = USBD_ERR_NONE;
|
|
CPU_INT08U recipient;
|
|
CPU_INT16U req_len;
|
|
CPU_BOOLEAN dev_to_host;
|
|
CPU_INT16U ep_addr;
|
|
|
|
|
|
switch (p_setup_req->bRequest) { /* Discard class req not supported by this class. */
|
|
case USBD_AUDIO_REQ_GET_CUR:
|
|
case USBD_AUDIO_REQ_GET_MIN:
|
|
case USBD_AUDIO_REQ_GET_MAX:
|
|
case USBD_AUDIO_REQ_GET_RES:
|
|
case USBD_AUDIO_REQ_SET_CUR:
|
|
case USBD_AUDIO_REQ_SET_MIN:
|
|
case USBD_AUDIO_REQ_SET_MAX:
|
|
case USBD_AUDIO_REQ_SET_RES:
|
|
break;
|
|
|
|
case USBD_AUDIO_REQ_GET_STAT:
|
|
case USBD_AUDIO_REQ_GET_MEM:
|
|
case USBD_AUDIO_REQ_SET_MEM:
|
|
default:
|
|
return (DEF_FAIL); /* Class req not supported. Ctrl EP will be stalled. */
|
|
}
|
|
|
|
req_len = p_setup_req->wLength; /* Length of param block. */
|
|
if (req_len > USBD_AUDIO_CFG_CLASS_REQ_MAX_LEN) { /* Check if enough room to process class req data. */
|
|
return (DEF_FAIL);
|
|
}
|
|
|
|
p_as_if = (USBD_AUDIO_AS_IF *)p_if_class_arg;
|
|
p_comm = p_as_if->CommPtr;
|
|
p_ctrl = p_comm->CtrlPtr;
|
|
|
|
dev_to_host = DEF_BIT_IS_SET(p_setup_req->bmRequestType, USBD_REQ_DIR_BIT);
|
|
recipient = p_setup_req->bmRequestType & USBD_REQ_RECIPIENT_MASK;
|
|
/* -------------------- SET REQUEST ------------------- */
|
|
/* See Note #1. */
|
|
if (dev_to_host == DEF_NO) {
|
|
/* Receive param block from host. */
|
|
USBD_CtrlRx( dev_nbr,
|
|
(void *)p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
USBD_AUDIO_CTRL_REQ_TIMEOUT_mS,
|
|
&err);
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_FAIL);
|
|
}
|
|
}
|
|
/* ------------------ REQ EXECUTION ------------------- */
|
|
switch (recipient) {
|
|
case USBD_REQ_RECIPIENT_ENDPOINT:
|
|
ep_addr = p_setup_req->wIndex;
|
|
p_as_alt = p_as_if->AS_IF_AltCurPtr;
|
|
|
|
if ((p_as_alt == DEF_NULL) &&
|
|
(p_as_alt->DataIsocAddr != ep_addr)) {
|
|
return (DEF_FAIL);
|
|
}
|
|
p_as_cfg = p_as_alt->AS_CfgPtr;
|
|
|
|
USBD_Audio_AS_EP_CtrlProcess(p_as_if,
|
|
p_as_cfg,
|
|
ep_addr,
|
|
p_setup_req->bRequest,
|
|
p_setup_req->wValue,
|
|
p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
&err);
|
|
break;
|
|
|
|
|
|
case USBD_REQ_RECIPIENT_INTERFACE:
|
|
default:
|
|
err = USBD_ERR_AUDIO_REQ_INVALID_CTRL; /* See Note #2. */
|
|
break;
|
|
}
|
|
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_FAIL);
|
|
}
|
|
/* -------------------- GET REQUEST ------------------- */
|
|
/* See Note #3. */
|
|
if (dev_to_host == DEF_YES) {
|
|
USBD_CtrlTx( dev_nbr, /* Send param block to host. */
|
|
(void *)p_ctrl->ReqBufPtr,
|
|
req_len,
|
|
USBD_AUDIO_CTRL_REQ_TIMEOUT_mS,
|
|
DEF_NO,
|
|
&err);
|
|
if (err != USBD_ERR_NONE) {
|
|
return (DEF_FAIL);
|
|
}
|
|
}
|
|
|
|
return (DEF_OK);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_AC_RecipientGet()
|
|
*
|
|
* Description : Get the entity recipient of the class request (see Note #1).
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to the class instance control structure.
|
|
*
|
|
* entity_id Terminal/Unit ID.
|
|
*
|
|
* p_recipient_type Pointer to the recipient Entity type.
|
|
*
|
|
* Return(s) : Pointer to the recipient information structure, if NO error(s).
|
|
*
|
|
* Null Pointer, otherwise.
|
|
*
|
|
* Note(s) : (1) The entity can be:
|
|
*
|
|
* (a) a Terminal (Input or Output).
|
|
*
|
|
* (b) an Unit (Feature, Mixer or Selector).
|
|
*
|
|
* (2) A 'virtual' Entity IF represents the entire global AudioControl interface. According
|
|
* to Audio 1.0 specification. This can be used to report global AudioControl
|
|
* interface changes to the host. This type of entity is not supported by the current
|
|
* audio class.
|
|
*
|
|
* (3) The audio class assigns IDs to terminals and units between 1 and the total number of
|
|
* entities composing the audio function. Any entity ID greater than the total number of
|
|
* entities is unknown.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void *USBD_Audio_AC_RecipientGet (const USBD_AUDIO_CTRL *p_ctrl,
|
|
CPU_INT08U entity_id,
|
|
USBD_AUDIO_ENTITY_TYPE *p_recipient_type)
|
|
{
|
|
void *p_recipient_info;
|
|
USBD_AUDIO_IT *p_it;
|
|
USBD_AUDIO_OT *p_ot;
|
|
USBD_AUDIO_FU *p_fu;
|
|
USBD_AUDIO_MU *p_mu;
|
|
USBD_AUDIO_SU *p_su;
|
|
|
|
|
|
if (entity_id == 0u) {
|
|
*p_recipient_type = USBD_AUDIO_ENTITY_UNKNOWN; /* Entity is a 'virtual' Entity IF (see Note #2). */
|
|
return (DEF_NULL);
|
|
}
|
|
|
|
if (entity_id > p_ctrl->EntityCnt) { /* Verify if entity exists (see Note #3). */
|
|
*p_recipient_type = USBD_AUDIO_ENTITY_UNKNOWN;
|
|
return (DEF_NULL);
|
|
}
|
|
|
|
*p_recipient_type = p_ctrl->EntityID_TblPtr[(entity_id - 1u)]->EntityType;
|
|
switch(*p_recipient_type) {
|
|
case USBD_AUDIO_ENTITY_IT:
|
|
p_it = (USBD_AUDIO_IT *)p_ctrl->EntityID_TblPtr[(entity_id - 1u)];
|
|
p_recipient_info = (void *)p_it;
|
|
break;
|
|
|
|
case USBD_AUDIO_ENTITY_OT:
|
|
p_ot = (USBD_AUDIO_OT *)p_ctrl->EntityID_TblPtr[(entity_id - 1u)];
|
|
p_recipient_info = (void *)p_ot;
|
|
break;
|
|
|
|
case USBD_AUDIO_ENTITY_FU:
|
|
p_fu = (USBD_AUDIO_FU *)p_ctrl->EntityID_TblPtr[(entity_id - 1u)];
|
|
p_recipient_info = (void *)p_fu;
|
|
break;
|
|
|
|
case USBD_AUDIO_ENTITY_MU:
|
|
p_mu = (USBD_AUDIO_MU *)p_ctrl->EntityID_TblPtr[(entity_id - 1u)];
|
|
p_recipient_info = (void *)p_mu;
|
|
break;
|
|
|
|
case USBD_AUDIO_ENTITY_SU:
|
|
p_su = (USBD_AUDIO_SU *)p_ctrl->EntityID_TblPtr[(entity_id - 1u)];
|
|
p_recipient_info = (void *)p_su;
|
|
break;
|
|
|
|
default:
|
|
*p_recipient_type = USBD_AUDIO_ENTITY_UNKNOWN;
|
|
p_recipient_info = DEF_NULL;
|
|
break;
|
|
}
|
|
|
|
return (p_recipient_info);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_CommGet()
|
|
*
|
|
* Description : Get the Comm structure with the specified configuration number.
|
|
*
|
|
* Argument(s) : p_ctrl Pointer to the class instance control structure.
|
|
*
|
|
* cfg_nbr Configuration number to look for.
|
|
*
|
|
* Return(s) : Pointer to the audio communication structure, if NO error(s).
|
|
*
|
|
* Null Pointer, otherwise.
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED) || \
|
|
(USBD_CFG_ERR_ARG_CHK_EXT_EN == DEF_ENABLED)
|
|
static USBD_AUDIO_COMM *USBD_Audio_CommGet (const USBD_AUDIO_CTRL *p_ctrl,
|
|
CPU_INT08U cfg_nbr)
|
|
{
|
|
USBD_AUDIO_COMM *p_comm;
|
|
CPU_INT08U ix;
|
|
|
|
|
|
p_comm = p_ctrl->CommHeadPtr;
|
|
for(ix = 0u; ix < p_ctrl->CommCnt; ix++) {
|
|
if (p_comm->CfgNbr == cfg_nbr) {
|
|
return (p_comm);
|
|
} else {
|
|
p_comm = p_comm->NextPtr;
|
|
}
|
|
}
|
|
|
|
return (DEF_NULL);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* USBD_Audio_MaxPktLenGet()
|
|
*
|
|
* Description : Compute maximum isochronous packet length.
|
|
*
|
|
* Argument(s) : p_as_cfg Pointer to the AudioStreaming interface structure.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* USBD_ERR_NONE Maximum packet length successfully computed.
|
|
* USBD_ERR_FAIL Wrong synchronization type.
|
|
*
|
|
* Return(s) : Maximum isochronous packet length, if NO error(s).
|
|
*
|
|
* 0, otherwise.
|
|
*
|
|
* Note(s) : (1) If the endpoint uses adaptive or asynchronous synchronization, one additional sample
|
|
* frame should be added to accommodate adjustments in the data rate. Section "2.2.1
|
|
* USB Packets" of Audio Data Formats 1.0 Specification limits variation in the packet
|
|
* size by +/- 1 sample frame.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#if (USBD_AUDIO_CFG_PLAYBACK_EN == DEF_ENABLED) || \
|
|
(USBD_AUDIO_CFG_RECORD_EN == DEF_ENABLED)
|
|
static CPU_INT16U USBD_Audio_MaxPktLenGet (USBD_AUDIO_AS_ALT_CFG *p_as_cfg,
|
|
USBD_ERR *p_err)
|
|
{
|
|
CPU_INT16U audio_frame_per_pkt;
|
|
CPU_INT08U audio_frame_len;
|
|
CPU_INT32U max_sam_freq;
|
|
CPU_INT08U sync_type;
|
|
CPU_INT08U sam_freq_ix;
|
|
CPU_INT16U max_pkt_len;
|
|
|
|
|
|
audio_frame_len = p_as_cfg->SubframeSize * p_as_cfg->NbrCh;
|
|
|
|
if (p_as_cfg->NbrSamplingFreq == 0u) {
|
|
max_sam_freq = p_as_cfg->UpperSamplingFreq;
|
|
} else {
|
|
max_sam_freq = 0u;
|
|
for(sam_freq_ix = 0u; sam_freq_ix < p_as_cfg->NbrSamplingFreq; sam_freq_ix++) {
|
|
if(p_as_cfg->SamplingFreqTblPtr[sam_freq_ix] > max_sam_freq) {
|
|
max_sam_freq = p_as_cfg->SamplingFreqTblPtr[sam_freq_ix];
|
|
}
|
|
}
|
|
}
|
|
/* Find the max number of audio frame per pkt (1ms)... */
|
|
audio_frame_per_pkt = max_sam_freq / 1000u; /* ...i.e. nbr of audio samples per frame. */
|
|
if ((max_sam_freq % 1000u) > 0u) {
|
|
audio_frame_per_pkt += 1u;
|
|
}
|
|
/* Find the max pkt len. */
|
|
sync_type = p_as_cfg->EP_SynchType & USBD_EP_TYPE_SYNC_MASK;
|
|
switch (sync_type) {
|
|
case USBD_EP_TYPE_SYNC_SYNC:
|
|
max_pkt_len = audio_frame_per_pkt * audio_frame_len;
|
|
*p_err = USBD_ERR_NONE;
|
|
break;
|
|
|
|
|
|
case USBD_EP_TYPE_SYNC_ASYNC:
|
|
case USBD_EP_TYPE_SYNC_ADAPTIVE:
|
|
/* See Note #1. */
|
|
max_pkt_len = (audio_frame_per_pkt + 1u) * audio_frame_len;
|
|
*p_err = USBD_ERR_NONE;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = USBD_ERR_FAIL;
|
|
max_pkt_len = 0u;
|
|
break;
|
|
}
|
|
|
|
return (max_pkt_len);
|
|
}
|
|
#endif
|
|
|