GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
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 |
/** */ |
||
15 |
/** USBX Component */ |
||
16 |
/** */ |
||
17 |
/** Device Storage 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_storage.h" |
||
29 |
#include "ux_device_stack.h" |
||
30 |
|||
31 |
|||
32 |
#if !defined(UX_DEVICE_STANDALONE) |
||
33 |
/**************************************************************************/ |
||
34 |
/* */ |
||
35 |
/* FUNCTION RELEASE */ |
||
36 |
/* */ |
||
37 |
/* _ux_device_class_storage_thread PORTABLE C */ |
||
38 |
/* 6.3.0 */ |
||
39 |
/* AUTHOR */ |
||
40 |
/* */ |
||
41 |
/* Chaoqiong Xiao, Microsoft Corporation */ |
||
42 |
/* */ |
||
43 |
/* DESCRIPTION */ |
||
44 |
/* */ |
||
45 |
/* This function is the thread of the storage class. */ |
||
46 |
/* */ |
||
47 |
/* It's for RTOS mode. */ |
||
48 |
/* */ |
||
49 |
/* INPUT */ |
||
50 |
/* */ |
||
51 |
/* class Address of storage class */ |
||
52 |
/* container */ |
||
53 |
/* */ |
||
54 |
/* OUTPUT */ |
||
55 |
/* */ |
||
56 |
/* None */ |
||
57 |
/* */ |
||
58 |
/* CALLS */ |
||
59 |
/* */ |
||
60 |
/* _ux_device_class_storage_format Storage class format */ |
||
61 |
/* _ux_device_class_storage_inquiry Storage class inquiry */ |
||
62 |
/* _ux_device_class_storage_mode_select Mode select */ |
||
63 |
/* _ux_device_class_storage_mode_sense Mode sense */ |
||
64 |
/* _ux_device_class_storage_prevent_allow_media_removal */ |
||
65 |
/* Prevent media removal */ |
||
66 |
/* _ux_device_class_storage_read Read */ |
||
67 |
/* _ux_device_class_storage_read_capacity */ |
||
68 |
/* Read capacity */ |
||
69 |
/* _ux_device_class_storage_read_format_capacity */ |
||
70 |
/* Read format capacity */ |
||
71 |
/* _ux_device_class_storage_request_sense */ |
||
72 |
/* Sense request */ |
||
73 |
/* _ux_device_class_storage_start_stop Start/Stop */ |
||
74 |
/* _ux_device_class_storage_synchronize_cache */ |
||
75 |
/* Synchronize cache */ |
||
76 |
/* _ux_device_class_storage_test_ready Ready test */ |
||
77 |
/* _ux_device_class_storage_verify Verify */ |
||
78 |
/* _ux_device_class_storage_write Write */ |
||
79 |
/* _ux_device_stack_endpoint_stall Endpoint stall */ |
||
80 |
/* _ux_device_stack_interface_delete Interface delete */ |
||
81 |
/* _ux_device_stack_transfer_request Transfer request */ |
||
82 |
/* _ux_utility_long_get Get 32-bit value */ |
||
83 |
/* _ux_utility_memory_allocate Allocate memory */ |
||
84 |
/* _ux_device_semaphore_create Create semaphore */ |
||
85 |
/* _ux_utility_delay_ms Sleep thread for several ms */ |
||
86 |
/* _ux_device_thread_suspend Suspend thread */ |
||
87 |
/* */ |
||
88 |
/* CALLED BY */ |
||
89 |
/* */ |
||
90 |
/* ThreadX */ |
||
91 |
/* */ |
||
92 |
/* RELEASE HISTORY */ |
||
93 |
/* */ |
||
94 |
/* DATE NAME DESCRIPTION */ |
||
95 |
/* */ |
||
96 |
/* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */ |
||
97 |
/* 09-30-2020 Chaoqiong Xiao Modified comment(s), */ |
||
98 |
/* used sleep instead of */ |
||
99 |
/* relinquish on error, */ |
||
100 |
/* optimized command logic, */ |
||
101 |
/* used UX prefix to refer to */ |
||
102 |
/* TX symbols instead of using */ |
||
103 |
/* them directly, */ |
||
104 |
/* resulting in version 6.1 */ |
||
105 |
/* 12-31-2020 Chaoqiong Xiao Modified comment(s), */ |
||
106 |
/* fixed USB CV test issues, */ |
||
107 |
/* resulting in version 6.1.3 */ |
||
108 |
/* 04-02-2021 Chaoqiong Xiao Modified comment(s), */ |
||
109 |
/* fixed compile issues with */ |
||
110 |
/* some macro options, */ |
||
111 |
/* resulting in version 6.1.6 */ |
||
112 |
/* 06-02-2021 Chaoqiong Xiao Modified comment(s), */ |
||
113 |
/* get interface and endpoints */ |
||
114 |
/* from configured device, */ |
||
115 |
/* resulting in version 6.1.7 */ |
||
116 |
/* 10-15-2021 Chaoqiong Xiao Modified comment(s), */ |
||
117 |
/* improved TAG management, */ |
||
118 |
/* resulting in version 6.1.9 */ |
||
119 |
/* 01-31-2022 Chaoqiong Xiao Modified comment(s), */ |
||
120 |
/* refined macros names, */ |
||
121 |
/* resulting in version 6.1.10 */ |
||
122 |
/* 04-25-2022 Chaoqiong Xiao Modified comment(s), */ |
||
123 |
/* internal clean up, */ |
||
124 |
/* resulting in version 6.1.11 */ |
||
125 |
/* 07-29-2022 Chaoqiong Xiao Modified comment(s), */ |
||
126 |
/* fixed parameter/variable */ |
||
127 |
/* names conflict C++ keyword, */ |
||
128 |
/* resulting in version 6.1.12 */ |
||
129 |
/* 10-31-2023 Chaoqiong Xiao Modified comment(s), */ |
||
130 |
/* added a new mode to manage */ |
||
131 |
/* endpoint buffer in classes, */ |
||
132 |
/* resulting in version 6.3.0 */ |
||
133 |
/* */ |
||
134 |
/**************************************************************************/ |
||
135 |
42 |
VOID _ux_device_class_storage_thread(ULONG storage_class) |
|
136 |
{ |
||
137 |
|||
138 |
UX_SLAVE_CLASS *class_ptr; |
||
139 |
UX_SLAVE_CLASS_STORAGE *storage; |
||
140 |
UX_SLAVE_TRANSFER *transfer_request; |
||
141 |
UX_SLAVE_DEVICE *device; |
||
142 |
UX_SLAVE_INTERFACE *interface_ptr; |
||
143 |
UX_SLAVE_ENDPOINT *endpoint_in; |
||
144 |
UX_SLAVE_ENDPOINT *endpoint_out; |
||
145 |
UINT status; |
||
146 |
ULONG length; |
||
147 |
ULONG cbwcb_length; |
||
148 |
ULONG lun; |
||
149 |
UCHAR *scsi_command; |
||
150 |
UCHAR *cbw_cb; |
||
151 |
|||
152 |
|||
153 |
/* This thread runs forever but can be suspended or resumed. */ |
||
154 |
while(1) |
||
155 |
{ |
||
156 |
|||
157 |
/* Cast properly the storage instance. */ |
||
158 |
137 |
UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, storage_class) |
|
159 |
|||
160 |
/* Get the storage instance from this class container. */ |
||
161 |
137 |
storage = (UX_SLAVE_CLASS_STORAGE *) class_ptr -> ux_slave_class_instance; |
|
162 |
|||
163 |
/* Get the pointer to the device. */ |
||
164 |
137 |
device = &_ux_system_slave -> ux_system_slave_device; |
|
165 |
|||
166 |
/* As long as the device is in the CONFIGURED state. */ |
||
167 |
✓✓ | 5227 |
while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) |
168 |
{ |
||
169 |
|||
170 |
/* We are activated. We need the interface to the class. */ |
||
171 |
5130 |
interface_ptr = storage -> ux_slave_class_storage_interface; |
|
172 |
|||
173 |
/* We assume the worst situation. */ |
||
174 |
5130 |
status = UX_ERROR; |
|
175 |
|||
176 |
/* Locate the endpoints. */ |
||
177 |
5130 |
endpoint_in = interface_ptr -> ux_slave_interface_first_endpoint; |
|
178 |
|||
179 |
/* Check the endpoint direction, if IN we have the correct endpoint. */ |
||
180 |
✓✓ | 5130 |
if ((endpoint_in -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN) |
181 |
{ |
||
182 |
|||
183 |
/* Wrong direction, we found the OUT endpoint first. */ |
||
184 |
976 |
endpoint_out = endpoint_in; |
|
185 |
|||
186 |
/* So the next endpoint has to be the IN endpoint. */ |
||
187 |
976 |
endpoint_in = endpoint_out -> ux_slave_endpoint_next_endpoint; |
|
188 |
} |
||
189 |
else |
||
190 |
{ |
||
191 |
|||
192 |
/* We found the endpoint IN first, so next endpoint is OUT. */ |
||
193 |
4154 |
endpoint_out = endpoint_in -> ux_slave_endpoint_next_endpoint; |
|
194 |
} |
||
195 |
|||
196 |
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1 |
||
197 |
|||
198 |
/* Assign endpoint buffers. */ |
||
199 |
endpoint_out -> ux_slave_endpoint_transfer_request. |
||
200 |
ux_slave_transfer_request_data_pointer = |
||
201 |
UX_DEVICE_CLASS_STORAGE_BULKOUT_BUFFER(storage); |
||
202 |
endpoint_in -> ux_slave_endpoint_transfer_request. |
||
203 |
ux_slave_transfer_request_data_pointer = |
||
204 |
UX_DEVICE_CLASS_STORAGE_BULKIN_BUFFER(storage); |
||
205 |
#endif |
||
206 |
|||
207 |
/* All SCSI commands are on the endpoint OUT, from the host. */ |
||
208 |
5130 |
transfer_request = &endpoint_out -> ux_slave_endpoint_transfer_request; |
|
209 |
|||
210 |
/* Check state, they must be both RESET. */ |
||
211 |
✓✓ | 5130 |
if (endpoint_out -> ux_slave_endpoint_state == UX_ENDPOINT_RESET && |
212 |
✓✓ | 2966 |
(UCHAR)storage -> ux_slave_class_storage_csw_status != UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR) |
213 |
{ |
||
214 |
|||
215 |
/* Send the request to the device controller. */ |
||
216 |
2702 |
status = _ux_device_stack_transfer_request(transfer_request, 64, 64); |
|
217 |
|||
218 |
} |
||
219 |
|||
220 |
/* Check the status. Our status is UX_ERROR if one of the endpoint was STALLED. We must wait for the host |
||
221 |
to clear the mess. */ |
||
222 |
✓✓ | 5097 |
if (status == UX_SUCCESS) |
223 |
{ |
||
224 |
|||
225 |
/* Obtain the length of the transaction. */ |
||
226 |
2544 |
length = transfer_request -> ux_slave_transfer_request_actual_length; |
|
227 |
|||
228 |
/* Obtain the buffer address containing the SCSI command. */ |
||
229 |
2544 |
scsi_command = transfer_request -> ux_slave_transfer_request_data_pointer; |
|
230 |
|||
231 |
/* Obtain the lun from the CBW. */ |
||
232 |
2544 |
lun = (ULONG) *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_LUN); |
|
233 |
2544 |
storage -> ux_slave_class_storage_cbw_lun = (UCHAR)lun; |
|
234 |
|||
235 |
/* We have to memorize the SCSI command tag for the CSW phase. */ |
||
236 |
2544 |
storage -> ux_slave_class_storage_scsi_tag = _ux_utility_long_get(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_TAG); |
|
237 |
|||
238 |
/* Get dCBWDataTransferLength: number of bytes to transfer. */ |
||
239 |
2544 |
storage -> ux_slave_class_storage_host_length = _ux_utility_long_get(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_DATA_LENGTH); |
|
240 |
|||
241 |
/* Save bmCBWFlags. */ |
||
242 |
2544 |
storage -> ux_slave_class_storage_cbw_flags = *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_FLAGS); |
|
243 |
|||
244 |
/* Reset CSW status. */ |
||
245 |
2544 |
storage -> ux_slave_class_storage_csw_residue = 0; |
|
246 |
2544 |
storage -> ux_slave_class_storage_csw_status = 0; |
|
247 |
|||
248 |
/* Ensure the LUN number is within our declared values and check the command |
||
249 |
content and format. First we make sure we have a complete CBW. */ |
||
250 |
✓✓✓✓ |
2544 |
if ((lun < storage -> ux_slave_class_storage_number_lun) && (length == UX_SLAVE_CLASS_STORAGE_CBW_LENGTH)) |
251 |
{ |
||
252 |
|||
253 |
/* The length of the CBW is correct, analyze the header. */ |
||
254 |
✓✓ | 4572 |
if (_ux_utility_long_get(scsi_command) == UX_SLAVE_CLASS_STORAGE_CBW_SIGNATURE_MASK) |
255 |
{ |
||
256 |
|||
257 |
/* Get the length of the CBWCB. */ |
||
258 |
2287 |
cbwcb_length = (ULONG) *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_CB_LENGTH); |
|
259 |
|||
260 |
/* Check the length of the CBWCB to ensure there is at least a command. */ |
||
261 |
✓✓ | 2287 |
if (cbwcb_length != 0) |
262 |
{ |
||
263 |
|||
264 |
/* Analyze the command stored in the CBWCB. */ |
||
265 |
2286 |
cbw_cb = scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_CB; |
|
266 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓ |
2286 |
switch (*(cbw_cb)) |
267 |
{ |
||
268 |
|||
269 |
368 |
case UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY: |
|
270 |
|||
271 |
368 |
_ux_device_class_storage_test_ready(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
272 |
368 |
break; |
|
273 |
|||
274 |
148 |
case UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE: |
|
275 |
|||
276 |
148 |
_ux_device_class_storage_request_sense(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
277 |
148 |
break; |
|
278 |
|||
279 |
1 |
case UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT: |
|
280 |
|||
281 |
1 |
_ux_device_class_storage_format(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
282 |
1 |
break; |
|
283 |
|||
284 |
190 |
case UX_SLAVE_CLASS_STORAGE_SCSI_INQUIRY: |
|
285 |
|||
286 |
190 |
_ux_device_class_storage_inquiry(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
287 |
190 |
break; |
|
288 |
|||
289 |
2 |
case UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP: |
|
290 |
|||
291 |
2 |
_ux_device_class_storage_start_stop(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
292 |
2 |
break; |
|
293 |
|||
294 |
1 |
case UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL: |
|
295 |
|||
296 |
1 |
_ux_device_class_storage_prevent_allow_media_removal(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
297 |
1 |
break; |
|
298 |
|||
299 |
353 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ_FORMAT_CAPACITY: |
|
300 |
|||
301 |
353 |
_ux_device_class_storage_read_format_capacity(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
302 |
353 |
break; |
|
303 |
|||
304 |
183 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ_CAPACITY: |
|
305 |
|||
306 |
183 |
_ux_device_class_storage_read_capacity(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
307 |
183 |
break; |
|
308 |
|||
309 |
1 |
case UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY: |
|
310 |
|||
311 |
1 |
_ux_device_class_storage_verify(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
312 |
1 |
break; |
|
313 |
|||
314 |
2 |
case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT: |
|
315 |
|||
316 |
2 |
_ux_device_class_storage_mode_select(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
317 |
2 |
break; |
|
318 |
|||
319 |
11 |
case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT: |
|
320 |
case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE: |
||
321 |
|||
322 |
11 |
_ux_device_class_storage_mode_sense(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
|
323 |
11 |
break; |
|
324 |
|||
325 |
1 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ32: |
|
326 |
|||
327 |
1 |
_ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbw_cb, |
|
328 |
UX_SLAVE_CLASS_STORAGE_SCSI_READ32); |
||
329 |
1 |
break; |
|
330 |
|||
331 |
614 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ16: |
|
332 |
|||
333 |
614 |
_ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbw_cb, |
|
334 |
UX_SLAVE_CLASS_STORAGE_SCSI_READ16); |
||
335 |
613 |
break; |
|
336 |
|||
337 |
1 |
case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32: |
|
338 |
|||
339 |
1 |
_ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbw_cb, |
|
340 |
UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32); |
||
341 |
1 |
break; |
|
342 |
|||
343 |
394 |
case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16: |
|
344 |
|||
345 |
394 |
_ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbw_cb, |
|
346 |
UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16); |
||
347 |
394 |
break; |
|
348 |
|||
349 |
11 |
case UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE: |
|
350 |
|||
351 |
11 |
_ux_device_class_storage_synchronize_cache(storage, lun, endpoint_in, endpoint_out, cbw_cb, *(cbw_cb)); |
|
352 |
11 |
break; |
|
353 |
|||
354 |
#ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC |
||
355 |
case UX_SLAVE_CLASS_STORAGE_SCSI_GET_STATUS_NOTIFICATION: |
||
356 |
|||
357 |
_ux_device_class_storage_get_status_notification(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
358 |
break; |
||
359 |
|||
360 |
case UX_SLAVE_CLASS_STORAGE_SCSI_GET_CONFIGURATION: |
||
361 |
|||
362 |
_ux_device_class_storage_get_configuration(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
363 |
break; |
||
364 |
|||
365 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DISK_INFORMATION: |
||
366 |
|||
367 |
_ux_device_class_storage_read_disk_information(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
368 |
break; |
||
369 |
|||
370 |
case UX_SLAVE_CLASS_STORAGE_SCSI_REPORT_KEY: |
||
371 |
|||
372 |
_ux_device_class_storage_report_key(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
373 |
break; |
||
374 |
|||
375 |
case UX_SLAVE_CLASS_STORAGE_SCSI_GET_PERFORMANCE: |
||
376 |
|||
377 |
_ux_device_class_storage_get_performance(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
378 |
break; |
||
379 |
|||
380 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DVD_STRUCTURE: |
||
381 |
|||
382 |
_ux_device_class_storage_read_dvd_structure(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
383 |
break; |
||
384 |
|||
385 |
case UX_SLAVE_CLASS_STORAGE_SCSI_READ_TOC: |
||
386 |
|||
387 |
status = _ux_device_class_storage_read_toc(storage, lun, endpoint_in, endpoint_out, cbw_cb); |
||
388 |
|||
389 |
/* Special treatment of TOC command. If error, default to Stall endpoint. */ |
||
390 |
if (status == UX_SUCCESS) |
||
391 |
break; |
||
392 |
#endif |
||
393 |
|||
394 |
/* fall through */ |
||
395 |
5 |
default: |
|
396 |
|||
397 |
/* The command is unknown or unsupported, so we stall the endpoint. */ |
||
398 |
|||
399 |
✓✓ | 5 |
if (storage -> ux_slave_class_storage_host_length > 0 && |
400 |
✓✓ | 2 |
((storage -> ux_slave_class_storage_cbw_flags & 0x80) == 0)) |
401 |
|||
402 |
/* Data-Out from host to device, stall OUT. */ |
||
403 |
1 |
_ux_device_stack_endpoint_stall(endpoint_out); |
|
404 |
else |
||
405 |
|||
406 |
/* Data-In from device to host, stall IN. */ |
||
407 |
4 |
_ux_device_stack_endpoint_stall(endpoint_in); |
|
408 |
|||
409 |
/* Initialize the request sense keys. */ |
||
410 |
5 |
storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status = |
|
411 |
UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST, |
||
412 |
UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND,0); |
||
413 |
|||
414 |
/* This is the tricky part of the SCSI state machine. We must send the CSW BUT need to wait |
||
415 |
for the endpoint_in to be reset by the host. */ |
||
416 |
✓✓ | 211537 |
while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED) |
417 |
{ |
||
418 |
|||
419 |
/* Check the endpoint state. */ |
||
420 |
✓✓ | 211536 |
if (endpoint_in -> ux_slave_endpoint_state == UX_ENDPOINT_RESET) |
421 |
{ |
||
422 |
|||
423 |
/* Now we set the CSW with failure. */ |
||
424 |
4 |
storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED; |
|
425 |
4 |
break; |
|
426 |
} |
||
427 |
|||
428 |
else |
||
429 |
|||
430 |
/* We must therefore wait a while. */ |
||
431 |
211532 |
_ux_device_thread_relinquish(); |
|
432 |
} |
||
433 |
5 |
break; |
|
434 |
} |
||
435 |
|||
436 |
/* Send CSW if not SYNC_CACHE. */ |
||
437 |
2285 |
status = _ux_device_class_storage_csw_send(storage, lun, endpoint_in, 0 /* Don't care */); |
|
438 |
|||
439 |
/* Check error code. */ |
||
440 |
✓✓ | 2282 |
if (status != UX_SUCCESS) |
441 |
|||
442 |
/* Error trap. */ |
||
443 |
3 |
_ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status); |
|
444 |
} |
||
445 |
else |
||
446 |
|||
447 |
/* Phase error! */ |
||
448 |
1 |
storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR; |
|
449 |
} |
||
450 |
|||
451 |
else |
||
452 |
|||
453 |
/* Phase error! */ |
||
454 |
1 |
storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR; |
|
455 |
} |
||
456 |
else |
||
457 |
|||
458 |
/* Phase error! */ |
||
459 |
256 |
storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR; |
|
460 |
} |
||
461 |
else |
||
462 |
{ |
||
463 |
|||
464 |
✓✓ | 2553 |
if ((UCHAR)storage -> ux_slave_class_storage_csw_status == UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR) |
465 |
{ |
||
466 |
|||
467 |
/* We should keep the endpoints stalled. */ |
||
468 |
1804 |
_ux_device_stack_endpoint_stall(endpoint_out); |
|
469 |
1804 |
_ux_device_stack_endpoint_stall(endpoint_in); |
|
470 |
} |
||
471 |
|||
472 |
/* We must therefore wait a while. */ |
||
473 |
2553 |
_ux_utility_delay_ms(2); |
|
474 |
} |
||
475 |
} |
||
476 |
|||
477 |
/* We need to suspend ourselves. We will be resumed by the |
||
478 |
device enumeration module. */ |
||
479 |
97 |
_ux_device_thread_suspend(&class_ptr -> ux_slave_class_thread); |
|
480 |
} |
||
481 |
} |
||
482 |
#endif |
Generated by: GCOVR (Version 4.1) |