/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2017 NXP * All rights reserved. * * * SPDX-License-Identifier: BSD-3-Clause */ #include "usb_device_config.h" #include "usb.h" #include "usb_device.h" #include "usb_device_class.h" #if ((defined(USB_DEVICE_CONFIG_DFU)) && (USB_DEVICE_CONFIG_DFU > 0U)) #include "usb_device_dfu.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ static usb_status_t USB_DeviceDfuAllocateHandle(usb_device_dfu_struct_t **handle); static usb_status_t USB_DeviceDfuFreeHandle(usb_device_dfu_struct_t *handle); /******************************************************************************* * Variables ******************************************************************************/ USB_GLOBAL static usb_device_dfu_struct_t s_UsbDeviceDfuHandle[USB_DEVICE_CONFIG_DFU]; /******************************************************************************* * Code ******************************************************************************/ /*! * @brief Allocate a device dfu class handle. * * This function allocates a device dfu class handle. * * @param handle It is out parameter, is used to return pointer of the device dfu class handle to the caller. * * @retval kStatus_USB_Success Get a device dfu class handle successfully. * @retval kStatus_USB_Busy Cannot allocate a device dfu class handle. */ static usb_status_t USB_DeviceDfuAllocateHandle(usb_device_dfu_struct_t **handle) { uint32_t count; for (count = 0U; count < USB_DEVICE_CONFIG_DFU; count++) { if (NULL == s_UsbDeviceDfuHandle[count].handle) { *handle = &s_UsbDeviceDfuHandle[count]; return kStatus_USB_Success; } } return kStatus_USB_Busy; } /*! * @brief Free a device dfu class handle. * * This function frees a device dfu class handle. * * @param handle The device dfu class handle. * * @retval kStatus_USB_Success Free device dfu class handle successfully. */ static usb_status_t USB_DeviceDfuFreeHandle(usb_device_dfu_struct_t *handle) { handle->handle = NULL; handle->configStruct = (usb_device_class_config_struct_t *)NULL; return kStatus_USB_Success; } /*! * @brief Handle the event passed to the dfu class. * * This function handles the event passed to the dfu class. * * @param handle The dfu class handle, got from the usb_device_class_config_struct_t::classHandle. * @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 Free device handle successfully. * @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_DeviceDfuEvent(void *handle, uint32_t event, void *param) { usb_device_dfu_struct_t *dfuHandle; usb_status_t error = kStatus_USB_Error; usb_device_class_event_t eventCode = (usb_device_class_event_t)event; if ((NULL == param) || (NULL == handle)) { return kStatus_USB_InvalidHandle; } /* Get the dfu class handle. */ dfuHandle = (usb_device_dfu_struct_t *)handle; switch (eventCode) { case kUSB_DeviceClassEventDeviceReset: error = kStatus_USB_Success; break; case kUSB_DeviceClassEventSetConfiguration: error = kStatus_USB_Success; break; case kUSB_DeviceClassEventClassRequest: { /* Handle the dfu class specific request. */ usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param; int32_t dfuRequest = -1; if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) != USB_REQUEST_TYPE_RECIPIENT_INTERFACE) { break; } if ((controlRequest->setup->wIndex & 0xFFU) != 0x00U /* Interface number is always 0 */) { break; } error = kStatus_USB_InvalidRequest; if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT) { switch (controlRequest->setup->bRequest) { case USB_DEVICE_DFU_DETACH: if (controlRequest->setup->wLength == 0U) { dfuRequest = (int32_t)kUSB_DeviceDfuEventDetach; } break; case USB_DEVICE_DFU_DNLOAD: dfuRequest = (int32_t)kUSB_DeviceDfuEventDownLoad; break; case USB_DEVICE_DFU_CLRSTATUS: if (controlRequest->setup->wLength == 0U) { dfuRequest = (int32_t)kUSB_DeviceDfuEventClearStatus; } break; case USB_DEVICE_DFU_ABORT: if (controlRequest->setup->wLength == 0U) { dfuRequest = (int32_t)kUSB_DeviceDfuEventAbort; } break; default: /* no action, return kStatus_USB_InvalidRequest */ break; } } else { switch (controlRequest->setup->bRequest) { case USB_DEVICE_DFU_UPLOAD: dfuRequest = (int32_t)kUSB_DeviceDfuEventUpLoad; break; case USB_DEVICE_DFU_GETSTATUS: if (controlRequest->setup->wLength != 0U) { dfuRequest = (int32_t)kUSB_DeviceDfuEventGetStatus; } break; case USB_DEVICE_DFU_GETSTATE: if (controlRequest->setup->wLength != 0U) { dfuRequest = (int32_t)kUSB_DeviceDfuEventGetState; } break; default: /* no action, return kStatus_USB_InvalidRequest */ break; } } if (dfuRequest != -1) { /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap, it is from the second parameter of classInit */ error = dfuHandle->configStruct->classCallback((class_handle_t)dfuHandle, dfuRequest, controlRequest); } } break; default: /*no action*/ break; } return error; } /*! * @brief Initialize the dfu class. * * This function is used to initialize the dfu class. * * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t. * @param config The class configuration information. * @param handle It is out parameter, is used to return pointer of the dfu class handle to the caller. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceDfuInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle) { usb_device_dfu_struct_t *dfuHandle; usb_status_t error; /* Allocate a dfu class handle. */ error = USB_DeviceDfuAllocateHandle(&dfuHandle); if (kStatus_USB_Success != error) { return error; } /* Get the device handle according to the controller id. */ error = USB_DeviceClassGetDeviceHandle(controllerId, &dfuHandle->handle); if (kStatus_USB_Success != error) { return error; } if (NULL == dfuHandle->handle) { return kStatus_USB_InvalidHandle; } /* Save the configuration of the class. */ dfuHandle->configStruct = config; *handle = (class_handle_t)dfuHandle; return error; } /*! * @brief De-initialize the device dfu class. * * The function de-initializes the device dfu class. * * @param handle The dfu class handle got from usb_device_class_config_struct_t::classHandle. * * @return A USB error code or kStatus_USB_Success. */ usb_status_t USB_DeviceDfuDeinit(class_handle_t handle) { usb_device_dfu_struct_t *dfuHandle; #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) usb_status_t error = kStatus_USB_Error; #endif dfuHandle = (usb_device_dfu_struct_t *)handle; if (NULL == dfuHandle) { return kStatus_USB_InvalidHandle; } /* Free the dfu class handle. */ #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U)) error = USB_DeviceDfuFreeHandle(dfuHandle); return error; #else (void)USB_DeviceDfuFreeHandle(dfuHandle); return kStatus_USB_Success; #endif } #endif