RT1050_FreeRTOS_USB_Hello/middleware/usb/host/class/usb_host_video.c

1171 lines
44 KiB
C

/*
* Copyright 2019 NXP
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "usb_host_config.h"
#if ((defined USB_HOST_CONFIG_VIDEO) && (USB_HOST_CONFIG_VIDEO))
#include "usb_host.h"
#include "usb_host_video.h"
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*!
* @brief open video control interface.
*
* @param videoInstance video instance pointer.
*
* @return kStatus_USB_Success or error codes.
*/
static usb_status_t USB_HostVideoControlOpenInterface(usb_host_video_instance_struct_t *videoInstance);
/*!
* @brief open video stream interface.
*
* @param videoInstance video instance pointer.
*
* @return kStatus_USB_Success or error codes.
*/
static usb_status_t USB_HostVideoStreamOpenInterface(usb_host_video_instance_struct_t *videoInstance);
/*!
* @brief video control pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoSetControlInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
/*!
* @brief video set interface callback, open pipes.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoSetStreamInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
/*!
* @brief video control command transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoControlCommandCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
/*!
* @brief video stream iso in pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoStreamIsoInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status);
/*!
* @brief video 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_HostVideoControl(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);
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief open video control interface.
*
* @param videoInstance video instance pointer.
*
* @return kStatus_USB_Success or error codes.
*/
static usb_status_t USB_HostVideoControlOpenInterface(usb_host_video_instance_struct_t *videoInstance)
{
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;
void *temp;
if (videoInstance->interruptPipe != NULL)
{
status = USB_HostClosePipe(videoInstance->hostHandle, videoInstance->interruptPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
videoInstance->interruptPipe = NULL;
}
/* open interface pipes */
temp = (void *)videoInstance->controlIntfHandle;
interface_ptr = (usb_host_interface_t *)temp;
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_INTERRUPT))
{
pipe_init.devInstance = videoInstance->deviceHandle;
pipe_init.pipeType = USB_ENDPOINT_INTERRUPT;
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 = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK));
pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
videoInstance->interruptInPacketSize = pipe_init.maxPacketSize;
videoInstance->interruptInEpNum = pipe_init.endpointAddress;
status = USB_HostOpenPipe(videoInstance->hostHandle, &videoInstance->interruptPipe, &pipe_init);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("usb_host_video_control_set_interface fail to open pipe\r\n");
#endif
return kStatus_USB_Error;
}
}
else
{
}
}
return kStatus_USB_Success;
}
/*!
* @brief open video stream interface.
*
* @param videoInstance video instance pointer.
*
* @return kStatus_USB_Success or error codes.
*/
static usb_status_t USB_HostVideoStreamOpenInterface(usb_host_video_instance_struct_t *videoInstance)
{
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;
void *temp;
if (videoInstance->streamIsoInPipe != NULL)
{
status = USB_HostClosePipe(videoInstance->hostHandle, videoInstance->streamIsoInPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
videoInstance->streamIsoInPipe = NULL;
}
/* open interface pipes */
temp = (void *)videoInstance->streamIntfHandle;
interface_ptr = (usb_host_interface_t *)temp;
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 = videoInstance->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 = (uint8_t)((USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(ep_desc->wMaxPacketSize) &
USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_MASK) >>
USB_DESCRIPTOR_ENDPOINT_MAXPACKETSIZE_MULT_TRANSACTIONS_SHFIT);
pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK;
videoInstance->isoInPacketSize = pipe_init.maxPacketSize;
videoInstance->isoInEpNum = pipe_init.endpointAddress;
status = USB_HostOpenPipe(videoInstance->hostHandle, &videoInstance->streamIsoInPipe, &pipe_init);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("usb_host_video_stream_set_interface fail to open pipe\r\n");
#endif
return kStatus_USB_Error;
}
}
else
{
}
}
return kStatus_USB_Success;
}
/*!
* @brief video control pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoSetControlInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)param;
videoInstance->controlTransfer = NULL;
if (status == kStatus_USB_Success)
{
status = USB_HostVideoControlOpenInterface(videoInstance);
}
if (videoInstance->controlCallbackFn != NULL)
{
/* callback to application, callback function is initialized in the _USB_HostAudioControl,
USB_HostVideoStreamSetInterface
or USB_HostVideoControlSetInterface, but is the same function */
videoInstance->controlCallbackFn(videoInstance->controlCallbackParam, transfer->transferBuffer,
transfer->transferSofar, status);
}
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
/*!
* @brief video set interface callback, open pipes.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoSetStreamInterfaceCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)param;
videoInstance->controlTransfer = NULL;
if (status == kStatus_USB_Success)
{
status = USB_HostVideoStreamOpenInterface(videoInstance);
}
if (videoInstance->controlCallbackFn != NULL)
{
/* callback to application, callback function is initialized in the _USB_HostAudioControl,
USB_HostAudioStreamSetInterface
or USB_HostAudioControlSetInterface, but is the same function */
videoInstance->controlCallbackFn(videoInstance->controlCallbackParam, NULL, 0U, status);
}
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
/*!
* @brief video control command transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoControlCommandCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)param;
if (videoInstance->controlCallbackFn != NULL)
{
/* callback to application, callback function is initialized in the USB_HostCdcControl,
USB_HostCdcSetControlInterface
or USB_HostCdcSetDataInterface, but is the same function */
videoInstance->controlCallbackFn(videoInstance->controlCallbackParam, transfer->transferBuffer,
transfer->transferSofar, status);
}
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
/*!
* @brief video stream iso in pipe transfer callback.
*
* @param param callback parameter.
* @param transfer callback transfer.
* @param status transfer status.
*/
static void USB_HostVideoStreamIsoInPipeCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)param;
if (videoInstance->streamIsoInCallbackFn != NULL)
{
/* callback function is initialized in USB_HosVideoStreamRecv */
videoInstance->streamIsoInCallbackFn(videoInstance->streamIsoInCallbackParam, transfer->transferBuffer,
transfer->transferSofar, status);
}
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
/*!
* @brief video 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_HostVideoControl(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)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_transfer_t *transfer;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
/* malloc one transfer */
if (USB_HostMallocTransfer(videoInstance->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 */
videoInstance->controlCallbackFn = callbackFn;
videoInstance->controlCallbackParam = callbackParam;
transfer->transferBuffer = data;
transfer->transferLength = wlength;
transfer->callbackFn = USB_HostVideoControlCommandCallback;
transfer->callbackParam = videoInstance;
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);
if (USB_HostSendSetup(videoInstance->hostHandle, videoInstance->controlPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("failed for USB_HostSendSetup\r\n");
#endif
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
return kStatus_USB_Error;
}
videoInstance->controlTransfer = transfer;
return kStatus_USB_Success;
}
/*!
* @brief set video class stream interface.
*
* This function bind the interface with the video 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_HostVideoStreamSetInterface(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_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *interface_ptr;
usb_host_transfer_t *transfer;
usb_host_video_descriptor_union_t descUnion;
uint32_t length, ep = 0U;
uint32_t descLength = 0;
void *temp;
if (classHandle == NULL)
{
return kStatus_USB_InvalidParameter;
}
videoInstance->streamIntfHandle = interfaceHandle;
status = USB_HostOpenDeviceInterface(videoInstance->deviceHandle, interfaceHandle); /* save the application callback function */
if (status != kStatus_USB_Success)
{
return status;
}
/* cancel transfers */
if (videoInstance->streamIsoInPipe != NULL)
{
status = USB_HostCancelTransfer(videoInstance->hostHandle, videoInstance->streamIsoInPipe, 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;
if (0U == alternateSetting)
{
descUnion.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if (descUnion.common->bDescriptorType == USB_HOST_DESC_CS_INTERFACE)
{
if (descUnion.common->bData[0] == USB_HOST_DESC_SUBTYPE_VS_INPUT_HEADER)
{
temp = (void *)descUnion.bufr;
videoInstance->vsInputHeaderDesc = (usb_host_video_stream_input_header_desc_t *)temp;
break;
}
}
length += descUnion.common->bLength;
descUnion.bufr += descUnion.common->bLength;
}
}
else
{
descUnion.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if ((descUnion.common->bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) &&
(descUnion.interface->bAlternateSetting == alternateSetting))
{
interface_ptr->epCount = descUnion.interface->bNumEndpoints;
break;
}
length += descUnion.common->bLength;
descUnion.bufr += descUnion.common->bLength;
}
while (ep < interface_ptr->epCount)
{
if (descUnion.common->bDescriptorType == USB_DESCRIPTOR_TYPE_ENDPOINT)
{
temp = (void *)descUnion.bufr;
interface_ptr->epList[ep].epDesc = (usb_descriptor_endpoint_t *)temp;
descLength = descUnion.common->bLength;
descUnion.bufr += descUnion.common->bLength;
if (USB_HOST_DESC_CS_ENDPOINT == descUnion.common->bDescriptorType)
{
interface_ptr->epList[ep].epExtension = descUnion.bufr;
interface_ptr->epList[ep].epExtensionLength = descUnion.common->bLength;
}
else
{
descUnion.bufr -= descLength;
}
ep++;
}
descUnion.bufr += descUnion.common->bLength;
}
}
if (alternateSetting == 0U) /* open interface directly */
{
if (callbackFn != NULL)
{
status = USB_HostVideoStreamOpenInterface(videoInstance);
callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success);
}
}
else /* send setup transfer */
{
/* malloc one transfer */
if (USB_HostMallocTransfer(videoInstance->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 */
videoInstance->controlCallbackFn = callbackFn;
videoInstance->controlCallbackParam = callbackParam;
/* initialize transfer */
transfer->callbackFn = USB_HostVideoSetStreamInterfaceCallback;
transfer->callbackParam = videoInstance;
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 *)videoInstance->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(videoInstance->hostHandle, videoInstance->controlPipe, transfer);
if (status == kStatus_USB_Success)
{
videoInstance->controlTransfer = transfer;
}
else
{
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
}
return status;
}
/*!
* @brief set control interface.
*
* This function bind the control interface with the video 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_HostVideoControlSetInterface(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_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *interface_ptr;
usb_host_transfer_t *transfer;
usb_host_video_descriptor_union_t desc;
uint32_t length = 0U;
void *temp;
if (classHandle == NULL)
{
return kStatus_USB_InvalidParameter;
}
videoInstance->controlIntfHandle = interfaceHandle;
interface_ptr = (usb_host_interface_t *)interfaceHandle;
status = USB_HostOpenDeviceInterface(videoInstance->deviceHandle, interfaceHandle); /* notify host driver the interface is open */
if (status != kStatus_USB_Success)
{
return status;
}
desc.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if (((interface_ptr->interfaceDesc->bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) &&
(interface_ptr->interfaceDesc->bAlternateSetting == alternateSetting)) ||
((desc.common->bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE) &&
(desc.interface->bAlternateSetting == alternateSetting)))
{
break;
}
length += desc.common->bLength;
desc.bufr += desc.common->bLength;
}
while (length < interface_ptr->interfaceExtensionLength)
{
if (desc.common->bDescriptorType == USB_HOST_DESC_CS_INTERFACE)
{
temp = (void *)desc.bufr;
if (desc.common->bData[0] == USB_HOST_DESC_SUBTYPE_VC_HEADER)
{
videoInstance->vcHeaderDesc = (usb_host_video_ctrl_header_desc_t *)temp;
}
else if (desc.common->bData[0] == USB_HOST_DESC_SUBTYPE_VC_INPUT_TERMINAL)
{
videoInstance->vcInputTerminalDesc = (usb_host_video_ctrl_it_desc_t *)temp;
}
else if (desc.common->bData[0] == USB_HOST_DESC_SUBTYPE_VC_OUTPUT_TERMINAL)
{
videoInstance->vcOutputTerminalDesc = (usb_host_video_ctrl_ot_desc_t *)temp;
}
else if (desc.common->bData[0] == USB_HOST_DESC_SUBTYPE_VC_PROCESSING_UNIT)
{
videoInstance->vcProcessingUnitDesc = (usb_host_video_ctrl_pu_desc_t *)temp;
}
else
{
/*no action*/
}
}
length += desc.common->bLength;
desc.bufr += desc.common->bLength;
}
if (alternateSetting == 0U) /* open interface directly */
{
if (callbackFn != NULL)
{
status = USB_HostVideoControlOpenInterface(videoInstance);
callbackFn(callbackParam, NULL, 0U, kStatus_USB_Success);
}
}
else /* send setup transfer */
{
/* malloc one transfer */
if (USB_HostMallocTransfer(videoInstance->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 */
videoInstance->controlCallbackFn = callbackFn;
videoInstance->controlCallbackParam = callbackParam;
/* initialize transfer */
transfer->callbackFn = USB_HostVideoSetControlInterfaceCallback;
transfer->callbackParam = videoInstance;
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 *)videoInstance->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(videoInstance->hostHandle, videoInstance->controlPipe, transfer);
if (status == kStatus_USB_Success)
{
videoInstance->controlTransfer = transfer;
}
else
{
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
}
}
return status;
}
/*!
* @brief video stream receive data.
*
* This function implements video receiving 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_HosVideoStreamRecv(usb_host_class_handle classHandle,
uint8_t *buffer,
uint32_t bufferLen,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_transfer_t *transfer;
if (classHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (videoInstance->streamIsoInPipe == NULL)
{
return kStatus_USB_Error;
}
/* malloc one transfer */
if (USB_HostMallocTransfer(videoInstance->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 */
videoInstance->streamIsoInCallbackFn = callbackFn;
videoInstance->streamIsoInCallbackParam = callbackParam;
transfer->transferBuffer = buffer;
transfer->transferLength = bufferLen;
transfer->callbackFn = USB_HostVideoStreamIsoInPipeCallback;
transfer->callbackParam = videoInstance;
if (USB_HostRecv(videoInstance->hostHandle, videoInstance->streamIsoInPipe, transfer) != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("failed to USB_HostRecv\r\n");
#endif
(void)USB_HostFreeTransfer(videoInstance->hostHandle, transfer);
return kStatus_USB_Error;
}
return kStatus_USB_Success;
}
/*!
* @brief initialize the video instance.
*
* This function allocate the resource for video 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_HostVideoInit(usb_device_handle deviceHandle, usb_host_class_handle *classHandle)
{
usb_host_video_instance_struct_t *videoInstance =
(usb_host_video_instance_struct_t *)OSA_MemoryAllocate(sizeof(usb_host_video_instance_struct_t));
uint32_t info_value;
uint32_t *temp;
if (videoInstance == NULL)
{
return kStatus_USB_AllocFail;
}
/* initialize video instance */
videoInstance->deviceHandle = deviceHandle;
videoInstance->controlIntfHandle = NULL;
videoInstance->streamIntfHandle = NULL;
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetHostHandle, &info_value);
temp = (uint32_t *)info_value;
videoInstance->hostHandle = (usb_host_handle)temp;
(void)USB_HostHelperGetPeripheralInformation(deviceHandle, (uint32_t)kUSB_HostGetDeviceControlPipe, &info_value);
temp = (uint32_t *)info_value;
videoInstance->controlPipe = (usb_host_pipe_handle)temp;
*classHandle = videoInstance;
return kStatus_USB_Success;
}
/*!
* @brief de-initialize the video instance.
*
* This function release the resource for video 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_HostVideoDeinit(usb_device_handle deviceHandle, usb_host_class_handle classHandle)
{
usb_status_t status;
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
if (deviceHandle == NULL)
{
return kStatus_USB_InvalidHandle;
}
if (classHandle != NULL)
{
/* cancel transfers */
if (videoInstance->streamIsoInPipe != NULL)
{
status = USB_HostCancelTransfer(videoInstance->hostHandle, videoInstance->streamIsoInPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
status = USB_HostClosePipe(videoInstance->hostHandle, videoInstance->streamIsoInPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
videoInstance->streamIsoInPipe = NULL;
}
(void)USB_HostCloseDeviceInterface(deviceHandle, videoInstance->streamIntfHandle);
/* cancel transfers */
if (videoInstance->interruptPipe != NULL)
{
status = USB_HostCancelTransfer(videoInstance->hostHandle, videoInstance->interruptPipe, NULL);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
status = USB_HostClosePipe(videoInstance->hostHandle, videoInstance->interruptPipe);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when close pipe\r\n");
#endif
}
videoInstance->interruptPipe = NULL;
}
/* cancel transfers */
if ((videoInstance->controlPipe != NULL) && (videoInstance->controlTransfer != NULL))
{
status = USB_HostCancelTransfer(videoInstance->hostHandle, videoInstance->controlPipe,
videoInstance->controlTransfer);
if (status != kStatus_USB_Success)
{
#ifdef HOST_ECHO
usb_echo("error when cancel pipe\r\n");
#endif
}
}
(void)USB_HostCloseDeviceInterface(deviceHandle, videoInstance->controlIntfHandle);
OSA_MemoryFree(videoInstance);
}
else
{
(void)USB_HostCloseDeviceInterface(deviceHandle, NULL);
}
return kStatus_USB_Success;
}
/*!
* @brief get video stream format descriptor.
*
* This function implements get video stream format descriptor.
*
* @param classHandle The class handle.
* @param subType The descriptor subtype.
* @param descriptor The pointer of specific format descriptor.
*
* @retval kStatus_USB_Success Get video stream format descriptor request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_InvalidParameter The descriptor is NULL pointer.
*
*/
usb_status_t USB_HostVideoStreamGetFormatDescriptor(usb_host_class_handle classHandle,
uint8_t subType,
void **descriptor)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *interface_ptr;
usb_host_video_descriptor_union_t descUnion;
uint32_t length = 0U;
if (NULL == classHandle)
{
return kStatus_USB_InvalidHandle;
}
/* get the steam interface handle */
interface_ptr = (usb_host_interface_t *)videoInstance->streamIntfHandle;
descUnion.bufr = interface_ptr->interfaceExtension;
length = 0U;
while (length < interface_ptr->interfaceExtensionLength)
{
if (descUnion.common->bDescriptorType == USB_HOST_DESC_CS_INTERFACE)
{
if (descUnion.common->bData[0] == subType)
{
*descriptor = descUnion.bufr;
return kStatus_USB_Success;
;
}
}
length += descUnion.common->bLength;
descUnion.bufr += descUnion.common->bLength;
}
return kStatus_USB_Error;
}
/*!
* @brief get specific video stream frame descriptor.
*
* This function implements get specific video stream frame descriptor.
*
* @param classHandle The class handle.
* @param formatDescriptor The frame descriptor pointer.
* @param index The specific frame descriptor id
* @param descriptor The pointer of specific frame descriptor.
*
* @retval kStatus_USB_Success Get video stream frame descriptor request successfully.
* @retval kStatus_USB_InvalidHandle The classHandle is NULL pointer.
* @retval kStatus_USB_InvalidParameter The descriptor is NULL pointer.
*
*/
usb_status_t USB_HostVideoStreamGetFrameDescriptor(
usb_host_class_handle classHandle, void *formatDescriptor, uint8_t subType, uint8_t frameIndex, void **descriptor)
{
usb_host_video_stream_payload_format_common_desc_t *formatDesc =
(usb_host_video_stream_payload_format_common_desc_t *)formatDescriptor;
usb_host_video_descriptor_union_t desc;
uint32_t i = 0U;
uint8_t frameCount = 0U;
if (NULL == classHandle)
{
return kStatus_USB_InvalidHandle;
}
if ((formatDesc == NULL) || (formatDesc->bDescriptorType != USB_HOST_DESC_CS_INTERFACE))
{
return kStatus_USB_InvalidParameter;
}
frameCount = formatDesc->bNumFrameDescriptors;
desc.bufr = (void *)formatDesc;
desc.bufr += desc.common->bLength;
while (i <= frameCount)
{
if ((desc.video_frame_common->bDescriptorType == USB_HOST_DESC_CS_INTERFACE) &&
(desc.video_frame_common->bDescriptorSubtype == subType))
{
if (desc.video_frame_common->bFrameIndex == frameIndex)
{
*descriptor = (void *)desc.bufr;
return kStatus_USB_Success;
}
}
i++;
desc.bufr += desc.common->bLength;
}
return kStatus_USB_Error;
}
/*!
* @brief video set probe.
*
* This function implements the Video class-specific request (set probe).
*
* @param classHandle the class handle.
* @param request setup packet request value.
* @param probe video probe data
* @param callbackFn this callback is called after this function completes.
* @param 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_InvalidParameter The interface descriptor is NULL pointer.
*/
usb_status_t USB_HostVideoSetProbe(usb_host_class_handle classHandle,
uint8_t request,
uint8_t *probe,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *streamInterface;
usb_status_t status;
streamInterface = (usb_host_interface_t *)videoInstance->streamIntfHandle;
if (NULL == streamInterface)
{
return kStatus_USB_InvalidHandle;
}
if (NULL == streamInterface->interfaceDesc)
{
return kStatus_USB_InvalidParameter;
}
status = USB_HostVideoControl(
classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
request, (uint16_t)(USB_HOST_VS_PROBE_CONTROL << 8UL), streamInterface->interfaceDesc->bInterfaceNumber, 26U,
probe, callbackFn, callbackParam);
return status;
}
/*!
* @brief video get probe.
*
* This function implements the Video class-specific request (get probe).
*
* @param classHandle the class handle.
* @param request setup packet request value.
* @param probe video probe data
* @param callbackFn this callback is called after this function completes.
* @param 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_InvalidParameter The interface descriptor is NULL pointer.
*/
usb_status_t USB_HostVideoGetProbe(usb_host_class_handle classHandle,
uint8_t request,
uint8_t *probe,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *streamInterface;
usb_status_t status;
streamInterface = (usb_host_interface_t *)videoInstance->streamIntfHandle;
if (NULL == streamInterface)
{
return kStatus_USB_InvalidHandle;
}
if (NULL == streamInterface->interfaceDesc)
{
return kStatus_USB_InvalidParameter;
}
status = USB_HostVideoControl(
classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
request, (uint16_t)(USB_HOST_VS_PROBE_CONTROL << 8UL), streamInterface->interfaceDesc->bInterfaceNumber, 26U,
probe, callbackFn, callbackParam);
return status;
}
/*!
* @brief video get commit.
*
* This function implements the Video class-specific request (get commit).
*
* @param classHandle the class handle.
* @param request setup packet request value.
* @param probe video probe data
* @param callbackFn this callback is called after this function completes.
* @param 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_InvalidParameter The interface descriptor is NULL pointer.
*/
usb_status_t USB_HostVideoGetCommit(usb_host_class_handle classHandle,
uint8_t brequest,
uint8_t *probe,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *streamInterface;
usb_status_t status;
streamInterface = (usb_host_interface_t *)videoInstance->streamIntfHandle;
if (NULL == streamInterface)
{
return kStatus_USB_InvalidHandle;
}
if (NULL == streamInterface->interfaceDesc)
{
return kStatus_USB_InvalidParameter;
}
status = USB_HostVideoControl(
classHandle, USB_REQUEST_TYPE_DIR_IN | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
brequest, (uint16_t)(USB_HOST_VS_COMMIT_CONTROL << 8UL), streamInterface->interfaceDesc->bInterfaceNumber, 26U,
probe, callbackFn, callbackParam);
return status;
}
/*!
* @brief video set commit.
*
* This function implements the Video class-specific request (set commit).
*
* @param classHandle the class handle.
* @param request setup packet request value.
* @param probe video probe data
* @param callbackFn this callback is called after this function completes.
* @param 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_InvalidParameter The interface descriptor is NULL pointer.
*/
usb_status_t USB_HostVideoSetCommit(usb_host_class_handle classHandle,
uint8_t brequest,
uint8_t *probe,
transfer_callback_t callbackFn,
void *callbackParam)
{
usb_host_video_instance_struct_t *videoInstance = (usb_host_video_instance_struct_t *)classHandle;
usb_host_interface_t *streamInterface;
usb_status_t status;
streamInterface = (usb_host_interface_t *)videoInstance->streamIntfHandle;
if (NULL == streamInterface)
{
return kStatus_USB_InvalidHandle;
}
if (NULL == streamInterface->interfaceDesc)
{
return kStatus_USB_InvalidParameter;
}
status = USB_HostVideoControl(
classHandle, USB_REQUEST_TYPE_DIR_OUT | USB_REQUEST_TYPE_TYPE_CLASS | USB_REQUEST_TYPE_RECIPIENT_INTERFACE,
brequest, (uint16_t)(USB_HOST_VS_COMMIT_CONTROL << 8UL), streamInterface->interfaceDesc->bInterfaceNumber, 26U,
probe, callbackFn, callbackParam);
return status;
}
#endif