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 RNDIS 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_rndis.h"
29 #include "ux_device_stack.h"
30
31
32 #if UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_CLASS_RNDIS_INTERRUPT_RESPONSE_LENGTH ||\
33 UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH < UX_DEVICE_CLASS_RNDIS_MAX_CONTROL_RESPONSE_LENGTH
34 #error UX_SLAVE_REQUEST_CONTROL_MAX_LENGTH too small, please check
35 #endif
36
37 /**************************************************************************/
38 /* */
39 /* FUNCTION RELEASE */
40 /* */
41 /* _ux_device_class_rndis_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 /* rndis Pointer to rndis 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 /* _ux_utility_memory_set Set memory */
65 /* _ux_utility_memory_copy Copy memory */
66 /* _ux_utility_long_get Get 32-bit value */
67 /* _ux_device_event_flags_set Set event flags */
68 /* _ux_device_class_rndis_msg_initialize Command initialize */
69 /* _ux_device_class_rndis_msg_query Command query */
70 /* _ux_device_class_rndis_msg_set Command set */
71 /* _ux_device_class_rndis_msg_reset Command reset */
72 /* _ux_device_class_rndis_msg_keep_alive Command keep alive */
73 /* */
74 /* CALLED BY */
75 /* */
76 /* RNDIS Class */
77 /* */
78 /* RELEASE HISTORY */
79 /* */
80 /* DATE NAME DESCRIPTION */
81 /* */
82 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
83 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
84 /* verified memset and memcpy */
85 /* cases, used UX prefix to */
86 /* refer to TX symbols instead */
87 /* of using them directly, */
88 /* resulting in version 6.1 */
89 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
90 /* fixed standalone compile, */
91 /* resulting in version 6.1.11 */
92 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
93 /* fixed parameter/variable */
94 /* names conflict C++ keyword, */
95 /* resulting in version 6.1.12 */
96 /* */
97 /**************************************************************************/
_ux_device_class_rndis_control_request(UX_SLAVE_CLASS_COMMAND * command)98 UINT _ux_device_class_rndis_control_request(UX_SLAVE_CLASS_COMMAND *command)
99 {
100
101 UX_SLAVE_TRANSFER *transfer_request;
102 UX_SLAVE_TRANSFER *transfer_request_in;
103 UX_SLAVE_DEVICE *device;
104 ULONG request;
105 ULONG request_length;
106 ULONG rndis_command;
107 UX_SLAVE_CLASS *class_ptr;
108 UX_SLAVE_CLASS_RNDIS *rndis;
109
110 /* Get the pointer to the device. */
111 device = &_ux_system_slave -> ux_system_slave_device;
112
113 /* Get the pointer to the transfer request associated with the control endpoint. */
114 transfer_request = &device -> ux_slave_device_control_endpoint.ux_slave_endpoint_transfer_request;
115
116 /* Extract all necessary fields of the request. */
117 request = *(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_REQUEST);
118 request_length = _ux_utility_short_get(transfer_request -> ux_slave_transfer_request_setup + UX_SETUP_LENGTH);
119
120 /* Get the class container. */
121 class_ptr = command -> ux_slave_class_command_class_ptr;
122
123 /* Get the rndis instance from this class container. */
124 rndis = (UX_SLAVE_CLASS_RNDIS *) class_ptr -> ux_slave_class_instance;
125
126 /* Here we proceed only the standard request we know of at the device level. */
127 switch (request)
128 {
129
130
131 case UX_DEVICE_CLASS_RNDIS_SEND_ENCAPSULATED_COMMAND :
132
133
134 /* We have received a command. Check if the command is valid and dispatch it. */
135 rndis_command = _ux_utility_long_get(transfer_request -> ux_slave_transfer_request_data_pointer);
136
137 switch (rndis_command)
138 {
139
140 case UX_DEVICE_CLASS_RNDIS_MSG_INITIALIZE :
141
142 _ux_device_class_rndis_msg_initialize(rndis, transfer_request);
143 break;
144
145 case UX_DEVICE_CLASS_RNDIS_MSG_HALT :
146 break;
147
148
149 case UX_DEVICE_CLASS_RNDIS_MSG_QUERY :
150 _ux_device_class_rndis_msg_query(rndis, transfer_request);
151 break;
152
153
154 case UX_DEVICE_CLASS_RNDIS_MSG_SET :
155 _ux_device_class_rndis_msg_set(rndis, transfer_request);
156 break;
157
158
159 case UX_DEVICE_CLASS_RNDIS_MSG_RESET :
160 _ux_device_class_rndis_msg_reset(rndis, transfer_request);
161 break;
162
163
164 case UX_DEVICE_CLASS_RNDIS_MSG_INDICATE_STATUS :
165 break;
166
167
168 case UX_DEVICE_CLASS_RNDIS_MSG_KEEP_ALIVE :
169 _ux_device_class_rndis_msg_keep_alive(rndis, transfer_request);
170 break;
171
172 default :
173
174 /* Unknown function. Stall the endpoint. */
175 _ux_device_stack_endpoint_stall(&device -> ux_slave_device_control_endpoint);
176 break;
177
178 }
179
180 /* Check the return status. If no error, we set the interrupt pipe to reply response available.
181 All RNDIS events are on the interrupt endpoint IN, from the host. */
182 transfer_request_in = &rndis -> ux_slave_class_rndis_interrupt_endpoint -> ux_slave_endpoint_transfer_request;
183
184 /* Reset the buffer. */
185 _ux_utility_memory_set(transfer_request_in -> ux_slave_transfer_request_data_pointer, 0, UX_DEVICE_CLASS_RNDIS_INTERRUPT_RESPONSE_LENGTH); /* Use case of memset is verified. */
186
187 /* Set the buffer of this transfer request with the flag for response available. */
188 transfer_request_in -> ux_slave_transfer_request_data_pointer[0] = UX_DEVICE_CLASS_RNDIS_INTERRUPT_RESPONSE_AVAILABLE_FLAG;
189
190 /* Set an event to wake up the interrupt thread. */
191 _ux_device_event_flags_set(&rndis -> ux_slave_class_rndis_event_flags_group, UX_DEVICE_CLASS_RNDIS_NEW_INTERRUPT_EVENT, UX_OR);
192
193 break;
194
195 case UX_DEVICE_CLASS_RNDIS_GET_ENCAPSULATED_RESPONSE :
196
197
198 /* Copy the response into the request data buffer. */
199 _ux_utility_memory_copy(transfer_request -> ux_slave_transfer_request_data_pointer, rndis -> ux_slave_class_rndis_response,
200 rndis -> ux_slave_class_rndis_response_length); /* Use case of memcpy is verified. */
201
202 /* Set the phase of the transfer to data out. */
203 transfer_request -> ux_slave_transfer_request_phase = UX_TRANSFER_PHASE_DATA_OUT;
204
205 /* We can return the RNDIS response. */
206 _ux_device_stack_transfer_request(transfer_request, rndis -> ux_slave_class_rndis_response_length, request_length);
207
208 break ;
209
210 default:
211
212 /* Unknown function. It's not handled. */
213 return(UX_ERROR);
214 }
215
216 /* It's handled. */
217 return(UX_SUCCESS);
218 }
219
220