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 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_ccid_control_request PORTABLE C */
36 /* 6.1.11 */
37 /* AUTHOR */
38 /* */
39 /* Chaoqiong Xiao, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function manages the requests sent by the host on the control */
44 /* endpoints with a CLASS or VENDOR SPECIFIC type. */
45 /* */
46 /* INPUT */
47 /* */
48 /* ccid Pointer to ccid class */
49 /* */
50 /* OUTPUT */
51 /* */
52 /* None */
53 /* */
54 /* CALLS */
55 /* */
56 /* _ux_device_stack_transfer_request Transfer request */
57 /* _ux_device_class_ccid_request_abort Abort slot */
58 /* _ux_utility_memory_copy Copy memory */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* CCID Class */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 04-25-2022 Chaoqiong Xiao Initial Version 6.1.11 */
69 /* */
70 /**************************************************************************/
_ux_device_class_ccid_control_request(UX_SLAVE_CLASS_COMMAND * command)71 UINT _ux_device_class_ccid_control_request(UX_SLAVE_CLASS_COMMAND *command)
72 {
73 UX_DEVICE_CLASS_CCID *ccid;
74 UX_DEVICE_CLASS_CCID_PARAMETER *parameter;
75 UX_SLAVE_CLASS *ccid_class;
76 UX_SLAVE_TRANSFER *transfer_request;
77 UX_SLAVE_DEVICE *device;
78 ULONG request;
79 UCHAR seq, slot;
80 ULONG request_length;
81 ULONG transmit_length;
82 UCHAR *transmit_buffer;
83
84 /* Get the class container. */
85 ccid_class = command -> ux_slave_class_command_class_ptr;
86
87 /* Get the class instance in the container. */
88 ccid = (UX_DEVICE_CLASS_CCID *) ccid_class -> ux_slave_class_instance;
89
90 /* Get the pointer to the device. */
91 device = &_ux_system_slave -> ux_system_slave_device;
92
93 /* Get the pointer to the transfer request associated with the control endpoint. */
94 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
95
96 /* Extract all necessary fields of the request. */
97 request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
98
99 /* Pickup the request length. */
100 request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
101
102 /* Here we proceed only the standard request we know of at the device level. */
103 switch (request)
104 {
105
106 case UX_DEVICE_CLASS_CCID_ABORT:
107 slot = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_VALUE];
108 seq = transfer_request -> ux_slave_transfer_request_setup[UX_SETUP_VALUE + 1];
109 return _ux_device_class_ccid_control_abort(ccid, slot, seq);
110
111 case UX_DEVICE_CLASS_CCID_GET_CLOCK_FREQUENCIES:
112 parameter = &ccid -> ux_device_class_ccid_parameter;
113
114 /* Check bNumClockSuppored. */
115 if (parameter -> ux_device_class_ccid_clocks == UX_NULL ||
116 parameter -> ux_device_class_ccid_n_clocks == 0)
117 return(UX_ERROR);
118
119 /* Calculate transmit length. */
120 transmit_length = parameter -> ux_device_class_ccid_n_clocks;
121 if (UX_OVERFLOW_CHECK_MULC_ULONG(transmit_length, 4))
122 return(UX_ERROR);
123 transmit_length <<= 2;
124
125 /* Update transmit buffer. */
126 transmit_buffer = (UCHAR *)parameter -> ux_device_class_ccid_clocks;
127 break;
128
129 case UX_DEVICE_CLASS_CCID_GET_DATA_RATES:
130 parameter = &ccid -> ux_device_class_ccid_parameter;
131
132 /* Check bNumDataRateSuppored. */
133 if (parameter -> ux_device_class_ccid_data_rates == UX_NULL ||
134 parameter -> ux_device_class_ccid_n_data_rates == 0)
135 return(UX_ERROR);
136
137 /* Calculate transmit length. */
138 transmit_length = parameter -> ux_device_class_ccid_n_data_rates;
139 if (UX_OVERFLOW_CHECK_MULC_ULONG(transmit_length, 4))
140 return(UX_ERROR);
141 transmit_length <<= 2;
142
143 /* Update transmit buffer. */
144 transmit_buffer = (UCHAR *)parameter -> ux_device_class_ccid_data_rates;
145 break ;
146
147 default:
148
149 /* Unknown function. It's not handled. */
150 return(UX_ERROR);
151 }
152
153 /* Limit transmit length. */
154 transmit_length = UX_MIN(transmit_length, UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH);
155 transmit_length = UX_MIN(transmit_length, request_length);
156
157 /* Copy data to transmit. */
158 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer,
159 transmit_buffer, transmit_length); /* Use case of memcpy is verified. */
160
161 /* Transmit. */
162 _ux_device_stack_transfer_request(transfer_request, transmit_length, request_length);
163
164 /* It's handled. */
165 return(UX_SUCCESS);
166 }
167