/* * 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 = 0U; 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) { if (audioPtr->itDesc == NULL) { audioPtr->itDesc = (void *)temp; } } else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_OUTPUT) { if (audioPtr->otDesc == NULL) { audioPtr->otDesc = (void *)temp; } } else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_FEATURE) { if (audioPtr->fuDesc == NULL) { audioPtr->fuDesc = (void *)temp; } } else if (ptr1.common->bData[0] == USB_AUDIO_DESC_SUBTYPE_CS_CLOCK_SOURE) { if (audioPtr->clockSource == NULL) { 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 */