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 CCID 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_ccid.h"
28 #include "ux_device_stack.h"
29 
30 
31 #if defined(UX_DEVICE_STANDALONE)
32 
33 
34 /**************************************************************************/
35 /*                                                                        */
36 /*  FUNCTION                                               RELEASE        */
37 /*                                                                        */
38 /*    _ux_device_class_ccid_notify_task_run               PORTABLE C      */
39 /*                                                           6.2.1        */
40 /*  AUTHOR                                                                */
41 /*                                                                        */
42 /*    Chaoqiong Xiao, Microsoft Corporation                               */
43 /*                                                                        */
44 /*  DESCRIPTION                                                           */
45 /*                                                                        */
46 /*    This function is the background task of the CCID.                   */
47 /*                                                                        */
48 /*    It's for standalone mode.                                           */
49 /*                                                                        */
50 /*  INPUT                                                                 */
51 /*                                                                        */
52 /*    ccid                                  Pointer to CCID class         */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    State machine status                                                */
57 /*    UX_STATE_EXIT                         Device not configured         */
58 /*    UX_STATE_IDLE                         No streaming transfer running */
59 /*    UX_STATE_WAIT                         Streaming transfer running    */
60 /*                                                                        */
61 /*  CALLS                                                                 */
62 /*                                                                        */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    USBX Device Stack                                                   */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  03-08-2023     Chaoqiong Xiao           Initial Version 6.2.1         */
73 /*                                                                        */
74 /**************************************************************************/
_ux_device_class_ccid_notify_task_run(UX_DEVICE_CLASS_CCID * ccid)75 UINT _ux_device_class_ccid_notify_task_run(UX_DEVICE_CLASS_CCID *ccid)
76 {
77 UX_INTERRUPT_SAVE_AREA
78 UX_SLAVE_DEVICE                                     *device;
79 UX_DEVICE_CLASS_CCID_SLOT                           *slot;
80 UX_SLAVE_ENDPOINT                                   *endpoint;
81 UX_SLAVE_TRANSFER                                   *transfer;
82 UCHAR                                               *buffer;
83 ULONG                                               length;
84 UCHAR                                               icc_mask;
85 INT                                                 immediate_state = UX_TRUE;
86 UINT                                                status;
87 
88 
89     /* Get the pointer to the device.  */
90     device =  &_ux_system_slave -> ux_system_slave_device;
91 
92     /* Check if the device is configured.  */
93     if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
94         return(UX_STATE_EXIT);
95 
96     /* Interrupt IN endpoint get (it's optional so it's OK not found).  */
97     endpoint = ccid -> ux_device_class_ccid_endpoint_notify;
98     if (endpoint == UX_NULL)
99         return(UX_STATE_IDLE);
100     transfer = &endpoint -> ux_slave_endpoint_transfer_request;
101 
102     /* Process states.  */
103     while(immediate_state)
104     {
105 
106         /* Check states.  */
107         switch(ccid -> ux_device_class_ccid_notify_state)
108         {
109 
110         case UX_DEVICE_CLASS_CCID_NOTIFY_IDLE:
111             return(UX_STATE_IDLE);
112 
113         case UX_DEVICE_CLASS_CCID_NOTIFY_LOCK:
114 
115             /* Wait until status locked.  */
116             UX_DISABLE
117             if (ccid -> ux_device_class_ccid_flags & UX_DEVICE_CLASS_CCID_FLAG_LOCK)
118             {
119                 UX_RESTORE
120                 return(UX_STATE_WAIT);
121             }
122             ccid -> ux_device_class_ccid_flags |= UX_DEVICE_CLASS_CCID_FLAG_LOCK;
123             UX_RESTORE
124 
125             /* Next: check if there is notification pending.  */
126             ccid -> ux_device_class_ccid_notify_state = UX_DEVICE_CLASS_CCID_NOTIFY_START;
127 
128             /* Fall through.  */
129         case UX_DEVICE_CLASS_CCID_NOTIFY_START:
130 
131             /* Check slot notifications (optimized for only one slot).  */
132             /* Get slot.  */
133             slot = ccid -> ux_device_class_ccid_slots;
134 
135             /* Build slot change/hardware error message.  */
136             buffer = transfer -> ux_slave_transfer_request_data_pointer;
137             length = 0;
138 
139             /* By default no message.  */
140             buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] = 0;
141 
142             /* Check hardware error notification.  */
143             if (slot -> ux_device_class_ccid_slot_flags &
144                 UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_HW_ERROR)
145             {
146                 slot -> ux_device_class_ccid_slot_flags &=
147                                 (UCHAR)~UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_HW_ERROR;
148                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] =
149                                 UX_DEVICE_CLASS_CCID_RDR_TO_PC_HARDWARE_ERROR;
150                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_SLOT] = 0;
151                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_SEQ] =
152                                 slot -> ux_device_class_ccid_slot_hw_error_seq;
153                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_HW_ERROR_CODE] =
154                                 slot -> ux_device_class_ccid_slot_hw_error;
155                 length = 4;
156             }
157 
158             /* Check slot change notification.  */
159             else if (slot -> ux_device_class_ccid_slot_flags &
160                 UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_CHANGE)
161             {
162                 slot -> ux_device_class_ccid_slot_flags &=
163                             (UCHAR)~UX_DEVICE_CLASS_CCID_FLAG_NOTIFY_CHANGE;
164 
165                 /* Message type.  */
166                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] =
167                     UX_DEVICE_CLASS_CCID_RDR_TO_PC_NOTIFY_SLOT_CHANGE;
168 
169                 /* Slot state bit.  */
170                 icc_mask = (UCHAR)((slot -> ux_device_class_ccid_slot_icc_status ==
171                         UX_DEVICE_CLASS_CCID_SLOT_STATUS_ICC_NOT_PRESENT) ?
172                         0u : 1u);
173 
174                 /* Slot change bit.  */
175                 icc_mask |= 0x02u;
176 
177                 /* Save slot state and change.  */
178                 buffer[UX_DEVICE_CLASS_CCID_OFFSET_SLOT_ICC_STATE] = icc_mask;
179 
180                 length = 2;
181             }
182 
183             /* Unlock status.  */
184             ccid -> ux_device_class_ccid_flags &= ~UX_DEVICE_CLASS_CCID_FLAG_LOCK;
185 
186             /* Check message to see if there is message to send.  */
187             if (buffer[UX_DEVICE_CLASS_CCID_OFFSET_MESSAGE_TYPE] == 0)
188             {
189 
190                 /* There is no pending meesage, -> idle.  */
191                 ccid -> ux_device_class_ccid_notify_state = UX_DEVICE_CLASS_CCID_NOTIFY_IDLE;
192                 return(UX_STATE_IDLE);
193             }
194 
195             /* There is message to send.  */
196             UX_SLAVE_TRANSFER_STATE_RESET(transfer);
197             transfer -> ux_slave_transfer_request_requested_length = length;
198             ccid -> ux_device_class_ccid_notify_state = UX_DEVICE_CLASS_CCID_NOTIFY_WAIT;
199 
200             /* Fall through.  */
201         case UX_DEVICE_CLASS_CCID_NOTIFY_WAIT:
202             length = transfer -> ux_slave_transfer_request_requested_length;
203             status = _ux_device_stack_transfer_run(transfer, length, length);
204 
205             /* Error/success (done) case.  */
206             if (status <= UX_STATE_NEXT)
207             {
208 
209                 /* Transfer done, check if there is pending message.  */
210                 ccid -> ux_device_class_ccid_notify_state = UX_DEVICE_CLASS_CCID_NOTIFY_LOCK;
211                 return(UX_STATE_WAIT);
212             }
213 
214             /* Wait transfer.  */
215             return(UX_STATE_WAIT);
216 
217         default:
218             break;
219         }
220 
221 
222     }
223 
224     /* Unhandled state.  */
225     return(UX_STATE_EXIT);
226 }
227 
228 #endif
229