summaryrefslogtreecommitdiff
path: root/usb_1.1.0/host/class/usb_host_audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb_1.1.0/host/class/usb_host_audio.c')
-rw-r--r--usb_1.1.0/host/class/usb_host_audio.c1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/usb_1.1.0/host/class/usb_host_audio.c b/usb_1.1.0/host/class/usb_host_audio.c
new file mode 100644
index 0000000..798d7ef
--- /dev/null
+++ b/usb_1.1.0/host/class/usb_host_audio.c
@@ -0,0 +1,1051 @@
+/*
+ * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "usb_host_config.h"
+#if ((defined USB_HOST_CONFIG_AUDIO) && (USB_HOST_CONFIG_AUDIO))
+#include "usb_host.h"
+#include "usb_host_audio.h"
+
+/*******************************************************************************
+ * 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 *)USB_OsaMemoryAllocate(sizeof(audio_instance_t));
+ uint32_t info_value;
+
+ if (audioPtr == NULL)
+ {
+ return kStatus_USB_AllocFail;
+ }
+
+ audioPtr->deviceHandle = deviceHandle;
+ audioPtr->controlIntfHandle = NULL;
+ audioPtr->streamIntfHandle = NULL;
+ USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &info_value);
+ audioPtr->hostHandle = (usb_host_handle)info_value;
+ USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &info_value);
+ audioPtr->controlPipe = (usb_host_pipe_handle)info_value;
+
+ *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;
+ 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);
+ 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);
+ 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;
+ }
+ USB_HostCloseDeviceInterface(deviceHandle, audioPtr->streamIntfHandle);
+
+ if ((audioPtr->controlPipe != NULL) && (audioPtr->controlTransfer != NULL))
+ {
+ status = USB_HostCancelTransfer(audioPtr->hostHandle, audioPtr->controlPipe, audioPtr->controlTransfer);
+ }
+ USB_HostCloseDeviceInterface(deviceHandle, audioPtr->controlIntfHandle);
+ USB_OsaMemoryFree(audioPtr);
+ }
+ else
+ {
+ USB_HostCloseDeviceInterface(deviceHandle, NULL);
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @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)
+ {
+ audioPtr->inCallbackFn(audioPtr->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, status);
+ }
+ 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)
+ {
+ audioPtr->outCallbackFn(audioPtr->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, status);
+ }
+ 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)
+ {
+ audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, transfer->transferBuffer, transfer->transferSofar,
+ status);
+ }
+ 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("failt for USB_HostSendSetup\r\n");
+#endif
+ USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
+ return kStatus_USB_Error;
+ }
+ audioPtr->controlTransfer = transfer;
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @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_host_pipe_init_t pipe_init;
+ 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))
+ {
+ pipe_init.devInstance = audioPtr->deviceHandle;
+ pipe_init.pipeType = USB_ENDPOINT_ISOCHRONOUS;
+ pipe_init.direction = USB_IN;
+ 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 = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
+ USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK);
+ pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
+
+ audioPtr->inPacketSize = pipe_init.maxPacketSize;
+ audioPtr->isoEpNum = pipe_init.endpointAddress;
+ status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoInPipe, &pipe_init);
+ 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))
+ {
+ pipe_init.devInstance = audioPtr->deviceHandle;
+ pipe_init.pipeType = USB_ENDPOINT_ISOCHRONOUS;
+ pipe_init.direction = USB_OUT;
+ 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 = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
+ USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK);
+ pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
+
+ audioPtr->outPacketSize = pipe_init.maxPacketSize;
+ audioPtr->isoEpNum = pipe_init.endpointAddress;
+ status = USB_HostOpenPipe(audioPtr->hostHandle, &audioPtr->isoOutPipe, &pipe_init);
+ 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_Error;
+ }
+ }
+
+ 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)
+ {
+ audioPtr->controlCallbackFn(audioPtr->controlCallbackParam, NULL, 0U, status);
+ }
+ 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;
+
+ 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)
+ {
+ if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AS_CS_GENERAL)
+ {
+ audioPtr->asIntfDesc = (usb_audio_stream_spepific_as_intf_desc_t *)ptr1.bufr;
+ }
+ else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AS_CS_FORMAT_TYPE)
+ {
+ audioPtr->formatTypeDesc = (usb_audio_stream_format_type_desc_t *)ptr1.bufr;
+ }
+ else
+ {
+ }
+ }
+ if (ptr1.common->bDescriptorType == 0x05U)
+ {
+ interface_ptr->epList[ep].epDesc = (usb_descriptor_endpoint_t *)ptr1.bufr;
+ audioPtr->isoEndpDesc = (usb_audio_stream_specific_iso_endp_desc_t *)ptr1.bufr;
+ ep++;
+ ptr1.bufr += ptr1.common->bLength;
+ interface_ptr->epList[ep].epExtension = ptr1.bufr;
+ interface_ptr->epList[ep].epExtensionLength = ptr1.common->bLength;
+ break;
+ }
+ 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
+ {
+ 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;
+ 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)
+ {
+ if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_HEADER)
+ {
+ audioPtr->headerDesc = (usb_audio_ctrl_header_desc_t *)ptr1.bufr;
+ }
+ else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_IT)
+ {
+ audioPtr->itDesc = (usb_audio_ctrl_it_desc_t *)ptr1.bufr;
+ }
+ else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_OT)
+ {
+ audioPtr->otDesc = (usb_audio_ctrl_ot_desc_t *)ptr1.bufr;
+ }
+ else if (ptr1.common->bData[0] == USB_DESC_SUBTYPE_AUDIO_CS_FU)
+ {
+ audioPtr->fuDesc = (usb_audio_ctrl_fu_desc_t *)ptr1.bufr;
+ }
+ else
+ {
+ }
+ }
+ 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
+ {
+ 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 kStatus_USB_InvalidHandle;
+ }
+
+ 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("failt to USB_HostRecv\r\n");
+#endif
+ 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("failt to USB_HostSend\r\n");
+#endif
+ USB_HostFreeTransfer(audioPtr->hostHandle, transfer);
+ return kStatus_USB_Error;
+ }
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief get audio stream current altsetting descriptor.
+ *
+ * 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_audio_stream_specific_iso_endp_desc_t **isoEndpDesc)
+{
+ audio_instance_t *audioPtr = (audio_instance_t *)classHandle;
+
+ if (classHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+ *asIntfDesc = audioPtr->asIntfDesc;
+ *formatTypeDesc = audioPtr->formatTypeDesc;
+ *isoEndpDesc = audioPtr->isoEndpDesc;
+
+ return kStatus_USB_Success;
+}
+
+/*!
+ * @brief usb audio feature unit request.
+ *
+ * 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;
+ uint8_t *bmacontrols = NULL;
+ uint8_t atribute_index;
+ usb_status_t status = kStatus_USB_Error;
+
+ if (classHandle == NULL)
+ {
+ return kStatus_USB_InvalidHandle;
+ }
+
+ if_ptr = (audio_instance_t *)classHandle;
+
+ /* pointer to command */
+ p_feature_request = &(s_usbAudioFuRequests[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;
+ }
+ windex = (uint16_t)((uint16_t)((uint16_t)(if_ptr->fuDesc->bunitid) << 8U) | (if_ptr->streamIfnum));
+ atribute_index = if_ptr->fuDesc->bcontrolsize * channelNo;
+
+ if (atribute_index < (if_ptr->fuDesc->blength - 7))
+ {
+ bmacontrols = &(if_ptr->fuDesc->bcontrolsize);
+ }
+
+ if (bmacontrols == NULL)
+ {
+ return kStatus_USB_Error;
+ }
+
+ bmacontrols++;
+ if (bmacontrols[atribute_index] & p_feature_request->controlMask)
+ {
+ status = kStatus_USB_Success;
+ }
+
+ if (kStatus_USB_Success == status)
+ {
+ status = _USB_HostAudioControl(classHandle, (p_feature_request->typeRequest | (cmdCode & 0x80U)),
+ (p_feature_request->codeRequest | (cmdCode & 0x80U)), request_value, windex,
+ p_feature_request->length, (uint8_t *)buf, callbackFn, callbackParam);
+ }
+ return status;
+}
+
+/*!
+ * @brief usb audio endpoint request.
+ *
+ * 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 = kStatus_USB_Error;
+ 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;
+
+ /* pointer to command */
+ p_endpoint_request = &(s_usbAudioEpRequests[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 ((audioPtr->isoEndpDesc->bmattributes) && (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 | (cmdCode & 0x80U)),
+ (p_endpoint_request->codeRequest | (cmdCode & 0x80U)), request_value, endp_num,
+ p_endpoint_request->length, (uint8_t *)buf, callbackFn, callbackParam);
+ }
+
+ return status;
+}
+#endif /* USB_HOST_CONFIG_AUDIO */