From f7cd9b461ca33845339f4a11f49bdc142696827a Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Tue, 28 Jun 2016 09:51:29 +0200 Subject: Apalis_TK1_K20: SPI Communication, ADC, TSC, GPIO Support for Communication between TK1 SoC and K20 MCU This patch includes ADC, TSC and GPIO functionality. Signed-off-by: Dominik Sliwa --- usb_1.1.0/host/class/usb_host_audio.c | 1051 +++++++++++++++++++++++++++++++++ 1 file changed, 1051 insertions(+) create mode 100644 usb_1.1.0/host/class/usb_host_audio.c (limited to 'usb_1.1.0/host/class/usb_host_audio.c') 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 */ -- cgit v1.2.3