1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Device CCID Class                                                   */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define UX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "ux_api.h"
28 #include "ux_device_class_ccid.h"
29 #include "ux_device_stack.h"
30 
31 
32 #if defined(UX_DEVICE_STANDALONE)
33 
34 static inline UINT _ux_device_class_ccid_cmd_task(UX_DEVICE_CLASS_CCID *ccid);
35 static inline UINT _ux_device_class_ccid_rsp_task(UX_DEVICE_CLASS_CCID *ccid);
36 
37 
38 /**************************************************************************/
39 /*                                                                        */
40 /*  FUNCTION                                               RELEASE        */
41 /*                                                                        */
42 /*    _ux_device_class_ccid_tasks_run                     PORTABLE C      */
43 /*                                                           6.2.1        */
44 /*  AUTHOR                                                                */
45 /*                                                                        */
46 /*    Chaoqiong Xiao, Microsoft Corporation                               */
47 /*                                                                        */
48 /*  DESCRIPTION                                                           */
49 /*                                                                        */
50 /*    This function is the background task of the CCID.                   */
51 /*                                                                        */
52 /*    It's for standalone mode.                                           */
53 /*                                                                        */
54 /*  INPUT                                                                 */
55 /*                                                                        */
56 /*    instance                              Pointer to CCID class         */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    State machine status                                                */
61 /*    UX_STATE_EXIT                         Device not configured         */
62 /*    UX_STATE_IDLE                         No streaming transfer running */
63 /*    UX_STATE_WAIT                         Streaming transfer running    */
64 /*                                                                        */
65 /*  CALLS                                                                 */
66 /*                                                                        */
67 /*    ux_device_class_ccid_notify_task_run Run interrupt notify task      */
68 /*    ux_device_class_ccid_runner_task_run Run slot command runner task   */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    USBX Device Stack                                                   */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  03-08-2023     Chaoqiong Xiao           Initial Version 6.2.1         */
79 /*                                                                        */
80 /**************************************************************************/
_ux_device_class_ccid_tasks_run(VOID * instance)81 UINT _ux_device_class_ccid_tasks_run(VOID *instance)
82 {
83 UX_SLAVE_DEVICE                 *device;
84 UX_DEVICE_CLASS_CCID            *ccid;
85 ULONG                           run_count = 0;
86 
87 
88     /* Get ccid instance.  */
89     ccid = (UX_DEVICE_CLASS_CCID *) instance;
90 
91     /* Get the pointer to the device.  */
92     device =  &_ux_system_slave -> ux_system_slave_device;
93 
94     /* Check if the device is configured.  */
95     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
96         return(UX_STATE_EXIT);
97 
98     /* Bulk OUT command process.  */
99     if (_ux_device_class_ccid_cmd_task(ccid) != UX_STATE_IDLE)
100         run_count ++;
101 
102     /* Bulk IN response process.  */
103     if (_ux_device_class_ccid_rsp_task(ccid) != UX_STATE_IDLE)
104         run_count ++;
105 
106     /* Interrupt IN notification process.  */
107     if (_ux_device_class_ccid_notify_task_run(ccid) != UX_STATE_IDLE)
108         run_count ++;
109 
110     /* Runner tasks process.  */
111     if (_ux_device_class_ccid_runner_task_run(ccid) != UX_STATE_IDLE)
112         run_count ++;
113 
114     return((run_count > 0) ? UX_STATE_WAIT : UX_STATE_IDLE);
115 }
_ux_device_class_ccid_cmd_task(UX_DEVICE_CLASS_CCID * ccid)116 static inline UINT _ux_device_class_ccid_cmd_task(UX_DEVICE_CLASS_CCID *ccid)
117 {
118 UX_INTERRUPT_SAVE_AREA
119 INT                                                 immediate_state = UX_TRUE;
120 UINT                                                status;
121 UX_DEVICE_CLASS_CCID_SLOT                           *slot;
122 UX_DEVICE_CLASS_CCID_RUNNER                         *runner = UX_NULL;
123 UX_DEVICE_CLASS_CCID_PARAMETER                      *parameter;
124 UX_DEVICE_CLASS_CCID_MESSAGES                       messages;
125 UX_SLAVE_ENDPOINT                                   *endpoint;
126 UX_SLAVE_TRANSFER                                   *transfer_cmd;
127 UX_DEVICE_CLASS_CCID_MESSAGE_HEADER                 *cmd;
128 UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER   *rsp;
129 UX_DEVICE_CLASS_CCID_COMMAND_SETT                   *cmd_sett;
130 CHAR                                                cmd_index;
131 UX_DEVICE_CLASS_CCID_HANDLE                         *handles;
132 
133 
134     /* Check endpoint.  */
135     endpoint = ccid -> ux_device_class_ccid_endpoint_out;
136     if (endpoint == UX_NULL)
137     {
138         ccid -> ux_device_class_ccid_cmd_state = UX_STATE_RESET;
139         return(UX_STATE_EXIT);
140     }
141     transfer_cmd = &endpoint -> ux_slave_endpoint_transfer_request;
142 
143     /* Get running settings.  */
144     parameter = &ccid -> ux_device_class_ccid_parameter;
145 
146     /* Wait Bulk-OUT command.  */
147     while(immediate_state)
148     {
149 
150         /* Process state.  */
151         switch(ccid -> ux_device_class_ccid_cmd_state)
152         {
153         case UX_DEVICE_CLASS_CCID_CMD_START:
154 
155             /* Prepare transfer, next: wait.  */
156             ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_WAIT;
157             UX_SLAVE_TRANSFER_STATE_RESET(transfer_cmd);
158 
159             /* Fall through.  */
160         case UX_DEVICE_CLASS_CCID_CMD_WAIT:
161             status = _ux_device_stack_transfer_run(transfer_cmd,
162                     parameter -> ux_device_class_ccid_max_transfer_length,
163                     parameter -> ux_device_class_ccid_max_transfer_length);
164 
165             /* Error case.  */
166             if (status < UX_STATE_NEXT)
167             {
168 
169                 ccid -> ux_device_class_ccid_cmd_state = UX_STATE_RESET;
170                 return(UX_STATE_ERROR);
171             }
172 
173             /* Success case.  */
174             if (status == UX_STATE_NEXT)
175             {
176 
177                 /* Check transfer results.  */
178                 if ((transfer_cmd -> ux_slave_transfer_request_completion_code != UX_SUCCESS) ||
179                     (transfer_cmd -> ux_slave_transfer_request_actual_length <
180                         UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH) ||
181                     (transfer_cmd -> ux_slave_transfer_request_actual_length >
182                         parameter -> ux_device_class_ccid_max_transfer_length))
183                 {
184 
185                     ccid -> ux_device_class_ccid_cmd_state = UX_STATE_RESET;
186                     return(UX_STATE_ERROR);
187                 }
188 
189                 /* Access to CCID command message header.  */
190                 cmd = (UX_DEVICE_CLASS_CCID_MESSAGE_HEADER *)
191                                 transfer_cmd -> ux_slave_transfer_request_data_pointer;
192 
193                 /* Get command setting index.  */
194                 cmd_sett = (UX_DEVICE_CLASS_CCID_COMMAND_SETT *)_ux_device_class_ccid_command_sett;
195                 for (cmd_index = 0; cmd_index < UX_DEVICE_CLASS_CCID_N_COMMANDS;)
196                 {
197                     if (cmd -> bMessageType ==
198                         cmd_sett -> ux_device_class_ccid_command_sett_command_type)
199                         break;
200 
201                     /* Next command setting.  */
202                     cmd_sett ++;
203                     cmd_index ++;
204                 }
205 
206                 /* Save command index for further actions.  */
207                 ccid -> ux_device_class_ccid_cmd_index = cmd_index;
208 
209                 /* Next: lock and update status.  */
210                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_LOCK;
211                 continue;
212             }
213 
214             /* Wait.  */
215             return(UX_STATE_WAIT);
216 
217         case UX_DEVICE_CLASS_CCID_CMD_LOCK:
218             UX_DISABLE
219             if (ccid -> ux_device_class_ccid_flags & UX_DEVICE_CLASS_CCID_FLAG_LOCK)
220             {
221                 UX_RESTORE
222                 return(UX_STATE_WAIT);
223             }
224             ccid -> ux_device_class_ccid_flags |= UX_DEVICE_CLASS_CCID_FLAG_LOCK;
225             UX_RESTORE
226 
227             /* Fall through.  */
228         case UX_DEVICE_CLASS_CCID_CMD_PROCESS:
229             cmd = (UX_DEVICE_CLASS_CCID_MESSAGE_HEADER *)
230                             transfer_cmd -> ux_slave_transfer_request_data_pointer;
231             cmd_index = ccid -> ux_device_class_ccid_cmd_index;
232             cmd_sett = (UX_DEVICE_CLASS_CCID_COMMAND_SETT *)&_ux_device_class_ccid_command_sett[(INT)cmd_index];
233             handles = (UX_DEVICE_CLASS_CCID_HANDLE *)parameter -> ux_device_class_ccid_handles;
234 
235             /* Initialize response.  */
236             rsp = (UX_DEVICE_CLASS_CCID_RDR_TO_PC_SLOT_STATUS_HEADER *)
237                                                 ccid -> ux_device_class_ccid_header;
238             _ux_utility_memory_set(rsp, 0, UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH); /* Use case of memset is verified. */
239             rsp -> bMessageType = cmd_sett -> ux_device_class_ccid_command_sett_response_type;
240             rsp -> bSlot        = cmd -> bSlot;
241             rsp -> bSeq         = cmd -> bSeq;
242 
243             /* Check command support (0,1,0).  */
244             if (rsp -> bMessageType == 0 ||
245                 handles[(INT)cmd_sett -> ux_device_class_ccid_command_sett_handle_index] == UX_NULL)
246             {
247 
248                 /* Response: command not supported (0,1,0).  */
249                 rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(0, 1);
250                 _ux_device_class_ccid_unlock(ccid);
251 
252                 /* Next: response.  */
253                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_RSP_START;
254                 return(UX_STATE_IDLE);
255             }
256 
257             /* check Slot exist (2,1,5).  */
258             if (cmd -> bSlot >= parameter -> ux_device_class_ccid_max_n_slots)
259             {
260 
261                 /* Response: Slot not exist.  */
262                 rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(2, 1);
263                 rsp -> bError  = 5;
264                 _ux_device_class_ccid_unlock(ccid);
265 
266                 /* Next: response.  */
267                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_RSP_START;
268                 return(UX_STATE_IDLE);
269             }
270 
271             /* Get slot instance for later usage (optimized only 1 slot).  */
272             slot = ccid -> ux_device_class_ccid_slots;
273 
274             /* Initialize response status from slot status.  */
275             rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
276                                 slot -> ux_device_class_ccid_slot_icc_status, 0);
277 
278             /* Initialize response clock status.  */
279             if (cmd_sett -> ux_device_class_ccid_command_sett_response_type == 0x81)
280                 rsp -> bClockStatus = slot -> ux_device_class_ccid_slot_clock_status;
281 
282             /* Abort command
283                 - return slot status(OK) anyway
284                 - clear aborting status
285                Aborting
286                 - return slot status(ABORTED)
287                Other command (except SetDataRateAndClockFrequency)
288                 - Check busy  */
289 
290             /* Abort command is handled differently.  */
291             if (cmd -> bMessageType != UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT ||
292                 !slot -> ux_device_class_ccid_slot_aborting)
293             {
294 
295                 /* Check if slot is idle (optimized one slot).  */
296                 runner = ccid -> ux_device_class_ccid_runners;
297                 if (ccid -> ux_device_class_ccid_n_busy == 0)
298                 {
299 
300                     /* It's not possible no runner found here, just execute runner.  */
301 
302                     /* Runner is busy now.  */
303                     runner -> ux_device_class_ccid_runner_slot = (CHAR)cmd->bSlot;
304                     runner -> ux_device_class_ccid_runner_command_index = cmd_index;
305                     ccid -> ux_device_class_ccid_n_busy ++;
306 
307                     /* Create a copy of command and response header.  */
308                     _ux_utility_memory_copy(runner -> ux_device_class_ccid_runner_command,
309                                             cmd,
310                                             transfer_cmd -> ux_slave_transfer_request_actual_length); /* Use case of memcpy is verified. */
311                     _ux_utility_memory_copy(runner -> ux_device_class_ccid_runner_response,
312                                             rsp, UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH); /* Use case of memcpy is verified. */
313 
314                     /* Pre-process of command done.  */
315                     _ux_device_class_ccid_unlock(ccid);
316 
317                     /* Update runner state to start.  */
318                     runner -> ux_device_class_ccid_runner_state = UX_DEVICE_CLASS_CCID_RUNNER_START;
319 
320                     /* Command processed, command is allowed when runner is executing.  */
321                     ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_START;
322                     return(UX_STATE_WAIT);
323                 }
324 
325                 /* Response: Slot Status(busy), optimized for 1 slot.  */
326                 rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
327                                 slot -> ux_device_class_ccid_slot_icc_status, 1);
328                 rsp -> bError = UX_DEVICE_CLASS_CCID_CMD_SLOT_BUSY;
329                 _ux_device_class_ccid_unlock(ccid);
330 
331                 /* Next: response (status busy).  */
332                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_RSP_START;
333                 continue;
334             }
335 
336             /* We are here when we see Abort command, or aborting.
337                 - Abort command : slot status (ok/fail)
338                 - Aborting : slot status (CMD_ABORTED)
339             */
340 
341             /* Abort command.  */
342             if (cmd -> bMessageType == UX_DEVICE_CLASS_CCID_PC_TO_RDR_ABORT)
343             {
344 
345                 /* Check sequence.  */
346                 if (cmd -> bSeq != slot -> ux_device_class_ccid_slot_aborting_seq)
347                 {
348 
349                     /* Response: sequence error.  */
350                     rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
351                                     slot -> ux_device_class_ccid_slot_icc_status, 1);
352                     rsp -> bError  = 6;
353                 }
354                 else
355                 {
356 
357                     /* Aborting.  */
358                     if (slot -> ux_device_class_ccid_slot_aborting)
359                     {
360 
361                         /* Call abort handle.  */
362                         messages.ux_device_class_ccid_messages_pc_to_rdr = (VOID *)cmd;
363                         messages.ux_device_class_ccid_messages_rdr_to_pc = (VOID *)rsp;
364                         messages.ux_device_class_ccid_messages_rdr_to_pc_length = 0;
365                         parameter -> ux_device_class_ccid_handles ->
366                                 ux_device_class_ccid_handles_abort(cmd -> bSlot, &messages);
367 
368                         /* Status(OK)  */
369                         rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
370                                         slot -> ux_device_class_ccid_slot_icc_status, 0);
371 
372                         /* Free runner (optimized only 1 slot).  */
373                         runner = ccid -> ux_device_class_ccid_runners;
374                         runner -> ux_device_class_ccid_runner_slot = -1;
375                         ccid -> ux_device_class_ccid_n_busy --;
376 
377                         /* Clear slot busy and aborting.  */
378                         slot -> ux_device_class_ccid_slot_runner = -1;
379                         slot -> ux_device_class_ccid_slot_aborting = UX_FALSE;
380                     }
381                     else
382                     {
383 
384                         /* Status(CMD_NOT_ABORTED)?  */
385                         rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
386                                         slot -> ux_device_class_ccid_slot_icc_status, 1);
387                         rsp -> bError  = UX_DEVICE_CLASS_CCID_CMD_SLOT_BUSY;
388                     }
389                 }
390 
391                 _ux_device_class_ccid_unlock(ccid);
392 
393                 /* Next: response.  */
394                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_RSP_START;
395                 return(UX_STATE_IDLE);
396             }
397 
398             /* Aborting.  */
399 
400             /* Response: Slot Status(aborted).  */
401             rsp -> bStatus = UX_DEVICE_CLASS_CCID_SLOT_STATUS(
402                                 slot -> ux_device_class_ccid_slot_icc_status, 1);
403             rsp -> bError = UX_DEVICE_CLASS_CCID_CMD_ABORTED;
404 
405             _ux_device_class_ccid_unlock(ccid);
406 
407             /* Next: response.  */
408             ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_RSP_START;
409 
410             /* Fall through.  */
411         case UX_DEVICE_CLASS_CCID_CMD_RSP_START:
412 
413             /* Wait until rsponse task is idle.  */
414             if (ccid -> ux_device_class_ccid_rsp_state != UX_DEVICE_CLASS_CCID_RSP_IDLE)
415                 return(UX_STATE_WAIT);
416 
417             /* Start response.  */
418             _ux_device_class_ccid_response(ccid,
419                                     ccid -> ux_device_class_ccid_header,
420                                     UX_DEVICE_CLASS_CCID_MESSAGE_HEADER_LENGTH);
421 
422             /* Command is idle and started after response sent.  */
423             ccid -> ux_device_class_ccid_flags |= UX_DEVICE_CLASS_CCID_FLAG_CMD_RSP;
424             ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_IDLE;
425 
426             /* Fall through.  */
427         case UX_DEVICE_CLASS_CCID_CMD_IDLE:
428             return(UX_STATE_IDLE);
429 
430         default:
431             break;
432         }
433 
434         /* Break the loop.  */
435         immediate_state = UX_FALSE;
436     }
437 
438     return(UX_STATE_WAIT);
439 }
_ux_device_class_ccid_rsp_task(UX_DEVICE_CLASS_CCID * ccid)440 static inline UINT _ux_device_class_ccid_rsp_task(UX_DEVICE_CLASS_CCID *ccid)
441 {
442 UX_INTERRUPT_SAVE_AREA
443 INT                                                 immediate_state = UX_TRUE;
444 UINT                                                status;
445 UX_SLAVE_ENDPOINT                                   *endpoint;
446 UX_SLAVE_TRANSFER                                   *transfer_rsp;
447 ULONG                                               length;
448 
449     /* Check endpoint.  */
450     endpoint = ccid -> ux_device_class_ccid_endpoint_in;
451     if (endpoint == UX_NULL)
452     {
453         ccid -> ux_device_class_ccid_cmd_state = UX_STATE_RESET;
454         return(UX_STATE_EXIT);
455     }
456     transfer_rsp = &endpoint -> ux_slave_endpoint_transfer_request;
457 
458     while(immediate_state)
459     {
460 
461         switch(ccid -> ux_device_class_ccid_rsp_state)
462         {
463 
464         case UX_DEVICE_CLASS_CCID_RSP_IDLE:
465             return(UX_STATE_IDLE);
466 
467         case UX_DEVICE_CLASS_CCID_RSP_START:
468             ccid -> ux_device_class_ccid_rsp_state = UX_DEVICE_CLASS_CCID_RSP_WAIT;
469 
470             /* Fall through.  */
471         case UX_DEVICE_CLASS_CCID_RSP_WAIT:
472 
473             /* Run bulk IN transfer.  */
474             length = transfer_rsp -> ux_slave_transfer_request_requested_length;
475             status = _ux_device_stack_transfer_run(transfer_rsp, length, length);
476 
477             /* Error/success case.  */
478             if (status <= UX_STATE_NEXT)
479             {
480 
481                 /* Transfer is done.  */
482 
483                 /* Check if it's command response or runner response.
484                    After runner response status needs update (optimized 1 slot).  */
485                 if (ccid -> ux_device_class_ccid_flags & UX_DEVICE_CLASS_CCID_FLAG_CMD_RSP)
486                 {
487                     ccid -> ux_device_class_ccid_flags &= ~UX_DEVICE_CLASS_CCID_FLAG_CMD_RSP;
488 
489                     /* CMD -RSP: done.  */
490                     ccid -> ux_device_class_ccid_rsp_state = UX_DEVICE_CLASS_CCID_RSP_DONE;
491                     continue;
492                 }
493 
494                 /* CMD - RUNNER - RSP : Update status.  */
495                 ccid -> ux_device_class_ccid_rsp_state = UX_DEVICE_CLASS_CCID_RSP_LOCK;
496                 continue;
497 
498             }
499 
500             /* Wait transfer.  */
501             return(UX_STATE_WAIT);
502 
503         case UX_DEVICE_CLASS_CCID_RSP_LOCK:
504             UX_DISABLE
505             if (ccid -> ux_device_class_ccid_flags & UX_DEVICE_CLASS_CCID_FLAG_LOCK)
506             {
507                 UX_RESTORE
508                 return(UX_STATE_WAIT);
509             }
510             ccid -> ux_device_class_ccid_flags |= UX_DEVICE_CLASS_CCID_FLAG_LOCK;
511             UX_RESTORE
512 
513             /* Fall through.  */
514         case UX_DEVICE_CLASS_CCID_RSP_UPDATE:
515 
516             /* Free runner and clear busy slot (optimized 1 slot).  */
517             if (ccid -> ux_device_class_ccid_n_busy > 0)
518                 ccid -> ux_device_class_ccid_n_busy --;
519 
520             /* Unlock.  */
521             ccid -> ux_device_class_ccid_flags &= ~UX_DEVICE_CLASS_CCID_FLAG_LOCK;
522 
523             /* Fall through.  */
524         case UX_DEVICE_CLASS_CCID_RSP_DONE:
525 
526             /* Start command.  */
527             if (ccid -> ux_device_class_ccid_cmd_state == UX_DEVICE_CLASS_CCID_CMD_IDLE)
528                 ccid -> ux_device_class_ccid_cmd_state = UX_DEVICE_CLASS_CCID_CMD_START;
529 
530             /* Next: idle.  */
531             ccid -> ux_device_class_ccid_rsp_state = UX_DEVICE_CLASS_CCID_RSP_IDLE;
532             return(UX_STATE_IDLE);
533 
534         default:
535             break;
536         }
537 
538         /* Break the loop.  */
539         immediate_state = UX_FALSE;
540     }
541 
542     /* Unhandled state.  */
543     return(UX_STATE_EXIT);
544 }
545 
546 #endif