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 +++++++++++++++++++++++++ usb_1.1.0/host/class/usb_host_audio.h | 549 +++++++++++++ usb_1.1.0/host/class/usb_host_cdc.c | 1200 +++++++++++++++++++++++++++++ usb_1.1.0/host/class/usb_host_cdc.h | 518 +++++++++++++ usb_1.1.0/host/class/usb_host_hid.c | 804 +++++++++++++++++++ usb_1.1.0/host/class/usb_host_hid.h | 411 ++++++++++ usb_1.1.0/host/class/usb_host_hub.c | 612 +++++++++++++++ usb_1.1.0/host/class/usb_host_hub.h | 390 ++++++++++ usb_1.1.0/host/class/usb_host_hub_app.c | 1106 +++++++++++++++++++++++++++ usb_1.1.0/host/class/usb_host_hub_app.h | 103 +++ usb_1.1.0/host/class/usb_host_msd.c | 1155 ++++++++++++++++++++++++++++ usb_1.1.0/host/class/usb_host_msd.h | 872 +++++++++++++++++++++ usb_1.1.0/host/class/usb_host_msd_ufi.c | 473 ++++++++++++ usb_1.1.0/host/class/usb_host_phdc.c | 1272 +++++++++++++++++++++++++++++++ usb_1.1.0/host/class/usb_host_phdc.h | 329 ++++++++ usb_1.1.0/host/class/usb_host_printer.c | 775 +++++++++++++++++++ usb_1.1.0/host/class/usb_host_printer.h | 301 ++++++++ 17 files changed, 11921 insertions(+) create mode 100644 usb_1.1.0/host/class/usb_host_audio.c create mode 100644 usb_1.1.0/host/class/usb_host_audio.h create mode 100644 usb_1.1.0/host/class/usb_host_cdc.c create mode 100644 usb_1.1.0/host/class/usb_host_cdc.h create mode 100644 usb_1.1.0/host/class/usb_host_hid.c create mode 100644 usb_1.1.0/host/class/usb_host_hid.h create mode 100644 usb_1.1.0/host/class/usb_host_hub.c create mode 100644 usb_1.1.0/host/class/usb_host_hub.h create mode 100644 usb_1.1.0/host/class/usb_host_hub_app.c create mode 100644 usb_1.1.0/host/class/usb_host_hub_app.h create mode 100644 usb_1.1.0/host/class/usb_host_msd.c create mode 100644 usb_1.1.0/host/class/usb_host_msd.h create mode 100644 usb_1.1.0/host/class/usb_host_msd_ufi.c create mode 100644 usb_1.1.0/host/class/usb_host_phdc.c create mode 100644 usb_1.1.0/host/class/usb_host_phdc.h create mode 100644 usb_1.1.0/host/class/usb_host_printer.c create mode 100644 usb_1.1.0/host/class/usb_host_printer.h (limited to 'usb_1.1.0/host/class') 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 */ diff --git a/usb_1.1.0/host/class/usb_host_audio.h b/usb_1.1.0/host/class/usb_host_audio.h new file mode 100644 index 0000000..e6728fd --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_audio.h @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef __USB_HOST_AUDIO_H__ +#define __USB_HOST_AUDIO_H__ + +/******************************************************************************* + * Audio class private structure, enumerations, macros + ******************************************************************************/ +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* Structure for an AUDIO class descriptor according to the 6.2.1 in Audio specification*/ +#define AUDIO_FU_MUTE 0x01 +#define AUDIO_FU_VOLUME 0x02 +#define AUDIO_FU_BASS 0x03 +#define AUDIO_FU_MID 0x04 +#define AUDIO_FU_TREBLE 0x05 +#define AUDIO_FU_GRAPHIC_EQ 0x06 +#define AUDIO_FU_AGC 0x07 +#define AUDIO_FU_DELAY 0x08 +#define AUDIO_FU_BASS_BOOST 0x09 + +/* Audio class codes */ +#define SET_COMMAND (0x00) +#define GET_COMMAND (0x80) +#define CUR_REQUEST (0x01) +#define MIN_REQUEST (0x02) +#define MAX_REQUEST (0x03) +#define RES_REQUEST (0x04) +#define MEM_REQUEST (0x05) +#define GET_STATUS (0xFF) + +#define ITF_REQUEST (0x21) +#define EP_REQUEST (0x22) + +#define AUDIO_FU_MUTE_MASK 0x01 +#define AUDIO_FU_VOLUME_MASK 0x02 +#define AUDIO_FU_BASS_MASK 0x04 +#define AUDIO_FU_MID_MASK 0x08 +#define AUDIO_FU_TREBLE_MASK 0x10 +#define AUDIO_FU_GRAPHIC_EQ_MASK 0x20 +#define AUDIO_FU_AGC_MASK 0x40 +#define AUDIO_FU_DELAY_MASK 0x80 +#define AUDIO_FU_BASS_BOOST_MASK 0x01 + +/* USB audio Endpoint Control Selectors */ +#define AUDIO_EP_CONTROL_UNDEFINED (0x00) +#define AUDIO_SAMPLING_FREQ_CONTROL (0x01) +#define AUDIO_PITCH_CONTROL (0x02) + +#define AUDIO_SAMPLING_FREQ_MASK (0x01) +#define AUDIO_PITCH_MASK (0x02) +typedef enum _fu_request_code +{ + kUSB_AudioCurMute = 0, + kUSB_AudioCurVolume, + kUSB_AudioMinVolume, + kUSB_AudioMaxVolume, + kUSB_AudioResVolume, + NUMBER_OF_FEATURE_COMMANDS, +} fu_request_code_t; + +typedef enum _ep_request_code +{ + kUSB_AudioCurPitch = 0, + kUSB_AudioCurSamplingFreq, + kUSB_AudioMinSamplingFreq, + kUSB_AudioMaxSamplingFreq, + kUSB_AudioResSamplingFreq, + NUMBER_OF_ENDPOINT_COMMANDS, +} ep_request_code_t; + +typedef union _audio_descriptor_union +{ + uint8_t *bufr; + usb_descriptor_common_t *common; + usb_descriptor_device_t *device; + usb_descriptor_configuration_t *configuration; + usb_descriptor_interface_t *interface; + usb_descriptor_endpoint_t *endpoint; +} audio_descriptor_union_t; + +/* Audio command structure */ +typedef struct _usb_audio_request +{ + uint8_t controlMask; + uint8_t typeRequest; + uint8_t codeRequest; + uint8_t requestValue; + uint8_t length; +} usb_audio_request_t; + +#define USB_DESC_SUBTYPE_AUDIO_CS_HEADER 0x01 +#define USB_DESC_SUBTYPE_AUDIO_CS_IT 0x02 +#define USB_DESC_SUBTYPE_AUDIO_CS_OT 0x03 +#define USB_DESC_SUBTYPE_AUDIO_CS_FU 0x06 +#define USB_DESC_CLASS_ENDPOINT_GENERAL 0x01 +#define USB_DESC_SUBTYPE_AS_CS_GENERAL 0X01 +#define USB_DESC_SUBTYPE_AS_CS_FORMAT_TYPE 0X02 + +/******************************************************************************* + * Audio class public structure, enumeration, macros, functions + ******************************************************************************/ +/*! + * @addtogroup usb_host_audio_drv + * @{ + */ +/*! @brief Audio class code */ +#define USB_AUDIO_CLASS_CODE 1 +/*! @brief Audio class control interface code*/ +#define USB_AUDIO_SUBCLASS_CODE_CONTROL 1 +/*! @brief Audio class stream interface code*/ +#define USB_AUDIO_SUBCLASS_CODE_AUDIOSTREAMING 2 + +/*! @brief AUDIO class-specific feature unit get current mute command*/ +#define USB_AUDIO_GET_CUR_MUTE 0x80 +/*! @brief AUDIO class-specific feature unit set current mute command*/ +#define USB_AUDIO_SET_CUR_MUTE 0x00 +/*! @brief AUDIO class-specific feature unit get current volume command*/ +#define USB_AUDIO_GET_CUR_VOLUME 0x81 +/*! @brief AUDIO class-specific feature unit set current volume command*/ +#define USB_AUDIO_SET_CUR_VOLUME 0x01 +/*! @brief AUDIO class-specific feature unit get minimum volume command*/ +#define USB_AUDIO_GET_MIN_VOLUME 0x82 +/*! @brief AUDIO class-specific feature unit set minimum volume command*/ +#define USB_AUDIO_SET_MIN_VOLUME 0x02 +/*! @brief AUDIO class-specific feature unit get maximum volume command*/ +#define USB_AUDIO_GET_MAX_VOLUME 0x83 +/*! @brief AUDIO class-specific feature unit set maximum volume command*/ +#define USB_AUDIO_SET_MAX_VOLUME 0x03 +/*! @brief AUDIO class-specific feature unit get resolution volume command*/ +#define USB_AUDIO_GET_RES_VOLUME 0x84 +/*! @brief AUDIO class-specific feature unit set resolution volume command*/ +#define USB_AUDIO_SET_RES_VOLUME 0x04 + +/*! @brief AUDIO class-specific endpoint get current pitch control command*/ +#define USB_AUDIO_GET_CUR_PITCH 0x80 +/*! @brief AUDIO class-specific endpoint set current pitch control command*/ +#define USB_AUDIO_SET_CUR_PITCH 0x00 +/*! @brief AUDIO class-specific endpoint get current sampling frequency command*/ +#define USB_AUDIO_GET_CUR_SAMPLING_FREQ 0x81 +/*! @brief AUDIO class-specific endpoint set current sampling frequency command*/ +#define USB_AUDIO_SET_CUR_SAMPLING_FREQ 0x01 +/*! @brief AUDIO class-specific endpoint get minimum sampling frequency command*/ +#define USB_AUDIO_GET_MIN_SAMPLING_FREQ 0x82 +/*! @brief AUDIO class-specific endpoint set minimum sampling frequency command*/ +#define USB_AUDIO_SET_MIN_SAMPLING_FREQ 0x02 +/*! @brief AUDIO class-specific endpoint get maximum sampling frequency command*/ +#define USB_AUDIO_GET_MAX_SAMPLING_FREQ 0x83 +/*! @brief AUDIO class-specific endpoint set maximum sampling frequency command*/ +#define USB_AUDIO_SET_MAX_SAMPLING_FREQ 0x03 +/*! @brief AUDIO class-specific endpoint get resolution sampling frequency command*/ +#define USB_AUDIO_GET_RES_SAMPLING_FREQ 0x84 +/*! @brief AUDIO class-specific endpoint set resolution sampling frequency command*/ +#define USB_AUDIO_SET_RES_SAMPLING_FREQ 0x04 + +/*! @brief Audio control interface header descriptor structure */ +typedef struct _usb_audio_ctrl_header_desc +{ + uint8_t blength; /*!< Total size of the header descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor type of audio header descriptor*/ + uint8_t bdescriptorsubtype; /*!< Subtype of an audio header descriptor*/ + uint8_t bcdcdc[2]; /*!< Audio Device Class Specification Release Number in Binary-Coded Decimal*/ + uint8_t wtotallength[2]; /*!< Total number of bytes returned for the class-specific AudioControl interface + descriptor. Includes the combined length of this descriptor header and all unit and + terminal descriptors.*/ + uint8_t bincollection; /*!< The number of AudioStreaming and MIDIStreaming interfaces in the Audio Interface + Collection to which this AudioControl interface belongs to*/ +} usb_audio_ctrl_header_desc_t; + +/*! @brief Audio control interface input terminal descriptor structure */ +typedef struct _usb_audio_ctrl_it_desc +{ + uint8_t blength; /*!< Total size of the input terminal descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor type of audio input terminal descriptor*/ + uint8_t bdescriptorsubtype; /*!< Subtype of audio input terminal descriptor*/ + uint8_t bterminalid; /*!< Constant uniquely identifying the Terminal within the audio function. This value is used + in all requests to address this Terminal*/ + uint8_t wterminaltype[2]; /*!< Constant characterizing the type of Terminal*/ + uint8_t bassocterminal; /*!< ID of the Output Terminal to which this Input Terminal is associated*/ + uint8_t bnrchannels; /*!< Number of logical output channels in the Terminal's output audio channel cluster*/ + uint8_t wchannelconfig[2]; /*!< Describes the spatial location of the logical channels.*/ + uint8_t ichannelnames; /*!< Index of a string descriptor, describing the name of the first logical channel*/ + uint8_t iterminal; /*!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 diff --git a/usb_1.1.0/host/class/usb_host_cdc.h b/usb_1.1.0/host/class/usb_host_cdc.h new file mode 100644 index 0000000..0acc181 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_cdc.h @@ -0,0 +1,518 @@ +/* + * 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. + */ + +#ifndef __USB_HOST_CDC_H__ +#define __USB_HOST_CDC_H__ + +/*! + * @addtogroup usb_host_cdc_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Class-specific request PSTN*/ +/*! @brief CDC class-specific request (SET_LINE_CODING) */ +#define USB_HOST_CDC_SET_LINE_CODING 0x20U +/*! @brief CDC class-specific request (GET_LINE_CODING) */ +#define USB_HOST_CDC_GET_LINE_CODING 0x21U +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) */ +#define USB_HOST_CDC_SET_CONTROL_LINE_STATE 0x22U + +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BTXCARRITER 0x01U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BRXCARRITER 0x02U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BBREAK 0x04U +/*! @brief CDC class-specific notifications(SerialState) bitmap*/ +#define USB_HOST_ACM_UART_STATE_BITMAP_BBRINGSIGNAL 0x10U + +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) bitmap*/ +#define USB_HOST_CDC_CONTROL_LINE_STATE_DTR 0x01U +/*! @brief CDC class-specific request (SET_CONTROL_LINE_STATE) bitmap*/ +#define USB_HOST_CDC_CONTROL_LINE_STATE_RTS 0x02U + +/*CDC SPEC*/ +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_HEADER 0x00U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_CM 0x01U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_ACM 0x02U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_DLM 0x03U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TR 0x04U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TC_LSR 0x05U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_UNION 0x06U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_CS 0x07U +/*! @brief CDC class-specific bDescriptor SubType in functional descriptors*/ +#define USB_HOST_DESC_SUBTYPE_TOM 0x08U + +/*See the CDC specification page20*/ +/*! @brief CDC class-specific code, Communications Interface Class Code*/ +#define USB_HOST_CDC_COMMUNICATIONS_CLASS_CODE 0x02U +/*! @brief CDC class-specific code,Communications Class Subclass Codes*/ +#define USB_HOST_CDC_SUBCLASS_ACM_CODE 0x02U +/*No class specific protocol required. See the CDC specification page22*/ +#define USB_HOST_CDC_PROTOCOL_CODE 0x00U +/*! @brief CDC class-specific code,Data Class Interface Codes*/ +#define USB_HOST_CDC_DATA_CLASS_CODE 0x0AU +/* This field is unused for Data Class interfaces and should have a value of 00h.*/ +#define USB_HOST_CDC_DATA_SUBCLASS_CODE 0x00U +/*No class-specific protocol required. See the CDC specification page22*/ +#define USB_HOST_CDC_DATA_PROTOCOL_CODE 0x00U + +/*! @brief CDC GetLineCoding structure according to the 6.3 in PSTN specification */ +typedef struct _usb_host_cdc_line_coding_struct +{ + uint32_t dwDTERate; /*!< Data terminal rate, in bits per second*/ + uint8_t bCharFormat; /*!< Stop bits*/ + uint8_t bParityType; /*!< Parity*/ + uint8_t bDataBits; /*!< Data bits (5, 6, 7, 8 or 16).*/ +} usb_host_cdc_line_coding_struct_t; + +/*! @brief CDC GetLineCoding structure according to the 6.3 in PSTN specification */ +typedef struct _usb_host_cdc_control_line_state_struct +{ + uint16_t line_state; /*!< D1, This signal corresponds to V.24 signal 105 and RS-232 signal RTS*/ + /*!< D0, This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR*/ +} usb_host_cdc_control_line_state_struct_t; + +/*! @brief CDC SerialState structure according to the 6.5.4 in PSTN specification */ +typedef struct _usb_host_cdc_acm_state_struct +{ + uint8_t reserved[8]; /*!< Notify response by the device, this is used as notification header, which is returned by the + device */ + uint8_t bmstate; /*!< UART State Bitmap Values*/ + uint8_t reserved1[1]; /*!< Fix 4B align issue*/ + uint8_t reserved2[2]; /*!< Fix 4B align issue*/ +} usb_host_cdc_acm_state_struct_t; + +/*! @brief CDC Header Functional Descriptor structure according to the 5.2.3 in CDC specification */ +typedef struct _usb_host_cdc_head_function_desc_struct +{ + uint8_t bFunctionLength; /*!controlTransfer = NULL; + if (hidInstance->inCallbackFn != NULL) + { + /* callback to application */ + hidInstance->inCallbackFn(hidInstance->inCallbackParam, hidInstance->stallDataBuffer, + hidInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (hidInstance->outCallbackFn != NULL) + { + /* callback to application */ + hidInstance->outCallbackFn(hidInstance->outCallbackParam, hidInstance->stallDataBuffer, + hidInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHidClearHalt(usb_host_hid_instance_t *hidInstance, + 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(hidInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + hidInstance->stallDataBuffer = stallTransfer->transferBuffer; + hidInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + hidInstance->controlCallbackFn = NULL; + hidInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = hidInstance; + 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(hidInstance->hostHandle, hidInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + } + hidInstance->controlTransfer = transfer; + + return status; +} +#endif + +static void USB_HostHidInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_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_HostHidClearHalt(hidInstance, transfer, USB_HostHidClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | + ((usb_host_pipe_t *)hidInstance->inPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return; + } + } +#endif + if (hidInstance->inCallbackFn != NULL) + { + hidInstance->inCallbackFn(hidInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_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_HostHidClearHalt(hidInstance, transfer, USB_HostHidClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | + ((usb_host_pipe_t *)hidInstance->outPipe)->endpointAddress)) == kStatus_USB_Success) + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return; + } + } +#endif + if (hidInstance->outCallbackFn != NULL) + { + hidInstance->outCallbackFn(hidInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static void USB_HostHidControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (hidInstance->controlCallbackFn != NULL) + { + hidInstance->controlCallbackFn(hidInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHidOpenInterface(usb_host_hid_instance_t *hidInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (hidInstance->inPipe != NULL) /* close interrupt in pipe if it is open */ + { + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->inPipe = NULL; + } + if (hidInstance->outPipe != NULL) /* close interrupt out pipe if it is open */ + { + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)hidInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + pipeInit.devInstance = hidInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + hidInstance->inPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(hidInstance->hostHandle, &hidInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostHidSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + pipeInit.devInstance = hidInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + hidInstance->outPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(hidInstance->hostHandle, &hidInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostHidSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostHidSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)param; + + hidInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostHidOpenInterface(hidInstance); /* hid open interface */ + } + + if (hidInstance->controlCallbackFn != NULL) + { + hidInstance->controlCallbackFn(hidInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); +} + +usb_status_t USB_HostHidInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_hid_instance_t)); /* malloc hid class instance */ + + if (hidInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize hid instance */ + hidInstance->deviceHandle = deviceHandle; + hidInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + hidInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + hidInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = hidInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidSetInterface(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_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + hidInstance->interfaceHandle = interfaceHandle; + status = USB_HostOpenDeviceInterface(hidInstance->deviceHandle, + interfaceHandle); /* notify host driver the interface is open */ + if (status != kStatus_USB_Success) + { + return status; + } + + /* cancel transfers */ + if (hidInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->inPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (hidInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->outPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostHidOpenInterface(hidInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save the application callback function */ + hidInstance->controlCallbackFn = callbackFn; + hidInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostHidSetInterfaceCallback; + transfer->callbackParam = hidInstance; + 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 *)hidInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(hidInstance->hostHandle, hidInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + hidInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostHidDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) /* class instance has initialized */ + { + if (hidInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->inPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->inPipe = NULL; + } + if (hidInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(hidInstance->hostHandle, hidInstance->outPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hidInstance->outPipe = NULL; + } + if ((hidInstance->controlPipe != NULL) && + (hidInstance->controlTransfer != NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = + USB_HostCancelTransfer(hidInstance->hostHandle, hidInstance->controlPipe, hidInstance->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + hidInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(hidInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +uint16_t USB_HostHidGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + if (classHandle == NULL) + { + return 0; + } + + if (pipeType == USB_ENDPOINT_INTERRUPT) + { + if (direction == USB_IN) + { + return hidInstance->inPacketSize; + } + else + { + return hidInstance->outPacketSize; + } + } + + return 0; +} + +usb_status_t USB_HostHidRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (hidInstance->inPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + hidInstance->inCallbackFn = callbackFn; + hidInstance->inCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHidInPipeCallback; + transfer->callbackParam = hidInstance; + + if (USB_HostRecv(hidInstance->hostHandle, hidInstance->inPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (hidInstance->outPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* save the application callback function */ + hidInstance->outCallbackFn = callbackFn; + hidInstance->outCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHidOutPipeCallback; + transfer->callbackParam = hidInstance; + + if (USB_HostSend(hidInstance->hostHandle, hidInstance->outPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostHidControl(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint8_t wvalueL, + uint8_t wvalueH, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hid_instance_t *hidInstance = (usb_host_hid_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(hidInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + hidInstance->controlCallbackFn = callbackFn; + hidInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = USB_HostHidControlCallback; + transfer->callbackParam = hidInstance; + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = (wvalueL | (uint16_t)((uint16_t)wvalueH << 8)); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)hidInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + + if (USB_HostSendSetup(hidInstance->hostHandle, hidInstance->controlPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { +#ifdef HOST_ECHO + usb_echo("failt for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(hidInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + hidInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHidGetReportDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t buffer_len, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_STANDARD | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_REQUEST_STANDARD_GET_DESCRIPTOR, 0, USB_DESCRIPTOR_TYPE_HID_REPORT, buffer_len, buffer, callbackFn, + callbackParam); +} + +usb_status_t USB_HostHidGetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t *idleRate, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_IDLE, reportId, 0, 1, idleRate, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t idleRate, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_IDLE, reportId, idleRate, 0, NULL, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidGetProtocol(usb_host_class_handle classHandle, + uint8_t *protocol, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_PROTOCOL, 0, 0, 1, protocol, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetProtocol(usb_host_class_handle classHandle, + uint8_t protocol, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_PROTOCOL, protocol, 0, 0, NULL, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidGetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_GET_REPORT, reportId, reportType, bufferLength, buffer, callbackFn, callbackParam); +} + +usb_status_t USB_HostHidSetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHidControl( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_HID_SET_REPORT, reportId, reportType, bufferLength, buffer, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_HID */ diff --git a/usb_1.1.0/host/class/usb_host_hid.h b/usb_1.1.0/host/class/usb_host_hid.h new file mode 100644 index 0000000..86e66d6 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hid.h @@ -0,0 +1,411 @@ +/* + * 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. + */ + +#ifndef _USB_HOST_HID_H_ +#define _USB_HOST_HID_H_ + +/******************************************************************************* + * HID class public structure, enumerations, macros, functions + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_hid_drv + * @{ + */ + +/*! @brief HID class-specific request (get report) */ +#define USB_HOST_HID_GET_REPORT (0x01U) +/*! @brief HID class-specific request (get idle) */ +#define USB_HOST_HID_GET_IDLE (0x02U) +/*! @brief HID class-specific request (get protocol) */ +#define USB_HOST_HID_GET_PROTOCOL (0x03U) +/*! @brief HID class-specific request (set report) */ +#define USB_HOST_HID_SET_REPORT (0x09U) +/*! @brief HID class-specific request (set idle) */ +#define USB_HOST_HID_SET_IDLE (0x0AU) +/*! @brief HID class-specific request (set protocol) */ +#define USB_HOST_HID_SET_PROTOCOL (0x0BU) + +/*! @brief HID class code */ +#define USB_HOST_HID_CLASS_CODE (3U) +/*! @brief HID sub-class code */ +#define USB_HOST_HID_SUBCLASS_CODE_NONE (0U) +/*! @brief HID sub-class code */ +#define USB_HOST_HID_SUBCLASS_CODE_BOOT (1U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_KEYBOARD (1U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_MOUSE (2U) +/*! @brief HID class protocol code */ +#define USB_HOST_HID_PROTOCOL_NONE (0U) + +/*! @brief HID get/set protocol request data code */ +#define USB_HOST_HID_REQUEST_PROTOCOL_BOOT (0U) +/*! @brief HID get/set protocol request data code */ +#define USB_HOST_HID_REQUEST_PROTOCOL_REPORT (1U) + +/*! @brief HID instance structure and HID usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_hid_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle inPipe; /*!< HID interrupt in pipe*/ + usb_host_pipe_handle outPipe; /*!< HID interrupt out pipe*/ + transfer_callback_t inCallbackFn; /*!< HID interrupt in transfer callback function pointer*/ + void *inCallbackParam; /*!< HID interrupt in transfer callback parameter*/ + transfer_callback_t outCallbackFn; /*!< HID interrupt out transfer callback function pointer*/ + void *outCallbackParam; /*!< HID interrupt out transfer callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< HID control transfer callback function pointer*/ + void *controlCallbackParam; /*!< HID control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; /*!< keep the data buffer for stall transfer's data*/ + uint32_t stallDataLength; /*!< keep the data length for stall transfer's data*/ +#endif + + uint16_t inPacketSize; /*!< HID interrupt in maximum packet size*/ + uint16_t outPacketSize; /*!< HID interrupt out maximum packet size*/ +} usb_host_hid_instance_t; + +/*! @brief HID descriptor structure according to the 6.2.1 in HID specification */ +typedef struct _usb_host_hid_descriptor +{ + uint8_t bLength; /*!< Total size of the HID descriptor*/ + uint8_t bDescriptorType; /*!< Constant name specifying type of HID descriptor*/ + uint8_t bcdHID[2]; /*!< Numeric expression identifying the HID Class Specification release*/ + uint8_t bCountryCode; /*!< Numeric expression identifying country code of the localized hardware*/ + uint8_t bNumDescriptors; /*!< Numeric expression specifying the number of class descriptors*/ + uint8_t bHidDescriptorType; /*!< Constant name identifying type of class descriptor*/ + uint8_t wDescriptorLength[2]; /*!< Numeric expression that is the total size of the Report descriptor*/ +} usb_host_hid_descriptor_t; + +/*! @brief HID descriptor structure according to the 6.2.1 in HID specification */ +typedef struct _usb_host_hid_class_descriptor +{ + uint8_t bHidDescriptorType; /*!< Constant name specifying type of optional descriptor*/ + uint8_t wDescriptorLength[2]; /*!< Numeric expression that is the total size of the optional descriptor*/ +} usb_host_hid_class_descriptor_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host HID class APIs + * @{ + */ + +/*! + * @brief Initializes the HID instance. + * + * This function allocate the resource for the HID instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostHidInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the HID instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostHidSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the the HID instance. + * + * This function frees the resources for the HID instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostHidDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum packet size. + */ +extern uint16_t USB_HostHidGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief HID get report descriptor. + * + * This function implements the HID report descriptor request. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] buffer_len The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetReportDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t buffer_len, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Receives data. + * + * This function implements the HID receiving data. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostRecv. + */ +extern usb_status_t USB_HostHidRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the HID sending data. + * + * @param[in] classHandle The class handle. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send 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. See the USB_HostSend. + */ +extern usb_status_t USB_HostHidSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get idle. + * + * This function implements the HID class-specific request (get idle). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[out] idleRate Return idle rate value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t *idleRate, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set idle. + * + * This function implements the HID class-specific request (set idle). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] idleRate Idle rate value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetIdle(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t idleRate, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get protocol. + * + * This function implements the HID class-specific request (get protocol). + * + * @param[in] classHandle The class handle. + * @param[out] protocol Return protocol value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetProtocol(usb_host_class_handle classHandle, + uint8_t *protocol, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set protocol. + * + * This function implements the HID class-specific request (set protocol). + * + * @param[in] classHandle The class handle. + * @param[in] protocol Protocol value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetProtocol(usb_host_class_handle classHandle, + uint8_t protocol, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID get report. + * + * This function implements the HID class-specific request (get report). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] reportType Report type. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidGetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HID set report. + * + * This function implements the HID class-specific request (set report). + * + * @param[in] classHandle The class handle. + * @param[in] reportId Report ID. + * @param[in] reportType Report type. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHidSetReport(usb_host_class_handle classHandle, + uint8_t reportId, + uint8_t reportType, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_HID_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_hub.c b/usb_1.1.0/host/class/usb_host_hub.c new file mode 100644 index 0000000..1200770 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub.c @@ -0,0 +1,612 @@ +/* + * 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_HUB) && (USB_HOST_CONFIG_HUB)) +#include "usb_host.h" +#include "usb_host_hub.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief hub control transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub interrupt in transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief USB_HostHubSendPortReset's transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief hub control transfer common code. + * + * @param classHandle the class handle. + * @param requestType request type. + * @param request setup packet request field. + * @param wvalue setup packet wValue field. + * @param windex setup packet wIndex field. + * @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. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + hubInstance->controlTransfer = NULL; + if (hubInstance->controlCallbackFn) + { + hubInstance->controlCallbackFn(hubInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->inCallbackFn) + { + hubInstance->inCallbackFn(hubInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); /* callback to application */ + } + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static void USB_HostHubResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + /* note: there is not callback to application, the re-enumeration will start automatically after reset. */ + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostHubClassRequestCommon(usb_host_class_handle classHandle, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (hubInstance->controlTransfer != NULL) + { + return kStatus_USB_Busy; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->controlCallbackFn = callbackFn; + hubInstance->controlCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubControlCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket.bmRequestType = requestType; + 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(bufferLength); + + /* send transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + hubInstance->controlTransfer = transfer; /* record the on-going setup transfer */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + /* malloc the hub instance */ + usb_host_hub_instance_t *hubInstance = + (usb_host_hub_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_hub_instance_t)); + uint32_t infoValue; + + if (hubInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize hub instance structure */ + hubInstance->deviceHandle = deviceHandle; + hubInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + hubInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + hubInstance->controlPipe = (usb_host_pipe_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + hubInstance->hubLevel = infoValue; + + *classHandle = hubInstance; /* return the hub class handle */ + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSetInterface(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_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_interface_t *interface = (usb_host_interface_t *)interfaceHandle; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_pipe_init_t pipeInit; + uint8_t epIndex; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hubInstance->interfaceHandle = interfaceHandle; /* save the interface handle */ + + /* notify the host driver that the interface is used by class */ + status = USB_HostOpenDeviceInterface(hubInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* open hub interrupt pipe */ + for (epIndex = 0; epIndex < interface->epCount; ++epIndex) + { + epDesc = interface->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + /* get pipe information from endpoint descriptor */ + pipeInit.devInstance = hubInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + /* open hub interrupt in pipe */ + status = USB_HostOpenPipe(hubInstance->hostHandle, &hubInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + break; + } + } + + /* hub don't support alternatesetting that is not 0 */ + if (alternateSetting == 0) + { + if (callbackFn != NULL) + { + callbackFn(callbackParam, NULL, 0, kStatus_USB_Success); + } + } + else + { +#ifdef HOST_ECHO + usb_echo("host don't supprt alternate setting\r\n"); +#endif + return kStatus_USB_Error; + } + + return status; +} + +usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + uint8_t status; + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) + { + /* close opened hub interrupt pipe */ + if (hubInstance->interruptPipe != NULL) + { + status = USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->interruptPipe, NULL); + status = USB_HostClosePipe(hubInstance->hostHandle, hubInstance->interruptPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub close interrupt pipe error\r\n"); +#endif + } + hubInstance->interruptPipe = NULL; + } + + /* cancel control transfer if exist */ + if ((hubInstance->controlPipe != NULL) && (hubInstance->controlTransfer != NULL)) + { + status = + USB_HostCancelTransfer(hubInstance->hostHandle, hubInstance->controlPipe, hubInstance->controlTransfer); + } + + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, hubInstance->interfaceHandle); + USB_OsaMemoryFree(hubInstance); + } + else + { + /* notify host driver that the interface will not be used */ + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save hub application callback */ + hubInstance->inCallbackFn = callbackFn; + hubInstance->inCallbackParam = callbackParam; + + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostHubInPipeCallback; + transfer->callbackParam = hubInstance; + + /* call host driver API to receive data */ + if (USB_HostRecv(hubInstance->hostHandle, hubInstance->interruptPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("failt to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* get transfer */ + if (USB_HostMallocTransfer(hubInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + + /* initialize transfer */ + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + transfer->callbackFn = USB_HostHubResetCallback; + transfer->callbackParam = hubInstance; + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER; + transfer->setupPacket.bRequest = USB_REQUEST_STANDARD_SET_FEATURE; + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(PORT_RESET); + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN(portNumber); + transfer->setupPacket.wLength = 0; + + /* send the transfer */ + if (USB_HostSendSetup(hubInstance->hostHandle, hubInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("Error in hid get report descriptor\r\n"); +#endif + USB_HostFreeTransfer(hubInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief hub get descriptor. + * + * This function implements get hub descriptor specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_DEVICE, + USB_REQUEST_STANDARD_GET_DESCRIPTOR, 0x00, 0, buffer, bufferLength, callbackFn, callbackParam); +} + +/*! + * @brief hub clear feature. + * + * This function implements clear hub feature specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, 0, NULL, 0, callbackFn, + callbackParam); +} + +/*! + * @brief hub get status. + * + * This function implements get hub status specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon(classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS, + USB_REQUEST_STANDARD_GET_STATUS, 0, 0, buffer, bufferLength, callbackFn, + callbackParam); +} + +/*! + * @brief hub set feature. + * + * This function implements set hub feature specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_SET_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub clear port feature. + * + * This function implements clear hub port feature specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_CLEAR_FEATURE, feature, portNumber, NULL, 0, callbackFn, callbackParam); +} + +/*! + * @brief hub port get status. + * + * This function implements get hub port status specific request. + * + * @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 send 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_HostSendSetup. + */ +usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + return USB_HostHubClassRequestCommon( + classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_OTHER, + USB_REQUEST_STANDARD_GET_STATUS, 0, portNumber, buffer, bufferLength, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/usb_1.1.0/host/class/usb_host_hub.h b/usb_1.1.0/host/class/usb_host_hub.h new file mode 100644 index 0000000..4ea3700 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub.h @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef _USB_HOST_HUB_H_ +#define _USB_HSOT_HUB_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief USB host HUB maximum port count */ +#define USB_HOST_HUB_MAX_PORT (7U) + +/*! @brief HUB class code */ +#define USB_HOST_HUB_CLASS_CODE (9U) +/*! @brief HUB sub-class code */ +#define USB_HOST_HUB_SUBCLASS_CODE_NONE (0U) + +/* HUB and PORT status according to Table 11-17 in chapter 11.*/ +/*! @brief Local Power Status Change: This field indicates that a change has occurred in the HUB's Local Power Source */ +#define C_HUB_LOCAL_POWER (0U) +/*! @brief Over-Current Change: This field indicates if a change has occurred in the Over-Current field*/ +#define C_HUB_OVER_CURRENT (1U) +/*! @brief Current Connect Status: This field reflects whether or not a device is currently connected to this port*/ +#define PORT_CONNECTION (0U) +/*! @brief Port Enabled/Disabled: Ports can be enabled by the USB System Software only. Ports +can be disabled by either a fault condition (disconnect event or other fault condition) or by the USB System +Software*/ +#define PORT_ENABLE (1U) +/*! @brief Suspend: This field indicates whether or not the device on this port is suspended */ +#define PORT_SUSPEND (2U) +/*! @brief this field indicate that the current drain on the port exceeds the specified maximum. */ +#define PORT_OVER_CURRENT (3U) +/*! @brief This field is set when the host wishes to reset the attached device */ +#define PORT_RESET (4U) +/*! @brief This field reflects a port's logical, power control state */ +#define PORT_POWER (8U) +/*! @brief Low- Speed Device Attached: This is relevant only if a device is attached */ +#define PORT_LOW_SPEED (9U) +/*! @brief High-speed Device Attached: This is relevant only if a device is attached */ +#define PORT_HIGH_SPEED (10U) +/*! @brief Connect Status Change: Indicates a change has occurred in the port's Current Connect Status */ +#define C_PORT_CONNECTION (16U) +/*! @brief Port Enable/Disable Change: This field is set to one when a port is disabled because of a Port_Error + * condition */ +#define C_PORT_ENABLE (17U) +/*! @brief Suspend Change: This field indicates a change in the host-visible suspend state of the attached device */ +#define C_PORT_SUSPEND (18U) +/*! @brief Over-Current Indicator Change: This field applies only to HUBs that report over-current conditions on a + * per-port basis */ +#define C_PORT_OVER_CURRENT (19U) +/*! @brief Reset Change: This field is set when reset processing on this port is complete */ +#define C_PORT_RESET (20U) + +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK (0x60U) +/*! @brief Get HUB think time value */ +#define USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT (5U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! @brief HUB descriptor structure */ +typedef struct _usb_host_hub_descriptor +{ + uint8_t blength; /*!< Number of bytes in this descriptor*/ + uint8_t bdescriptortype; /*!< Descriptor Type*/ + uint8_t bnrports; /*!< Number of downstream facing ports that this HUB supports*/ + uint8_t whubcharacteristics[2]; /*!< HUB characteristics please reference to Table 11-13 in usb2.0 specification*/ + uint8_t bpwron2pwrgood; /*!< Time (in 2 ms intervals) from the time the power-on sequence begins on a port until + power is good on that port.*/ + uint8_t bhubcontrcurrent; /*!< Maximum current requirements of the HUB Controller electronics in mA*/ + uint8_t deviceremovable; /*!< Indicates if a port has a removable device attached*/ +} usb_host_hub_descriptor_t; + +/*! @brief HUB port instance structure */ +typedef struct _usb_host_hub_port_instance +{ + usb_device_handle deviceHandle; /*!< Device handle*/ + uint8_t portStatus; /*!< Port running status*/ + uint8_t resetCount; /*!< Port reset time*/ + uint8_t speed; /*!< Port's device speed*/ +} usb_host_hub_port_instance_t; + +/*! @brief HUB instance structure */ +typedef struct _usb_host_hub_instance +{ + struct _usb_host_hub_instance *next; /*!< Next HUB instance*/ + usb_host_handle hostHandle; /*!< Host handle*/ + usb_device_handle deviceHandle; /*!< Device handle*/ + usb_host_interface_handle interfaceHandle; /*!< Interface handle*/ + usb_host_pipe_handle controlPipe; /*!< Control pipe handle*/ + usb_host_pipe_handle interruptPipe; /*!< HUB interrupt in pipe handle*/ + usb_host_hub_port_instance_t *portList; /*!< HUB's port instance list*/ + usb_host_transfer_t *controlTransfer; /*!< Control transfer in progress*/ + transfer_callback_t inCallbackFn; /*!< Interrupt in callback*/ + void *inCallbackParam; /*!< Interrupt in callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< Control callback*/ + void *controlCallbackParam; /*!< Control callback parameter*/ + /* HUB property */ + uint16_t totalThinktime; /*!< HUB total think time*/ + uint8_t hubLevel; /*!< HUB level, the root HUB's level is 1*/ + + /* HUB application parameter */ + uint8_t hubDescriptor[7 + (USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB descriptor buffer*/ + uint8_t hubBitmapBuffer[(USB_HOST_HUB_MAX_PORT >> 3) + 1]; /*!< HUB receiving bitmap data buffer*/ + uint8_t hubStatusBuffer[4]; /*!< HUB status buffer*/ + uint8_t portStatusBuffer[4]; /*!< Port status buffer*/ + uint8_t hubStatus; /*!< HUB instance running status*/ + uint8_t portCount; /*!< HUB port count*/ + uint8_t portIndex; /*!< Record the index when processing ports in turn*/ + uint8_t portProcess; /*!< The port that is processing*/ + uint8_t primeStatus; /*!< Data prime transfer status*/ + uint8_t invalid; /*!< 0/1, when invalid, cannot send transfer to the class*/ +} usb_host_hub_instance_t; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @brief Initializes the HUB instance. + * + * This function allocates the resource for HUB 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. + */ +extern usb_status_t USB_HostHubInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets interface. + * + * This function binds the interfaces with the HUB 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 Open pipe fail. See the USB_HostOpenPipe. + * Or send transfer fail. See the USB_HostSendSetup, + */ +extern usb_status_t USB_HostHubSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the HUB instance. + * + * This function releases the resource for HUB instance. + * + * @param deviceHandle The device handle. + * @param classHandle The class handle. + * + * @retval kStatus_USB_Success The device is deinitialized successfully. + */ +extern usb_status_t USB_HostHubDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Receives data. + * + * This function implements the HUB 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. See the USB_HostRecv. + */ +extern usb_status_t USB_HostHubInterruptRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Port reset setup. + * + * This function sends the HUB port reset transfer. + * + * @param classHandle The class handle. + * @param portNumber Port number. + * + * @retval kStatus_USB_Success Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSendPortReset(usb_host_class_handle classHandle, uint8_t portNumber); + +/*! + * @brief HUB get descriptor. + * + * This function implements get HUB descriptor-specific request. + * + * @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 Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetDescriptor(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear feature. + * + * This function implements clear HUB feature specific request. + * + * @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 send 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_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearFeature(usb_host_class_handle classHandle, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB get status. + * + * This function implements the get HUB status-specific request. + * + * @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 Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetStatus(usb_host_class_handle classHandle, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB set feature. + * + * This function implements the set HUB feature-specific request. + * + * @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 Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubSetPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB clear port feature. + * + * This function implements the clear HUB port feature-specific request. + * + * @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 Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubClearPortFeature(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t feature, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief HUB port get status. + * + * This function implements the get HUB port status-specific request. + * + * @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 Send 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostHubGetPortStatus(usb_host_class_handle classHandle, + uint8_t portNumber, + uint8_t *buffer, + uint16_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +#ifdef __cplusplus +} +#endif + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HSOT_HUB_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_hub_app.c b/usb_1.1.0/host/class/usb_host_hub_app.c new file mode 100644 index 0000000..1755b69 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub_app.c @@ -0,0 +1,1106 @@ +/* + * Copyright (c) 2015, 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_HUB) && (USB_HOST_CONFIG_HUB)) + +#include "usb_host.h" +#include "usb_host_hub.h" +#include "usb_host_hub_app.h" +#include "usb_host_devices.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief prime interrupt in data. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub process state machine. hub is enable after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port attach process state machine. one device is attached to the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port detach process state machine. one device is detached from the port after the state machine. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub port process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub interrupt in data process. + * + * @param hubInstance hub instance pointer. + */ +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance); + +/*! + * @brief hub control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/*! + * @brief hub interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +static usb_device_handle s_HubDeviceHandle; +static usb_host_interface_handle s_HubInterfaceHandle; +static usb_host_hub_global_t s_HubGlobal; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostHubGetInterruptStatus(usb_host_hub_instance_t *hubInstance) +{ + if (hubInstance == NULL) + { + return; + } + + /* there is no prime for control or interrupt */ + if (hubInstance->primeStatus != kPrimeNone) + { + return; + } + + /* receive interrupt data */ + if (USB_HostHubInterruptRecv(hubInstance, hubInstance->hubBitmapBuffer, (hubInstance->portCount >> 3) + 1, + USB_HostHubInterruptInCallback, hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in hub interrupt recv\r\n"); +#endif + } + else + { + hubInstance->primeStatus = kPrimeInterrupt; + } +} + +static void USB_HostHubProcess(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 0; /* need to prime interrupt in transfer (0 - don't need; 1 - need) */ + uint8_t processSuccess = 0; /* the code excute successfully (0 - fail; 1 - success) */ + uint32_t tmp = 0; + usb_host_hub_descriptor_t *hubDescriptor; + + switch (hubInstance->hubStatus) + { + case kHubRunIdle: + case kHubRunInvalid: + break; + + case kHubRunWaitSetInterface: + hubInstance->hubStatus = kHubRunGetDescriptor7; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7, USB_HostHubControlCallback, + hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor 7 error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor7: + hubDescriptor = (usb_host_hub_descriptor_t *)&hubInstance->hubDescriptor[0]; + + /* get the hub think time */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetHubThinkTime, &tmp); + hubInstance->totalThinktime = tmp + (((uint32_t)hubDescriptor->whubcharacteristics[0] & + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_MASK) >> + USB_HOST_HUB_DESCRIPTOR_CHARACTERISTICS_THINK_TIME_SHIFT); + + /* get hub port number */ + hubInstance->portCount = hubDescriptor->bnrports; + if (hubInstance->portCount > USB_HOST_HUB_MAX_PORT) + { +#ifdef HOST_ECHO + usb_echo("port number is bigger than USB_HOST_HUB_MAX_PORT\r\n"); +#endif + return; + } + + hubInstance->hubStatus = kHubRunGetDescriptor; /* update as next state */ + /* get hub descriptor */ + if (USB_HostHubGetDescriptor(hubInstance, hubInstance->hubDescriptor, 7 + (hubInstance->portCount >> 3) + 1, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* control transfer is on-going */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("hub get descriptor\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("hub get descriptor error\r\n"); +#endif + break; + } + break; + + case kHubRunGetDescriptor: + /* malloc port instance for the hub's ports */ + hubInstance->portList = (usb_host_hub_port_instance_t *)USB_OsaMemoryAllocate( + hubInstance->portCount * sizeof(usb_host_hub_port_instance_t)); + if (hubInstance->portList == NULL) + { +#ifdef HOST_ECHO + usb_echo("port list allocate fail\r\n"); +#endif + hubInstance->hubStatus = kHubRunInvalid; + break; + } + /* TODO: port instance status -> can be removed. app_status */ + + hubInstance->hubStatus = kHubRunSetPortPower; /* update as next state */ + hubInstance->portIndex = 0; + + /* there is no significance, just for fixing misra error */ + if (hubInstance->hubStatus != kHubRunSetPortPower) + { + break; + } + + case kHubRunSetPortPower: + /* set PORT_POWER for all ports */ + if (hubInstance->portIndex < hubInstance->portCount) + { + hubInstance->portIndex++; + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portIndex, PORT_POWER, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; /* update as next state */ + processSuccess = 1; +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER\r\n"); +#endif + } + else + { +#ifdef HOST_ECHO + usb_echo("set port feature PORT_POWER fail\r\n"); +#endif + needPrimeInterrupt = 1; + break; + } + break; + } + hubInstance->portProcess = 0; + /* reset port information as default */ + for (tmp = 0; tmp < hubInstance->portCount; ++tmp) + { + hubInstance->portList[tmp].deviceHandle = NULL; + hubInstance->portList[tmp].resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + hubInstance->portList[tmp].portStatus = kPortRunWaitPortChange; + } + hubInstance->hubStatus = kHubRunIdle; + needPrimeInterrupt = 1; + break; + + case kHubRunGetStatusDone: /* process hub status change */ + tmp = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS((&hubInstance->hubStatusBuffer[2])); + hubInstance->hubStatus = kHubRunIdle; + if ((1 << C_HUB_LOCAL_POWER) & tmp) /* C_HUB_LOCAL_POWER */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_LOCAL_POWER, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else if ((1 << C_HUB_OVER_CURRENT) & tmp) /* C_HUB_OVER_CURRENT */ + { + if (USB_HostHubClearFeature(hubInstance, C_HUB_OVER_CURRENT, USB_HostHubControlCallback, hubInstance) == + kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + processSuccess = 1; + } + else + { + needPrimeInterrupt = 1; + } + } + else + { + needPrimeInterrupt = 1; + } + break; + + default: + break; + } + + if (needPrimeInterrupt == 1) /* prime interrupt in transfer */ + { + hubInstance->hubStatus = kHubRunIdle; + USB_HostHubGetInterruptStatus(hubInstance); + } + else + { + if (processSuccess == 0) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } +} + +static void USB_HostHubProcessPort(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + + /* for device attach */ + if (portInstance->deviceHandle == NULL) + { + USB_HostHubProcessPortAttach(hubInstance); + } + else /* for device detach */ + { + USB_HostHubProcessPortDetach(hubInstance); + } +} + +static void USB_HostHubProcessPortAttach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + uint8_t feature; + uint32_t infoValue; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + case kPortRunWaitPortChange: /* (1) port is changed, and get port status */ + portInstance->portStatus = kPortRunCheckCPortConnection; /* update as next state */ + /* send class-specific request to get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckCPortConnection: /* (2) check port status, and clear the status bits */ + feature = 0; + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS((hubInstance->portStatusBuffer)); + if ((1 << C_PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunGetPortConnection; /* update as next state */ + /* clear C_PORT_CONNECTION */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + break; + } + else if ((1 << C_PORT_RESET) & specStatus) + { + feature = C_PORT_RESET; /* clear C_PORT_RESET */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_RESET when detached\r\n"); +#endif + } + else if ((1 << C_PORT_ENABLE) & specStatus) + { + feature = C_PORT_ENABLE; /* clear C_PORT_ENABLE */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_ENABLE when detached\r\n"); +#endif + } + else if ((1 << C_PORT_OVER_CURRENT) & specStatus) + { + feature = C_PORT_OVER_CURRENT; /* clear C_PORT_OVER_CURRENT */ +#ifdef HOST_ECHO + usb_echo("hub: C_PORT_OVER_CURRENT when detached\r\n"); +#endif + } + else + { + } + + if (feature != 0) + { + portInstance->portStatus = kPortRunWaitPortChange; /* update as next state */ + /* clear feature */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, feature, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunGetPortConnection: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckPortConnection; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; /* control transfer is on-going */ + processSuccess = 1; + } + break; + + case kPortRunCheckPortConnection: /* (4) check PORT_CONNECTION bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) + { + portInstance->portStatus = kPortRunWaitPortResetDone; /* update as next state */ + /* set PORT_RESET */ + if (USB_HostHubSetPortFeature(hubInstance, hubInstance->portProcess, PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + if (portInstance->resetCount > 0) + { + portInstance->resetCount--; + } + } + } + break; + + case kPortRunWaitPortResetDone: /* (5) wait port change */ + portInstance->portStatus = kPortRunWaitCPortReset; /* update as next state */ + processSuccess = 1; + /* must wait the enumeration done, then operate the next port */ + USB_HostHubGetInterruptStatus(hubInstance); + break; + + case kPortRunWaitCPortReset: /* (6) get port satus for checking C_PORT_RESET */ + portInstance->portStatus = KPortRunCheckCPortReset; /* update as next state */ + /* get port status bits */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case KPortRunCheckCPortReset: /* (7) check C_PORT_RESET and clear C_PORT_RESET */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << C_PORT_RESET) & specStatus) + { + if (portInstance->resetCount == 0) + { + portInstance->portStatus = kPortRunPortAttached; /* update as next state */ + /* get port's device speed */ + if (specStatus & (1 << PORT_HIGH_SPEED)) + { + portInstance->speed = USB_SPEED_HIGH; + } + else if (specStatus & (1 << PORT_LOW_SPEED)) + { + portInstance->speed = USB_SPEED_LOW; + } + else + { + portInstance->speed = USB_SPEED_FULL; + } + } + else + { + portInstance->portStatus = kPortRunResetAgain; /* update as next state */ + } + + /* clear C_PORT_RESET */ + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_RESET, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + } + break; + + case kPortRunResetAgain: /* (8) reset again */ + portInstance->portStatus = kPortRunCheckPortConnection; /* check connection then reset again */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunPortAttached: /* (9) the port have one device attached */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + USB_HostAttachDevice(hubInstance->hostHandle, portInstance->speed, infoValue, hubInstance->portProcess, + hubInstance->hubLevel + 1, &portInstance->deviceHandle); + processSuccess = 1; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + USB_HostHubGetInterruptStatus(hubInstance); + break; + + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunWaitPortChange; + hubInstance->portProcess = 0; + s_HubGlobal.hubProcess = NULL; + portInstance->resetCount = USB_HOST_HUB_PORT_RESET_TIMES; + + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessPortDetach(usb_host_hub_instance_t *hubInstance) +{ + usb_host_hub_port_instance_t *portInstance = &hubInstance->portList[hubInstance->portProcess - 1]; + uint8_t processSuccess = 0; + uint32_t specStatus; + + switch (portInstance->portStatus) + { + case kPortRunIdle: + case kPortRunInvalid: + break; + + case kPortRunPortAttached: /* (1) port is changed, then get port status */ + portInstance->portStatus = kPortRunCheckPortDetach; + /* get port status */ + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckPortDetach: /* (2) check port status bits */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + portInstance->portStatus = kPortRunGetConnectionBit; + if ((1 << C_PORT_CONNECTION) & specStatus) /* C_PORT_CONNECTION */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_CONNECTION, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else if ((1 << C_PORT_ENABLE) & specStatus) /* C_PORT_ENABLE */ + { + if (USB_HostHubClearPortFeature(hubInstance, hubInstance->portProcess, C_PORT_ENABLE, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + } + else + { + /* don't break to check CONNECTION bit */ + } + + case kPortRunGetConnectionBit: /* (3) get port status */ + portInstance->portStatus = kPortRunCheckConnectionBit; + if (USB_HostHubGetPortStatus(hubInstance, hubInstance->portProcess, hubInstance->portStatusBuffer, 4, + USB_HostHubControlCallback, hubInstance) == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimePortControl; + processSuccess = 1; + } + break; + + case kPortRunCheckConnectionBit: /* (4) check port connection bit */ + specStatus = USB_LONG_FROM_LITTLE_ENDIAN_ADDRESS(hubInstance->portStatusBuffer); + if ((1 << PORT_CONNECTION) & specStatus) /* PORT_CONNECTION */ + { + portInstance->portStatus = kPortRunPortAttached; +#ifdef HOST_ECHO + usb_echo("PORT_CONNECTION in attach for detach\r\n"); +#endif + } + else + { + processSuccess = 1; + /* port's device is detached */ + portInstance->portStatus = kPortRunWaitPortChange; + USB_HostDetachDeviceInternal(hubInstance->hostHandle, portInstance->deviceHandle); + portInstance->deviceHandle = NULL; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + break; + default: + break; + } + + if (processSuccess == 0) + { + portInstance->portStatus = kPortRunPortAttached; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +static void USB_HostHubProcessData(usb_host_hub_instance_t *hubInstance) +{ + uint8_t needPrimeInterrupt = 1; + uint8_t portIndex; + + /* process the port which status change */ + for (portIndex = 0; portIndex <= hubInstance->portCount; ++portIndex) + { + if ((0x01u << (portIndex & 0x07u)) & (hubInstance->hubBitmapBuffer[portIndex >> 3])) + { + if (portIndex == 0) /* hub status change */ + { + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0))) + { + hubInstance->hubStatus = kHubRunGetStatusDone; + if (USB_HostHubGetStatus(hubInstance, hubInstance->hubStatusBuffer, 4, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error in usb_class_hub_get_status\r\n"); +#endif + hubInstance->hubStatus = kHubRunIdle; + } + else + { + hubInstance->primeStatus = kPrimeHubControl; + needPrimeInterrupt = 0; + } + } + } + else /* port's status change */ + { + /* process the on-going port or process one new port */ + if ((s_HubGlobal.hubProcess == NULL) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == 0)) || + ((s_HubGlobal.hubProcess == hubInstance) && (hubInstance->portProcess == portIndex))) + { + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = hubInstance; + hubInstance->portProcess = portIndex; + needPrimeInterrupt = 0; + USB_HostHubProcessPort(hubInstance); + } + break; /* process the port change in turn */ + } + } + } + } + + if (needPrimeInterrupt == 1) + { + USB_HostHubGetInterruptStatus(hubInstance); + } +} + +void USB_HostHubControlCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + if (status != kStatus_USB_Success) + { + /* if transfer fail, prime a new interrupt in transfer */ + hubInstance->primeStatus = kPrimeNone; + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + return; + } + + if (hubInstance->primeStatus == kPrimeHubControl) /* hub related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcess(hubInstance); + } + else if (hubInstance->primeStatus == kPrimePortControl) /* hub's port related control transfer */ + { + hubInstance->primeStatus = kPrimeNone; + USB_HostHubProcessPort(hubInstance); + } + else + { + } +} + +void USB_HostHubInterruptInCallback(void *param, uint8_t *data, uint32_t data_len, usb_status_t status) +{ + usb_host_hub_instance_t *hubInstance = (usb_host_hub_instance_t *)param; + + if (hubInstance->invalid == 1) + { + return; + } + /* interrupt data received */ + hubInstance->primeStatus = kPrimeNone; + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("hub interrupt in data callback error\r\n"); +#endif + /* prime nexe interrupt transfer */ + if (hubInstance->controlTransfer == NULL) + { + s_HubGlobal.hubProcess = NULL; + hubInstance->portProcess = 0; + USB_HostHubGetInterruptStatus(hubInstance); + } + } + else + { + USB_HostHubProcessData(hubInstance); /* process the interrupt data */ + } +} + +/*! + * @brief host hub callback function. + * + * This function should be called in the host callback function. + * + * @param deviceHandle device handle. + * @param configurationHandle attached device's configuration descriptor information. + * @param event_code callback event code, please reference to enumeration host_event_t. + * + * @retval kStatus_USB_Success The host is initialized successfully. + * @retval kStatus_USB_NotSupported The configuration don't contain hub interface. + */ +usb_status_t USB_HostHubDeviceEvent(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + usb_host_configuration_t *configuration; + usb_host_interface_t *interface; + uint8_t interfaceIndex; + uint8_t id; + usb_status_t status = kStatus_USB_Success; + usb_host_class_handle hubClassHandle; + usb_host_hub_instance_t *hubInstance; + usb_host_hub_instance_t *prevInstance; + uint32_t infoValue; + usb_osa_status_t osaStatus; + + switch (eventCode) + { + case kUSB_HostEventAttach: + /* judge whether is configurationHandle supported */ + configuration = (usb_host_configuration_t *)configurationHandle; + for (interfaceIndex = 0; interfaceIndex < configuration->interfaceCount; ++interfaceIndex) + { + interface = &configuration->interfaceList[interfaceIndex]; + id = interface->interfaceDesc->bInterfaceClass; + if (id != USB_HOST_HUB_CLASS_CODE) + { + continue; + } + id = interface->interfaceDesc->bInterfaceSubClass; + if (id != USB_HOST_HUB_SUBCLASS_CODE_NONE) + { + continue; + } + else + { + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + if (infoValue > 5) + { +#ifdef HOST_ECHO + usb_echo("Host can support max 5 level hubs\r\n"); +#endif + continue; + } + /* the interface is hub */ + s_HubDeviceHandle = deviceHandle; + s_HubInterfaceHandle = interface; + return kStatus_USB_Success; + } + } + status = kStatus_USB_NotSupported; + break; + + case kUSB_HostEventEnumerationDone: + /* the device enumeration is done */ + if ((s_HubDeviceHandle != NULL) && (s_HubInterfaceHandle != NULL)) + { + /* print hub information */ + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub attached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + + /* initialize hub mutex */ + if (s_HubGlobal.hubMutex == (usb_osa_mutex_handle)NULL) + { + osaStatus = USB_OsaMutexCreate(&s_HubGlobal.hubMutex); + if (osaStatus != kStatus_USB_OSA_Success) + { + s_HubGlobal.hubMutex = NULL; +#ifdef HOST_ECHO + usb_echo("hub mutex error\r\n"); +#endif + } + } + + /* initialize hub class instance */ + status = USB_HostHubInit(s_HubDeviceHandle, &hubClassHandle); + hubInstance = (usb_host_hub_instance_t *)hubClassHandle; + + /* link hub instance to list */ + USB_HostHubLock(); + hubInstance->next = s_HubGlobal.hubList; + s_HubGlobal.hubList = hubInstance; + USB_HostHubUnlock(); + + /* set hub instance's interface */ + if (status == kStatus_USB_Success) + { + hubInstance->primeStatus = kPrimeHubControl; + hubInstance->hubStatus = kHubRunWaitSetInterface; + if (USB_HostHubSetInterface(hubClassHandle, s_HubInterfaceHandle, 0, USB_HostHubControlCallback, + hubInstance) != kStatus_USB_Success) + { + hubInstance->hubStatus = kHubRunInvalid; + } + } + } + break; + + case kUSB_HostEventDetach: + /* the device is detached */ + hubInstance = NULL; + + /* get device's hub instance handle */ + USB_HostHubLock(); + prevInstance = s_HubGlobal.hubList; + if (prevInstance->deviceHandle == deviceHandle) + { + hubInstance = prevInstance; + s_HubGlobal.hubList = prevInstance->next; + } + else + { + hubInstance = prevInstance->next; + while (hubInstance != NULL) + { + if (hubInstance->deviceHandle == deviceHandle) + { + prevInstance->next = hubInstance->next; + break; + } + prevInstance = hubInstance; + hubInstance = hubInstance->next; + } + } + USB_HostHubUnlock(); + + if (hubInstance != NULL) + { + if (hubInstance == s_HubGlobal.hubProcess) + { + s_HubGlobal.hubProcess = NULL; + } + /* print hub information */ + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceLevel, &infoValue); + usb_echo("hub detached:level=%d ", infoValue); + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + usb_echo("address=%d\r\n", infoValue); + hubInstance->invalid = 1; + /* detach hub ports' devices */ + for (uint8_t portIndex = 0; portIndex < hubInstance->portCount; ++portIndex) + { + if ((hubInstance->portList != NULL) && (hubInstance->portList[portIndex].deviceHandle != NULL)) + { + USB_HostDetachDeviceInternal(hubInstance->hostHandle, + hubInstance->portList[portIndex].deviceHandle); + hubInstance->portList[portIndex].deviceHandle = NULL; + } + } + if (hubInstance->portList != NULL) + { + USB_OsaMemoryFree(hubInstance->portList); + } + USB_HostHubDeinit(deviceHandle, hubInstance); /* de-initialize hub instance */ + } + + /* destory hub mutex if there is no hub instance */ + if (s_HubGlobal.hubList == NULL) + { + if (s_HubGlobal.hubMutex != NULL) + { + USB_OsaMutexDestroy(s_HubGlobal.hubMutex); + s_HubGlobal.hubMutex = NULL; + } + } + break; + + default: + break; + } + + return status; +} + +/*! + * @brief remove attached device. called by USB_HostRemoveDevice. + * + * @param hubNumber the device attached hub. + * @param portNumber the device attached port. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostHubRemovePort(uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_hub_instance_t *hubInstance; + uint32_t infoValue; + + /* get hub number's hub instance handle */ + hubInstance = (usb_host_hub_instance_t *)s_HubGlobal.hubList; + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &infoValue); + if (infoValue == hubNumber) + { + break; + } + hubInstance = hubInstance->next; + } + + /* set port's status as default, and reset port */ + if (hubInstance != NULL) + { + hubInstance->portList[portNumber - 1].deviceHandle = NULL; + hubInstance->portList[portNumber - 1].portStatus = kPortRunInvalid; + if (hubInstance->portProcess == portNumber) + { + hubInstance->portProcess = 0; + } + USB_HostHubSendPortReset(hubInstance, portNumber); + } + return kStatus_USB_Error; +} + +/*! + * @brief get device's high-speed hub's address. + * + * @param parent_hub_no device's parent hub's address. + * + * @return hub number. + */ +uint32_t USB_HostHubGetHsHubNumber(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubNumber; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubNumber = parentHubNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, + &hubNumber); + } + return hubNumber; + } + return 0; +} + +/*! + * @brief get device's high-speed hub's port number. + * + * @param parent_hub_no device's parent hub's address. + * @param parent_port_no device's parent port no. + * + * @return port number. + */ +uint32_t USB_HostHubGetHsHubPort(uint8_t parentHubNo, uint8_t parentPortNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceInfo; + uint32_t hubPort; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceInfo); + if (parentHubNo == deviceInfo) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceSpeed, &deviceInfo); + if (deviceInfo == USB_SPEED_HIGH) /* parent hub is HS */ + { + hubPort = parentPortNo; + } + else /* parent hub is not HS */ + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceHSHubNumber, &hubPort); + } + return hubPort; + } + return 0; +} + +/*! + * @brief get device's hub total think time. + * + * @param parent_hub_no device's parent hub's address. + * + * @return think time value. + */ +uint32_t USB_HostHubGetTotalThinkTime(uint8_t parentHubNo) +{ + usb_host_hub_instance_t *hubInstance = s_HubGlobal.hubList; + uint32_t deviceAddress; + + /* get parentHubNo's hub instance handle */ + while (hubInstance != NULL) + { + USB_HostHelperGetPeripheralInformation(hubInstance->deviceHandle, kUSB_HostGetDeviceAddress, &deviceAddress); + if (parentHubNo == deviceAddress) + { + break; + } + hubInstance = hubInstance->next; + } + if (hubInstance != NULL) + { + return hubInstance->totalThinktime; + } + return 0; +} + +#endif /* USB_HOST_CONFIG_HUB */ diff --git a/usb_1.1.0/host/class/usb_host_hub_app.h b/usb_1.1.0/host/class/usb_host_hub_app.h new file mode 100644 index 0000000..fd7df5b --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_hub_app.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef _USB_HOST_HUB_APP_H_ +#define _USB_HOST_HUB_APP_H_ + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief HUB reset times*/ +#define USB_HOST_HUB_PORT_RESET_TIMES (1) + +/*! @brief HUB lock */ +#define USB_HostHubLock() USB_OsaMutexLock(s_HubGlobal.hubMutex) +/*! @brief HUB unlock */ +#define USB_HostHubUnlock() USB_OsaMutexUnlock(s_HubGlobal.hubMutex) + +/*! @brief HUB application global structure */ +typedef struct _usb_host_hub_global +{ + usb_host_handle hostHandle; /*!< This HUB list belong to this host*/ + usb_host_hub_instance_t *hubProcess; /*!< HUB in processing*/ + usb_host_hub_instance_t *hubList; /*!< host's HUB list*/ + usb_osa_mutex_handle hubMutex; /*!< HUB mutex*/ +} usb_host_hub_global_t; + +/*! @brief HUB application status */ +typedef enum _usb_host_hub_app_status +{ + kHubRunIdle = 0, /*!< Idle */ + kHubRunInvalid, /*!< Invalid state */ + kHubRunWaitSetInterface, /*!< Wait callback of set interface */ + kHubRunGetDescriptor7, /*!< Get 7 bytes HUB descriptor */ + kHubRunGetDescriptor, /*!< Get all HUB descriptor */ + kHubRunSetPortPower, /*!< Set HUB's port power */ + kHubRunGetStatusDone, /*!< HUB status changed */ +} usb_host_hub_app_status_t; + +/*! @brief HUB port application status */ +typedef enum _usb_host_port_app_status +{ + kPortRunIdle = 0, /*!< Idle */ + kPortRunInvalid, /*!< Invalid state */ + kPortRunWaitPortChange, /*!< Wait port status change */ + kPortRunCheckCPortConnection, /*!< Check C_PORT_CONNECTION */ + kPortRunGetPortConnection, /*!< Get port status data */ + kPortRunCheckPortConnection, /*!< Check PORT_CONNECTION */ + kPortRunWaitPortResetDone, /*!< Wait port reset transfer done */ + kPortRunWaitCPortReset, /*!< Wait C_PORT_RESET */ + KPortRunCheckCPortReset, /*!< Check C_PORT_RESET */ + kPortRunResetAgain, /*!< Reset port again */ + kPortRunPortAttached, /*!< Device is attached on the port */ + kPortRunCheckPortDetach, /*!< Check port is detached */ + kPortRunGetConnectionBit, /*!< Get the port status data */ + kPortRunCheckConnectionBit, /*!< Check PORT_CONNECTION */ +} usb_host_port_app_status_t; + +/*! @brief HUB data prime status */ +typedef enum _usb_host_hub_prime_status +{ + kPrimeNone = 0, /*!< Don't prime data*/ + kPrimeHubControl, /*!< Prime HUB control transfer*/ + kPrimePortControl, /*!< Prime port control transfer*/ + kPrimeInterrupt, /*!< Prime interrupt transfer*/ +} usb_host_hub_prime_status_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#endif /* USB_HOST_CONFIG_HUB */ + +#endif /* _USB_HOST_HUB_APP_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_msd.c b/usb_1.1.0/host/class/usb_host_msd.c new file mode 100644 index 0000000..ecb9706 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd.c @@ -0,0 +1,1155 @@ +/* + * 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_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" +#include "usb_host_hci.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief clear stall transfer callback. + * + * @param param callback parameter. + * @param transfer transfer. + * @param status transfer result status. + */ +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief send clear stall transfer. + * + * @param msdInstance msd instance pointer. + * @param callbackFn callback function. + * @param endpoint endpoint address. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint); + +/*! + * @brief mass storage reset three step processes are done. + * + * @param msdInstance msd instance pointer. + * @param status result status. + */ +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief mass storage reset process step 3 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 2 callback. + * + * @param msdInstance msd instance pointer. + * @transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage reset process step 1 callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief mass storage control transfer callback function. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief this function is called when ufi command is done. + * + * @param msdInstance msd instance pointer. + */ +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status); + +/*! + * @brief csw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief cbw transfer callback. + * + * @param msdInstance msd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief data transfer callback. + * + * @param msdInstance sd instance pointer. + * @param transfer transfer + * @param status result status. + */ +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd open interface. + * + * @param msdInstance msd instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance); + +/*! + * @brief msd set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief msd control transfer common code. + * + * This function allocate the resource for msd instance. + * + * @param msdInstance the msd class instance. + * @param pipeCallbackFn inner callback function. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param requestType request type. + * @param requestValue request value. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue); + +/*! + * @brief command process function, this function is called many time for one command's different state. + * + * @param msdInstance the msd class instance. + * + * @return An error code or kStatus_USB_Success. + */ +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void USB_HostMsdClearHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_TransferCancel); + } + + if (msdInstance->commandStatus == kMSD_CommandErrorDone) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } +} + +static usb_status_t USB_HostMsdClearHalt(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t callbackFn, + uint8_t endpoint) +{ + usb_status_t status; + usb_host_transfer_t *transfer; + + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = NULL; + msdInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = msdInstance; + 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(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + msdInstance->controlTransfer = transfer; + + return status; +} + +static void USB_HostMsdResetDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->internalResetRecovery == 1) /* internal mass reset recovery */ + { + msdInstance->internalResetRecovery = 0; + + if ((status != kStatus_USB_Success) || (msdInstance->commandStatus == kMSD_CommandErrorDone)) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); /* command fail */ + } + else + { + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + } + else /* user call mass storage reset recovery */ + { + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + } +} + +static void USB_HostMsdMassResetClearOutCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ +} + +static void USB_HostMsdMassResetClearInCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + + if (status == kStatus_USB_Success) + { + if (msdInstance->outPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt( + msdInstance, USB_HostMsdMassResetClearOutCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->outPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdMassResetCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + if (status == kStatus_USB_Success) + { + if (msdInstance->inPipe != NULL) + { + /* continue to process mass storage reset */ + USB_HostMsdClearHalt(msdInstance, USB_HostMsdMassResetClearInCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)); + } + } + else + { + USB_HostMsdResetDone(msdInstance, status); /* mass storage reset done */ + } +} + +static void USB_HostMsdControlCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +static void USB_HostMsdCommandDone(usb_host_msd_instance_t *msdInstance, usb_status_t status) +{ + if (msdInstance->commandCallbackFn != NULL) + { + /* callback to application */ + msdInstance->commandCallbackFn(msdInstance->commandCallbackParam, msdInstance->msdCommand.dataBuffer, + msdInstance->msdCommand.dataSofar, status); + } + msdInstance->commandStatus = kMSD_CommandIdle; +} + +static void USB_HostMsdCswCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if ((transfer->transferSofar == 13) && + (msdInstance->msdCommand.cswBlock.CSWSignature == USB_HOST_MSD_CSW_SIGNATURE)) + { + switch (msdInstance->msdCommand.cswBlock.CSWStatus) + { + case 0: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + case 1: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + + case 2: + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + break; + + default: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_MSDStatusFail); + break; + } + } + else + { + /* mass reset recovery to end ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } +} + +static void USB_HostMsdCbwCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + if (transfer->transferSofar == USB_HOST_UFI_CBW_LENGTH) + { + msdInstance->commandStatus = kMSD_CommandTransferData; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (msdInstance->msdCommand.retryTime > 0) + { + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt( + msdInstance, USB_HostMsdClearHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; + } + if (msdInstance->msdCommand.retryTime > 0) + { + USB_HostMsdProcessCommand(msdInstance); /* retry the last step transaction */ + } + else + { + /* mass reset recovery to continue ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } + return; + } +} + +static void USB_HostMsdDataCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + uint8_t direction; + + if (status == kStatus_USB_Success) + { + /* kStatus_USB_Success */ + msdInstance->msdCommand.dataSofar += transfer->transferSofar; + USB_HostMsdProcessCommand(msdInstance); /* continue to process ufi command */ + } + else + { + if (status == kStatus_USB_TransferStall) /* case 1: stall */ + { + if (msdInstance->msdCommand.retryTime > 0) + { + msdInstance->msdCommand.retryTime--; /* retry reduce when error */ + } + if (transfer->direction == USB_IN) + { + direction = USB_REQUEST_TYPE_DIR_IN; + } + else + { + direction = USB_REQUEST_TYPE_DIR_OUT; + } + + if (msdInstance->msdCommand.retryTime == 0) + { + msdInstance->commandStatus = kMSD_CommandTransferCSW; /* next step */ + } + /* clear stall to continue the ufi command */ + if (USB_HostMsdClearHalt(msdInstance, USB_HostMsdClearHaltCallback, + (direction | ((usb_host_pipe_t *)msdInstance->inPipe)->endpointAddress)) != + kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + else if (status == kStatus_USB_TransferCancel) /* case 2: cancel */ + { + USB_HostMsdCommandDone(msdInstance, status); /* command cancel */ + } + else /* case 3: error */ + { + /* mass reset recovery to finish ufi command */ + msdInstance->internalResetRecovery = 1; + msdInstance->commandStatus = kMSD_CommandErrorDone; + if (USB_HostMsdMassStorageReset(msdInstance, NULL, NULL) != kStatus_USB_Success) + { + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Error); + } + } + } +} + +static usb_status_t USB_HostMsdProcessCommand(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_transfer_t *transfer; + + if (msdInstance->msdCommand.transfer == NULL) + { + /* malloc one transfer */ + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + } + transfer = msdInstance->msdCommand.transfer; + switch (msdInstance->commandStatus) + { + case kMSD_CommandTransferCBW: /* ufi CBW phase */ + transfer->direction = USB_OUT; + transfer->transferBuffer = (uint8_t *)(&(msdInstance->msdCommand.cbwBlock)); + transfer->transferLength = USB_HOST_UFI_CBW_LENGTH; + transfer->callbackFn = USB_HostMsdCbwCallback; + transfer->callbackParam = msdInstance; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + break; + + case kMSD_CommandTransferData: /* ufi DATA phase */ + if (msdInstance->msdCommand.dataBuffer != NULL) + { + transfer->direction = msdInstance->msdCommand.dataDirection; + transfer->transferBuffer = (msdInstance->msdCommand.dataBuffer + msdInstance->msdCommand.dataSofar); + transfer->transferLength = (msdInstance->msdCommand.dataLength - msdInstance->msdCommand.dataSofar); + transfer->callbackParam = msdInstance; + if (msdInstance->msdCommand.dataSofar != msdInstance->msdCommand.dataLength) + { + if (transfer->direction == USB_OUT) + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostSend(msdInstance->hostHandle, msdInstance->outPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host send error\r\n"); +#endif + } + } + else + { + transfer->callbackFn = USB_HostMsdDataCallback; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + } + break; + } + else + { + /* don't break */ + } + } + else + { + /* don't break */ + } + case kMSD_CommandTransferCSW: /* ufi CSW phase */ + transfer->direction = USB_IN; + transfer->transferBuffer = (uint8_t *)&msdInstance->msdCommand.cswBlock; + transfer->transferLength = sizeof(usb_host_csw_t); + transfer->callbackFn = USB_HostMsdCswCallback; + transfer->callbackParam = msdInstance; + status = USB_HostRecv(msdInstance->hostHandle, msdInstance->inPipe, transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("host recv error\r\n"); +#endif + } + break; + + case kMSD_CommandDone: + USB_HostMsdCommandDone(msdInstance, kStatus_USB_Success); + break; + + default: + break; + } + return status; +} + +/*! + * @brief all ufi function calls this api. + * + * This function implements the common ufi commands. + * + * @param classHandle the class msd handle. + * @param buffer buffer pointer. + * @param bufferLength buffer length. + * @param callbackFn callback function. + * @param callbackParam callback parameter. + * @param direction command direction. + * @param byteValues ufi command fields value. + * + * @return An error code or kStatus_USB_Success. + */ +usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_cbw_t *cbwPointer = &(msdInstance->msdCommand.cbwBlock); + uint8_t index = 0; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (msdInstance->commandStatus != kMSD_CommandIdle) + { + return kStatus_USB_Busy; + } + + /* save the application callback function */ + msdInstance->commandCallbackFn = callbackFn; + msdInstance->commandCallbackParam = callbackParam; + + /* initialize CBWCB fields */ + for (index = 0; index < USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; ++index) + { + cbwPointer->CBWCB[index] = byteValues[index]; + } + + /* initialize CBW fields */ + cbwPointer->CBWDataTransferLength = USB_LONG_TO_LITTLE_ENDIAN(bufferLength); + cbwPointer->CBWFlags = direction; + cbwPointer->CBWLun = (byteValues[1] >> USB_HOST_UFI_LOGICAL_UNIT_POSITION); + cbwPointer->CBWCBLength = USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH; + + msdInstance->commandStatus = kMSD_CommandTransferCBW; + if (direction == USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN) + { + msdInstance->msdCommand.dataDirection = USB_IN; + } + else + { + msdInstance->msdCommand.dataDirection = USB_OUT; + } + msdInstance->msdCommand.dataBuffer = buffer; + + msdInstance->msdCommand.dataLength = bufferLength; + msdInstance->msdCommand.dataSofar = 0; + msdInstance->msdCommand.retryTime = USB_HOST_MSD_RETRY_MAX_TIME; + + return USB_HostMsdProcessCommand(msdInstance); /* start to process ufi command */ +} + +static usb_status_t USB_HostMsdOpenInterface(usb_host_msd_instance_t *msdInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (msdInstance->inPipe != NULL) /* close bulk in pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->inPipe = NULL; + } + if (msdInstance->outPipe != NULL) /* close bulk out pipe if the pipe is open */ + { + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + msdInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)msdInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = msdInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + status = USB_HostOpenPipe(msdInstance->hostHandle, &msdInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("usb_host_hid_set_interface fail to open pipe\r\n"); +#endif + return status; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostMsdSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)param; + + msdInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostMsdOpenInterface(msdInstance); /* msd open interface */ + } + + if (msdInstance->controlCallbackFn != NULL) + { + msdInstance->controlCallbackFn(msdInstance->controlCallbackParam, NULL, 0, + status); /* callback to application */ + } + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); +} + +usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + usb_status_t status; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)USB_OsaMemoryAllocate( + sizeof(usb_host_msd_instance_t)); /* malloc msd class instance */ + + if (msdInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize msd instance */ + msdInstance->deviceHandle = deviceHandle; + msdInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + msdInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + msdInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + msdInstance->msdCommand.cbwBlock.CBWSignature = USB_LONG_TO_LITTLE_ENDIAN(USB_HOST_MSD_CBW_SIGNATURE); + status = USB_HostMallocTransfer(msdInstance->hostHandle, &(msdInstance->msdCommand.transfer)); + if (status != kStatus_USB_Success) + { + msdInstance->msdCommand.transfer = NULL; +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + } + + *classHandle = msdInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_status_t status = kStatus_USB_Error; + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + status = USB_HostOpenDeviceInterface(msdInstance->deviceHandle, + interfaceHandle); /* notify host driver the interface is open */ + if (status != kStatus_USB_Success) + { + return status; + } + msdInstance->interfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostMsdOpenInterface(msdInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostMsdSetInterfaceCallback; + transfer->callbackParam = msdInstance; + 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 *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + msdInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + usb_status_t status; + + if (classHandle != NULL) + { + if (msdInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->inPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if (msdInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(msdInstance->hostHandle, msdInstance->outPipe); /* close pipe */ + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + } + if ((msdInstance->controlPipe != NULL) && + (msdInstance->controlTransfer != NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = + USB_HostCancelTransfer(msdInstance->hostHandle, msdInstance->controlPipe, msdInstance->controlTransfer); + } + if (msdInstance->msdCommand.transfer) + { + USB_HostFreeTransfer(msdInstance->hostHandle, msdInstance->msdCommand.transfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + msdInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(msdInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostMsdControl(usb_host_msd_instance_t *msdInstance, + host_inner_transfer_callback_t pipeCallbackFn, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t *buffer, + uint16_t bufferLength, + uint8_t requestType, + uint8_t requestValue) +{ + usb_host_transfer_t *transfer; + + if (msdInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(msdInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + msdInstance->controlCallbackFn = callbackFn; + msdInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = pipeCallbackFn; + transfer->callbackParam = msdInstance; + + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = requestValue; + transfer->setupPacket.wValue = 0x0000; + transfer->setupPacket.wIndex = + ((usb_host_interface_t *)msdInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber; + transfer->setupPacket.wLength = bufferLength; + + if (USB_HostSendSetup(msdInstance->hostHandle, msdInstance->controlPipe, transfer) != + kStatus_USB_Success) /* call host driver api */ + { + USB_HostFreeTransfer(msdInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + msdInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl(msdInstance, USB_HostMsdMassResetCallback, callbackFn, callbackParam, NULL, 0, + (USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_MASS_STORAGE_RESET); +} + +usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_msd_instance_t *msdInstance = (usb_host_msd_instance_t *)classHandle; + + return USB_HostMsdControl( + msdInstance, USB_HostMsdControlCallback, callbackFn, callbackParam, logicalUnitNumber, 1, + (USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE), + USB_HOST_HID_GET_MAX_LUN); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/usb_1.1.0/host/class/usb_host_msd.h b/usb_1.1.0/host/class/usb_host_msd.h new file mode 100644 index 0000000..b062d9a --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd.h @@ -0,0 +1,872 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef _USB_HOST_MSD_H_ +#define _USB_HOST_MSD_H_ + +/******************************************************************************* + * MSD class private structure, enumeration, macro + ******************************************************************************/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* CBW and CSW Macros */ +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT (0x00U) +#define USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN (0x80U) +#define USB_HOST_MSD_CBW_SIGNATURE (0x43425355U) +#define USB_HOST_MSD_CSW_SIGNATURE (0x53425355U) + +/* UFI data bit macro */ +#define USB_HOST_UFI_BLOCK_DATA_VALID_LENGTH (10U) +#define USB_HOST_UFI_LOGICAL_UNIT_POSITION (5U) +#define USB_HOST_UFI_CBW_LENGTH (31U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT (6U) +#define USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT (0U) +#define USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT (1U) +#define USB_HOST_UFI_START_STOP_UNIT_START_SHIFT (0U) +#define USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT (2U) + +/******************************************************************************* + * MSD class public structure, enumeration, macro, function + ******************************************************************************/ +/*! + * @addtogroup usb_host_msc_drv + * @{ + */ + +/*! @brief retry time when transfer fail, when all the retries fail the transfer callback with error status */ +#define USB_HOST_MSD_RETRY_MAX_TIME (1U) +/*! @brief mass storage block size */ +#define USB_HOST_MSD_BLOCK_SIZE (512U) + +/*! @brief MSD class code */ +#define USB_HOST_MSD_CLASS_CODE (8U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_UFI (4U) +/*! @brief MSD sub-class code */ +#define USB_HOST_MSD_SUBCLASS_CODE_SCSI (6U) +/*! @brief MSD protocol code */ +#define USB_HOST_MSD_PROTOCOL_BULK (0x50U) + +/*! @brief MSD class-specific request (mass storage reset) */ +#define USB_HOST_HID_MASS_STORAGE_RESET (0xFFU) +/*! @brief MSD class-specific request (get maximum logical unit number) */ +#define USB_HOST_HID_GET_MAX_LUN (0xFEU) + +/*! @brief UFI command process status */ +typedef enum _usb_host_msd_command_status +{ + kMSD_CommandIdle = 0, + kMSD_CommandTransferCBW, + kMSD_CommandTransferData, + kMSD_CommandTransferCSW, + kMSD_CommandDone, + kMSD_CommandCancel, + kMSD_CommandErrorDone, +} usb_host_msd_command_status_t; + +/*! @brief MSC Bulk-Only command block wrapper (CBW) */ +typedef struct _usb_host_cbw +{ + uint32_t CBWSignature; /*!< Signature that helps identify this data packet as a CBW. The signature field shall + contain the value 43425355h (little endian), indicating a CBW */ + uint32_t + CBWTag; /*!< A Command Block Tag sent by the host. The device shall echo the contents of this field back to the + host in the dCSWTag field of the associated CSW */ + uint32_t CBWDataTransferLength; /*!< The number of bytes of data that the host expects to transfer on the Bulk-In or + Bulk-Out endpoint during the execution of this command */ + uint8_t CBWFlags; /*!< + Bit 7 Direction - the device shall ignore this bit if the dCBWDataTransferLength field is + zero, otherwise: + 0 = Data-Out from host to the device, + 1 = Data-In from the device to the host. + Bit 6 Obsolete. The host shall set this bit to zero. + Bits 5..0 Reserved - the host shall set these bits to zero. + */ + uint8_t CBWLun; /*!< The device Logical Unit Number (LUN) to which the command block is being sent */ + uint8_t CBWCBLength; /*!< The valid length of the CBWCB in bytes. This defines the valid length of the command + block. The only legal values are 1 through 16 (01h through 10h).*/ + uint8_t CBWCB[16]; /*!< The command block to be executed by the device*/ +} usb_host_cbw_t; + +/*! @brief MSC Bulk-Only command status wrapper (CSW) */ +typedef struct _usb_host_csw +{ + uint32_t CSWSignature; /*!< Signature that helps identify this data packet as a CSW. The signature field shall + contain the value 53425355h (little endian), indicating CSW.*/ + uint32_t CSWTag; /*!< The device shall set this field to the value received in the dCBWTag of the associated CBW*/ + uint32_t CSWDataResidue; /*!< the difference between the amount of data expected as stated in the + dCBWDataTransferLength and the actual amount of relevant data processed by the device.*/ + uint8_t CSWStatus; /*!< + bCSWStatus indicates the success or failure of the command. + 00h - Command passed. + 01h - Command Failed. + 02h - Phase error. + others - Reserved. + */ +} usb_host_csw_t; + +/*! @brief MSC UFI command information structure */ +typedef struct _usb_host_msd_command +{ + usb_host_cbw_t cbwBlock; /*!< CBW data block*/ + usb_host_csw_t cswBlock; /*!< CSW data block*/ + uint8_t *dataBuffer; /*!< Data buffer pointer*/ + uint32_t dataLength; /*!< Data buffer length*/ + uint32_t dataSofar; /*!< Successful transfer data length*/ + usb_host_transfer_t *transfer; /*!< The transfer is used for processing the UFI command*/ + uint8_t retryTime; /*!< The UFI command residual retry time, when it reduce to zero the UFI command fail */ + uint8_t dataDirection; /*!< The data direction, its value is USB_OUT or USB_IN*/ +} usb_host_msd_command_t; + +/*! @brief MSD instance structure, MSD usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_msd_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle outPipe; /*!< MSD bulk out pipe*/ + usb_host_pipe_handle inPipe; /*!< MSD bulk in pipe*/ + transfer_callback_t commandCallbackFn; /*!< MSD UFI command callback function pointer*/ + void *commandCallbackParam; /*!< MSD UFI command callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< MSD control transfer callback function pointer*/ + void *controlCallbackParam; /*!< MSD control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ + usb_host_msd_command_t msdCommand; /*!< Ongoing MSD UFI command information*/ + uint8_t commandStatus; /*!< UFI command process status, see command_status_t*/ + uint8_t internalResetRecovery; /*!< 1 - class driver internal mass storage reset recovery is on-going; 0 - + application call USB_HostMsdMassStorageReset to reset or there is no reset*/ +} usb_host_msd_instance_t; + +/*! @brief UFI standard sense data structure */ +typedef struct _usb_host_ufi_sense_data +{ + uint8_t errorCode; /*!< This field shall contain a value of 70h to indicate current errors*/ + uint8_t reserved1; /*!< Reserved field*/ + uint8_t senseKey; /*!< Provide a hierarchy of error or command result information*/ + uint8_t information[4]; /*!< This field is command-specific; it is typically used by some commands to return a + logical block address denoting where an error occurred*/ + uint8_t additionalSenseLength; /*!< The UFI device sets the value of this field to ten, to indicate that ten more + bytes of sense data follow this field*/ + uint8_t reserved2[4]; /*!< Reserved field*/ + uint8_t additionalSenseCode; /*!< Provide a hierarchy of error or command result information*/ + uint8_t additionalSenseCodeQualifier; /*!< Provide a hierarchy of error or command result information*/ + uint8_t reserved3[4]; /*!< Reserved field*/ +} usb_host_ufi_sense_data_t; + +/*! @brief UFI standard inquiry data structure */ +typedef struct _usb_host_ufi_inquiry_data +{ + uint8_t peripheralDeviceType; /*!< Identifies the device currently connected to the requested logical unit*/ + uint8_t removableMediaBit; /*!< This shall be set to one to indicate removable media*/ + uint8_t version; /*!< Version*/ + uint8_t responseDataFormat; /*!< A value of 01h shall be used for UFI device*/ + uint8_t additionalLength; /*!< Specify the length in bytes of the parameters*/ + uint8_t reserved1[3]; /*!< Reserved field*/ + uint8_t vendorInformation[8]; /*!< Contains 8 bytes of ASCII data identifying the vendor of the product*/ + uint8_t productIdentification[16]; /*!< Contains 16 bytes of ASCII data as defined by the vendor*/ + uint8_t productRevisionLevel[4]; /*!< Contains 4 bytes of ASCII data as defined by the vendor*/ +} usb_host_ufi_inquiry_data_t; + +/*! @brief UFI read capacity data structure */ +typedef struct _usb_host_ufi_read_capacity +{ + uint8_t lastLogicalBlockAddress[4]; /*!< The logical block number*/ + uint8_t blockLengthInBytes[4]; /*!< Block size*/ +} usb_host_ufi_read_capacity_t; + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @name USB host MSD class APIs + * @{ + */ + +/*! + * @brief Initializes the MSD instance. + * + * This function allocates the resources for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostMsdInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the MSD instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeeded. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostMsdSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the MSD instance. + * + * This function frees the resource for the MSD instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostMsdDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Mass storage reset. + * + * This function implements the mass storage reset request. + * + * @param[in] classHandle The class handle. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostMsdMassStorageReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Gets the maximum logical unit number. + * + * This function implements the get maximum LUN request. + * + * @param[in] classHandle The class handle. + * @param[out] logicalUnitNumber Return logical unit number value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostSendSetup. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdGetMaxLun(usb_host_class_handle classHandle, + uint8_t *logicalUnitNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (10). + * + * This function implements the UFI READ(10) command. This command requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read (12). + * + * This function implements the UFI READ(12) command and requests that the UFI + * device transfer data to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Read block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (10). + * + * This function implements the UFI WRITE(10) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write (12). + * + * This function implements the UFI WRITE(12) command and requests that the UFI device + * write the data transferred by the host to the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read capacity. + * + * This function implements the UFI READ CAPACITY command and allows the host to request + * capacities of the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage test unit ready. + * + * This function implements the UFI TEST UNIT READY command and + * checks if the UFI device is ready. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief mass storage request sense. + * + * This function implements the UFI REQUEST SENSE command, this command instructs + * the UFI device to transfer sense data to the host for the specified logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode select. + * + * This function implements the UFI MODE SELECT command and allows the host + * to specify medium or device parameters to the UFI device. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage mode sense. + * + * This function implements the UFI MODE SENSE command and allows the UFI + * device to report medium or device parameters to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] pageControl The page control field specifies the type of mode parameters to return. + * @param[in] pageCode Buffer pointer. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage inquiry. + * + * This function implements the UFI INQUIRY command and requests that information regarding + * parameters of the UFI device itself be sent to the host. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage read format capacities. + * + * This function implements the UFI READ FORMAT CAPACITIES command and allows the host to request + * a list of the possible capacities that can be formatted on the currently installed medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[out] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage format unit. + * + * This function implements the UFI FORMAT UNIT command and the host sends this command to physically format one + * track of a diskette according to the selected options. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] trackNumber This specifies which track is to be formatted. + * @param[in] interLeave This specifies the interleave that shall be used for formatting. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage prevents/allows a medium removal. + * + * This function implements the UFI PREVENT-ALLOW MEDIUM REMOVAL command and notifies the FUI device + * to enable or disable the removal of the medium in the logical unit. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] prevent Prevent or allow + * - 0: enable (allow) the removal of the medium + * - 1: disable (prevent) removal of the medium + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage write and verify. + * + * This function implements the UFI WRITE AND VERIFY command and requests that the UFI device + * writes the data transferred by the host to the medium, then verifies the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] buffer Buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] blockNumber Write and verify block number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage start stop unit. + * + * This function implements the UFI START-STOP UNIT command and instructs the UFI device + * to enable or disable media access operations . + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] loadEject A Load Eject (LoEj) bit of zero requests that no eject action be performed. A LoEj bit of + * one, with the + * Start bit cleared to zero, which instructs the UFI device to eject the media. + * @param[in] start A Start bit of one instructs the UFI device to enable media access operations. A Start bit + * of zero instructs the UFI device to disable media access operations. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage verify. + * + * This function implements the UFI VERIFY command and requests that the UFI device + * verify the data on the medium. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] verificationLength The data length that need to be verified. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage rezero. + * + * This function implements the UFI REZERO UNIT command. This command positions the head of + * the drive to the cylinder 0. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage seek(10). + * + * This function implements the UFI SEEK(10) command and requests that the UFI device + * seek to the specified Logical Block Address. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] blockAddress The start block address. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Mass storage send diagnostic. + * + * This function implements the UFI SEND DIAGNOSTIC command. This command requests the UFI device + * to do a reset or perform a self-test. + * + * @param[in] classHandle The class MSD handle. + * @param[in] logicalUnit Logical unit number. + * @param[in] selfTest 0 = perform special diagnostic test; 1 = perform default self-test. + * @param[in] callbackFn This callback is called after this command completes. + * @param[in] 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 The previous command is executing or there is no idle transfer. + * @retval kStatus_USB_Error Send transfer fail. See the USB_HostSend/USB_HostRecv. + * @retval kStatus_USB_Success Callback return status, the command succeed. + * @retval kStatus_USB_MSDStatusFail Callback return status, the CSW status indicate this command fail. + * @retval kStatus_USB_Error Callback return status, the command fail. + */ +extern usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_MSD_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_msd_ufi.c b/usb_1.1.0/host/class/usb_host_msd_ufi.c new file mode 100644 index 0000000..0e47e79 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_msd_ufi.c @@ -0,0 +1,473 @@ +/* + * Copyright (c) 2015, 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_MSD) && (USB_HOST_CONFIG_MSD)) +#include "usb_host.h" +#include "usb_host_msd.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* UFI command code */ +#define UFI_FORMAT_UNIT (0x04U) +#define UFI_INQUIRY (0x12U) +#define UFI_START_STOP (0x1BU) +#define UFI_MODE_SELECT (0x55U) +#define UFI_MODE_SENSE (0x5AU) +#define UFI_MEDIUM_REMOVAL (0x1EU) +#define UFI_READ10 (0x28U) +#define UFI_READ12 (0xA8U) +#define UFI_READ_CAPACITY (0x25U) +#define UFI_READ_FORMAT_CAPACITY (0x23U) +#define UFI_REQUEST_SENSE (0x03U) +#define UFI_REZERO_UINT (0x01U) +#define UFI_SEEK (0x2BU) +#define UFI_SEND_DIAGNOSTIC (0x1DU) +#define UFI_TEST_UNIT_READY (0x00U) +#define UFI_VERIFY (0x2FU) +#define UFI_WRITE10 (0x2AU) +#define UFI_WRITE12 (0xAAU) +#define UFI_WRITE_VERIFY (0x2EU) + +#define GET_BYTE_FROM_LE_LONG(b, n) \ + ((uint8_t)((USB_LONG_TO_LITTLE_ENDIAN(b)) >> (n * 8))) /* get the byte from the long value */ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +extern usb_status_t USB_HostMsdCommand(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam, + uint8_t direction, + uint8_t byteValues[10]); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +usb_status_t USB_HostMsdRead10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdRead12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdWrite10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE10, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdWrite12(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE12, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + GET_BYTE_FROM_LE_LONG(blockNumber, 3), + GET_BYTE_FROM_LE_LONG(blockNumber, 2), + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0)}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdReadCapacity(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdTestUnitReady(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_TEST_UNIT_READY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRequestSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REQUEST_SENSE, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdModeSelect(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SELECT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdModeSense(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t pageControl, + uint8_t pageCode, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MODE_SENSE, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + (uint8_t)(((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CONTROL_SHIFT) | + ((uint32_t)pageCode << USB_HOST_UFI_MODE_SENSE_PAGE_CODE_SHIFT)), + 0x00, 0x00, 0x00, 0x00, GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdInquiry(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_INQUIRY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + (uint8_t)bufferLength, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdReadFormatCapacities(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_READ_FORMAT_CAPACITY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_IN, ufiBytes); +} + +usb_status_t USB_HostMsdFormatUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t trackNumber, + uint16_t interLeave, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_FORMAT_UNIT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + trackNumber, + GET_BYTE_FROM_LE_LONG(interLeave, 1), + GET_BYTE_FROM_LE_LONG(interLeave, 0), + 0x00, + 0x00, + GET_BYTE_FROM_LE_LONG(bufferLength, 1), + GET_BYTE_FROM_LE_LONG(bufferLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdPreventAllowRemoval(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t prevent, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_MEDIUM_REMOVAL, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + prevent, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdWriteAndVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint8_t *buffer, + uint32_t bufferLength, + uint32_t blockNumber, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_WRITE_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(blockNumber, 1), + GET_BYTE_FROM_LE_LONG(blockNumber, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, buffer, bufferLength, callbackFn, callbackParam, + USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, ufiBytes); +} + +usb_status_t USB_HostMsdStartStopUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t loadEject, + uint8_t start, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_START_STOP, (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), 0x00, 0x00, + (uint8_t)(((uint32_t)loadEject << USB_HOST_UFI_START_STOP_UNIT_LOEJ_SHIFT) | + ((uint32_t)start << USB_HOST_UFI_START_STOP_UNIT_START_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdVerify(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + uint16_t verificationLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_VERIFY, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + GET_BYTE_FROM_LE_LONG(verificationLength, 1), + GET_BYTE_FROM_LE_LONG(verificationLength, 0), + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdRezeroUnit(usb_host_class_handle classHandle, + uint8_t logicalUnit, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSeek10(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint32_t blockAddress, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_SEEK, + (uint8_t)(logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION), + GET_BYTE_FROM_LE_LONG(blockAddress, 3), + GET_BYTE_FROM_LE_LONG(blockAddress, 2), + GET_BYTE_FROM_LE_LONG(blockAddress, 1), + GET_BYTE_FROM_LE_LONG(blockAddress, 0), + 0x00, + 0x00, + 0x00, + 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +usb_status_t USB_HostMsdSendDiagnostic(usb_host_class_handle classHandle, + uint8_t logicalUnit, + uint8_t selfTest, + transfer_callback_t callbackFn, + void *callbackParam) +{ + uint8_t ufiBytes[] = {UFI_REZERO_UINT, + (uint8_t)(((uint32_t)logicalUnit << USB_HOST_UFI_LOGICAL_UNIT_POSITION) | + ((uint32_t)selfTest << USB_HOST_UFI_SEND_DIAGNOSTIC_SELF_TEST_SHIFT)), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return USB_HostMsdCommand(classHandle, NULL, 0, callbackFn, callbackParam, USB_HOST_MSD_CBW_FLAGS_DIRECTION_OUT, + ufiBytes); +} + +#endif /* USB_HOST_CONFIG_MSD */ diff --git a/usb_1.1.0/host/class/usb_host_phdc.c b/usb_1.1.0/host/class/usb_host_phdc.c new file mode 100644 index 0000000..e740487 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_phdc.c @@ -0,0 +1,1272 @@ +/* + * 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_PHDC) && (USB_HOST_CONFIG_PHDC)) +#include "usb_host.h" +#include "usb_host_phdc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief phdc control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc set and clear feature endpoint halt callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param, + usb_host_transfer_t *transfer, + usb_status_t status); + +/*! + * @brief phdc interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc bulk in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc bulk out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief phdc set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief meta-data message preamble signature string */ +static char const metaDataMsgPreambleSignature[] = "PhdcQoSSignature"; + +/******************************************************************************* + * Code + ******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + +static void USB_HostPhdcClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */ + phdcInstance->numberTransferBulkIn = 0U; + if (phdcInstance->inCallbackFn != NULL) + { + /* callback to application */ + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, phdcInstance->stallDataBuffer, + phdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +static void USB_HostPhdcClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + if (phdcInstance->outCallbackFn != NULL) + { + /* callback to application */ + phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, phdcInstance->stallDataBuffer, + phdcInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostPhdcClearHalt(usb_host_phdc_instance_t *phdcInstance, + 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(phdcInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + phdcInstance->stallDataBuffer = stallTransfer->transferBuffer; + phdcInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + phdcInstance->controlCallbackFn = NULL; + phdcInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = phdcInstance; + 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(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + } + phdcInstance->controlTransfer = transfer; + + return status; +} + +#endif + +/*! + * @brief phdc control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + phdcInstance->controlTransfer = NULL; + if (kStatus_USB_Success == status) + { + if (USB_HOST_PHDC_SET_FEATURE_REQUEST == transfer->setupPacket.bRequest) + { + /* Meta-data message preamble feature is enabled */ + phdcInstance->isMessagePreambleEnabled = 1U; + } + else if (USB_HOST_PHDC_CLEAR_FEATURE_REQUEST == transfer->setupPacket.bRequest) + { + /* Meta-data message preamble feature is disable */ + phdcInstance->isMessagePreambleEnabled = 0U; + } + else + { + } + } + if (NULL != phdcInstance->controlCallbackFn) + { + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc set and clear feature endpoint halt callback for meta-data message preamble error. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetClearFeatureEndpointHaltCallback(void *param, + usb_host_transfer_t *transfer, + usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + phdcInstance->controlTransfer = NULL; + if (kStatus_USB_Success == status) + { + if ((transfer->setupPacket.bRequest == USB_REQUEST_STANDARD_SET_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(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress))) + { + /* The host shall issue CLEAR_FEATURE ENDPOINT_HALT request to the device */ + usb_host_process_feature_param_t featureParam; + featureParam.requestType = kRequestEndpoint; + featureParam.featureSelector = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT; + featureParam.interfaceOrEndpoint = phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress; + if (kStatus_USB_Success != USB_HostPhdcSetClearFeatureEndpointHalt(phdcInstance->hostHandle, + USB_REQUEST_STANDARD_CLEAR_FEATURE, + &featureParam, NULL, NULL)) + { +#ifdef HOST_ECHO + usb_echo("Error for USB_HostPhdcSetClearFeatureEndpointHalt\r\n"); +#endif + } + } + if ((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(phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress))) + { + /* Reduces the number of bulk transfer to 0 to expect new message preamble transfer */ + phdcInstance->numberTransferBulkIn = 0U; + } + } + if (NULL != phdcInstance->controlCallbackFn) + { + /* Notify to application the status of request */ + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc interrupt pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcInterruptPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_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_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->interruptPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (NULL != phdcInstance->inCallbackFn) + { + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc bulk in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_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_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)phdcInstance->bulkInPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (status == kStatus_USB_Success) + { + /* The meta-data message preamble is implemented and enabled */ + if (phdcInstance->isMessagePreambleEnabled == 1U) + { + /* The meta-data message preamble feature is enabled, then all data transfers or sets + of data transfers shall be preceded by a meta-data message preamble transfer. The + numberTransferBulkIn is initialized as zero for receiving this message preamble data, + then it is updated to the value of bNumTransfers field of message preamble data */ + if (phdcInstance->numberTransferBulkIn) + { + /* When numberTransferBulkIn reduces to 0, a new meta-data message preamble shall + be transferred */ + phdcInstance->numberTransferBulkIn--; + } + else + { + uint8_t preambleSignatureChecking = 1U; + /* The received packet is meta-data message preamble */ + usb_host_phdc_metadata_preamble_t *metaDataMsgPreamble = + (usb_host_phdc_metadata_preamble_t *)transfer->transferBuffer; + /* Meta-data message preamble signature checking */ + for (uint8_t i = 0U; i < USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE; i++) + { + if (*(transfer->transferBuffer + i) != metaDataMsgPreambleSignature[i]) + { + preambleSignatureChecking = 0U; + break; + } + } + if (preambleSignatureChecking) + { + /* Checks if the meta-data message preamble contains an invalid bmLatencyReliability value + or bNumTransfers value */ + if ((!(metaDataMsgPreamble->bNumberTransfers)) || /* bNumTransfers shall never equal zero */ + (metaDataMsgPreamble->bQosEncodingVersion != 0x01U) || /* Encoding version should be 0x01 */ + ((metaDataMsgPreamble->bmLatencyReliability != + 0x02U) && /* Medium.Good latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x04U) && /* Medium.Better latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x08U) && /* Medium.Best latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x10U) && /* High.Best latency, reliability bin */ + (metaDataMsgPreamble->bmLatencyReliability != + 0x20U) /* VeryHigh.Best latency, reliability bin */)) + { + /* The host shall issue SET_FEATURE ENDPOINT_HALT request to the device */ + usb_host_process_feature_param_t featureParam; + featureParam.requestType = kRequestEndpoint; + featureParam.featureSelector = USB_REQUEST_STANDARD_FEATURE_SELECTOR_ENDPOINT_HALT; + featureParam.interfaceOrEndpoint = + phdcInstance->bulkInEndpointInformation.epDesc->bEndpointAddress; + if (kStatus_USB_Success != + USB_HostPhdcSetClearFeatureEndpointHalt( + phdcInstance->hostHandle, USB_REQUEST_STANDARD_SET_FEATURE, &featureParam, NULL, NULL)) + { +#ifdef HOST_ECHO + usb_echo( + "USB_HostPhdcBulkInPipeCallback: Error for " + "USB_HostPhdcSetClearFeatureEndpointHalt\r\n"); +#endif + } + } + else + { + /* The meta-data message preamble data is correct, update the phdc status and + * numberTransferBulkIn value */ + phdcInstance->numberTransferBulkIn = metaDataMsgPreamble->bNumberTransfers; + } + } + } + } + } + if (NULL != phdcInstance->inCallbackFn) + { + phdcInstance->inCallbackFn(phdcInstance->inCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc bulk out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcBulkOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_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_HostPhdcClearHalt( + phdcInstance, transfer, USB_HostPhdcClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)phdcInstance->bulkOutPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return; + } + } +#endif + if (NULL != phdcInstance->outCallbackFn) + { + phdcInstance->outCallbackFn(phdcInstance->outCallbackParam, transfer->transferBuffer, transfer->transferSofar, + status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief phdc open interface. + * + * @param phdcInstance phdc instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostPhdcOpenInterface(usb_host_phdc_instance_t *phdcInstance) +{ + usb_status_t status; + uint8_t epIndex = 0U; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interface; + if (NULL != phdcInstance->interruptPipe) + { + /* Close the PHDC interrupt pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->interruptPipe = NULL; + } + + if (NULL != phdcInstance->bulkInPipe) + { + /* Close the PHDC bulk in pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkInPipe = NULL; + } + + if (NULL != phdcInstance->bulkOutPipe) + { + /* Close the PHDC bulk out pipe if it is opening */ + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + + /* open interface pipes */ + interface = (usb_host_interface_t *)phdcInstance->interfaceHandle; + for (epIndex = 0U; epIndex < interface->epCount; ++epIndex) + { + epDesc = interface->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_INTERRUPT)) + { + /* Initialize the interrupt pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_INTERRUPT; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->interruptPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save interrupt in endpoint information */ + phdcInstance->interruptInEndpointInformation = interface->epList[epIndex]; + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + /* Initialize bulk in pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkInPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save bulk in endpoint information */ + phdcInstance->bulkInEndpointInformation = interface->epList[epIndex]; + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + /* Initialize bulk out pipe */ + pipeInit.devInstance = phdcInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + status = USB_HostOpenPipe(phdcInstance->hostHandle, &phdcInstance->bulkOutPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcOpenInterface: Error when open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + /* save bulk out endpoint information */ + phdcInstance->bulkOutEndpointInformation = interface->epList[epIndex]; + } + else + { + } + } + return kStatus_USB_Success; +} + +/*! + * @brief phdc set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPhdcSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)param; + + phdcInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + /* set interface is done, open the interface */ + status = USB_HostPhdcOpenInterface(phdcInstance); + } + + if (NULL != phdcInstance->controlCallbackFn) + { + /* Notify to application the status of set interface request */ + phdcInstance->controlCallbackFn(phdcInstance->controlCallbackParam, NULL, 0U, status); + } + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); +} + +/*! + * @brief set interface. + * + * This function binds the interface with the phdc 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_HostPhdcSetInterface(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_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidParameter; + } + + phdcInstance->interfaceHandle = interfaceHandle; + + status = USB_HostOpenDeviceInterface(phdcInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + + /* Cancel interrupt transfers */ + if (NULL != phdcInstance->interruptPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + } + /* Cancel bulk in transfers */ + if (NULL != phdcInstance->bulkInPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + } + /* Cancel bulk out transfers */ + if (NULL != phdcInstance->bulkOutPipe) + { + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error when cancel pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + if (0U == alternateSetting) + { + if (NULL != callbackFn) + { + status = USB_HostPhdcOpenInterface(phdcInstance); + callbackFn(callbackParam, NULL, 0U, status); + } + } + else + { + /* Create transfer buffer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSetInterface: Error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize transfer */ + transfer->callbackFn = USB_HostPhdcSetInterfaceCallback; + transfer->callbackParam = phdcInstance; + 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 *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + /* Send set interface request to device */ + status = USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer); + if (status == kStatus_USB_Success) + { + phdcInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + } + } + return status; +} + +/*! + * @brief initialize the phdc instance. + * + * This function allocates the resource for phdc 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_HostPhdcInit(usb_host_handle deviceHandle, usb_host_class_handle *classHandle) +{ + usb_host_phdc_instance_t *phdcInstance = + (usb_host_phdc_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_phdc_instance_t)); + uint32_t infoValue; + + if (NULL == phdcInstance) + { + return kStatus_USB_AllocFail; + } + /* Initialize PHDC instance */ + phdcInstance->deviceHandle = deviceHandle; + phdcInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + phdcInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + phdcInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = phdcInstance; + return kStatus_USB_Success; +} + +/*! + * @brief de-initialize the phdc instance. + * + * This function release the resource for phdc 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_HostPhdcDeinit(usb_host_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + + if (NULL == deviceHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL != classHandle) + { + if (NULL != phdcInstance->interruptPipe) + { + /* Cancel/close interrupt transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->interruptPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->interruptPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->interruptPipe = NULL; + } + if (NULL != phdcInstance->bulkInPipe) + { + /* Cancel/close bulk in transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkInPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkInPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkInPipe = NULL; + } + if (NULL != phdcInstance->bulkOutPipe) + { + /* Cancel/close bulk out transfers/pipe */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, NULL); + status = USB_HostClosePipe(phdcInstance->hostHandle, phdcInstance->bulkOutPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcDeinit: Error when close pipe\r\n"); +#endif + } + phdcInstance->bulkOutPipe = NULL; + } + if ((NULL != phdcInstance->controlPipe) && (NULL != phdcInstance->controlTransfer)) + { + /* Cancel control transfers */ + status = USB_HostCancelTransfer(phdcInstance->hostHandle, phdcInstance->controlPipe, + phdcInstance->controlTransfer); + } + /* Close device interface */ + USB_HostCloseDeviceInterface(deviceHandle, phdcInstance->interfaceHandle); + /* Release PHDC instance */ + USB_OsaMemoryFree(phdcInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + return kStatus_USB_Success; +} + +/*! + * @brief receive data. + * + * This function implements phdc receiving data. + * + * @param classHandle the class handle. + * @param qos QoS of the data being received. + * @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_HostPhdcRecv(usb_host_class_handle classHandle, + uint8_t qos, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + usb_host_pipe_handle pipe; + usb_host_phdc_qos_descriptor_t *qosDesc = NULL; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if ((NULL == phdcInstance->interruptPipe) && (NULL == phdcInstance->bulkInPipe)) + { + return kStatus_USB_Error; + } + /* Allocate the transfer buffer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->inCallbackFn = callbackFn; + phdcInstance->inCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackParam = phdcInstance; + /* The on can receive the data on interrupt pipe or bulk in pipe depends on the QoS value */ + pipe = (qos & 0x01U) ? (phdcInstance->interruptPipe) : (phdcInstance->bulkInPipe); + if (pipe == phdcInstance->bulkInPipe) + { + /* get bulk in QoS descriptor */ + qosDesc = (usb_host_phdc_qos_descriptor_t *)phdcInstance->bulkInEndpointInformation.epExtension; + transfer->callbackFn = USB_HostPhdcBulkInPipeCallback; + } + else + { + /* get interrupt in QoS descriptor */ + qosDesc = (usb_host_phdc_qos_descriptor_t *)phdcInstance->interruptInEndpointInformation.epExtension; + transfer->callbackFn = USB_HostPhdcInterruptPipeCallback; + } + /* Latency and reliability checking */ + if (!(qos & qosDesc->bmLatencyReliability)) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcRecv, ERROR: invalid QoS bin"); +#endif + return kStatus_USB_Error; + } + /* The previous control transfer is pending */ + if (NULL != phdcInstance->controlTransfer) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcRecv, ERROR: Control transfer is in progress"); +#endif + return kStatus_USB_Busy; + } + if (USB_HostRecv(phdcInstance->hostHandle, pipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +/*! + * @brief send data. + * + * This function implements phdc 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 send 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_HostPhdcSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + usb_status_t status; + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->bulkOutPipe) + { + return kStatus_USB_Error; + } + if (NULL != phdcInstance->controlTransfer) + { + status = kStatus_USB_Busy; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: control transfer is in progress"); +#endif + return status; + } + /* The meta-data message preamble is implemented and enabled */ + if (phdcInstance->isMessagePreambleEnabled == 1U) + { + /* The meta-data message preamble feature is enabled, then all data transfers or sets + of data transfers shall be preceded by a meta-data message preamble transfer. The + numberTransferBulkOut is initialized as zero for sending this message preamble data, + then it is updated to the value of bNumTransfers field of message preamble data */ + if (phdcInstance->numberTransferBulkOut) + { + /* When numberTransferBulkOut reduces to 0, a new meta-data message preamble shall + be transferred */ + phdcInstance->numberTransferBulkOut--; + } + else + { + usb_host_phdc_qos_descriptor_t *qosDesc = + (usb_host_phdc_qos_descriptor_t *)phdcInstance->bulkOutEndpointInformation.epExtension; + ; + uint8_t latencyReliability = ((usb_host_phdc_metadata_preamble_t *)buffer)->bmLatencyReliability; + /* Latency reliability validity checking */ + if ((latencyReliability != 0x02U) && /* Medium.Good latency, reliability bin */ + (latencyReliability != 0x04U) && /* Medium.Better latency, reliability bin */ + (latencyReliability != 0x08U) && /* Medium.Best latency, reliability bin */ + (latencyReliability != 0x10U) && /* High.Best latency, reliability bin */ + (latencyReliability != 0x20U) /* VeryHigh.Best latency, reliability bin */) + { + status = kStatus_USB_InvalidRequest; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: invalid LatencyReliability"); +#endif + return status; + } + /* LatencyReliablity checking */ + if (0U == (qosDesc->bmLatencyReliability & latencyReliability)) + { + status = kStatus_USB_Error; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: the latency reliability is not supported by Bulk OUT endpoint"); +#endif + return status; + } + if (0U == ((usb_host_phdc_metadata_preamble_t *)buffer)->bNumberTransfers) + { + status = kStatus_USB_Error; +#ifdef HOST_ECHO + usb_echo("USB_HostPhdcSend, Error: the numTransfer should never zero"); +#endif + return status; + } + /* Update the number of bulk out transfer */ + phdcInstance->numberTransferBulkOut = ((usb_host_phdc_metadata_preamble_t *)buffer)->bNumberTransfers; + } + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save the application callback function and parameter */ + phdcInstance->outCallbackFn = callbackFn; + phdcInstance->outCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPhdcBulkOutPipeCallback; + transfer->callbackParam = phdcInstance; + if (USB_HostSend(phdcInstance->hostHandle, phdcInstance->bulkOutPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + return kStatus_USB_Success; +} + +/*! + * @brief phdc sends control request. + * + * @param classHandle the class handle. + * @param request_type setup packet request. + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send 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_HostPhdcSendControlRequest(usb_host_class_handle classHandle, + uint8_t request, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_status_t status = kStatus_USB_Success; + usb_host_transfer_t *transfer; + + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->controlPipe) + { + return kStatus_USB_Error; + } + + if (NULL != phdcInstance->controlTransfer) + { + return kStatus_USB_Busy; + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save the callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize the transfer pointer */ + transfer->callbackFn = USB_HostPhdcControlPipeCallback; + transfer->callbackParam = phdcInstance; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wIndex = USB_SHORT_TO_LITTLE_ENDIAN( + ((usb_host_interface_t *)phdcInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + switch (request) + { + case USB_HOST_PHDC_GET_STATUS_REQUEST: + /* Initialize the PHDC get status request */ + transfer->setupPacket.wValue = 0U; + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wLength = 2U; + break; + case USB_HOST_PHDC_SET_FEATURE_REQUEST: + case USB_HOST_PHDC_CLEAR_FEATURE_REQUEST: + /* Initialize the PHDC set/clear feature request */ + transfer->setupPacket.bmRequestType = + USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE; + transfer->setupPacket.wValue = + (USB_HOST_PHDC_FEATURE_METADATA | (uint16_t)((uint16_t)USB_HOST_PHDC_QOS_ENCODING_VERSION << 8U)); + transfer->setupPacket.wLength = 0U; + break; + default: + status = kStatus_USB_InvalidRequest; + break; + } + if (USB_HostSendSetup(phdcInstance->hostHandle, phdcInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + phdcInstance->controlTransfer = transfer; + + return status; +} + +/*! + * @brief phdc set and clear feature endpoint halt request for meta-data message preamble error. + * + * @param classHandle the class handle. + * @param request setup packet request. + * @param param request parameter + * @param callbackFn this callback is called after this function completes. + * @param callbackParam the first parameter in the callback function. + * + * @retval kStatus_USB_Success send 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_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle, + uint8_t request, + void *param, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_transfer_t *transfer; + if (NULL == classHandle) + { + return kStatus_USB_InvalidHandle; + } + + if (NULL == phdcInstance->controlPipe) + { + return kStatus_USB_Error; + } + + if (NULL != phdcInstance->controlTransfer) + { + return kStatus_USB_Busy; + } + /* Allocate the transfer pointer */ + if (USB_HostMallocTransfer(phdcInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* Save application callback function and parameter */ + phdcInstance->controlCallbackFn = callbackFn; + phdcInstance->controlCallbackParam = callbackParam; + /* Initialize the transfer request */ + transfer->callbackFn = USB_HostPhdcSetClearFeatureEndpointHaltCallback; + transfer->callbackParam = phdcInstance; + if (USB_HostRequestControl(phdcInstance->hostHandle, request, transfer, param)) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostRequestControl\r\n"); +#endif + USB_HostFreeTransfer(phdcInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + phdcInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +/*! + * @brief USB_HostPhdcGetEndpointInformation. + * This function returns the PHDC endpoint information structure contains endpoint + * descriptor and endpoint extended descriptor. + * + * @param classHandle the class handle. + * @param pipeType pipe type. + * @param direction pipe direction. + * + * @retval endpointReturn All input parameters are valid. + * @retval NULL One or more input parameters are invalid. + */ +usb_host_ep_t *USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle, + uint8_t pipeType, + uint8_t direction) +{ + usb_host_phdc_instance_t *phdcInstance = (usb_host_phdc_instance_t *)classHandle; + usb_host_ep_t *endpointReturn = NULL; + if (NULL != classHandle) + { + if (pipeType == USB_ENDPOINT_BULK) + { + if (direction == USB_IN) + { + /* bulk in endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkInEndpointInformation; + } + else + { + /* bulk out endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->bulkOutEndpointInformation; + } + } + else if (pipeType == USB_ENDPOINT_INTERRUPT) + { + /* interrupt in endpoint information */ + endpointReturn = (usb_host_ep_t *)&phdcInstance->interruptInEndpointInformation; + } + else + { + } + } + return endpointReturn; +} +#endif diff --git a/usb_1.1.0/host/class/usb_host_phdc.h b/usb_1.1.0/host/class/usb_host_phdc.h new file mode 100644 index 0000000..4b62b6b --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_phdc.h @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2015, 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. + */ + +#ifndef __USB_HOST_PHDC_H__ +#define __USB_HOST_PHDC_H__ + +/******************************************************************************* + * PHDC class public structure, enumeration, macro, function + ******************************************************************************/ +/*! + * @addtogroup usb_host_phdc_drv + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHDC class code */ +#define USB_HOST_PHDC_CLASS_CODE (0x0FU) +/*! @brief PHDC sub class code */ +#define USB_HOST_PHDC_SUBCLASS_CODE (0x00U) +/*! @brief PHDC protocol */ +#define USB_HOST_PHDC_PROTOCOL (0x00U) +/*! @brief PHDC get status request */ +#define USB_HOST_PHDC_GET_STATUS_REQUEST (0x00U) +/*! @brief PHDC set feature request */ +#define USB_HOST_PHDC_SET_FEATURE_REQUEST (0x03U) +/*! @brief PHDC clear feature request */ +#define USB_HOST_PHDC_CLEAR_FEATURE_REQUEST (0x01U) +/*! @brief PHDC meta-data feature */ +#define USB_HOST_PHDC_FEATURE_METADATA (0x01U) +/*! @brief PHDC QoS information encoding feature */ +#define USB_HOST_PHDC_QOS_ENCODING_VERSION (0x01U) + +/*! @brief meta-data message preamble signature size */ +#define USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE (0x10U) + +/*! @brief PHDC class function descriptor type */ +#define USB_HOST_PHDC_CLASSFUNCTION_DESCRIPTOR (0x20U) +/*! @brief PHDC QoS descriptor type */ +#define USB_HOST_PHDC_QOS_DESCRIPTOR (0x21U) +/*! @brief PHDC function extension descriptor type */ +#define USB_HOST_PHDC_11073PHD_FUNCTION_DESCRIPTOR (0x30U) +/*! @brief PHDC meta-data descriptor type */ +#define USB_HOST_PHDC_METADATA_DESCRIPTOR (0x22U) + +/*! @brief PHDC class function descriptor structure as defined by the PHDC class specification */ +typedef struct _usb_host_phdc_class_function_desciptor +{ + uint8_t bLength; /*!< Class function descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_CLASSFUNCTION_DESCRIPTOR type */ + uint8_t bPhdcDataCode; /*!< Data/Messaging format code */ + uint8_t bmCapability; /*!< If bit 0 is 1 the meta-data message preamble is implemented and 0 if it is not */ +} usb_host_phdc_class_function_desciptor_t; + +/*! @brief Function extension descriptor (device specialization) structure as defined by the PHDC class specification. + */ +typedef struct _usb_host_phdc_function_extension_descriptor +{ + uint8_t bLength; /*!< Function extension descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_CLASSFUNCTION_DESCRIPTOR type */ + uint8_t bReserved; /*!< Reserved for future use */ + uint8_t bNumDevSpecs; /*!< Number of wDevSpecializations */ + uint16_t *wDevSpecializations; /*!< Variable length list that defines the device specialization */ +} usb_host_phdc_function_extension_descriptor_t; + +/*! @brief QoS descriptor structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_qos_descriptor +{ + uint8_t bLength; /*!< QoS descriptor length */ + uint8_t bDescriptortype; /*!< PHDC_QOS_DESCRIPTOR type */ + uint8_t bQosEncodingVersion; /*!< Version of QoS information encoding */ + uint8_t bmLatencyReliability; /*!< Latency/reliability bin for the QoS data */ +} usb_host_phdc_qos_descriptor_t; + +/*! @brief Metadata descriptor structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_metadata_descriptor +{ + uint8_t bLength; /*!< Metadata descriptor length */ + uint8_t bDescriptortype; /*!< Descriptor type */ + uint8_t *bOpaqueData; /*!< Opaque metadata */ +} usb_host_phdc_metadata_descriptor_t; + +/*! @brief Metadata message preamble structure as defined by the PHDC class specification. */ +typedef struct _usb_host_phdc_metadata_preamble +{ + uint8_t + aSignature[USB_HOST_PHDC_MESSAGE_PREAMBLE_SIGNATURE_SIZE]; /*!< Constant used to give preamble verifiability */ + uint8_t bNumberTransfers; /*!< Count of following transfer to which the QoS setting applies */ + uint8_t bQosEncodingVersion; /*!< Version of QoS information encoding */ + uint8_t bmLatencyReliability; /*!< See latency/reliability bin for the QoS data */ + uint8_t bOpaqueDataSize; /*!< Opaque QoS data or meta-data size */ + uint8_t *bOpaqueData; /*!< Opaque metadata */ +} usb_host_phdc_metadata_preamble_t; + +/*! @brief PHDC instance structure */ +typedef struct _usb_host_phdc_instance +{ + usb_host_handle hostHandle; /*!< The host handle */ + usb_device_handle deviceHandle; /*!< The device handle */ + usb_host_interface_handle interfaceHandle; /*!< The interface handle */ + usb_host_pipe_handle controlPipe; /*!< The control pipe */ + usb_host_pipe_handle interruptPipe; /*!< The interrupt pipe */ + usb_host_pipe_handle bulkInPipe; /*!< The bulk in pipe */ + usb_host_pipe_handle bulkOutPipe; /*!< The bulk out pipe */ + transfer_callback_t inCallbackFn; /*!< The callback function is called when the PHDC receives complete */ + void *inCallbackParam; /*!< The first parameter of the in callback function */ + transfer_callback_t outCallbackFn; /*!< The callback function is called when the PHDC sends complete */ + void *outCallbackParam; /*!< The first parameter of the out callback function */ + transfer_callback_t controlCallbackFn; /*!< The control callback function */ + void *controlCallbackParam; /*!< The first parameter of the control callback function */ + usb_host_transfer_t *controlTransfer; /*!< The control transfer pointer */ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; /*!< keep the data buffer for stall transfer's data*/ + uint32_t stallDataLength; /*!< keep the data length for stall transfer's data*/ +#endif + + usb_host_ep_t interruptInEndpointInformation; /*!< The interrupt in information */ + usb_host_ep_t bulkInEndpointInformation; /*!< The bulk in information */ + usb_host_ep_t bulkOutEndpointInformation; /*!< The bulk out information */ + uint8_t isMessagePreambleEnabled; /*!< The flag is used to check the message preamble feature is enabled or not */ + uint8_t numberTransferBulkOut; /*!< The number of transfer that follow Meta-data Message Preamble */ + uint8_t numberTransferBulkIn; /*!< The number of transfer that follow Meta-data Message Preamble */ +} usb_host_phdc_instance_t; + +/******************************************************************************* + * API + ******************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host PHDC class APIs + * @{ + */ + +/*! + * @brief Initializes the PHDC instance. + * + * This function allocates the resource for PHDC 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. + */ +extern usb_status_t USB_HostPhdcInit(usb_host_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets an interface. + * + * This function binds the interface with the PHDC 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. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostPhdcSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Deinitializes the PHDC instance. + * + * This function frees the resource for the PHDC instance. + * + * @param deviceHandle The device handle. + * @param classHandle The class handle. + * + * @retval kStatus_USB_Success The device is deinitialized successfully. + */ +extern usb_status_t USB_HostPhdcDeinit(usb_host_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Receives data. + * + * This function implements the PHDC receiving data. + * + * @param classHandle The class handle. + * @param qos QoS of the data being received. + * @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. See the USB_HostRecv. + */ +extern usb_status_t USB_HostPhdcRecv(usb_host_class_handle classHandle, + uint8_t qos, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the PHDC 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 Send 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. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief PHDC sends the control request. + * + * @param classHandle The class handle. + * @param request Setup packet request. + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send 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. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSendControlRequest(usb_host_class_handle classHandle, + uint8_t request, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief PHDC set and clear feature endpoint halt request. + * + * @param classHandle The class handle. + * @param request Setup packet request. + * @param param Request parameter + * @param callbackFn This callback is called after this function completes. + * @param callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send 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. See the USB_HostSend. + */ +extern usb_status_t USB_HostPhdcSetClearFeatureEndpointHalt(usb_host_class_handle classHandle, + uint8_t request, + void *param, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief USB_HostPhdcGetEndpointInformation. + * This function returns the PHDC endpoint information structure, which contains an endpoint + * descriptor and an endpoint extended descriptor. + * + * @param classHandle The class handle. + * @param pipeType Pipe type. + * @param direction Pipe direction. + * + * @retval endpointReturn All input parameters are valid. + * @retval NULL One or more input parameters are invalid. + */ +usb_host_ep_t *USB_HostPhdcGetEndpointInformation(usb_host_class_handle classHandle, + uint8_t pipeType, + uint8_t direction); + +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* _USB_HOST_PHDC_H_ */ diff --git a/usb_1.1.0/host/class/usb_host_printer.c b/usb_1.1.0/host/class/usb_host_printer.c new file mode 100644 index 0000000..5a10038 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_printer.c @@ -0,0 +1,775 @@ +/* + * Copyright (c) 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_PRINTER) && (USB_HOST_CONFIG_PRINTER)) +#include "usb_host.h" +#include "usb_host_printer.h" + +/******************************************************************************* + * API + ******************************************************************************/ + +/*! + * @brief printer in pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer out pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer control pipe transfer callback. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer open interface. It is called when set interface request success or open alternate setting 0 interface. + * + * @param printerInstance printer instance pointer. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostPrinterOpenInterface(usb_host_printer_instance_t *printerInstance); + +/*! + * @brief printer set interface callback, open pipes. + * + * @param param callback parameter. + * @param transfer callback transfer. + * @param status transfer status. + */ +static void USB_HostPrinterSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status); + +/*! + * @brief printer send control transfer common code. + * + * @param classHandle the class handle. + * @param requestType setup packet request type. + * @param request setup packet request value. + * @param wvalue setup packet wValue. + * @param windex setup packet wIndex. + * @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. + */ +static usb_status_t USB_HostPrinterControl(usb_host_printer_instance_t *printerInstance, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam); + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/******************************************************************************* + * Variables + ******************************************************************************/ +/******************************************************************************* + * Code + ******************************************************************************/ + +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) +static void USB_HostPrinterClearInHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + if (printerInstance->inCallbackFn != NULL) + { + /* callback to application */ + printerInstance->inCallbackFn(printerInstance->outCallbackParam, printerInstance->stallDataBuffer, + printerInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterClearOutHaltCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + if (printerInstance->outCallbackFn != NULL) + { + /* callback to application */ + printerInstance->outCallbackFn(printerInstance->outCallbackParam, printerInstance->stallDataBuffer, + printerInstance->stallDataLength, kStatus_USB_TransferStall); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterClearHalt(usb_host_printer_instance_t *printerInstance, + 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(printerInstance->hostHandle, &transfer); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("allocate transfer error\r\n"); +#endif + return status; + } + printerInstance->stallDataBuffer = stallTransfer->transferBuffer; + printerInstance->stallDataLength = stallTransfer->transferSofar; + /* save the application callback function */ + printerInstance->controlCallbackFn = NULL; + printerInstance->controlCallbackParam = NULL; + /* initialize transfer */ + transfer->callbackFn = callbackFn; + transfer->callbackParam = printerInstance; + 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(printerInstance->hostHandle, printerInstance->controlPipe, transfer); + + if (status != kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + } + printerInstance->controlTransfer = transfer; + + return status; +} +#endif + +static void USB_HostPrinterInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_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_HostPrinterClearHalt( + printerInstance, transfer, USB_HostPrinterClearInHaltCallback, + (USB_REQUEST_TYPE_DIR_IN | ((usb_host_pipe_t *)printerInstance->inPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return; + } + } +#endif + + if (printerInstance->inCallbackFn != NULL) + { + /* callback to application */ + printerInstance->inCallbackFn(printerInstance->inCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterOutPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_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_HostPrinterClearHalt( + printerInstance, transfer, USB_HostPrinterClearOutHaltCallback, + (USB_REQUEST_TYPE_DIR_OUT | ((usb_host_pipe_t *)printerInstance->outPipe)->endpointAddress)) == + kStatus_USB_Success) + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return; + } + } +#endif + if (printerInstance->outCallbackFn != NULL) + { + /* callback to application */ + printerInstance->outCallbackFn(printerInstance->outCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static void USB_HostPrinterControlPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + printerInstance->controlTransfer = NULL; + if (printerInstance->controlCallbackFn != NULL) + { + /* callback to application */ + printerInstance->controlCallbackFn(printerInstance->controlCallbackParam, transfer->transferBuffer, + transfer->transferSofar, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +static usb_status_t USB_HostPrinterOpenInterface(usb_host_printer_instance_t *printerInstance) +{ + usb_status_t status; + uint8_t epIndex = 0; + usb_host_pipe_init_t pipeInit; + usb_descriptor_endpoint_t *epDesc = NULL; + usb_host_interface_t *interfacePointer; + + if (printerInstance->inPipe != NULL) + { + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->inPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->inPipe = NULL; + } + if (printerInstance->outPipe != NULL) /* close interrupt out pipe if it is open */ + { + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->outPipe); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->outPipe = NULL; + } + + /* open interface pipes */ + interfacePointer = (usb_host_interface_t *)printerInstance->interfaceHandle; + for (epIndex = 0; epIndex < interfacePointer->epCount; ++epIndex) + { + epDesc = interfacePointer->epList[epIndex].epDesc; + if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_IN) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = printerInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_IN; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + printerInstance->inPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(printerInstance->hostHandle, &printerInstance->inPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPrinterSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else if (((epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) == + USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_OUT) && + ((epDesc->bmAttributes & USB_DESCRIPTOR_ENDPOINT_ATTRIBUTE_TYPE_MASK) == USB_ENDPOINT_BULK)) + { + pipeInit.devInstance = printerInstance->deviceHandle; + pipeInit.pipeType = USB_ENDPOINT_BULK; + pipeInit.direction = USB_OUT; + pipeInit.endpointAddress = (epDesc->bEndpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK); + pipeInit.interval = epDesc->bInterval; + pipeInit.maxPacketSize = (uint16_t)(USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_SIZE_MASK); + pipeInit.numberPerUframe = (USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(epDesc->wMaxPacketSize) & + USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK); + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + + printerInstance->outPacketSize = pipeInit.maxPacketSize; + + status = USB_HostOpenPipe(printerInstance->hostHandle, &printerInstance->outPipe, &pipeInit); + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("USB_HostPrinterSetInterface fail to open pipe\r\n"); +#endif + return kStatus_USB_Error; + } + } + else + { + } + } + + return kStatus_USB_Success; +} + +static void USB_HostPrinterSetInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)param; + + printerInstance->controlTransfer = NULL; + if (status == kStatus_USB_Success) + { + status = USB_HostPrinterOpenInterface(printerInstance); /* printer open interface */ + } + + if (printerInstance->controlCallbackFn != NULL) + { + /* callback to application */ + printerInstance->controlCallbackFn(printerInstance->controlCallbackParam, NULL, 0, status); + } + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); +} + +usb_status_t USB_HostPrinterInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle) +{ + uint32_t infoValue; + /* malloc printer class instance */ + usb_host_printer_instance_t *printerInstance = + (usb_host_printer_instance_t *)USB_OsaMemoryAllocate(sizeof(usb_host_printer_instance_t)); + + if (printerInstance == NULL) + { + return kStatus_USB_AllocFail; + } + + /* initialize printer instance */ + printerInstance->deviceHandle = deviceHandle; + printerInstance->interfaceHandle = NULL; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetHostHandle, &infoValue); + printerInstance->hostHandle = (usb_host_handle)infoValue; + USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceControlPipe, &infoValue); + printerInstance->controlPipe = (usb_host_pipe_handle)infoValue; + + *classHandle = printerInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterSetInterface(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_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + /* notify host driver the interface is open */ + status = USB_HostOpenDeviceInterface(printerInstance->deviceHandle, interfaceHandle); + if (status != kStatus_USB_Success) + { + return status; + } + printerInstance->interfaceHandle = interfaceHandle; + + /* cancel transfers */ + if (printerInstance->inPipe != NULL) + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->inPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + if (printerInstance->outPipe != NULL) + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->outPipe, NULL); + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when cancel pipe\r\n"); +#endif + } + } + + if (alternateSetting == 0) /* open interface directly */ + { + if (callbackFn != NULL) + { + status = USB_HostPrinterOpenInterface(printerInstance); + callbackFn(callbackParam, NULL, 0, status); + } + } + else /* send setup transfer */ + { + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + + /* save the application callback function */ + printerInstance->controlCallbackFn = callbackFn; + printerInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->callbackFn = USB_HostPrinterSetInterfaceCallback; + transfer->callbackParam = printerInstance; + 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 *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber); + transfer->setupPacket.wValue = USB_SHORT_TO_LITTLE_ENDIAN(alternateSetting); + transfer->setupPacket.wLength = 0; + transfer->transferBuffer = NULL; + transfer->transferLength = 0; + status = USB_HostSendSetup(printerInstance->hostHandle, printerInstance->controlPipe, transfer); + + if (status == kStatus_USB_Success) + { + printerInstance->controlTransfer = transfer; + } + else + { + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + } + } + + return status; +} + +usb_status_t USB_HostPrinterDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle) +{ + usb_status_t status; + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (classHandle != NULL) /* class instance has initialized */ + { + if (printerInstance->inPipe != NULL) + { + status = + USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->inPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->inPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->inPipe = NULL; + } + if (printerInstance->outPipe != NULL) + { + status = + USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->outPipe, NULL); /* cancel pipe */ + status = USB_HostClosePipe(printerInstance->hostHandle, printerInstance->outPipe); /* close pipe */ + + if (status != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + printerInstance->outPipe = NULL; + } + if ((printerInstance->controlPipe != NULL) && + (printerInstance->controlTransfer != + NULL)) /* cancel control transfer if there is on-going control transfer */ + { + status = USB_HostCancelTransfer(printerInstance->hostHandle, printerInstance->controlPipe, + printerInstance->controlTransfer); + } + USB_HostCloseDeviceInterface(deviceHandle, + printerInstance->interfaceHandle); /* notify host driver the interface is closed */ + USB_OsaMemoryFree(printerInstance); + } + else + { + USB_HostCloseDeviceInterface(deviceHandle, NULL); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (printerInstance->inPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + printerInstance->inCallbackFn = callbackFn; + printerInstance->inCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPrinterInPipeCallback; + transfer->callbackParam = printerInstance; + + /* call host driver api */ + if (USB_HostRecv(printerInstance->hostHandle, printerInstance->inPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostRecv\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction) +{ + usb_host_printer_instance_t *phdcInstance = (usb_host_printer_instance_t *)classHandle; + if (classHandle == NULL) + { + return 0; + } + + if (pipeType == USB_ENDPOINT_INTERRUPT) + { + if (direction == USB_IN) + { + return phdcInstance->inPacketSize; + } + else + { + return phdcInstance->outPacketSize; + } + } + + return 0; +} + +usb_status_t USB_HostPrinterSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + usb_host_transfer_t *transfer; + + if (classHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (printerInstance->outPipe == NULL) + { + return kStatus_USB_Error; + } + + /* malloc one transfer */ + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + /* save the application callback function */ + printerInstance->outCallbackFn = callbackFn; + printerInstance->outCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = buffer; + transfer->transferLength = bufferLength; + transfer->callbackFn = USB_HostPrinterOutPipeCallback; + transfer->callbackParam = printerInstance; + + /* call host driver api */ + if (USB_HostSend(printerInstance->hostHandle, printerInstance->outPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail to USB_HostSend\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + + return kStatus_USB_Success; +} + +static usb_status_t USB_HostPrinterControl(usb_host_printer_instance_t *printerInstance, + uint8_t requestType, + uint8_t request, + uint16_t wvalue, + uint16_t windex, + uint16_t wlength, + uint8_t *data, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_transfer_t *transfer; + + if (printerInstance == NULL) + { + return kStatus_USB_InvalidHandle; + } + + if (USB_HostMallocTransfer(printerInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Busy; + } + /* save the application callback function */ + printerInstance->controlCallbackFn = callbackFn; + printerInstance->controlCallbackParam = callbackParam; + /* initialize transfer */ + transfer->transferBuffer = data; + transfer->transferLength = wlength; + transfer->callbackFn = USB_HostPrinterControlPipeCallback; + transfer->callbackParam = printerInstance; + transfer->setupPacket.bmRequestType = requestType; + transfer->setupPacket.bRequest = request; + transfer->setupPacket.wValue = wvalue; + transfer->setupPacket.wIndex = windex; + transfer->setupPacket.wLength = USB_SHORT_TO_LITTLE_ENDIAN(wlength); + + /* call host driver api */ + if (USB_HostSendSetup(printerInstance->hostHandle, printerInstance->controlPipe, transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("fail for USB_HostSendSetup\r\n"); +#endif + USB_HostFreeTransfer(printerInstance->hostHandle, transfer); + return kStatus_USB_Error; + } + printerInstance->controlTransfer = transfer; + + return kStatus_USB_Success; +} + +usb_status_t USB_HostPrinterGetDeviceId(usb_host_class_handle classHandle, + uint8_t interfaceIndex, + uint8_t alternateSetting, + uint8_t *buffer, + uint32_t length, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + uint32_t infoValue; + + USB_HostHelperGetPeripheralInformation(printerInstance->deviceHandle, kUSB_HostGetDeviceConfigIndex, &infoValue); + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_GET_DEVICE_ID, (uint16_t)infoValue, + (uint16_t)((uint16_t)((uint16_t)interfaceIndex << 8U) | alternateSetting), length, buffer, callbackFn, + callbackParam); +} + +usb_status_t USB_HostPrinterGetPortStatus(usb_host_class_handle classHandle, + uint8_t *portStatus, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_GET_PORT_STATUS, 0, + (uint16_t)(((usb_host_interface_t *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber), 1, + portStatus, callbackFn, callbackParam); +} + +usb_status_t USB_HostPrinterSoftReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam) +{ + usb_host_printer_instance_t *printerInstance = (usb_host_printer_instance_t *)classHandle; + + return USB_HostPrinterControl( + printerInstance, USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE, + USB_HOST_PRINTER_SOFT_RESET, 0, + (uint16_t)(((usb_host_interface_t *)printerInstance->interfaceHandle)->interfaceDesc->bInterfaceNumber), 0, + NULL, callbackFn, callbackParam); +} + +#endif /* USB_HOST_CONFIG_PRINTER */ diff --git a/usb_1.1.0/host/class/usb_host_printer.h b/usb_1.1.0/host/class/usb_host_printer.h new file mode 100644 index 0000000..371ea80 --- /dev/null +++ b/usb_1.1.0/host/class/usb_host_printer.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 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. + */ + +#ifndef __USB_HOST_PRINTER_H__ +#define __USB_HOST_PRINTER_H__ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @addtogroup usb_host_printer_drv + * @{ + */ + +/*! @brief Printer class code */ +#define USB_HOST_PRINTER_CLASS_CODE (7U) +/*! @brief Printer sub-class code */ +#define USB_HOST_PRINTER_SUBCLASS_CODE (1U) +/*! @brief Printer class protocol code (Unidirectional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_UNIDIRECTION (1U) +/*! @brief Printer class protocol code (Bi-directional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_BIDIRECTION (2U) +/*! @brief Printer class protocol code (IEEEĀ® 1284.4 compatible bi-directional interface) */ +#define USB_HOST_PRINTER_PROTOCOL_IEEE1284 (3U) + +/*! @brief Printer class-specific request (GET_DEVICE_ID) */ +#define USB_HOST_PRINTER_GET_DEVICE_ID (0) +/*! @brief Printer class-specific request (GET_PORT_STATUS) */ +#define USB_HOST_PRINTER_GET_PORT_STATUS (1) +/*! @brief Printer class-specific request (SOFT_RESET) */ +#define USB_HOST_PRINTER_SOFT_RESET (2) + +/*! @brief Paper empty bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_PAPER_EMPTRY_MASK (0x20U) +/*! @brief Select bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_SELECT_MASK (0x10U) +/*! @brief Error bit mask for GET_PORT_STATUS */ +#define USB_HOST_PRINTER_PORT_STATUS_NOT_ERROR_MASK (0x08U) + +/*! @brief Printer instance structure and printer usb_host_class_handle pointer to this structure */ +typedef struct _usb_host_printer_instance +{ + usb_host_handle hostHandle; /*!< This instance's related host handle*/ + usb_device_handle deviceHandle; /*!< This instance's related device handle*/ + usb_host_interface_handle interfaceHandle; /*!< This instance's related interface handle*/ + usb_host_pipe_handle controlPipe; /*!< This instance's related device control pipe*/ + usb_host_pipe_handle inPipe; /*!< Printer bulk in pipe*/ + usb_host_pipe_handle outPipe; /*!< Printer bulk out pipe*/ + transfer_callback_t inCallbackFn; /*!< Printer bulk in transfer callback function pointer*/ + void *inCallbackParam; /*!< Printer bulk in transfer callback parameter*/ + transfer_callback_t outCallbackFn; /*!< Printer bulk out transfer callback function pointer*/ + void *outCallbackParam; /*!< Printer bulk out transfer callback parameter*/ + transfer_callback_t controlCallbackFn; /*!< Printer control transfer callback function pointer*/ + void *controlCallbackParam; /*!< Printer control transfer callback parameter*/ + usb_host_transfer_t *controlTransfer; /*!< Ongoing control transfer*/ +#if ((defined USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) && USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL) + uint8_t *stallDataBuffer; + uint32_t stallDataLength; +#endif + + uint16_t inPacketSize; /*!< Printer bulk in maximum packet size*/ + uint16_t outPacketSize; /*!< Printer bulk out maximum packet size*/ +} usb_host_printer_instance_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * @name USB host printer class APIs + * @{ + */ + +/*! + * @brief Initializes the printer instance. + * + * This function allocate the resource for the printer instance. + * + * @param[in] deviceHandle The device handle. + * @param[out] classHandle Return class handle. + * + * @retval kStatus_USB_Success The device is initialized successfully. + * @retval kStatus_USB_AllocFail Allocate memory fail. + */ +extern usb_status_t USB_HostPrinterInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle); + +/*! + * @brief Sets the interface. + * + * This function binds the interface with the printer instance. + * + * @param[in] classHandle The class handle. + * @param[in] interfaceHandle The interface handle. + * @param[in] alternateSetting The alternate setting value. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostSendSetup. + * @retval kStatus_USB_Busy Callback return status, there is no idle pipe. + * @retval kStatus_USB_TransferStall Callback return status, the transfer is stalled by the device. + * @retval kStatus_USB_Error Callback return status, open pipe fail. See the USB_HostOpenPipe. + */ +extern usb_status_t USB_HostPrinterSetInterface(usb_host_class_handle classHandle, + usb_host_interface_handle interfaceHandle, + uint8_t alternateSetting, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief De-initializes the the printer instance. + * + * This function frees the resources for the printer instance. + * + * @param[in] deviceHandle The device handle. + * @param[in] classHandle The class handle. + * + * @retval kStatus_USB_Success The device is de-initialized successfully. + */ +extern usb_status_t USB_HostPrinterDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. + * See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum Packet size. + */ +extern uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief Receives data. + * + * This function implements the printer receiving data. + * + * @param[in] classHandle The class handle. + * @param[out] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] 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. See the USB_HostRecv. + */ +extern usb_status_t USB_HostPrinterRecv(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Sends data. + * + * This function implements the printer sending data. + * + * @param[in] classHandle The class handle. + * @param[in] buffer The buffer pointer. + * @param[in] bufferLength The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Send 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. See the USB_HostSend. + */ +extern usb_status_t USB_HostPrinterSend(usb_host_class_handle classHandle, + uint8_t *buffer, + uint32_t bufferLength, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Gets the pipe maximum packet size. + * + * @param[in] classHandle The class handle. + * @param[in] pipeType Its value is USB_ENDPOINT_CONTROL, USB_ENDPOINT_ISOCHRONOUS, USB_ENDPOINT_BULK or + * USB_ENDPOINT_INTERRUPT. See the usb_spec.h + * @param[in] direction Pipe direction. + * + * @retval 0 The classHandle is NULL. + * @retval Maximum Packet size. + */ +extern uint16_t USB_HostPrinterGetPacketsize(usb_host_class_handle classHandle, uint8_t pipeType, uint8_t direction); + +/*! + * @brief Printer get device ID. + * + * This function implements the printer class-specific request (GET_DEVICE_ID). + * + * @param[in] classHandle The class handle. + * @param[in] interfaceIndex Interface index. + * @param[in] alternateSetting Get the alternateSetting's device ID. + * @param[out] buffer The buffer pointer. + * @param[in] length The buffer length. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterGetDeviceId(usb_host_class_handle classHandle, + uint8_t interfaceIndex, + uint8_t alternateSetting, + uint8_t *buffer, + uint32_t length, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Printer get port status. + * + * This function implements the printer class-specific request (GET_PORT_STATUS). + * + * @param[in] classHandle The class handle. + * @param[in] portStatus Port status buffer. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterGetPortStatus(usb_host_class_handle classHandle, + uint8_t *portStatus, + transfer_callback_t callbackFn, + void *callbackParam); + +/*! + * @brief Printer soft reset. + * + * This function implements the printer class-specific request (SOFT_RESET). + * + * @param[in] classHandle The class handle. + * @param[in] portStatus Port status buffer. + * @param[in] callbackFn This callback is called after this function completes. + * @param[in] callbackParam The first parameter in the callback function. + * + * @retval kStatus_USB_Success Request successful. + * @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. See the USB_HostSendSetup. + */ +extern usb_status_t USB_HostPrinterSoftReset(usb_host_class_handle classHandle, + transfer_callback_t callbackFn, + void *callbackParam); +/*! @}*/ + +#ifdef __cplusplus +} +#endif + +/*! @}*/ + +#endif /* __USB_HOST_PRINTER_H__ */ -- cgit v1.2.3