1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 /**************************************************************************/
12 /**************************************************************************/
13 /**                                                                       */
14 /** USBX Component                                                        */
15 /**                                                                       */
16 /**   Device DFU Class                                                    */
17 /**                                                                       */
18 /**************************************************************************/
19 /**************************************************************************/
20 
21 #define UX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "ux_api.h"
27 #include "ux_device_class_dfu.h"
28 #include "ux_device_stack.h"
29 
30 
31 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
32 static inline VOID _ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU *,
33     UX_SLAVE_TRANSFER *, UCHAR, UCHAR, UCHAR, UCHAR);
34 #endif
35 
36 
37 /**************************************************************************/
38 /*                                                                        */
39 /*  FUNCTION                                               RELEASE        */
40 /*                                                                        */
41 /*    _ux_device_class_dfu_control_request                PORTABLE C      */
42 /*                                                           6.1.12       */
43 /*  AUTHOR                                                                */
44 /*                                                                        */
45 /*    Chaoqiong Xiao, Microsoft Corporation                               */
46 /*                                                                        */
47 /*  DESCRIPTION                                                           */
48 /*                                                                        */
49 /*    This function manages the based sent by the host on the control     */
50 /*    endpoints with a CLASS or VENDOR SPECIFIC type.                     */
51 /*                                                                        */
52 /*  INPUT                                                                 */
53 /*                                                                        */
54 /*    dfu                                       Pointer to dfu class      */
55 /*                                                                        */
56 /*  OUTPUT                                                                */
57 /*                                                                        */
58 /*    None                                                                */
59 /*                                                                        */
60 /*  CALLS                                                                 */
61 /*                                                                        */
62 /*    _ux_device_stack_endpoint_stall       Endpoint stall                */
63 /*    _ux_device_stack_transfer_request     Transfer request              */
64 /*                                                                        */
65 /*  CALLED BY                                                             */
66 /*                                                                        */
67 /*    DFU Class                                                           */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
74 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
75 /*                                            used UX prefix to refer to  */
76 /*                                            TX symbols instead of using */
77 /*                                            them directly,              */
78 /*                                            resulting in version 6.1    */
79 /*  04-02-2021     Chaoqiong Xiao           Modified comment(s),          */
80 /*                                            added DFU_UPLOAD support,   */
81 /*                                            removed block count (it's   */
82 /*                                            from host request wValue),  */
83 /*                                            resulting in version 6.1.6  */
84 /*  10-15-2021     Chaoqiong Xiao           Modified comment(s),          */
85 /*                                            fixed compile warning,      */
86 /*                                            resulting in version 6.1.9  */
87 /*  01-31-2022     Chaoqiong Xiao           Modified comment(s),          */
88 /*                                            added UPLOAD length check,  */
89 /*                                            added standalone support,   */
90 /*                                            resulting in version 6.1.10 */
91 /*  04-25-2022     Chaoqiong Xiao           Modified comment(s),          */
92 /*                                            checked r/w callback status,*/
93 /*                                            resulting in version 6.1.11 */
94 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
95 /*                                            fixed parameter/variable    */
96 /*                                            names conflict C++ keyword, */
97 /*                                            added UPLOAD length check   */
98 /*                                            in _UPLOAD_IDLE state,      */
99 /*                                            added DNLOAD REQ            */
100 /*                                            validation,                 */
101 /*                                            resulting in version 6.1.12 */
102 /*                                                                        */
103 /**************************************************************************/
_ux_device_class_dfu_control_request(UX_SLAVE_CLASS_COMMAND * command)104 UINT  _ux_device_class_dfu_control_request(UX_SLAVE_CLASS_COMMAND *command)
105 {
106 
107 UX_SLAVE_TRANSFER       *transfer_request;
108 UX_SLAVE_DEVICE         *device;
109 UX_SLAVE_CLASS          *class_ptr;
110 UX_SLAVE_CLASS_DFU      *dfu;
111 
112 ULONG                   request;
113 ULONG                   request_type;
114 ULONG                   request_value;
115 ULONG                   request_length;
116 ULONG                   actual_length;
117 UINT                    status;
118 #if defined(UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE) || (UX_DEVICE_CLASS_DFU_STATUS_MODE != 1)
119 ULONG                   media_status;
120 #endif
121 
122 
123     /* Get the pointer to the device.  */
124     device =  &_ux_system_slave -> ux_system_slave_device;
125 
126      /* Get the class container.  */
127     class_ptr =  command -> ux_slave_class_command_class_ptr;
128 
129     /* Get the storage instance from this class container.  */
130     dfu =  (UX_SLAVE_CLASS_DFU *) class_ptr -> ux_slave_class_instance;
131 
132     /* Get the pointer to the transfer request associated with the control endpoint.  */
133     transfer_request =  &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
134 
135 #ifdef UX_DEVICE_CLASS_DFU_CUSTOM_REQUEST_ENABLE
136     if (dfu -> ux_device_class_dfu_custom_request)
137     {
138 
139         /* The status simply tells us if the registered callback handled the
140             request - if there was an issue processing the request, it would've
141             stalled the control endpoint, notifying the host (and not us).  */
142         media_status = dfu -> ux_device_class_dfu_custom_request(dfu, transfer_request);
143 
144         /* Custom request handled.  */
145         if (media_status == UX_SUCCESS)
146             return(media_status);
147 
148         /* Try to handle with standard handler.  */
149     }
150 #endif
151 
152     /* Extract all necessary fields of the request.  */
153     request =  *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
154     request_type = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST_TYPE);
155 
156     /* Pickup the request wValue.  */
157     request_value =    _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_VALUE);
158 
159     /* Pickup the request wLength.  */
160     request_length =   _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
161 
162     /* What state are we in ? */
163     switch (_ux_system_slave -> ux_system_slave_device_dfu_state_machine)
164     {
165 
166         case UX_SYSTEM_DFU_STATE_APP_IDLE         :
167 
168 
169             /* Here we process only the request we can accept in the APP IDLE state.  */
170             switch (request)
171             {
172 
173                 case UX_SLAVE_CLASS_DFU_COMMAND_DETACH :
174 
175                     /* The host is asking for a Detach and switch to the DFU mode. Either we force the reset here or
176                        we wait for a specified timer. If there is no reset while this timer is running we abandon
177                        the DFU Detach.*/
178                     if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities &  UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH)
179                     {
180 
181                         /* Wake up the DFU thread and send a detach request..  */
182                         _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
183                     }
184                     else
185                     {
186 
187                         /* We expect the host to issue a reset.  Arm a timer in the DFU thread.  */
188                         _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_WAIT_RESET);
189                     }
190 
191                     /* We can switch dfu state machine.  */
192                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_APP_DETACH;
193 
194                     break;
195 
196                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
197 
198 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
199                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
200 #else
201                     /* Fill the status data payload.  First with status.  */
202                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
203 
204                     /* Poll time out value is set to 1ms.  */
205                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
206                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
207                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
208 
209                     /* Next state.  */
210                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
211 
212                     /* String index set to 0.  */
213                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
214 #endif
215 
216                     /* We have a request to obtain the status of the DFU instance. */
217                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
218 
219                     break;
220 
221                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
222 
223                     /* Fill the status data payload.  First with state.  */
224                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
225 
226                     /* We have a request to obtain the status of the DFU instance. */
227                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
228 
229                     break;
230 
231                 default:
232 
233                     /* Unknown function. Stall the endpoint.  */
234                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
235                     break;
236             }
237 
238             break;
239 
240         case UX_SYSTEM_DFU_STATE_APP_DETACH         :
241 
242             /* Here we process only the request we can accept in the APP DETACH state.  */
243             switch (request)
244             {
245 
246                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
247 
248 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
249                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
250 #else
251 
252                     /* Fill the status data payload.  First with status.  */
253                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
254 
255                     /* Poll time out value is set to 1ms.  */
256                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
257                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
258                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
259 
260                     /* Next state.  */
261                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
262 
263                     /* String index set to 0.  */
264                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
265 #endif
266 
267                     /* We have a request to obtain the status of the DFU instance. */
268                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
269 
270                     break;
271 
272                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
273 
274                     /* Fill the status data payload.  First with state.  */
275                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
276 
277                     /* We have a request to obtain the status of the DFU instance. */
278                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
279 
280                     break;
281 
282                 default:
283 
284                     /* Unknown function. Stall the endpoint.  */
285                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
286                     break;
287             }
288 
289             break;
290 
291         case UX_SYSTEM_DFU_STATE_DFU_IDLE         :
292 
293             /* Here we process only the request we can accept in the DFU mode IDLE state.  */
294             switch (request)
295             {
296 
297                 case UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD :
298 
299                     /* Command verify: check bmRequestType and data length.  */
300                     if ((request_type != UX_DEVICE_CLASS_DFU_REQTYPE_INTERFACE_SET) ||
301                         (request_length != transfer_request -> ux_slave_transfer_request_actual_length))
302                     {
303 
304                         /* Zero length download is not accepted. Stall the endpoint.  */
305                         _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
306 
307                         /* In the system, state the DFU state machine to dfu ERROR.  */
308                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
309                     }
310 
311                     /* We received a DOWNLOAD command. Check the length field of the request. It cannot be 0.  */
312                     else if (request_length == 0)
313                     {
314 
315                         /* Zero length download is not accepted. Stall the endpoint.  */
316                         _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
317 
318                         /* In the system, state the DFU state machine to dfu ERROR.  */
319                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
320 
321                     }
322                     else
323                     {
324 
325                         /* Have we declared a DOWNLOAD possible in our device framework ? */
326                         if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_CAN_DOWNLOAD)
327                         {
328 
329                             /* Send a notification to the application.  Begin of transfer.  */
330                             dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_DOWNLOAD);
331 
332                             /* Write the first block to the firmware.  */
333                             status = dfu -> ux_slave_class_dfu_write(dfu, request_value,
334                                                                 transfer_request -> ux_slave_transfer_request_data_pointer,
335                                                                 request_length,
336                                                                 &actual_length);
337 
338                             /* Application can actively reject and set error state.  */
339                             if (status != UX_SUCCESS)
340                             {
341                                 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
342                                 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
343                                 break;
344                             }
345 
346                             /* In the system, state the DFU state machine to dfu DOWNLOAD SYNC.  */
347                             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC;
348 
349                         }
350                         else
351                         {
352 
353                             /* Download is not accepted. Stall the endpoint.  */
354                             _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
355 
356                             /* In the system, state the DFU state machine to dfu ERROR.  */
357                             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
358 
359                         }
360 
361                     }
362                     break;
363 
364                 case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
365 
366                         /* Send a notification to the application.  */
367                         dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD);
368 
369                         /* In the system, state the DFU state machine to dfu IDLE.  */
370                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
371 
372                     break;
373 
374                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
375 
376 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
377                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
378 #else
379 
380                     /* Fill the status data payload.  First with status.  */
381                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
382 
383                     /* Poll time out value is set to 1ms.  */
384                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
385                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
386                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
387 
388                     /* Next state.  */
389                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) UX_SYSTEM_DFU_STATE_DFU_IDLE;
390 
391                     /* String index set to 0.  */
392                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
393 #endif
394 
395                     /* We have a request to obtain the status of the DFU instance. */
396                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
397 
398                     break;
399 
400                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
401 
402                     /* Fill the status data payload.  First with state.  */
403                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
404 
405                     /* We have a request to obtain the status of the DFU instance. */
406                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
407 
408                     break;
409 
410 #ifndef UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE
411                 case UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD:
412 
413                     /* bitCanUpload != 1, or length = 0, or length > wTransferSize (we can support max of control buffer size).  */
414                     if (!(_ux_system_slave -> ux_system_slave_device_dfu_capabilities & UX_SLAVE_CLASS_DFU_CAPABILITY_CAN_UPLOAD) ||
415                         (request_length == 0) ||
416                         (request_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH))
417                     {
418                         _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
419 
420                         /* In the system, state the DFU state machine to dfu ERROR.  */
421                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
422 
423                         break;
424                     }
425 
426                     /* bitCanUpload = 1.  */
427 
428                     /* Send a notification to the application.  Begin of transfer.  */
429                     dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_BEGIN_UPLOAD);
430 
431                     /* Read the first block to the firmware.  */
432                     status = dfu -> ux_slave_class_dfu_read(dfu, request_value,
433                                                         transfer_request -> ux_slave_transfer_request_data_pointer,
434                                                         request_length,
435                                                         &actual_length);
436 
437                     /* Application can actively reject and set error state.  */
438                     if (status != UX_SUCCESS)
439                     {
440                         _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
441                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
442                         break;
443                     }
444 
445                     /* In the system, state the DFU state machine to dfu UPLOAD IDLE.  */
446                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_UPLOAD_IDLE;
447 
448                     /* We have a request to upload DFU firmware block. */
449                     _ux_device_stack_transfer_request(transfer_request, actual_length, request_length);
450 
451                     break;
452 #endif
453 
454                 default:
455 
456                     /* Unknown function. Stall the endpoint.  */
457                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
458 
459                     /* In the system, state the DFU state machine to dfu ERROR.  */
460                        _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
461 
462                     break;
463             }
464 
465             break;
466 
467 
468         case UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC         :
469 
470             /* Here we process only the request we can accept in the DFU mode DOWNLOAD state.  */
471             switch (request)
472             {
473 
474                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
475 
476 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
477                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_TRUE,
478                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE,
479                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNBUSY,
480                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR);
481 #else
482 
483                     /* Check if the device is still buys performing the write. Write could be delayed.  */
484                     dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
485 
486                     /* Check status of device.  */
487                     switch (media_status)
488                     {
489 
490                         case     UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK        :
491 
492                             /* Set the next state for idle and no error status.  */
493                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
494                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE;
495                             break;
496 
497                         case     UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY    :
498 
499                             /* Set the next state for busy but no error status.  */
500                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
501                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNBUSY;
502                             break;
503 
504                         case    UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR   :
505 
506                             /* Set the next state for busy and error status.  */
507                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_ERROR_WRITE ;
508                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR;
509                             break;
510 
511                     }
512 
513                     /* Fill the status data payload.  First with status.  */
514                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
515 
516                     /* Poll time out value is set to 1ms.  */
517                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
518                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
519                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
520 
521                     /* Next state.  */
522                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
523 
524                     /* String index set to 0.  */
525                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
526 #endif
527 
528                     /* We have a request to obtain the status of the DFU instance. */
529                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
530 
531                     break;
532 
533                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
534 
535                     /* Fill the status data payload.  First with state.  */
536                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
537 
538                     /* We have a request to obtain the status of the DFU instance. */
539                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
540 
541                     break;
542 
543                 default:
544 
545                     /* Unknown function. Stall the endpoint.  */
546                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
547 
548                     /* In the system, state the DFU state machine to dfu ERROR.  */
549                        _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
550 
551                     break;
552             }
553 
554             break;
555 
556         case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_DNLOAD_IDLE         :
557 
558             /* Here we process only the request we can accept in the DFU mode DNLOAD state.  */
559             switch (request)
560             {
561 
562                 case UX_SLAVE_CLASS_DFU_COMMAND_DOWNLOAD :
563 
564                     /* Command verify: check bmRequestType and data length.  */
565                     if ((request_type != UX_DEVICE_CLASS_DFU_REQTYPE_INTERFACE_SET) ||
566                         (request_length != transfer_request -> ux_slave_transfer_request_actual_length))
567                     {
568 
569                         /* Zero length download is not accepted. Stall the endpoint.  */
570                         _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
571 
572                         /* In the system, state the DFU state machine to dfu ERROR.  */
573                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
574                     }
575 
576                     /* We received a DOWNLOAD command. Check the length field of the request. If it is 0,
577                        we are done with the transfer.  */
578                     else if (request_length == 0)
579                     {
580 
581                         /* Send the notification of end of download to application.  */
582                         dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_END_DOWNLOAD);
583 
584                         /* In the system, state the DFU state machine to DFU MANIFEST SYNCH.  */
585                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC;
586 
587                     }
588 
589                     else
590                     {
591 
592                         /* Write the next block to the firmware.  */
593                         status = dfu -> ux_slave_class_dfu_write(dfu, request_value,
594                                                             transfer_request -> ux_slave_transfer_request_data_pointer,
595                                                             request_length,
596                                                             &actual_length);
597 
598                         /* Application can actively reject and set error state.  */
599                         if (status != UX_SUCCESS)
600                         {
601                             _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
602                             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
603                             break;
604                         }
605 
606                         /* In the system, state the DFU state machine to dfu DOWNLOAD SYNC.  */
607                         _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_DNLOAD_SYNC;
608                     }
609 
610                     break;
611 
612                 case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
613 
614                     /* Send a notification to the application.  */
615                     dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_DOWNLOAD);
616 
617                     /* In the system, state the DFU state machine to dfu IDLE.  */
618                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
619 
620                     break;
621 
622                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
623 
624 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
625                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
626 #else
627 
628                     /* Fill the status data payload.  First with status.  */
629                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
630 
631                     /* Poll time out value is set to 1ms.  */
632                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
633                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
634                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
635 
636                     /* Next state.  */
637                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
638 
639                     /* String index set to 0.  */
640                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
641 #endif
642 
643                     /* We have a request to obtain the status of the DFU instance. */
644                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
645 
646                     break;
647 
648                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
649 
650                     /* Fill the status data payload.  First with state.  */
651                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
652 
653                     /* We have a request to obtain the status of the DFU instance. */
654                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
655 
656                     break;
657 
658                 default:
659 
660                     /* Unknown function. Stall the endpoint.  */
661                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
662 
663                     /* In the system, state the DFU state machine to dfu ERROR.  */
664                        _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
665 
666                     break;
667             }
668 
669             break;
670 
671         case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_SYNC         :
672 
673             /* Here we process only the request we can accept in the MANIFEST SYNCH state.  */
674             switch (request)
675             {
676 
677                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
678 
679 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
680                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_TRUE,
681                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET,
682                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST,
683                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR);
684                     if ((_ux_system_slave -> ux_system_slave_device_dfu_state_machine ==
685                             UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET) &&
686                         (_ux_system_slave -> ux_system_slave_device_dfu_capabilities &
687                             UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH))
688                     {
689 
690                         /* Wake up the DFU thread and send a detach request..  */
691                         _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
692                     }
693 #else
694 
695                     /* Check if the device is still buys performing the write. Write could be delayed.  */
696                     dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
697 
698                     /* Check status of device.  */
699                     switch (media_status)
700                     {
701 
702                         case     UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK        :
703 
704                             /* Set the next state for wait reset and no error status.  */
705                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
706                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST_WAIT_RESET;
707 
708                             /* Check who is responsible for the RESET.  */
709                             if (_ux_system_slave -> ux_system_slave_device_dfu_capabilities &  UX_SLAVE_CLASS_DFU_CAPABILITY_WILL_DETACH)
710                             {
711 
712                                 /* Wake up the DFU thread and send a detach request..  */
713                                 _ux_device_class_dfu_event_flags_set(dfu, UX_DEVICE_CLASS_DFU_THREAD_EVENT_DISCONNECT);
714 
715                             }
716 
717                             break;
718 
719                         case     UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY    :
720 
721                             /* Set the next state for busy but no error status.  */
722                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_OK ;
723                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_MANIFEST;
724                             break;
725 
726                         case    UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR   :
727 
728                             /* Set the next state for busy and error status.  */
729                             dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_STATUS_ERROR_WRITE ;
730                                _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR;
731                             break;
732                     }
733 
734                     /* Fill the status data payload.  First with status.  */
735                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
736 
737                     /* Poll time out value is set to 1ms.  */
738                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
739                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
740                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
741 
742                     /* Next state.  */
743                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
744 
745                     /* String index set to 0.  */
746                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
747 #endif
748 
749                     /* We have a request to obtain the status of the DFU instance. */
750                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
751 
752                     break;
753 
754                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
755 
756                     /* Fill the status data payload.  First with state.  */
757                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
758 
759                     /* We have a request to obtain the status of the DFU instance. */
760                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
761 
762                     break;
763 
764                 default:
765 
766                     /* Unknown function. Stall the endpoint.  */
767                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
768                     break;
769             }
770 
771             break;
772 
773         case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_ERROR         :
774 
775             /* Here we process only the request we can accept in the ERROR state.  */
776             switch (request)
777             {
778 
779 #ifdef UX_DEVICE_CLASS_DFU_ERROR_GET_ENABLE
780                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
781 
782                     /* Fill the status data payload.  First with status.  */
783                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
784 
785                     /* Poll time out value is set to 1ms.  */
786                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = 1;
787                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = 0;
788                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = 0;
789 
790                     /* Next state.  */
791                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
792 
793                     /* String index set to 0.  */
794                     *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
795 
796                     /* We have a request to obtain the status of the DFU instance. */
797                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
798 
799                     break;
800 
801                 case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
802 
803                     /* Fill the status data payload.  First with state.  */
804                     *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
805 
806                     /* We have a request to obtain the status of the DFU instance. */
807                     _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
808 
809                     break;
810 #endif
811 
812                 case UX_SLAVE_CLASS_DFU_COMMAND_CLEAR_STATUS :
813 
814                     /* In the system, state the DFU state machine to dfu IDLE.  */
815                     dfu -> ux_slave_class_dfu_status = UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK;
816                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
817 
818                     break;
819 
820                 default:
821 
822                     /* Unknown function. Stall the endpoint.  */
823                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
824                     break;
825 
826             }
827 
828             break;
829 
830 #ifndef UX_DEVICE_CLASS_DFU_UPLOAD_DISABLE
831         case UX_SLAVE_CLASS_DFU_STATUS_STATE_DFU_UPLOAD_IDLE: /* bitCanUpload == 1.  */
832 
833             /* Here we process only the request we can accept in the DFU mode UPLOAD IDLE state.  */
834             switch (request)
835             {
836 
837             case UX_SLAVE_CLASS_DFU_COMMAND_UPLOAD:
838 
839                 /* Check if length > wTransferSize (we can support max of control buffer size).  */
840                 if (request_length > UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH)
841                 {
842                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
843                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
844                     break;
845                 }
846 
847                 /* Length 0 case undefined, just keep state.  */
848                 if (request_length == 0)
849                     break;
850 
851                 /* We received a UPLOAD command with length > 0.  */
852 
853                 /* Read the next block from the firmware.  */
854                 status = dfu -> ux_slave_class_dfu_read(dfu, request_value,
855                                                     transfer_request -> ux_slave_transfer_request_data_pointer,
856                                                     request_length,
857                                                     &actual_length);
858 
859                 /* Application can actively reject and set error state.  */
860                 if (status != UX_SUCCESS)
861                 {
862                     _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
863                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
864                     break;
865                 }
866 
867                 /* If it's short frame, switch to dfu IDLE.  */
868                 if (actual_length < request_length)
869                 {
870 
871                     /* Send a notification to the application.  */
872                     dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_END_UPLOAD);
873 
874                     /* In the system, state the DFU state machine to dfu IDLE.  */
875                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
876                 }
877 
878                 /* We have a request to upload DFU firmware block. */
879                 _ux_device_stack_transfer_request(transfer_request, actual_length, request_length);
880 
881                 break;
882 
883             case UX_SLAVE_CLASS_DFU_COMMAND_ABORT :
884 
885                     /* Send a notification to the application.  */
886                     dfu -> ux_slave_class_dfu_notify(dfu, UX_SLAVE_CLASS_DFU_NOTIFICATION_ABORT_UPLOAD);
887 
888                     /* In the system, state the DFU state machine to dfu IDLE.  */
889                     _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_IDLE;
890 
891                     break;
892 
893             case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATUS :
894 
895 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
896                     _ux_device_class_dfu_status_get(dfu, transfer_request, UX_FALSE, 0, 0, 0);
897 #else
898 
899                 /* Fill the status data payload.  First with status.  */
900                 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) dfu -> ux_slave_class_dfu_status;
901 
902                 /* Poll time out value is set to 1ms.  */
903                 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
904                 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
905                 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT);
906 
907                 /* Next state.  */
908                 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
909 
910                 /* String index set to 0.  */
911                 *(transfer_request -> ux_slave_transfer_request_data_pointer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
912 #endif
913 
914                 /* We have a request to obtain the status of the DFU instance. */
915                 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATUS_LENGTH);
916 
917                 break;
918 
919             case UX_SLAVE_CLASS_DFU_COMMAND_GET_STATE :
920 
921                 /* Fill the status data payload.  First with state.  */
922                 *transfer_request -> ux_slave_transfer_request_data_pointer = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
923 
924                 /* We have a request to obtain the status of the DFU instance. */
925                 _ux_device_stack_transfer_request(transfer_request, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH, UX_SLAVE_CLASS_DFU_GET_STATE_LENGTH);
926 
927                 break;
928 
929             default:
930 
931                 /* Unknown function. Stall the endpoint.  */
932                 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
933 
934                 /* In the system, state the DFU state machine to dfu ERROR.  */
935                 _ux_system_slave -> ux_system_slave_device_dfu_state_machine = UX_SYSTEM_DFU_STATE_DFU_ERROR;
936 
937                 break;
938             }
939 
940             break;
941 #endif
942 
943         default:
944 
945             /* Unknown state. Should not happen.  */
946             return(UX_ERROR);
947     }
948 
949     return(UX_SUCCESS);
950 }
951 
952 #if UX_DEVICE_CLASS_DFU_STATUS_MODE == 1
_ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU * dfu,UX_SLAVE_TRANSFER * transfer,UCHAR move_state,UCHAR state_ok,UCHAR state_busy,UCHAR state_error)953 static inline VOID _ux_device_class_dfu_status_get(UX_SLAVE_CLASS_DFU *dfu,
954     UX_SLAVE_TRANSFER *transfer,
955     UCHAR move_state,
956     UCHAR state_ok, UCHAR state_busy, UCHAR state_error)
957 {
958 ULONG media_status = ((UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK) |
959                         (UX_SLAVE_CLASS_DFU_STATUS_OK << 4) |
960                         (UX_DEVICE_CLASS_DFU_STATUS_POLLTIMEOUT << 8));
961 UCHAR *buffer = transfer -> ux_slave_transfer_request_data_pointer;
962 ULONG dfu_status, dfu_polltimeout;
963 
964     /* Get status from application.  */
965     dfu -> ux_slave_class_dfu_get_status(dfu, &media_status);
966 
967     /* Extract bStatus and bwPollTimeout.  */
968     dfu_status = (media_status >> 4) & 0xFu;
969     dfu_polltimeout = (media_status >> 8) & 0xFFFFFFu;
970     dfu -> ux_slave_class_dfu_status = dfu_status;
971 
972     /* Move state based on returned status.  */
973     if (move_state)
974     {
975 
976         /* OK/BUSY/ERROR ? */
977         switch((media_status & 0xF))
978         {
979         case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_OK:
980             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_ok;
981             break;
982         case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_BUSY:
983             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_busy;
984             break;
985         case UX_SLAVE_CLASS_DFU_MEDIA_STATUS_ERROR:
986         default:
987             _ux_system_slave -> ux_system_slave_device_dfu_state_machine = state_error;
988             break;
989         }
990     }
991 
992     /* Fill the status data payload.  First with status.  */
993     *buffer = (UCHAR) dfu_status;
994 
995     /* Poll time out value is set to 1ms.  */
996     *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT) = UX_DW0(dfu_polltimeout);
997     *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 1) = UX_DW1(dfu_polltimeout);
998     *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_POLL_TIMEOUT + 2) = UX_DW2(dfu_polltimeout);
999 
1000     /* Next state.  */
1001     *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STATE) = (UCHAR) _ux_system_slave -> ux_system_slave_device_dfu_state_machine;
1002 
1003     /* String index set to 0.  */
1004     *(buffer + UX_SLAVE_CLASS_DFU_GET_STATUS_STRING) = 0;
1005 }
1006 #endif
1007