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)75UINT _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