/* * 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_CDC) && (USB_HOST_CONFIG_CDC)) #include "usb_host.h" #include "usb_host_cdc.h" #include "usb_host_devices.h" #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) static void USB_HostCdcClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; cdcInstance->controlTransfer = NULL; if (cdcInstance->inCallbackFn != NULL) { /* callback to application */ cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, cdcInstance->stallDataBuffer, cdcInstance->stallDataLength, kStatus_USB_TransferStall); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } static void USB_HostCdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; cdcInstance->controlTransfer = NULL; if (cdcInstance->outCallbackFn != NULL) { /* callback to application */ cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, cdcInstance->stallDataBuffer, cdcInstance->stallDataLength, kStatus_USB_TransferStall); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } static void USB_HostCdcClearInterruptHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; cdcInstance->controlTransfer = NULL; if (cdcInstance->interruptCallbackFn != NULL) { /* callback to application */ cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, cdcInstance->stallDataBuffer, cdcInstance->stallDataLength, kStatus_USB_TransferStall); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } static usb_status_t USB_HostCdcClearHalt(usb_host_cdc_instance_struct_t *cdcInstance, usb_host_transfer_t *stallTransfer, host_inner_transfer_callback_t callbackFn, uint8_t endpoint) { usb_status_t status; usb_host_transfer_t *transfer; /* malloc one transfer */ status = USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("allocate transfer error\r\n"); #endif return status; } cdcInstance->stallDataBuffer = stallTransfer->transferBuffer; cdcInstance->stallDataLength = stallTransfer->transferSofar; /* save the application callback function */ cdcInstance->controlCallbackFn = NULL; cdcInstance->controlCallbackParam = NULL; /* initialize transfer */ transfer->callbackFn = callbackFn; transfer->callbackParam = cdcInstance; transfer->transferBuffer = NULL; transfer->transferLength = 0; transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_CLEAR_FEATURE; transfer->setupPacket.bmRequestType = USB_REQUEST_TYPE_RECIPIENT_ENDPOINT; transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT); transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(endpoint); transfer->setupPacket.wLength = 0; status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); if (status != kStatus_USB_Success) { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } cdcInstance->controlTransfer = transfer; return status; } #endif /*! * @brief cdc data in pipe transfer callback. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ void USB_HostCdcDataInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) if (status == kStatus_USB_TransferStall) { if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearInHaltCallback, (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)cdcInstance->inPipe)->endpointAddress)) == kStatus_USB_Success) { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return; } } #endif if (cdcInstance->inCallbackFn != NULL) { cdcInstance->inCallbackFn(cdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief cdc data out pipe transfer callback. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ void USB_HostCdcDataOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) if (status == kStatus_USB_TransferStall) { if (USB_HostCdcClearHalt(cdcInstance, transfer, USB_HostCdcClearOutHaltCallback, (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)cdcInstance->outPipe)->endpointAddress)) == kStatus_USB_Success) { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return; } } #endif if (cdcInstance->outCallbackFn != NULL) { cdcInstance->outCallbackFn(cdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief cdc data out pipe transfer callback. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ void USB_HostCdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; #if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) if (status == kStatus_USB_TransferStall) { if (USB_HostCdcClearHalt( cdcInstance, transfer, USB_HostCdcClearInterruptHaltCallback, (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)cdcInstance->interruptPipe)->endpointAddress)) == kStatus_USB_Success) { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return; } } #endif if (cdcInstance->interruptCallbackFn != NULL) { cdcInstance->interruptCallbackFn(cdcInstance->interruptCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief cdc data out pipe transfer callback. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ void USB_HostCdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; if (cdcInstance->controlCallbackFn != NULL) { cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, transfer->transferBuffer, transfer->transferSofar, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief cdc open data interface. * * @param cdcInstance cdc instance pointer. * * @return kStatus_USB_Success or error codes. */ static usb_status_t USB_HostCdcOpenDataInterface(usb_host_cdc_instance_struct_t *cdcInstance) { usb_status_t status; uint8_t ep_index = 0; usb_host_pipe_init_t pipeInit; usb_descriptor_endpoint_t *ep_desc = NULL; usb_host_interface_t *interfaceHandle; if (cdcInstance->inPipe != NULL) { status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->inPipe = NULL; } if (cdcInstance->outPipe != NULL) { status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->outPipe = NULL; } status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->dataInterfaceHandle); if (status != kStatus_USB_Success) { return status; } /* open interface pipes */ interfaceHandle = (usb_host_interface_t *)cdcInstance->dataInterfaceHandle; for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index) { ep_desc = interfaceHandle->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_BULK)) { pipeInit.devInstance = cdcInstance->deviceHandle; pipeInit.pipeType = USB_ENDPOINT_BULK; pipeInit.direction = USB_IN; pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); pipeInit.interval = ep_desc->bInterval; pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; cdcInstance->bulkInPacketSize = pipeInit.maxPacketSize; status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->inPipe, &pipeInit); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("usb_host_audio_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_BULK)) { pipeInit.devInstance = cdcInstance->deviceHandle; pipeInit.pipeType = USB_ENDPOINT_BULK; pipeInit.direction = USB_OUT; pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); pipeInit.interval = ep_desc->bInterval; pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; cdcInstance->bulkOutPacketSize = pipeInit.maxPacketSize; status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->outPipe, &pipeInit); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("usb_host_cdc_set_dat_interface fail to open pipe\r\n"); #endif return kStatus_USB_Error; } } else { } } return kStatus_USB_Success; } /*! * @brief cdc set data interface callback, open pipes. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ static void USB_HostCdcSetDataInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; cdcInstance->controlTransfer = NULL; if (status == kStatus_USB_Success) { status = USB_HostCdcOpenDataInterface(cdcInstance); } if (cdcInstance->controlCallbackFn != NULL) { cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief cdc open control interface. * * @param cdcInstance cdc instance pointer. * * @return kStatus_USB_Success or error codes. */ static usb_status_t USB_HostCdcOpenControlInterface(usb_host_cdc_instance_struct_t *cdcInstance) { usb_status_t status; uint8_t ep_index = 0; usb_host_pipe_init_t pipeInit; usb_descriptor_endpoint_t *ep_desc = NULL; usb_host_interface_t *interfaceHandle; if (cdcInstance->interruptPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->interruptPipe = NULL; } status = USB_HostOpenDeviceInterface(cdcInstance->deviceHandle, cdcInstance->controlInterfaceHandle); if (status != kStatus_USB_Success) { return status; } /* open interface pipes */ interfaceHandle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle; for (ep_index = 0; ep_index < interfaceHandle->epCount; ++ep_index) { ep_desc = interfaceHandle->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_INTERRUPT)) { pipeInit.devInstance = cdcInstance->deviceHandle; pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; pipeInit.direction = USB_IN; pipeInit.endpointAddress = (ep_desc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); pipeInit.interval = ep_desc->bInterval; pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) & USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; cdcInstance->packetSize = pipeInit.maxPacketSize; status = USB_HostOpenPipe(cdcInstance->hostHandle, &cdcInstance->interruptPipe, &pipeInit); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("USB_HostCdcSetControlInterface fail to open pipe\r\n"); #endif return kStatus_USB_Error; } } } return kStatus_USB_Success; } /*! * @brief cdc set control interface callback, open pipes. * * @param param callback parameter. * @param transfer callback transfer. * @param status transfer status. */ static void USB_HostCdcSetContorlInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)param; cdcInstance->controlTransfer = NULL; if (status == kStatus_USB_Success) { status = USB_HostCdcOpenControlInterface(cdcInstance); } if (cdcInstance->controlCallbackFn != NULL) { cdcInstance->controlCallbackFn(cdcInstance->controlCallbackParam, NULL, 0, status); } USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } /*! * @brief initialize the cdc instance. * * This function allocate the resource for cdc instance. * * @param deviceHandle the device handle. * @param classHandle return class handle. * * @retval kStatus_USB_Success The device is initialized successfully. * @retval kStatus_USB_AllocFail Allocate memory fail. */ usb_status_t USB_HostCdcInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) { usb_host_cdc_instance_struct_t *control_ptr = (usb_host_cdc_instance_struct_t *)USB_OsaMemoryAllocate(sizeof(usb_host_cdc_instance_struct_t)); uint32_t info_value; if (control_ptr == NULL) { return kStatus_USB_AllocFail; } control_ptr->deviceHandle = deviceHandle; control_ptr->controlInterfaceHandle = NULL; control_ptr->dataInterfaceHandle = NULL; USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &info_value); control_ptr->hostHandle = (usb_host_handle)info_value; USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &info_value); control_ptr->controlPipe = (usb_host_pipe_handle)info_value; *classHandle = control_ptr; return kStatus_USB_Success; } /*! * @brief set control interface. * * This function bind the control interface with the cdc instance. * * @param classHandle the class handle. * @param interfaceHandle the control 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_HostCdcSetControlInterface(usb_host_class_handle classHandle, usb_host_interface_handle interfaceHandle, uint8_t alternateSetting, transfer_callback_t callbackFn, void *callbackParam) { usb_status_t status; usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; status = kStatus_USB_Success; if (classHandle == NULL) { return kStatus_USB_InvalidParameter; } cdcInstance->controlInterfaceHandle = interfaceHandle; /* cancel transfers */ if (cdcInstance->interruptPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when cancel pipe\r\n"); #endif } } if (alternateSetting == 0) { if (callbackFn != NULL) { status = USB_HostCdcOpenControlInterface(cdcInstance); callbackFn(callbackParam, NULL, 0, status); } } else { if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->controlCallbackFn = callbackFn; cdcInstance->controlCallbackParam = callbackParam; /* initialize transfer */ transfer->callbackFn = USB_HostCdcSetContorlInterfaceCallback; transfer->callbackParam = cdcInstance; 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 *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber); transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); transfer->setupPacket.wLength = 0; transfer->transferBuffer = NULL; transfer->transferLength = 0; status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); if (status == kStatus_USB_Success) { cdcInstance->controlTransfer = transfer; } else { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } } return status; } /*! * @brief set data interface. * * This function bind the control interface with the cdc instance. * * @param classHandle the class handle. * @param interfaceHandle the data 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_HostCdcSetDataInterface(usb_host_class_handle classHandle, usb_host_interface_handle interfaceHandle, uint8_t alternateSetting, transfer_callback_t callbackFn, void *callbackParam) { usb_status_t status; usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; status = kStatus_USB_Success; if (classHandle == NULL) { return kStatus_USB_InvalidParameter; } cdcInstance->dataInterfaceHandle = interfaceHandle; /* cancel transfers */ if (cdcInstance->inPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when cancel pipe\r\n"); #endif } } if (cdcInstance->outPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when cancel pipe\r\n"); #endif } } if (alternateSetting == 0) { if (callbackFn != NULL) { status = USB_HostCdcOpenDataInterface(cdcInstance); callbackFn(callbackParam, NULL, 0, status); } } else { if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->controlCallbackFn = callbackFn; cdcInstance->controlCallbackParam = callbackParam; /* initialize transfer */ transfer->callbackFn = USB_HostCdcSetDataInterfaceCallback; transfer->callbackParam = cdcInstance; 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 *)cdcInstance->dataInterfaceHandle)->interfaceDesc->bInterfaceNumber); transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); transfer->setupPacket.wLength = 0; transfer->transferBuffer = NULL; transfer->transferLength = 0; status = USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer); if (status == kStatus_USB_Success) { cdcInstance->controlTransfer = transfer; } else { USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); } } return status; } /*! * @brief de-initialize the cdc instance. * * This function release the resource for cdc 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_HostCdcDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) { usb_status_t status; usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; if (deviceHandle == NULL) { return kStatus_USB_InvalidHandle; } if (classHandle != NULL) { if (cdcInstance->interruptPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->interruptPipe, NULL); status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->interruptPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->interruptPipe = NULL; } USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->controlInterfaceHandle); if (cdcInstance->inPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->inPipe, NULL); status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->inPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->inPipe = NULL; } if (cdcInstance->outPipe != NULL) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->outPipe, NULL); status = USB_HostClosePipe(cdcInstance->hostHandle, cdcInstance->outPipe); if (status != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error when close pipe\r\n"); #endif } cdcInstance->outPipe = NULL; } if ((cdcInstance->controlPipe != NULL) && (cdcInstance->controlTransfer != NULL)) { status = USB_HostCancelTransfer(cdcInstance->hostHandle, cdcInstance->controlPipe, cdcInstance->controlTransfer); } USB_HostCloseDeviceInterface(deviceHandle, cdcInstance->dataInterfaceHandle); USB_OsaMemoryFree(cdcInstance); } else { USB_HostCloseDeviceInterface(deviceHandle, NULL); } return kStatus_USB_Success; } /*! * @brief receive data. * * This function implements cdc receiving data. * * @param classHandle the class handle. * @param buffer the buffer pointer. * @param bufferLength 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_HostCdcDataRecv(usb_host_class_handle classHandle, uint8_t *buffer, uint32_t bufferLength, transfer_callback_t callbackFn, void *callbackParam) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; if (classHandle == NULL) { return kStatus_USB_InvalidHandle; } if (cdcInstance->inPipe == NULL) { return kStatus_USB_Error; } if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->inCallbackFn = callbackFn; cdcInstance->inCallbackParam = callbackParam; transfer->transferBuffer = buffer; transfer->transferLength = bufferLength; transfer->callbackFn = USB_HostCdcDataInPipeCallback; transfer->callbackParam = cdcInstance; if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->inPipe, transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("failt to USB_HostRecv\r\n"); #endif USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return kStatus_USB_Error; } return kStatus_USB_Success; } /*! * @brief send data. * * This function implements cdc sending data. * * @param classHandle the class handle. * @param buffer the buffer pointer. * @param bufferLength 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_HostCdcDataSend(usb_host_class_handle classHandle, uint8_t *buffer, uint32_t bufferLength, transfer_callback_t callbackFn, void *callbackParam) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; if (classHandle == NULL) { return kStatus_USB_InvalidHandle; } if (cdcInstance->outPipe == NULL) { return kStatus_USB_Error; } if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->outCallbackFn = callbackFn; cdcInstance->outCallbackParam = callbackParam; transfer->transferBuffer = buffer; transfer->transferLength = bufferLength; transfer->callbackFn = USB_HostCdcDataOutPipeCallback; transfer->callbackParam = cdcInstance; if (USB_HostSend(cdcInstance->hostHandle, cdcInstance->outPipe, transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("failt to USB_HostSend\r\n"); #endif USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return kStatus_USB_Error; } return kStatus_USB_Success; } /*! * @brief interrupt receive data. * * This function implements interrupt receiving data. * * @param classHandle the class handle. * @param buffer the buffer pointer. * @param bufferLength 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_HostCdcInterruptRecv(usb_host_class_handle classHandle, uint8_t *buffer, uint32_t bufferLength, transfer_callback_t callbackFn, void *callbackParam) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; if (classHandle == NULL) { return kStatus_USB_InvalidHandle; } if (cdcInstance->interruptPipe == NULL) { return kStatus_USB_Error; } if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->interruptCallbackFn = callbackFn; cdcInstance->interruptCallbackParam = callbackParam; transfer->transferBuffer = buffer; transfer->transferLength = bufferLength; transfer->callbackFn = USB_HostCdcInterruptPipeCallback; transfer->callbackParam = cdcInstance; if (USB_HostRecv(cdcInstance->hostHandle, cdcInstance->interruptPipe, transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("failt to usb_interrupt_recv\r\n"); #endif USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return kStatus_USB_Error; } return kStatus_USB_Success; } /*! * @brief get pipe max packet size. * * @param[in] classHandle the class handle. * @param[in] 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[in] direction pipe direction. * * @retval 0 The classHandle is NULL. * @retval max packet size. */ uint16_t USB_HostCdcGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; if (classHandle == NULL) { return 0; } if (pipeType == USB_ENDPOINT_BULK) { if (direction == USB_IN) { return cdcInstance->bulkInPacketSize; } else { return cdcInstance->bulkOutPacketSize; } } return 0; } /*! * @brief cdc send control transfer common code. * * @param classHandle the class handle. * @param request_type setup packet request type. * @param request setup packet request value. * @param wvalue_l setup packet wvalue low byte. * @param wvalue_h setup packet wvalue high byte. * @param wlength setup packet wlength value. * @param data data buffer pointer * @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. */ usb_status_t USB_HostCdcControl(usb_host_class_handle classHandle, uint8_t request_type, uint8_t request, uint8_t wvalue_l, uint8_t wvalue_h, uint16_t wlength, uint8_t *data, transfer_callback_t callbackFn, void *callbackParam) { usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_host_transfer_t *transfer; if (classHandle == NULL) { return kStatus_USB_InvalidHandle; } if (USB_HostMallocTransfer(cdcInstance->hostHandle, &transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("error to get transfer\r\n"); #endif return kStatus_USB_Error; } cdcInstance->controlCallbackFn = callbackFn; cdcInstance->controlCallbackParam = callbackParam; transfer->transferBuffer = data; transfer->transferLength = wlength; transfer->callbackFn = USB_HostCdcControlPipeCallback; transfer->callbackParam = cdcInstance; transfer->setupPacket.bmRequestType = request_type; transfer->setupPacket.bRequest = request; transfer->setupPacket.wValue = (wvalue_l | (uint16_t)((uint16_t)wvalue_h << 8)); transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( ((usb_host_interface_t *)cdcInstance->controlInterfaceHandle)->interfaceDesc->bInterfaceNumber); transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); if (USB_HostSendSetup(cdcInstance->hostHandle, cdcInstance->controlPipe, transfer) != kStatus_USB_Success) { #ifdef HOST_ECHO usb_echo("failt for USB_HostSendSetup\r\n"); #endif USB_HostFreeTransfer(cdcInstance->hostHandle, transfer); return kStatus_USB_Error; } cdcInstance->controlTransfer = transfer; return kStatus_USB_Success; } /*! * @brief cdc get line coding. * * This function implements cdc GetLineCoding request.refer to pstn spec. * * @param classHandle the class handle. * @param buffer the buffer pointer. * @param bufferLength 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 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_HostCdcGetAcmLineCoding(usb_host_class_handle classHandle, usb_host_cdc_line_coding_struct_t *uartLineCoding, transfer_callback_t callbackFn, void *callbackParam) { return USB_HostCdcControl( classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, USB_HOST_CDC_GET_LINE_CODING, 0, 0, 7, (uint8_t *)uartLineCoding, callbackFn, callbackParam); } /*! * @brief cdc setControlLineState. * * This function implements cdc etControlLineState request.refer to pstn spec. * * @param classHandle the class handle. * @param buffer the buffer pointer. * @param bufferLength 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 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_HostCdcSetAcmCtrlState( usb_host_class_handle classHandle, uint8_t dtr, uint8_t rts, transfer_callback_t callbackFn, void *callbackParam) { uint16_t lineState = 0; usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; lineState = dtr ? USB_HOST_CDC_CONTROL_LINE_STATE_DTR : 0; lineState |= rts ? USB_HOST_CDC_CONTROL_LINE_STATE_RTS : 0; return USB_HostCdcControl( cdcInstance, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, USB_HOST_CDC_SET_CONTROL_LINE_STATE, USB_SHORT_GET_LOW(lineState), USB_SHORT_GET_HIGH(lineState), 0, NULL, callbackFn, callbackParam); } /*! * @brief cdc get acm descriptor. * * This function is hunting for class specific acm decriptor in the configuration ,get the corresponding * descriptor . * * @param classHandle the class handle. * @param headDesc the head function descriptor pointer. * @param callManageDesc the call management functional descriptor pointer. * @param abstractControlDesc the abstract control management functional pointer. * @param unionInterfaceDesc the union functional descriptor pointer. * * @retval kStatus_USB_Error analyse descriptor error. */ usb_status_t USB_HostCdcGetAcmDescriptor(usb_host_class_handle classHandle, usb_host_cdc_head_function_desc_struct_t **headDesc, usb_host_cdc_call_manage_desc_struct_t **callManageDesc, usb_host_cdc_abstract_control_desc_struct_t **abstractControlDesc, usb_host_cdc_union_interface_desc_struct_t **unionInterfaceDesc) { usb_status_t status; usb_descriptor_union_t *ptr1; uint32_t end_address; usb_host_cdc_instance_struct_t *cdcInstance = (usb_host_cdc_instance_struct_t *)classHandle; usb_cdc_func_desc_struct_t *cdc_common_ptr; usb_host_interface_t *interface_handle; status = kStatus_USB_Success; interface_handle = (usb_host_interface_t *)cdcInstance->controlInterfaceHandle; ptr1 = (usb_descriptor_union_t *)interface_handle->interfaceExtension; end_address = (uint32_t)(interface_handle->interfaceExtension + interface_handle->interfaceExtensionLength); while ((uint32_t)ptr1 < end_address) { cdc_common_ptr = (usb_cdc_func_desc_struct_t *)&ptr1->common; switch (cdc_common_ptr->common.bDescriptorSubtype) { case USB_HOST_DESC_SUBTYPE_HEADER: *headDesc = &cdc_common_ptr->head; if ((((uint32_t)((*headDesc)->bcdCDC[1]) << 8) + (*headDesc)->bcdCDC[0]) > 0x0110) { status = kStatus_USB_Error; } break; case USB_HOST_DESC_SUBTYPE_UNION: if (cdc_common_ptr->unionDesc.bControlInterface == interface_handle->interfaceDesc->bInterfaceNumber) { *unionInterfaceDesc = &cdc_common_ptr->unionDesc; } else { status = kStatus_USB_Error; } break; case USB_HOST_DESC_SUBTYPE_CM: *callManageDesc = &cdc_common_ptr->callManage; break; case USB_HOST_DESC_SUBTYPE_ACM: *abstractControlDesc = &cdc_common_ptr->acm; break; default: break; } if (kStatus_USB_Success != status) { break; } ptr1 = (usb_descriptor_union_t *)((uint8_t *)ptr1 + ptr1->common.bLength); } cdcInstance->headDesc = *headDesc; cdcInstance->callManageDesc = *callManageDesc; cdcInstance->abstractControlDesc = *abstractControlDesc; cdcInstance->unionInterfaceDesc = *unionInterfaceDesc; return status; } #endif