Files
firmware/right/include/usb/usb_device_class.c

572 lines
22 KiB
C

/*
* 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_device_config.h"
#include "usb.h"
#include "usb_device.h"
#include "usb_device_ch9.h"
#include "usb_device_class.h"
#if ((defined(USB_DEVICE_CONFIG_NUM)) && (USB_DEVICE_CONFIG_NUM > 0U))
/* Include the class drivers according to the usb_device_config.h. */
#if ((defined(USB_DEVICE_CONFIG_HID)) && (USB_DEVICE_CONFIG_HID > 0U))
#include "usb_device_hid.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_CDC_ACM)) && (USB_DEVICE_CONFIG_CDC_ACM > 0U))
#include "usb_device_cdc_acm.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_MSC)) && (USB_DEVICE_CONFIG_MSC > 0U))
#include "usb_device_msc.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_AUDIO)) && (USB_DEVICE_CONFIG_AUDIO > 0U))
#include "usb_device_audio.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_PHDC)) && (USB_DEVICE_CONFIG_PHDC > 0U))
#include "usb_device_phdc.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_VIDEO)) && (USB_DEVICE_CONFIG_VIDEO > 0U))
#include "usb_device_video.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_PRINTER)) && (USB_DEVICE_CONFIG_PRINTER > 0U))
#include "usb_device_printer_config.h"
#include "usb_device_printer.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_DFU)) && (USB_DEVICE_CONFIG_DFU > 0U))
#include "usb_device_dfu_config.h"
#include "usb_device_dfu.h"
#endif
#if ((defined(USB_DEVICE_CONFIG_CCID)) && (USB_DEVICE_CONFIG_CCID > 0U))
#include "usb_device_ccid.h"
#endif
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
static usb_status_t USB_DeviceClassAllocateHandle(uint8_t controllerId, usb_device_common_class_struct_t **handle);
static usb_status_t USB_DeviceClassFreeHandle(uint8_t controllerId);
static usb_status_t USB_DeviceClassGetHandleByControllerId(uint8_t controllerId,
usb_device_common_class_struct_t **handle);
static usb_status_t USB_DeviceClassGetHandleByDeviceHandle(usb_device_handle deviceHandle,
usb_device_common_class_struct_t **handle);
/*******************************************************************************
* Variables
******************************************************************************/
/* The device class driver list. */
static const usb_device_class_map_t s_UsbDeviceClassInterfaceMap[] = {
#if ((defined(USB_DEVICE_CONFIG_HID)) && (USB_DEVICE_CONFIG_HID > 0U))
{USB_DeviceHidInit, USB_DeviceHidDeinit, USB_DeviceHidEvent, kUSB_DeviceClassTypeHid},
#endif
#if ((defined(USB_DEVICE_CONFIG_CDC_ACM)) && (USB_DEVICE_CONFIG_CDC_ACM > 0U))
{USB_DeviceCdcAcmInit, USB_DeviceCdcAcmDeinit, USB_DeviceCdcAcmEvent, kUSB_DeviceClassTypeCdc},
#endif
#if ((defined(USB_DEVICE_CONFIG_MSC)) && (USB_DEVICE_CONFIG_MSC > 0U))
{USB_DeviceMscInit, USB_DeviceMscDeinit, USB_DeviceMscEvent, kUSB_DeviceClassTypeMsc},
#endif
#if ((defined USB_DEVICE_CONFIG_AUDIO) && (USB_DEVICE_CONFIG_AUDIO > 0U))
{USB_DeviceAudioInit, USB_DeviceAudioDeinit, USB_DeviceAudioEvent, kUSB_DeviceClassTypeAudio},
#endif
#if ((defined USB_DEVICE_CONFIG_PHDC) && (USB_DEVICE_CONFIG_PHDC > 0U))
{USB_DevicePhdcInit, USB_DevicePhdcDeinit, USB_DevicePhdcEvent, kUSB_DeviceClassTypePhdc},
#endif
#if ((defined USB_DEVICE_CONFIG_VIDEO) && (USB_DEVICE_CONFIG_VIDEO > 0U))
{USB_DeviceVideoInit, USB_DeviceVideoDeinit, USB_DeviceVideoEvent, kUSB_DeviceClassTypeVideo},
#endif
#if ((defined USB_DEVICE_CONFIG_PRINTER) && (USB_DEVICE_CONFIG_PRINTER > 0U))
{usb_device_printer_init, usb_device_printer_deinit, usb_device_printer_event, kUSB_DeviceClassTypePrinter},
#endif
#if ((defined USB_DEVICE_CONFIG_DFU) && (USB_DEVICE_CONFIG_DFU > 0U))
{usb_device_dfu_init, usb_device_dfu_deinit, usb_device_dfu_event, kUSB_DeviceClassTypeDfu},
#endif
#if ((defined USB_DEVICE_CONFIG_CCID) && (USB_DEVICE_CONFIG_CCID > 0U))
{USB_DeviceCcidInit, USB_DeviceCcidDeinit, USB_DeviceCcidEvent, kUSB_DeviceClassTypeCcid},
#endif
{(usb_device_class_init_call_t)NULL, (usb_device_class_deinit_call_t)NULL, (usb_device_class_event_callback_t)NULL,
(usb_device_class_type_t)0},
};
USB_GLOBAL static usb_device_common_class_struct_t s_UsbDeviceCommonClassStruct[USB_DEVICE_CONFIG_NUM];
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief Allocate a device common class handle.
*
* This function allocates a a device common class handle.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
* @param handle It is out parameter, is used to return pointer of the device common class handle to the
* caller.
*
* @retval kStatus_USB_Success Get a device handle successfully.
* @retval kStatus_USB_Busy Cannot allocate a common class handle.
* @retval kStatus_USB_Error The common class has been initialized.
*/
static usb_status_t USB_DeviceClassAllocateHandle(uint8_t controllerId, usb_device_common_class_struct_t **handle)
{
int32_t count;
USB_OSA_SR_ALLOC();
USB_OSA_ENTER_CRITICAL();
/* Check the controller is initialized or not. */
for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++)
{
if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) &&
(controllerId == s_UsbDeviceCommonClassStruct[count].controllerId))
{
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Error;
}
}
/* Get a free common class handle. */
for (count = 0U; count < USB_DEVICE_CONFIG_NUM; count++)
{
if (NULL == s_UsbDeviceCommonClassStruct[count].handle)
{
s_UsbDeviceCommonClassStruct[count].controllerId = controllerId;
*handle = &s_UsbDeviceCommonClassStruct[count];
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Success;
}
}
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Busy;
}
/*!
* @brief Free a device common class handle.
*
* This function frees a device common class handle.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
*
* @retval kStatus_USB_Success Free device hanlde successfully.
* @retval kStatus_USB_InvalidParameter The common class can not be found.
*/
static usb_status_t USB_DeviceClassFreeHandle(uint8_t controllerId)
{
int32_t count = 0U;
USB_OSA_SR_ALLOC();
USB_OSA_ENTER_CRITICAL();
for (; count < USB_DEVICE_CONFIG_NUM; count++)
{
if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) &&
(controllerId == s_UsbDeviceCommonClassStruct[count].controllerId))
{
s_UsbDeviceCommonClassStruct[count].handle = NULL;
s_UsbDeviceCommonClassStruct[count].configList = (usb_device_class_config_list_struct_t *)NULL;
s_UsbDeviceCommonClassStruct[count].controllerId = 0U;
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Success;
}
}
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_InvalidParameter;
}
/*!
* @brief Get the device common class handle according to the controller id.
*
* This function gets the device common class handle according to the controller id.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
* @param handle It is out parameter, is used to return pointer of the device common class handle to the
* caller.
*
* @retval kStatus_USB_Success Free device hanlde successfully.
* @retval kStatus_USB_InvalidParameter The common class can not be found.
*/
static usb_status_t USB_DeviceClassGetHandleByControllerId(uint8_t controllerId,
usb_device_common_class_struct_t **handle)
{
int32_t count = 0U;
USB_OSA_SR_ALLOC();
USB_OSA_ENTER_CRITICAL();
for (; count < USB_DEVICE_CONFIG_NUM; count++)
{
if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) &&
(controllerId == s_UsbDeviceCommonClassStruct[count].controllerId))
{
*handle = &s_UsbDeviceCommonClassStruct[count];
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Success;
}
}
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_InvalidParameter;
}
/*!
* @brief Get the device common class handle according to the device handle.
*
* This function gets the device common class handle according to the device handle.
*
* @param deviceHandle The device handle, got from the USB_DeviceInit.
* @param handle It is out parameter, is used to return pointer of the device common class handle to the
* caller.
*
* @retval kStatus_USB_Success Free device hanlde successfully.
* @retval kStatus_USB_InvalidParameter The common class can not be found.
*/
static usb_status_t USB_DeviceClassGetHandleByDeviceHandle(usb_device_handle deviceHandle,
usb_device_common_class_struct_t **handle)
{
int32_t count = 0U;
USB_OSA_SR_ALLOC();
USB_OSA_ENTER_CRITICAL();
for (; count < USB_DEVICE_CONFIG_NUM; count++)
{
if (deviceHandle == s_UsbDeviceCommonClassStruct[count].handle)
{
*handle = &s_UsbDeviceCommonClassStruct[count];
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Success;
}
}
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_InvalidParameter;
}
/*!
* @brief Get the device handle according to the controller id.
*
* This function gets the device handle according to the controller id.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
* @param handle It is out parameter, is used to return pointer of the device handle to the caller.
*
* @retval kStatus_USB_Success Free device hanlde successfully.
* @retval kStatus_USB_InvalidParameter The device handle not be found.
*/
usb_status_t USB_DeviceClassGetDeviceHandle(uint8_t controllerId, usb_device_handle *handle)
{
int32_t count = 0U;
USB_OSA_SR_ALLOC();
USB_OSA_ENTER_CRITICAL();
for (; count < USB_DEVICE_CONFIG_NUM; count++)
{
if ((NULL != s_UsbDeviceCommonClassStruct[count].handle) &&
(controllerId == s_UsbDeviceCommonClassStruct[count].controllerId))
{
*handle = s_UsbDeviceCommonClassStruct[count].handle;
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_Success;
}
}
USB_OSA_EXIT_CRITICAL();
return kStatus_USB_InvalidParameter;
}
/*!
* @brief Handle the event passed to the class drivers.
*
* This function handles the event passed to the class drivers.
*
* @param handle The device handle, got from the USB_DeviceInit.
* @param event The event codes. Please refer to the enumeration usb_device_class_event_t.
* @param param The param type is determined by the event code.
*
* @return A USB error code or kStatus_USB_Success.
* @retval kStatus_USB_Success A valid request has been handled.
* @retval kStatus_USB_InvalidParameter The device handle not be found.
* @retval kStatus_USB_InvalidRequest The request is invalid, and the control pipe will be stalled by the caller.
*/
usb_status_t USB_DeviceClassEvent(usb_device_handle handle, usb_device_class_event_t event, void *param)
{
usb_device_common_class_struct_t *classHandle;
uint8_t mapIndex;
uint8_t classIndex;
usb_status_t errorReturn = kStatus_USB_Error;
usb_status_t error = kStatus_USB_Error;
if (NULL == param)
{
return kStatus_USB_InvalidParameter;
}
/* Get the common class handle according to the device handle. */
errorReturn = USB_DeviceClassGetHandleByDeviceHandle(handle, &classHandle);
if (kStatus_USB_Success != errorReturn)
{
return kStatus_USB_InvalidParameter;
}
for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++)
{
for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t));
mapIndex++)
{
if (s_UsbDeviceClassInterfaceMap[mapIndex].type ==
classHandle->configList->config[classIndex].classInfomation->type)
{
/* Call class event callback of supported class */
errorReturn = s_UsbDeviceClassInterfaceMap[mapIndex].classEventCallback(
(void *)classHandle->configList->config[classIndex].classHandle, event, param);
/* Return the error code kStatus_USB_InvalidRequest immediately, when a class returns
* kStatus_USB_InvalidRequest. */
if (kStatus_USB_InvalidRequest == errorReturn)
{
return kStatus_USB_InvalidRequest;
}
/* For composite device, it should return kStatus_USB_Success once a valid request has been handled */
if (kStatus_USB_Success == errorReturn)
{
error = kStatus_USB_Success;
}
break;
}
}
}
return error;
}
/*!
* @brief Handle the common class callback.
*
* This function handles the common class callback.
*
* @param handle The device handle, got from the USB_DeviceInit.
* @param event The event codes. Please refer to the enumeration usb_device_event_t.
* @param param The param type is determined by the event code.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceClassCallback(usb_device_handle handle, uint32_t event, void *param)
{
usb_device_common_class_struct_t *classHandle;
usb_status_t error = kStatus_USB_Error;
/* Get the common class handle according to the device handle. */
error = USB_DeviceClassGetHandleByDeviceHandle(handle, &classHandle);
if (kStatus_USB_Success != error)
{
return error;
}
if (kUSB_DeviceEventBusReset == event)
{
/* Initialize the control pipes */
USB_DeviceControlPipeInit(handle, classHandle);
/* Notify the classes the USB bus reset signal detected. */
USB_DeviceClassEvent(handle, kUSB_DeviceClassEventDeviceReset, classHandle);
}
/* Call the application device callback function. */
error = classHandle->configList->deviceCallback(handle, event, param);
return error;
}
/*!
* @brief Initialize the common class and the supported classes.
*
* This function is used to initialize the common class and the supported classes.
*
* @param[in] controllerId The controller id of the USB IP. Please refer to the enumeration #usb_controller_index_t.
* @param[in] configList The class configurations. The pointer must point to the goblal variable.
* Please refer to the structure #usb_device_class_config_list_struct_t.
* @param[out] handle It is out parameter, is used to return pointer of the device handle to the caller.
* The value of parameter is a pointer points the device handle, and this design is uesd to
* make simple device align with composite device. For composite device, there are many
* kinds of class handle, but there is only one device handle. So the handle points to
* a device instead of a class. And the class handle can be got from the
* #usb_device_class_config_struct_t::classHandle after the the function successfully.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceClassInit(
uint8_t controllerId, /*!< [IN] Controller ID */
usb_device_class_config_list_struct_t *configList, /*!< [IN] Pointer to class configuration list */
usb_device_handle *handle /*!< [OUT] Pointer to the device handle */
)
{
usb_device_common_class_struct_t *classHandle;
usb_status_t error = kStatus_USB_Error;
uint8_t mapIndex;
uint8_t classIndex;
if ((NULL == handle) || (NULL == configList) || ((usb_device_callback_t)NULL == configList->deviceCallback))
{
return kStatus_USB_InvalidParameter;
}
/* Allocate a common class driver handle. */
error = USB_DeviceClassAllocateHandle(controllerId, &classHandle);
if (kStatus_USB_Success != error)
{
return error;
}
/* Save the configuration list */
classHandle->configList = configList;
/* Initialize the device stack. */
error = USB_DeviceInit(controllerId, USB_DeviceClassCallback, &classHandle->handle);
if (kStatus_USB_Success != error)
{
USB_DeviceDeinit(classHandle->handle);
USB_DeviceClassFreeHandle(controllerId);
return error;
}
/* Initialize the all supported classes according to the configuration list. */
for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++)
{
for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t));
mapIndex++)
{
if (classHandle->configList->config[classIndex].classInfomation->type ==
s_UsbDeviceClassInterfaceMap[mapIndex].type)
{
(void)s_UsbDeviceClassInterfaceMap[mapIndex].classInit(
controllerId, &classHandle->configList->config[classIndex],
&classHandle->configList->config[classIndex].classHandle);
}
}
}
*handle = classHandle->handle;
return error;
}
/*!
* @brief De-initialize the common class and the supported classes.
*
* This function is used to de-initialize the common class and the supported classes.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceClassDeinit(uint8_t controllerId /*!< [IN] Controller ID */
)
{
usb_device_common_class_struct_t *classHandle;
usb_status_t error = kStatus_USB_Error;
uint8_t mapIndex;
uint8_t classIndex;
/* Get the common class handle according to the controller id. */
error = USB_DeviceClassGetHandleByControllerId(controllerId, &classHandle);
if (kStatus_USB_Success != error)
{
return error;
}
/* De-initialize the all supported classes according to the configuration list. */
for (classIndex = 0U; classIndex < classHandle->configList->count; classIndex++)
{
for (mapIndex = 0U; mapIndex < (sizeof(s_UsbDeviceClassInterfaceMap) / sizeof(usb_device_class_map_t));
mapIndex++)
{
if (classHandle->configList->config[classIndex].classInfomation->type ==
s_UsbDeviceClassInterfaceMap[mapIndex].type)
{
(void)s_UsbDeviceClassInterfaceMap[mapIndex].classDeinit(
classHandle->configList->config[classIndex].classHandle);
}
}
}
/* De-initialize the USB device stack. */
error = USB_DeviceDeinit(classHandle->handle);
if (kStatus_USB_Success == error)
{
/* Free the common class handle. */
(void)USB_DeviceClassFreeHandle(controllerId);
}
return error;
}
/*!
* @brief Get the USB bus speed.
*
* This function is used to get the USB bus speed.
*
* @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
* @param speed It is an OUT parameter, return current speed of the controller.
*
* @return A USB error code or kStatus_USB_Success.
*/
usb_status_t USB_DeviceClassGetSpeed(uint8_t controllerId, /*!< [IN] Controller ID */
uint8_t *speed /*!< [OUT] Current speed */
)
{
usb_device_common_class_struct_t *classHandle;
usb_status_t error = kStatus_USB_Error;
/* Get the common class handle according to the controller id. */
error = USB_DeviceClassGetHandleByControllerId(controllerId, &classHandle);
if (kStatus_USB_Success != error)
{
return error;
}
/* Get the current speed. */
error = USB_DeviceGetStatus(classHandle->handle, kUSB_DeviceStatusSpeed, speed);
return error;
}
#endif /* USB_DEVICE_CONFIG_NUM */