1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2017 NXP
4 * All rights reserved.
5 *
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 */
9
10 #include "usb_device_config.h"
11 #include "usb.h"
12 #include "usb_device.h"
13
14 #include "usb_device_class.h"
15
16 #if ((defined(USB_DEVICE_CONFIG_DFU)) && (USB_DEVICE_CONFIG_DFU > 0U))
17 #include "usb_device_dfu.h"
18
19 /*******************************************************************************
20 * Definitions
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * Prototypes
25 ******************************************************************************/
26
27 static usb_status_t USB_DeviceDfuAllocateHandle(usb_device_dfu_struct_t **handle);
28 static usb_status_t USB_DeviceDfuFreeHandle(usb_device_dfu_struct_t *handle);
29
30 /*******************************************************************************
31 * Variables
32 ******************************************************************************/
33
34 USB_GLOBAL static usb_device_dfu_struct_t s_UsbDeviceDfuHandle[USB_DEVICE_CONFIG_DFU];
35
36 /*******************************************************************************
37 * Code
38 ******************************************************************************/
39
40 /*!
41 * @brief Allocate a device dfu class handle.
42 *
43 * This function allocates a device dfu class handle.
44 *
45 * @param handle It is out parameter, is used to return pointer of the device dfu class handle to the caller.
46 *
47 * @retval kStatus_USB_Success Get a device dfu class handle successfully.
48 * @retval kStatus_USB_Busy Cannot allocate a device dfu class handle.
49 */
USB_DeviceDfuAllocateHandle(usb_device_dfu_struct_t ** handle)50 static usb_status_t USB_DeviceDfuAllocateHandle(usb_device_dfu_struct_t **handle)
51 {
52 uint32_t count;
53 for (count = 0U; count < USB_DEVICE_CONFIG_DFU; count++)
54 {
55 if (NULL == s_UsbDeviceDfuHandle[count].handle)
56 {
57 *handle = &s_UsbDeviceDfuHandle[count];
58 return kStatus_USB_Success;
59 }
60 }
61
62 return kStatus_USB_Busy;
63 }
64
65 /*!
66 * @brief Free a device dfu class handle.
67 *
68 * This function frees a device dfu class handle.
69 *
70 * @param handle The device dfu class handle.
71 *
72 * @retval kStatus_USB_Success Free device dfu class handle successfully.
73 */
USB_DeviceDfuFreeHandle(usb_device_dfu_struct_t * handle)74 static usb_status_t USB_DeviceDfuFreeHandle(usb_device_dfu_struct_t *handle)
75 {
76 handle->handle = NULL;
77 handle->configStruct = (usb_device_class_config_struct_t *)NULL;
78 return kStatus_USB_Success;
79 }
80
81 /*!
82 * @brief Handle the event passed to the dfu class.
83 *
84 * This function handles the event passed to the dfu class.
85 *
86 * @param handle The dfu class handle, got from the usb_device_class_config_struct_t::classHandle.
87 * @param event The event codes. Please refer to the enumeration usb_device_class_event_t.
88 * @param param The param type is determined by the event code.
89 *
90 * @return A USB error code or kStatus_USB_Success.
91 * @retval kStatus_USB_Success Free device handle successfully.
92 * @retval kStatus_USB_InvalidParameter The device handle not be found.
93 * @retval kStatus_USB_InvalidRequest The request is invalid, and the control pipe will be stalled by the caller.
94 */
USB_DeviceDfuEvent(void * handle,uint32_t event,void * param)95 usb_status_t USB_DeviceDfuEvent(void *handle, uint32_t event, void *param)
96 {
97 usb_device_dfu_struct_t *dfuHandle;
98 usb_status_t error = kStatus_USB_Error;
99 usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
100
101 if ((NULL == param) || (NULL == handle))
102 {
103 return kStatus_USB_InvalidHandle;
104 }
105
106 /* Get the dfu class handle. */
107 dfuHandle = (usb_device_dfu_struct_t *)handle;
108
109 switch (eventCode)
110 {
111 case kUSB_DeviceClassEventDeviceReset:
112 error = kStatus_USB_Success;
113 break;
114 case kUSB_DeviceClassEventSetConfiguration:
115 error = kStatus_USB_Success;
116 break;
117 case kUSB_DeviceClassEventClassRequest:
118 {
119 /* Handle the dfu class specific request. */
120 usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
121 int32_t dfuRequest = -1;
122
123 if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
124 USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
125 {
126 break;
127 }
128
129 if ((controlRequest->setup->wIndex & 0xFFU) != 0x00U /* Interface number is always 0 */)
130 {
131 break;
132 }
133
134 error = kStatus_USB_InvalidRequest;
135 if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == USB_REQUEST_TYPE_DIR_OUT)
136 {
137 switch (controlRequest->setup->bRequest)
138 {
139 case USB_DEVICE_DFU_DETACH:
140 if (controlRequest->setup->wLength == 0U)
141 {
142 dfuRequest = (int32_t)kUSB_DeviceDfuEventDetach;
143 }
144 break;
145 case USB_DEVICE_DFU_DNLOAD:
146 dfuRequest = (int32_t)kUSB_DeviceDfuEventDownLoad;
147 break;
148 case USB_DEVICE_DFU_CLRSTATUS:
149 if (controlRequest->setup->wLength == 0U)
150 {
151 dfuRequest = (int32_t)kUSB_DeviceDfuEventClearStatus;
152 }
153 break;
154 case USB_DEVICE_DFU_ABORT:
155 if (controlRequest->setup->wLength == 0U)
156 {
157 dfuRequest = (int32_t)kUSB_DeviceDfuEventAbort;
158 }
159 break;
160 default:
161 /* no action, return kStatus_USB_InvalidRequest */
162 break;
163 }
164 }
165 else
166 {
167 switch (controlRequest->setup->bRequest)
168 {
169 case USB_DEVICE_DFU_UPLOAD:
170 dfuRequest = (int32_t)kUSB_DeviceDfuEventUpLoad;
171 break;
172 case USB_DEVICE_DFU_GETSTATUS:
173 if (controlRequest->setup->wLength != 0U)
174 {
175 dfuRequest = (int32_t)kUSB_DeviceDfuEventGetStatus;
176 }
177 break;
178 case USB_DEVICE_DFU_GETSTATE:
179 if (controlRequest->setup->wLength != 0U)
180 {
181 dfuRequest = (int32_t)kUSB_DeviceDfuEventGetState;
182 }
183 break;
184 default:
185 /* no action, return kStatus_USB_InvalidRequest */
186 break;
187 }
188 }
189
190 if (dfuRequest != -1)
191 {
192 /* ClassCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
193 it is from the second parameter of classInit */
194 error = dfuHandle->configStruct->classCallback((class_handle_t)dfuHandle, dfuRequest, controlRequest);
195 }
196 }
197 break;
198 default:
199 /*no action*/
200 break;
201 }
202 return error;
203 }
204
205 /*!
206 * @brief Initialize the dfu class.
207 *
208 * This function is used to initialize the dfu class.
209 *
210 * @param controllerId The controller id of the USB IP. Please refer to the enumeration usb_controller_index_t.
211 * @param config The class configuration information.
212 * @param handle It is out parameter, is used to return pointer of the dfu class handle to the caller.
213 *
214 * @return A USB error code or kStatus_USB_Success.
215 */
USB_DeviceDfuInit(uint8_t controllerId,usb_device_class_config_struct_t * config,class_handle_t * handle)216 usb_status_t USB_DeviceDfuInit(uint8_t controllerId, usb_device_class_config_struct_t *config, class_handle_t *handle)
217 {
218 usb_device_dfu_struct_t *dfuHandle;
219 usb_status_t error;
220
221 /* Allocate a dfu class handle. */
222 error = USB_DeviceDfuAllocateHandle(&dfuHandle);
223
224 if (kStatus_USB_Success != error)
225 {
226 return error;
227 }
228
229 /* Get the device handle according to the controller id. */
230 error = USB_DeviceClassGetDeviceHandle(controllerId, &dfuHandle->handle);
231
232 if (kStatus_USB_Success != error)
233 {
234 return error;
235 }
236
237 if (NULL == dfuHandle->handle)
238 {
239 return kStatus_USB_InvalidHandle;
240 }
241 /* Save the configuration of the class. */
242 dfuHandle->configStruct = config;
243
244 *handle = (class_handle_t)dfuHandle;
245 return error;
246 }
247
248 /*!
249 * @brief De-initialize the device dfu class.
250 *
251 * The function de-initializes the device dfu class.
252 *
253 * @param handle The dfu class handle got from usb_device_class_config_struct_t::classHandle.
254 *
255 * @return A USB error code or kStatus_USB_Success.
256 */
USB_DeviceDfuDeinit(class_handle_t handle)257 usb_status_t USB_DeviceDfuDeinit(class_handle_t handle)
258 {
259 usb_device_dfu_struct_t *dfuHandle;
260 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
261 usb_status_t error = kStatus_USB_Error;
262 #endif
263
264 dfuHandle = (usb_device_dfu_struct_t *)handle;
265
266 if (NULL == dfuHandle)
267 {
268 return kStatus_USB_InvalidHandle;
269 }
270
271 /* Free the dfu class handle. */
272 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
273 error = USB_DeviceDfuFreeHandle(dfuHandle);
274 return error;
275 #else
276 (void)USB_DeviceDfuFreeHandle(dfuHandle);
277 return kStatus_USB_Success;
278 #endif
279 }
280 #endif
281