RT1050_FreeRTOS_USB_Hello/middleware/usb/host/class/usb_host_audio.c

1777 lines
62 KiB
C

/*
* Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
* Copyright 2016,2019 - 2020 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "usb_host_config.h"
#if ((defined USB_HOST_CONFIG_AUDIO) && (USB_HOST_CONFIG_AUDIO))
#include "usb_host.h"
#include "usb_host_audio.h"
/*******************************************************************************
* Definitions
******************************************************************************/
typedef union usb_audio_ctrl_common_fu_desc_t
{
usb_audio_ctrl_fu_desc_t fuDesc10;
usb_audio_2_0_ctrl_fu_desc_t fuDesc20;
} usb_audio_ctrl_common_fu_desc;
/*******************************************************************************
* Variables
******************************************************************************/
/* usb audio feature uint command request declaration */
static usb_audio_request_t s_usbAudioFuRequests[NUMBER_OF_FEATURE_COMMANDS] = {
/* Mute command request */
{AUDIO_FU_MUTE_MASK, ITF_REQUEST, CUR_REQUEST, AUDIO_FU_MUTE, 1U},
/* Volume command request */
{AUDIO_FU_VOLUME_MASK, ITF_REQUEST, CUR_REQUEST, AUDIO_FU_VOLUME, 2U},
{AUDIO_FU_VOLUME_MASK, ITF_REQUEST, MIN_REQUEST, AUDIO_FU_VOLUME, 2U},
{AUDIO_FU_VOLUME_MASK, ITF_REQUEST, MAX_REQUEST, AUDIO_FU_VOLUME, 2U},
{AUDIO_FU_VOLUME_MASK, ITF_REQUEST, RES_REQUEST, AUDIO_FU_VOLUME, 2U},
};
/* USB audio endpoint command declaration */
static usb_audio_request_t s_usbAudioEpRequests[NUMBER_OF_ENDPOINT_COMMANDS] = {
/* USB audio Pitch command request */
{AUDIO_PITCH_MASK, EP_REQUEST, CUR_REQUEST, AUDIO_PITCH_CONTROL, 1U},
/* USB audio Sampling frequency command request */
{AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, CUR_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U},
{AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, MIN_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U},
{AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, MAX_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U},
{AUDIO_SAMPLING_FREQ_MASK, EP_REQUEST, RES_REQUEST, AUDIO_SAMPLING_FREQ_CONTROL, 3U},
};
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief initialize the audio instance.
*
* This function allocate the resource for audio instance.
*
* @param deviceHandle The device handle.
* @param classHandlePtr return class handle.
*
* @retval kStatus_USB_Success The device is initialized successfully.
* @retval kStatus_USB_AllocFail Allocate memory fail.
*/
usb_status_t USB_HostAudioInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandlePtr)
{
audio_instance_t *audioPtr = (audio_instance_t *)OSA_MemoryAllocate(sizeof(audio_instance_t));
uint32_t info_value;
uint32_t *temp;
if (audioPtr == NULL)
{
return kStatus_USB_AllocFail;
}
audioPtr->deviceHandle = deviceHandle;
audioPtr->controlIntfHandle = NULL;
audioPtr->streamIntfHandle = NULL;
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetHostHandle, &info_value);
temp = (uint32_t *)info_value;
audioPtr->hostHandle = (usb_host_handle)temp;
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceControlPipe, &info_value);
temp = (uint32_t *)info_value;
audioPtr->controlPipe = (usb_host_pipe_handle)temp;
*classHandlePtr = audioPtr;
return kStatus_USB_Success;
}
/*!
* @brief de-initialize the audio instance.
*
* This function release the resource for audio instance.
*
* @param deviceHandle the device handle.
* @param classHandle the class handle.
*
* @retval kStatus_USB_Success The device is de-initialized successfully.
*/
usb_status_t USB_HostAudioDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle)
{
usb_status_t status = kStatus_USB_Success;
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
if (deviceHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (classHandle != NULL)
{
if (audioPtr->isoInPipe != NULL)
{
status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoInPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoInPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
audioPtr->isoInPipe = NULL;
}
if (audioPtr->isoOutPipe != NULL)
{
status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoOutPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoOutPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
audioPtr->isoOutPipe = NULL;
}
(void)USB_HostCloseDeviceInterface(deviceHandle, audioPtr->streamIntfHandle);
if ((audioPtr->controlPipe != NULL) && (audioPtr->controlTransfer != NULL))
{
status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->controlPipe, audioPtr->controlTransfer);
}
(void)USB_HostCloseDeviceInterface(deviceHandle, audioPtr->controlIntfHandle);
OSA_MemoryFree(audioPtr);
}
else
{
(void)USB_HostCloseDeviceInterface(deviceHandle, NULL);
}
return status;
}
/*!
* @brief audiostream iso in pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void _USB_HostAudioStreamIsoInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
audio_instance_t *audioPtr = (audio_instance_t *)param;
if (audioPtr->inCallbackFn != NULL)
{
/* callback function is initialized in USB_HostAudioStreamRecv */
audioPtr->inCallbackFn(audioPtr->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, status);
}
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
}
/*!
* @brief audiostream iso out pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void _USB_HostAudioStreamIsoOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
audio_instance_t *audioPtr = (audio_instance_t *)param;
if (audioPtr->outCallbackFn != NULL)
{
/* callback function is initialized in USB_HostAudioStreamSend */
audioPtr->outCallbackFn(audioPtr->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, status);
}
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
}
/*!
* @brief audiocontrol pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void _USB_HostAudioControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
audio_instance_t *audioPtr = (audio_instance_t *)param;
audioPtr->controlTransfer = NULL;
if (audioPtr->controlCallbackFn != NULL)
{
/* callback to application, callback function is initialized in the _USB_HostAudioControl,
USB_HostAudioStreamSetInterface
or USB_HostAudioControlSetInterface, but is the same function */
audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, transfer->transferBuffer, transfer->transferSofar,
status);
}
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
audioPtr->isSetup = 0U;
}
/*!
* @brief hid send control transfer common code.
*
* @param classHandle the class handle.
* @param typeRequest setup packet request type.
* @param request setup packet request value.
* @param wvalue setup packet wvalue value.
* @param windex setup packet index value.
* @param wlength setup packet wlength value.
* @param data data buffer pointer will be transfer.
* @param callbackFn this callback is called after this function completes.
* @param callbackParam the first parameter in the callback function.
*
* @return An error code or kStatus_USB_Success.
*/
static usb_status_t _USB_HostAudioControl(usb_host_class_handle classHandle,
uint8_t typeRequest,
uint8_t request,
uint16_t wvalue,
uint16_t windex,
uint16_t wlength,
uint8_t *data,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_host_transfer_t *transfer;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error to get transfer\r\n");
#endif
return kStatus_USB_Error;
}
audioPtr->controlCallbackFn = callbackFn;
audioPtr->controlCallbackParam = callbackParam;
transfer->transferBuffer = data;
transfer->transferLength = wlength;
transfer->callbackFn = _USB_HostAudioControlCallback;
transfer->callbackParam = audioPtr;
transfer->setupPacket->bmRequestType = typeRequest;
transfer->setupPacket->bRequest = request;
transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(wvalue);
transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(windex);
transfer->setupPacket->wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength);
audioPtr->isSetup = 1;
if (USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("failed for USB_HostSendSetup\r\n");
#endif
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
return kStatus_USB_Error;
}
audioPtr->controlTransfer = transfer;
return kStatus_USB_Success;
}
static usb_status_t _USB_HostAudioInitEndpoint(audio_instance_t *audioPtr, usb_descriptor_endpoint_t *ep_desc)
{
usb_host_pipe_init_t pipe_init;
usb_status_t status;
pipe_init.devInstance = audioPtr->deviceHandle;
pipe_init.pipeType = USB_ENDPOINT_ISOCHRONOUS;
pipe_init.direction = ((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT);
pipe_init.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
pipe_init.interval = ep_desc->bInterval;
pipe_init.maxPacketSize = (uint16_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK));
pipe_init.numberPerUframe = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
if (pipe_init.direction == USB_IN)
{
audioPtr->inPacketSize = pipe_init.maxPacketSize;
audioPtr->isoEpNum = pipe_init.endpointAddress;
status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoInPipe, &pipe_init);
}
else
{
audioPtr->outPacketSize = pipe_init.maxPacketSize;
audioPtr->isoEpNum = pipe_init.endpointAddress;
status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoOutPipe, &pipe_init);
}
return status;
}
/*!
* @brief audio open interface.
*
* @param audioPtr audio instance pointer.
*
* @return kStatus_USB_Success or error codes.
*/
static usb_status_t _USB_HostAudioOpenInterface(audio_instance_t *audioPtr)
{
usb_status_t status;
uint8_t ep_index = 0U;
usb_descriptor_endpoint_t *ep_desc = NULL;
usb_host_interface_t *interface_ptr;
if (audioPtr->isoInPipe != NULL)
{
status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoInPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
audioPtr->isoInPipe = NULL;
}
if (audioPtr->isoOutPipe != NULL)
{
status = USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoOutPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
audioPtr->isoOutPipe = NULL;
}
/* open interface pipes */
interface_ptr = (usb_host_interface_t *)audioPtr->streamIntfHandle;
for (ep_index = 0U; ep_index < interface_ptr->epCount; ++ep_index)
{
ep_desc = interface_ptr->epList[ep_index].epDesc;
if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) &&
((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_ISOCHRONOUS))
{
status = _USB_HostAudioInitEndpoint(audioPtr, ep_desc);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("usb_host_audio_stream_set_interface fail to open pipe\r\n");
#endif
return kStatus_USB_Error;
}
}
else if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_ISOCHRONOUS))
{
status = _USB_HostAudioInitEndpoint(audioPtr, ep_desc);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("usb_host_audio_stream_set_interface fail to open pipe\r\n");
#endif
return kStatus_USB_Error;
}
}
else
{
}
}
return kStatus_USB_Success;
}
/*!
* @brief audio set interface callback, open pipes.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void _USB_HostAudioSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
audio_instance_t *audioPtr = (audio_instance_t *)param;
audioPtr->controlTransfer = NULL;
if (status == kStatus_USB_Success)
{
status = _USB_HostAudioOpenInterface(audioPtr);
}
if (audioPtr->controlCallbackFn != NULL)
{
/* callback to application, callback function is initialized in the _USB_HostAudioControl,
USB_HostAudioStreamSetInterface
or USB_HostAudioControlSetInterface, but is the same function */
audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, NULL, 0U, status);
}
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
}
/*!
* @brief set audioclass stream interface.
*
* This function bind the interface with the audio instance.
*
* @param classHandle The class handle.
* @param interfaceHandle The interface handle.
* @param alternateSetting The alternate setting value.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success The device is initialized successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup.
* @retval kStatus_USB_Busy callback return status, there is no idle pipe.
* @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device.
* @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe.
*/
usb_status_t USB_HostAudioStreamSetInterface(usb_host_class_handle classHandle,
usb_host_interface_handle interfaceHandle,
uint8_t alternateSetting,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_status_t status;
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_host_interface_t *interface_ptr;
usb_host_transfer_t *transfer;
audio_descriptor_union_t ptr1;
uint32_t length = 0U, ep = 0U;
void *temp;
usb_descriptor_endpoint_t *endpointDesc;
if (classHandle == NULL)
{
return kStatus_USB_InvalidParameter;
}
audioPtr->streamIntfHandle = interfaceHandle;
status = USB_HostOpenDeviceInterface(audioPtr->deviceHandle, interfaceHandle);
if (status != kStatus_USB_Success)
{
return status;
}
if (audioPtr->isoInPipe != NULL)
{
status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoInPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
}
if (audioPtr->isoOutPipe != NULL)
{
status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->isoOutPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
}
/* open interface pipes */
interface_ptr = (usb_host_interface_t *)interfaceHandle;
ptr1.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if ((ptr1.common->bDescriptorType == 0x04U) && (ptr1.interface->bAlternateSetting == alternateSetting))
{
interface_ptr->epCount = ptr1.interface->bNumEndpoints;
break;
}
ptr1.bufr += ptr1.common->bLength;
length += ptr1.common->bLength;
}
while (ep < interface_ptr->epCount)
{
if (ptr1.common->bDescriptorType == 0x24U)
{
temp = (void *)ptr1.bufr;
if (AUDIO_DEVICE_VERSION_01 == audioPtr->deviceAudioVersion)
{
if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_AS_GENERAL)
{
audioPtr->asIntfDesc = temp;
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_AS_FORMAT_TYPE)
{
audioPtr->formatTypeDesc = temp;
}
else
{
/*no action*/
}
}
else if (AUDIO_DEVICE_VERSION_02 == audioPtr->deviceAudioVersion)
{
if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_AS_GENERAL_20)
{
audioPtr->asIntfDesc = temp;
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_AS_FORMAT_TYPE_20)
{
audioPtr->formatTypeDesc = temp;
}
else
{
/*no action*/
}
}
else
{
/*no action*/
}
}
else
{
/*no action*/
}
if (ptr1.common->bDescriptorType == 0x05U)
{
uint32_t descLength = 0;
temp = (void *)ptr1.bufr;
/*Bits 5..4: Usage Type,
00 = Data endpoint
01 = Feedback endpoint
10 = Implicit feedback Data endpoit, usb Spec 9.6*/
endpointDesc = (usb_descriptor_endpoint_t *)temp;
if (0x00U == ((endpointDesc->bmAttributes >> 4U) & 0x3U))
{
interface_ptr->epList[ep].epDesc = (usb_descriptor_endpoint_t *)temp;
audioPtr->isoEndpDesc = (usb_descriptor_endpoint_t *)temp;
}
else if (0x01U == ((endpointDesc->bmAttributes >> 4U) & 0x3U))
{
/*feedback endpoint*/
}
else
{
/*TO DO*/
}
descLength = ptr1.common->bLength;
ptr1.bufr += ptr1.common->bLength;
if ((0x25U == ptr1.common->bDescriptorType))
{
interface_ptr->epList[ep].epExtension = ptr1.bufr;
interface_ptr->epList[ep].epExtensionLength = ptr1.common->bLength;
}
else
{
ptr1.bufr -= descLength;
}
ep++;
}
ptr1.bufr += ptr1.common->bLength;
}
if (alternateSetting == 0U)
{
if (callbackFn != NULL)
{
status = _USB_HostAudioOpenInterface(audioPtr);
callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success);
}
}
else
{
if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error to get transfer\r\n");
#endif
return kStatus_USB_Error;
}
audioPtr->controlCallbackFn = callbackFn;
audioPtr->controlCallbackParam = callbackParam;
/* initialize transfer */
transfer->callbackFn = _USB_HostAudioSetInterfaceCallback;
transfer->callbackParam = audioPtr;
transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_INTERFACE;
transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(
((usb_host_interface_t *)audioPtr->streamIntfHandle)->interfaceDesc->bInterfaceNumber);
transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting);
transfer->setupPacket->wLength = 0;
transfer->transferBuffer = NULL;
transfer->transferLength = 0;
status = USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer);
if (status == kStatus_USB_Success)
{
audioPtr->controlTransfer = transfer;
}
else
{
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
}
}
return status;
}
/*!
* @brief set audioclass control interface.
*
* This function bind the interface with the audio instance.
*
* @param classHandle The class handle.
* @param interfaceHandle The interface handle.
* @param alternateSetting The alternate setting value.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success The device is initialized successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error send transfer fail, please reference to USB_HostSendSetup.
* @retval kStatus_USB_Busy callback return status, there is no idle pipe.
* @retval kStatus_USB_TransferStall callback return status, the transfer is stall by device.
* @retval kStatus_USB_Error callback return status, open pipe fail, please reference to USB_HostOpenPipe.
*/
usb_status_t USB_HostAudioControlSetInterface(usb_host_class_handle classHandle,
usb_host_interface_handle interfaceHandle,
uint8_t alternateSetting,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_status_t status;
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_host_interface_t *interface_ptr;
usb_host_transfer_t *transfer;
audio_descriptor_union_t ptr1;
void *temp;
void *header;
usb_audio_ctrl_common_header_desc_t *commonHeader;
uint32_t length = 0U;
if (classHandle == NULL)
{
return kStatus_USB_InvalidParameter;
}
audioPtr->controlIntfHandle = interfaceHandle;
interface_ptr = (usb_host_interface_t *)interfaceHandle;
status = USB_HostOpenDeviceInterface(audioPtr->deviceHandle, interfaceHandle);
if (status != kStatus_USB_Success)
{
return status;
}
ptr1.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if (((interface_ptr->interfaceDesc->bDescriptorType == 0x04U) &&
(interface_ptr->interfaceDesc->bAlternateSetting == alternateSetting)) ||
((ptr1.common->bDescriptorType == 0x04U) && (ptr1.interface->bAlternateSetting == alternateSetting)))
{
break;
}
ptr1.bufr += ptr1.common->bLength;
length += ptr1.common->bLength;
}
while (length < interface_ptr->interfaceExtensionLength)
{
if (ptr1.common->bDescriptorType == 0x24U)
{
temp = (void *)ptr1.bufr;
if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_HEADER)
{
audioPtr->headerDesc = (void *)temp;
commonHeader = (usb_audio_ctrl_common_header_desc_t *)temp;
header = (void *)&commonHeader->bcdcdc;
audioPtr->deviceAudioVersion = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t *)header));
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_INPUT)
{
audioPtr->itDesc = (void *)temp;
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_OUTPUT)
{
audioPtr->otDesc = (void *)temp;
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_FEATURE)
{
audioPtr->fuDesc = (void *)temp;
}
else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_CLOCK_SOURE)
{
audioPtr->clockSource = (void *)temp;
}
else
{
/*no action*/
}
}
ptr1.bufr += ptr1.common->bLength;
length += ptr1.common->bLength;
}
if (alternateSetting == 0U)
{
if (callbackFn != NULL)
{
callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success);
}
}
else
{
if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error to get transfer\r\n");
#endif
return kStatus_USB_Error;
}
audioPtr->controlCallbackFn = callbackFn;
audioPtr->controlCallbackParam = callbackParam;
/* initialize transfer */
transfer->callbackFn = _USB_HostAudioControlCallback;
transfer->callbackParam = audioPtr;
transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_INTERFACE;
transfer->setupPacket->bmRequestType = USB_REQUEST_TYPE_RECIPIENT_INTERFACE;
transfer->setupPacket->wIndex = USB_SHORT_TO_LITTLE_ENDIAN(
((usb_host_interface_t *)audioPtr->controlIntfHandle)->interfaceDesc->bInterfaceNumber);
transfer->setupPacket->wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting);
transfer->setupPacket->wLength = 0;
transfer->transferBuffer = NULL;
transfer->transferLength = 0;
status = USB_HostSendSetup(audioPtr->hostHandle, audioPtr->controlPipe, transfer);
if (status == kStatus_USB_Success)
{
audioPtr->controlTransfer = transfer;
}
else
{
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
}
}
return status;
}
/*!
* @brief get pipe max packet size.
*
* @param classHandle the class handle.
* @param pipeType It's value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or
* USB_ENDPOINT_INTERRUPT.
* Please reference to usb_spec.h
* @param direction pipe direction.
*
* @retval 0 The classHandle is NULL.
* @retval max packet size.
*/
uint16_t USB_HostAudioPacketSize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
if (classHandle == NULL)
{
return 0U;
}
if (pipeType == USB_ENDPOINT_ISOCHRONOUS)
{
if (direction == USB_IN)
{
return audioPtr->inPacketSize;
}
else
{
return audioPtr->outPacketSize;
}
}
return 0U;
}
/*!
* @brief audio stream receive data.
*
* This function implements audioreceiving data.
*
* @param classHandle The class handle.
* @param buffer The buffer pointer.
* @param bufferLen The buffer length.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Receive request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error pipe is not initialized.
* Or, send transfer fail, please reference to USB_HostRecv.
*/
usb_status_t USB_HostAudioStreamRecv(usb_host_class_handle classHandle,
uint8_t *buffer,
uint32_t bufferLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_host_transfer_t *transfer;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (audioPtr->isoInPipe == NULL)
{
return kStatus_USB_Error;
}
if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error to get transfer\r\n");
#endif
return kStatus_USB_Error;
}
audioPtr->inCallbackFn = callbackFn;
audioPtr->inCallbackParam = callbackParam;
transfer->transferBuffer = buffer;
transfer->transferLength = bufferLen;
transfer->callbackFn = _USB_HostAudioStreamIsoInPipeCallback;
transfer->callbackParam = audioPtr;
if (USB_HostRecv(audioPtr->hostHandle, audioPtr->isoInPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("failed to USB_HostRecv\r\n");
#endif
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
return kStatus_USB_Error;
}
return kStatus_USB_Success;
}
/*!
* @brief audio stream send data.
*
* This function implements audio sending data.
*
* @param classHandle The class handle.
* @param buffer The buffer pointer.
* @param bufferLen The buffer length.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Receive request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error pipe is not initialized.
* Or, send transfer fail, please reference to USB_HostSend.
*/
usb_status_t USB_HostAudioStreamSend(usb_host_class_handle classHandle,
uint8_t *buffer,
uint32_t bufferLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_host_transfer_t *transfer;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (audioPtr->isoOutPipe == NULL)
{
return kStatus_USB_Error;
}
if (USB_HostMallocTransfer(audioPtr->hostHandle, &transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error to get transfer\r\n");
#endif
return kStatus_USB_Error;
}
audioPtr->outCallbackFn = callbackFn;
audioPtr->outCallbackParam = callbackParam;
transfer->transferBuffer = buffer;
transfer->transferLength = bufferLen;
transfer->callbackFn = _USB_HostAudioStreamIsoOutPipeCallback;
transfer->callbackParam = audioPtr;
if (USB_HostSend(audioPtr->hostHandle, audioPtr->isoOutPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("failed to USB_HostSend\r\n");
#endif
(void)USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
return kStatus_USB_Error;
}
return kStatus_USB_Success;
}
/*!
* @brief get audio control current altsetting descriptor.
*
* This function implements get audio stream current altsetting descriptor.
*
* @param classHandle The class handle.
* @param DescriptorType The descriptor type.
* @param DescriptorSubType The descriptor subtype, 0 for no subtype.
* @param Descriptor The pointer of descriptor pointer.
*
* @retval kStatus_USB_Success Get audio stream current altsetting descriptor request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
*
*/
usb_status_t USB_HostAudioControlGetCurrentAltsettingSpecificDescriptors(
usb_host_class_handle classHandle, uint32_t DescriptorType, uint32_t DescriptorSubType, void **Descriptor)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_status_t status = kStatus_USB_Error;
uint32_t **descriptorPointer = (uint32_t **)Descriptor;
if ((classHandle == NULL) || NULL == Descriptor)
{
return kStatus_USB_InvalidParameter;
}
if (USB_AUDIO_DESCRIPTOR_TYPE_CS_INTERFACE == DescriptorType)
{
if (AUDIO_DEVICE_VERSION_01 == audioPtr->deviceAudioVersion)
{
if (USB_AUDIO_DESC_SUBTYPE_CS_EXTENSION <= DescriptorSubType)
{
/*descriptor type code bigger than EXTENSION is not support by audio 1.0*/
return kStatus_USB_InvalidParameter;
}
}
switch (DescriptorSubType)
{
case USB_AUDIO_DESC_SUBTYPE_CS_HEADER:
*descriptorPointer = (uint32_t *)audioPtr->headerDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_CS_INPUT:
*descriptorPointer = (uint32_t *)audioPtr->itDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_CS_OUTPUT:
*descriptorPointer = (uint32_t *)audioPtr->otDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_CS_FEATURE:
*descriptorPointer = (uint32_t *)audioPtr->fuDesc;
status = kStatus_USB_Success;
break;
default:
/*no action*/
break;
}
}
return status;
}
/*!
* @brief get audio control current altsetting descriptor.
*
* This function implements get audio stream current altsetting descriptor.
*
* @param classHandle The class handle.
* @param DescriptorType The descriptor type.
* @param DescriptorSubType The descriptor subtype, default 0.
* @param Descriptor The pointer of descriptor pointer.
*
* @retval kStatus_USB_Success Get audio stream current altsetting descriptor request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
*
*/
usb_status_t USB_HostAudioStreamGetCurrentAltsettingSpecificDescriptors(
usb_host_class_handle classHandle, uint32_t DescriptorType, uint32_t DescriptorSubType, void **Descriptor)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_status_t status = kStatus_USB_Error;
uint32_t **descriptorPointer = (uint32_t **)Descriptor;
void *temp;
if ((classHandle == NULL) || NULL == Descriptor)
{
return kStatus_USB_InvalidParameter;
}
if (USB_AUDIO_DESCRIPTOR_TYPE_CS_INTERFACE == DescriptorType)
{
if (AUDIO_DEVICE_VERSION_01 == audioPtr->deviceAudioVersion)
{
switch (DescriptorSubType)
{
case USB_AUDIO_DESC_SUBTYPE_AS_GENERAL:
*descriptorPointer = (uint32_t *)audioPtr->asIntfDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_AS_FORMAT_TYPE:
*descriptorPointer = (uint32_t *)audioPtr->formatTypeDesc;
status = kStatus_USB_Success;
break;
default:
/*no action*/
break;
}
}
else if (AUDIO_DEVICE_VERSION_02 == audioPtr->deviceAudioVersion)
{
switch (DescriptorSubType)
{
case USB_AUDIO_DESC_SUBTYPE_AS_GENERAL_20:
*descriptorPointer = (uint32_t *)audioPtr->asIntfDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_AS_FORMAT_TYPE_20:
*descriptorPointer = (uint32_t *)audioPtr->formatTypeDesc;
status = kStatus_USB_Success;
break;
case USB_AUDIO_DESC_SUBTYPE_AS_FORMAT_ENCODER_20:
/*no action*/
break;
default:
/*no action*/
break;
}
}
else
{
/*To DO*/
}
}
else if (USB_DESCRIPTOR_TYPE_ENDPOINT == DescriptorType)
{
if (0x0U == DescriptorSubType)
{
/*iso data endpoint descriptor*/
temp = (void *)audioPtr->isoEndpDesc;
*descriptorPointer = (uint32_t *)temp;
status = kStatus_USB_Success;
}
else
{
/*TO DO*/
}
}
else
{
/*To DO*/
}
return status;
}
/*!
* @brief get audio stream current altsetting descriptor.
* @deprecated Do not use this function. It has been superceded by @ref
* USB_HostAudioStreamGetCurrentAltsettingSpecificDescriptors.
*
* This function implements get audio stream current altsetting descriptor.
*
* @param classHandle The class handle.
* @param asIntfDesc The pointer of class specific AS interface descriptor.
* @param formatTypeDesc The pointer of format type descriptor.
* @param isoEndpDesc The pointer of specific iso endp descriptor.
*
* @retval kStatus_USB_Success Get audio stream current altsetting descriptor request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
*
*/
usb_status_t USB_HostAudioStreamGetCurrentAltsettingDescriptors(
usb_host_class_handle classHandle,
usb_audio_stream_spepific_as_intf_desc_t **asIntfDesc,
usb_audio_stream_format_type_desc_t **formatTypeDesc,
usb_descriptor_endpoint_t **isoEndpDesc)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
*asIntfDesc = (usb_audio_stream_spepific_as_intf_desc_t *)audioPtr->asIntfDesc;
*formatTypeDesc = (usb_audio_stream_format_type_desc_t *)audioPtr->formatTypeDesc;
*isoEndpDesc = (usb_descriptor_endpoint_t *)audioPtr->isoEndpDesc;
return kStatus_USB_Success;
}
/*!
* @brief usb audio set/get feature unit request.
*
* This function implements usb audio feature unit request.
*
* @param classHandle The class handle.
* @param csAndCn The CS and CN or MCN for wValue field in setup Request.
* @param cmdCode The bRequest code in lower 8bit of lower word and get(1)/set(0) flag in higher 8bit of lower
* word.
* @param buf The feature unit request buffer pointer.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Feature unit request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup.
*
*/
usb_status_t USB_HostAudioGetSetFeatureUnitRequest(usb_host_class_handle classHandle,
uint32_t csAndCn,
uint32_t cmdCode,
void *buf,
uint32_t bufLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *if_ptr;
uint8_t *bmacontrols = NULL;
usb_audio_ctrl_common_fu_desc *fuDesc;
uint16_t windex;
uint8_t request;
uint8_t atribute_index;
uint16_t length = 0U;
uint8_t typeRequest;
uint8_t controlSelector;
usb_status_t status = kStatus_USB_Error;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if_ptr = (audio_instance_t *)classHandle;
/* Check whether this attribute valid or not */
if (if_ptr->fuDesc == NULL)
{
return kStatus_USB_Error;
}
fuDesc = (usb_audio_ctrl_common_fu_desc *)if_ptr->fuDesc;
if (AUDIO_DEVICE_VERSION_01 == if_ptr->deviceAudioVersion)
{
windex = (uint16_t)((uint16_t)((uint16_t)(fuDesc->fuDesc10.bunitid) << 8U) | (if_ptr->streamIfnum));
atribute_index = (uint8_t)(fuDesc->fuDesc10.bcontrolsize * ((uint16_t)csAndCn & 0xFFU));
/*Size of this descriptor, in bytes: 7+(ch+1)*n*/
if (atribute_index < (fuDesc->fuDesc10.blength - 7U))
{
bmacontrols = &(fuDesc->fuDesc10.bcontrolsize);
}
}
else if (AUDIO_DEVICE_VERSION_02 == if_ptr->deviceAudioVersion)
{
windex = (uint16_t)((uint16_t)((uint16_t)(fuDesc->fuDesc20.bunitid) << 8U) | (if_ptr->streamIfnum));
/*BmControl is 4byte, refer to *audio2.0 4.7.2.8 Size of this descriptor, in bytes: 6+(ch+1)*4*/
atribute_index = (uint8_t)(4U * ((uint16_t)csAndCn & 0xFFU));
if (atribute_index < (fuDesc->fuDesc20.blength - 6U))
{
bmacontrols = &(fuDesc->fuDesc20.bmaControls0[0]);
}
}
else
{
/*TO DO*/
}
if (bmacontrols == NULL)
{
return kStatus_USB_Error;
}
request = (uint8_t)(((uint16_t)cmdCode & 0xFFU));
controlSelector = (uint8_t)((uint16_t)(csAndCn >> 8) & 0xFFU);
if (AUDIO_DEVICE_VERSION_01 == if_ptr->deviceAudioVersion)
{
/*control selector */
switch (controlSelector)
{
/*note ,all the length is defined in audio1.0 Spec chapter 5.2.2.4.3*/
case AUDIO_FU_MUTE:
status = kStatus_USB_Success;
length = 1U;
break;
case AUDIO_FU_VOLUME:
status = kStatus_USB_Success;
length = 2U;
break;
case AUDIO_FU_BASS:
/*TO DO*/
break;
default:
/*no action*/
break;
}
}
else if (AUDIO_DEVICE_VERSION_02 == if_ptr->deviceAudioVersion)
{
if ((request != USB_AUDIO_CS_REQUEST_CODE_RANGE_20) && (request != USB_AUDIO_CS_REQUEST_CODE_CUR_20))
{
return kStatus_USB_Error;
}
switch (controlSelector)
{
/*note ,all the length is defined in audio2.0 Spec chapter 5.2.5.7*/
case AUDIO_FU_MUTE:
if (bufLen != 1U)
{
return kStatus_USB_Error;
}
status = kStatus_USB_Success;
length = 1U;
break;
case AUDIO_FU_VOLUME:
status = kStatus_USB_Success;
if (USB_AUDIO_CS_REQUEST_CODE_RANGE_20 == request)
{
/*the len for volume is 2+6*n*/
if (bufLen < 8U)
{
return kStatus_USB_Error;
}
}
else if (USB_AUDIO_CS_REQUEST_CODE_CUR_20 == request)
{
if (bufLen != 2U)
{
return kStatus_USB_Error;
}
}
else
{
/*TO DO*/
}
length = (uint16_t)bufLen;
break;
case AUDIO_FU_BASS:
/*TO DO*/
break;
default:
/*no action*/
break;
}
}
else
{
/*TO DO*/
}
if (status != kStatus_USB_Success)
{
/*the request is not support*/
return kStatus_USB_Error;
}
if (0U == ((uint16_t)(cmdCode >> 8U) & 0xFFU))
{
/*refer to audio Spec 2.0 chapter 5.2.2*/
typeRequest = 0x21U;
}
else
{
typeRequest = 0xA1U;
}
status = _USB_HostAudioControl(classHandle, typeRequest, request, (uint16_t)csAndCn, windex, length, (uint8_t *)buf,
callbackFn, callbackParam);
return status;
}
/*!
* @brief usb audio set/get feature unit request.
*
* This function implements usb audio feature unit request.
*
* @param classHandle The class handle.
* @param csAndCn The CS and CN or MCN for wValue field in setup Request.
* @param cmdCode The bRequest code in lower 8bit of lower word and get(1)/set(0) flag in higher 8bit of lower
word.
* @param buf The feature unit request buffer pointer.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Feature unit request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup.
*
*/
usb_status_t USB_HostAudioGetSetClockSourceRequest(usb_host_class_handle classHandle,
uint32_t csAndCn,
uint32_t cmdCode,
void *buf,
uint32_t bufLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *if_ptr;
usb_audio_2_0_ctrl_clock_source_desc_t *clockDesc;
uint16_t windex;
uint16_t controlSelector;
uint8_t length = 0U;
uint8_t typeRequest;
uint8_t request;
usb_status_t status = kStatus_USB_Error;
if (classHandle == NULL)
{
return kStatus_USB_InvalidParameter;
}
if_ptr = (audio_instance_t *)classHandle;
if (AUDIO_DEVICE_VERSION_02 == if_ptr->deviceAudioVersion)
{
clockDesc = (usb_audio_2_0_ctrl_clock_source_desc_t *)if_ptr->clockSource;
windex = (uint16_t)((uint16_t)((uint16_t)(clockDesc->bClockID) << 8U) | (if_ptr->streamIfnum));
}
else
{
return kStatus_USB_Error;
}
request = (uint8_t)(((uint16_t)cmdCode & 0xFFU));
controlSelector = (uint8_t)((uint16_t)(csAndCn >> 8U) & 0xFFU);
if (USB_AUDIO_CS_SAM_FREQ_CONTROL_20 == controlSelector)
{
/*note ,all the length is defined in audio2.0 Spec chapter 5.2.5.1.1*/
if (USB_AUDIO_CS_REQUEST_CODE_RANGE_20 == request)
{
/*the len for volume is 2+6*n*/
if (bufLen < 12U)
{
return kStatus_USB_Error;
}
else
{
length = (uint8_t)bufLen;
}
}
else if (USB_AUDIO_CS_REQUEST_CODE_CUR_20 == request)
{
if (bufLen != 4U)
{
return kStatus_USB_Error;
}
length = (uint8_t)bufLen;
}
else
{
return kStatus_USB_Error;
}
status = kStatus_USB_Success;
}
else if (USB_AUDIO_CS_CLOCK_VALID_CONTROL_20 == controlSelector)
{
status = kStatus_USB_Success;
if (bufLen < 1U)
{
return kStatus_USB_Error;
}
length = 1U;
}
else
{
/**TO DO*/
}
if (status != kStatus_USB_Success)
{
/*the request is not support*/
return kStatus_USB_Error;
}
if (0U == ((uint16_t)(cmdCode >> 8U) & 0xFFU))
{
/*refer to audio Spec 2.0 chapter 5.2.2*/
typeRequest = 0x21U;
}
else
{
typeRequest = 0xA1U;
}
status = _USB_HostAudioControl(classHandle, typeRequest, request, (uint16_t)csAndCn, windex, length, (uint8_t *)buf,
callbackFn, callbackParam);
return status;
}
/*!
* @brief usb audio feature unit request.
* @deprecated Do not use this function. It has been superceded by @ref USB_HostAudioGetSetFeatureUnitRequest.
*
* This function implements usb audio feature unit request.
*
* @param classHandle The class handle.
* @param channelNo The channel number of audio feature unit.
* @param buf The feature unit request buffer pointer.
* @param cmdCode The feature unit command code, for example USB_AUDIO_GET_CUR_MUTE etc.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Feature unit request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup.
*
*/
usb_status_t USB_HostAudioFeatureUnitRequest(usb_host_class_handle classHandle,
uint8_t channelNo,
void *buf,
uint32_t cmdCode,
transfer_callback_t callbackFn,
void *callbackParam)
{ /* Body */
uint16_t windex;
uint16_t request_value;
audio_instance_t *if_ptr;
usb_audio_request_t *p_feature_request;
usb_audio_ctrl_fu_desc_t *fuDesc;
uint8_t *bmacontrols = NULL;
uint8_t atribute_index;
usb_status_t status;
if ((classHandle == NULL))
{
return kStatus_USB_InvalidHandle;
}
if_ptr = (audio_instance_t *)classHandle;
if (AUDIO_DEVICE_VERSION_01 != if_ptr->deviceAudioVersion)
{
return kStatus_USB_Error;
}
/* pointer to command */
p_feature_request = &(s_usbAudioFuRequests[(uint8_t)cmdCode & 0xfU]);
/* get request value */
request_value = (uint16_t)((uint16_t)((uint16_t)p_feature_request->requestValue << 8U) | channelNo);
/* Check whether this attribute valid or not */
if (if_ptr->fuDesc == NULL)
{
return kStatus_USB_Error;
}
fuDesc = (usb_audio_ctrl_fu_desc_t *)if_ptr->fuDesc;
windex = (uint16_t)((uint16_t)((uint16_t)(fuDesc->bunitid) << 8U) | (if_ptr->streamIfnum));
atribute_index = fuDesc->bcontrolsize * channelNo;
if (atribute_index < (fuDesc->blength - 7U))
{
bmacontrols = &(fuDesc->bcontrolsize);
}
if (bmacontrols == NULL)
{
return kStatus_USB_Error;
}
status = _USB_HostAudioControl(classHandle, (p_feature_request->typeRequest | ((uint8_t)cmdCode & 0x80U)),
(p_feature_request->codeRequest | ((uint8_t)cmdCode & 0x80U)), request_value, windex,
p_feature_request->length, (uint8_t *)buf, callbackFn, callbackParam);
return status;
}
/*!
* @brief usb audio set/get endp unit request.
*
* This function implements usb audio feature unit request.
*
* @param classHandle The class handle.
* @param csAndCn The CS for wValue field in setup Request.
* @param cmdCode The bRequest code in lower 8bit of lower word and get(1)/set(0) flag in higher 8bit of lower
word.
* @param buf The feature unit request buffer pointer.
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Feature unit request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup.
*
*/
usb_status_t USB_HostAudioGetSetEndpointRequest(usb_host_class_handle classHandle,
uint32_t csAndCn,
uint32_t cmdCode,
void *buf,
uint32_t bufLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
audio_instance_t *if_ptr;
uint16_t windex;
uint8_t request;
uint8_t length = 0U;
uint8_t typeRequest;
uint8_t controlSelector;
usb_status_t status = kStatus_USB_Error;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if_ptr = (audio_instance_t *)classHandle;
if (AUDIO_DEVICE_VERSION_01 == if_ptr->deviceAudioVersion)
{
if ((NULL == if_ptr->isoInPipe) && (NULL == if_ptr->isoOutPipe))
{
return kStatus_USB_InvalidParameter;
}
else if (NULL != if_ptr->isoInPipe)
{
windex = (((uint16_t)if_ptr->isoEpNum) | 0x80U);
}
else
{
windex = if_ptr->isoEpNum;
}
}
else if (AUDIO_DEVICE_VERSION_02 == if_ptr->deviceAudioVersion)
{
/*TO DO*/
}
else
{
/*TO DO*/
}
request = (uint8_t)(((uint16_t)cmdCode & 0xFFU));
controlSelector = (uint8_t)((uint16_t)(csAndCn >> 8U) & 0xFFU);
if (AUDIO_DEVICE_VERSION_01 == if_ptr->deviceAudioVersion)
{
/*control selector */
/*note ,all the length is defined in audio1.0 Spec chapter 5.2.3.2.3*/
if (USB_AUDIO_EP_CS_SAMPING_FREQ_CONTROL == controlSelector)
{
if (bufLen > 3U)
{
/*fixed length*/
length = 3U;
status = kStatus_USB_Success;
}
else
{
/*TO DO*/
}
}
else if (USB_AUDIO_EP_CS_PINTCH_CONTROL == controlSelector)
{
/*TO DO*/
}
else
{
/*TO DO*/
}
}
else if (AUDIO_DEVICE_VERSION_02 == if_ptr->deviceAudioVersion)
{
switch (controlSelector)
{
/*note ,all the length is defined in audio2.0 Spec chapter 5.2.6*/
case USB_AUDIO_EP_CS_PINTCH_CONTROL_20:
/*TO DO*/
break;
case USB_AUDIO_EP_CS_OVERRUN_CONTROL_20:
/*TO DO*/
break;
case USB_AUDIO_EP_CS_UNDERRUN_CONTROL_20:
/*TO DO*/
break;
default:
/*no action*/
break;
}
}
else
{
/*TO DO*/
}
if (status != kStatus_USB_Success)
{
/*the request is not support*/
return kStatus_USB_Error;
}
if (0U == ((uint16_t)(cmdCode >> 8U) & 0xFFU))
{
/*refer to audio Spec 2.0 chapter 5.2.2*/
typeRequest = 0x22U;
}
else
{
typeRequest = 0xA2U;
}
status = _USB_HostAudioControl(classHandle, typeRequest, request, (uint16_t)csAndCn, windex, length, (uint8_t *)buf,
callbackFn, callbackParam);
return status;
}
/*!
* @brief usb audio endpoint request.
* @deprecated Do not use this function. It has been superceded by @ref USB_HostAudioGetSetEndpointRequest.
*
* This function implements usb audio endpoint request.
*
* @param classHandle The class handle.
* @param buf The feature unit buffer pointer.
* @param cmdCode The feature unit command code, for example USB_AUDIO_GET_CUR_PITCH etc .
* @param callbackFn This callback is called after this function completes.
* @param callbackParam The first parameter in the callback function.
*
* @retval kStatus_USB_Success Endpoint request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_Busy There is no idle transfer.
* @retval kStatus_USB_Error Send transfer fail, please reference to USB_HostSendSetup.
*
*/
usb_status_t USB_HostAudioEndpointRequest(
usb_host_class_handle classHandle, void *buf, uint32_t cmdCode, transfer_callback_t callbackFn, void *callbackParam)
{
uint8_t endp_num;
usb_status_t status;
uint16_t request_value;
usb_audio_request_t *p_endpoint_request;
audio_instance_t *audioPtr;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
audioPtr = (audio_instance_t *)classHandle;
if (AUDIO_DEVICE_VERSION_01 != audioPtr->deviceAudioVersion)
{
return kStatus_USB_Error;
}
/* pointer to command */
p_endpoint_request = &(s_usbAudioEpRequests[(uint8_t)cmdCode & 0xfU]);
/* get request value */
request_value = (uint16_t)((uint16_t)((uint16_t)p_endpoint_request->requestValue << 8U));
/* Check whether this attribute valid or not */
if (audioPtr->isoEndpDesc == NULL)
{
return kStatus_USB_Error;
}
if ((0U != audioPtr->isoEndpDesc->bmAttributes) && (0U != p_endpoint_request->controlMask))
{
status = kStatus_USB_Success;
}
else
{
status = kStatus_USB_InvalidRequest;
}
if (kStatus_USB_Success == status)
{
/* Any isochronous pipe is supported? */
if ((NULL == audioPtr->isoInPipe) && (NULL == audioPtr->isoOutPipe))
{
return kStatus_USB_InvalidParameter;
}
else if (NULL != audioPtr->isoInPipe)
{
endp_num = (audioPtr->isoEpNum | 0x80U);
}
else
{
endp_num = audioPtr->isoEpNum;
} /* Endif */
status = _USB_HostAudioControl(classHandle, (p_endpoint_request->typeRequest | ((uint8_t)cmdCode & 0x80U)),
(p_endpoint_request->codeRequest | ((uint8_t)cmdCode & 0x80U)), request_value,
endp_num, p_endpoint_request->length, (uint8_t *)buf, callbackFn, callbackParam);
}
return status;
}
usb_status_t USB_HostAudioSetStreamOutDataInterval(usb_host_class_handle classHandle, uint8_t intervalValue)
{
audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
usb_status_t status = kStatus_USB_Error;
uint8_t ep_index = 0U;
usb_descriptor_endpoint_t *ep_desc = NULL;
usb_host_interface_t *interface_ptr;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (audioPtr->isoOutPipe != NULL)
{
(void)USB_HostClosePipe(audioPtr->hostHandle, audioPtr->isoOutPipe);
audioPtr->isoOutPipe = NULL;
}
/* open interface pipes */
interface_ptr = (usb_host_interface_t *)audioPtr->streamIntfHandle;
for (ep_index = 0U; ep_index < interface_ptr->epCount; ++ep_index)
{
ep_desc = interface_ptr->epList[ep_index].epDesc;
if (((ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) ==
USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) &&
((ep_desc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_ISOCHRONOUS))
{
uint8_t intervalBackUp = ep_desc->bInterval;
ep_desc->bInterval = intervalValue;
status = _USB_HostAudioInitEndpoint(audioPtr, ep_desc);
ep_desc->bInterval = intervalBackUp;
}
}
return status;
}
#endif /* USB_HOST_CONFIG_AUDIO */