GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_device_classes/src/ux_device_class_storage_thread.c Lines: 103 103 100.0 %
Date: 2026-03-06 18:57:10 Branches: 47 47 100.0 %

Line Branch Exec Source
1
/***************************************************************************
2
 * Copyright (c) 2024 Microsoft Corporation
3
 * Copyright (c) 2026-present Eclipse ThreadX contributors
4
 *
5
 * This program and the accompanying materials are made available under the
6
 * terms of the MIT License which is available at
7
 * https://opensource.org/licenses/MIT.
8
 *
9
 * SPDX-License-Identifier: MIT
10
 **************************************************************************/
11
12
13
/**************************************************************************/
14
/**************************************************************************/
15
/**                                                                       */
16
/** USBX Component                                                        */
17
/**                                                                       */
18
/**   Device Storage Class                                                */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define UX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "ux_api.h"
29
#include "ux_device_class_storage.h"
30
#include "ux_device_stack.h"
31
32
33
#if !defined(UX_DEVICE_STANDALONE)
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _ux_device_class_storage_thread                     PORTABLE C      */
39
/*                                                           6.3.0        */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Chaoqiong Xiao, Microsoft Corporation                               */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function is the thread of the storage class.                   */
47
/*                                                                        */
48
/*    It's for RTOS mode.                                                 */
49
/*                                                                        */
50
/*  INPUT                                                                 */
51
/*                                                                        */
52
/*    class                                 Address of storage class      */
53
/*                                            container                   */
54
/*                                                                        */
55
/*  OUTPUT                                                                */
56
/*                                                                        */
57
/*    None                                                                */
58
/*                                                                        */
59
/*  CALLS                                                                 */
60
/*                                                                        */
61
/*    _ux_device_class_storage_format       Storage class format          */
62
/*    _ux_device_class_storage_inquiry      Storage class inquiry         */
63
/*    _ux_device_class_storage_mode_select  Mode select                   */
64
/*    _ux_device_class_storage_mode_sense   Mode sense                    */
65
/*    _ux_device_class_storage_prevent_allow_media_removal                */
66
/*                                          Prevent media removal         */
67
/*    _ux_device_class_storage_read         Read                          */
68
/*    _ux_device_class_storage_read_capacity                              */
69
/*                                          Read capacity                 */
70
/*    _ux_device_class_storage_read_format_capacity                       */
71
/*                                          Read format capacity          */
72
/*    _ux_device_class_storage_request_sense                              */
73
/*                                          Sense request                 */
74
/*    _ux_device_class_storage_start_stop   Start/Stop                    */
75
/*    _ux_device_class_storage_synchronize_cache                          */
76
/*                                          Synchronize cache             */
77
/*    _ux_device_class_storage_test_ready   Ready test                    */
78
/*    _ux_device_class_storage_verify       Verify                        */
79
/*    _ux_device_class_storage_write        Write                         */
80
/*    _ux_device_stack_endpoint_stall       Endpoint stall                */
81
/*    _ux_device_stack_interface_delete     Interface delete              */
82
/*    _ux_device_stack_transfer_request     Transfer request              */
83
/*    _ux_utility_long_get                  Get 32-bit value              */
84
/*    _ux_utility_memory_allocate           Allocate memory               */
85
/*    _ux_device_semaphore_create           Create semaphore              */
86
/*    _ux_utility_delay_ms                  Sleep thread for several ms   */
87
/*    _ux_device_thread_suspend             Suspend thread                */
88
/*                                                                        */
89
/*  CALLED BY                                                             */
90
/*                                                                        */
91
/*    ThreadX                                                             */
92
/*                                                                        */
93
/**************************************************************************/
94
43
VOID  _ux_device_class_storage_thread(ULONG storage_class)
95
{
96
97
UX_SLAVE_CLASS              *class_ptr;
98
UX_SLAVE_CLASS_STORAGE      *storage;
99
UX_SLAVE_TRANSFER           *transfer_request;
100
UX_SLAVE_DEVICE             *device;
101
UX_SLAVE_INTERFACE          *interface_ptr;
102
UX_SLAVE_ENDPOINT           *endpoint_in;
103
UX_SLAVE_ENDPOINT           *endpoint_out;
104
UINT                        status;
105
ULONG                       length;
106
ULONG                       cbwcb_length;
107
ULONG                       lun;
108
UCHAR                       *scsi_command;
109
UCHAR                       *cbw_cb;
110
111
112
    /* This thread runs forever but can be suspended or resumed.  */
113
    while(1)
114
    {
115
116
        /* Cast properly the storage instance.  */
117
138
        UX_THREAD_EXTENSION_PTR_GET(class_ptr, UX_SLAVE_CLASS, storage_class)
118
119
        /* Get the storage instance from this class container.  */
120
138
        storage =  (UX_SLAVE_CLASS_STORAGE *) class_ptr -> ux_slave_class_instance;
121
122
        /* Get the pointer to the device.  */
123
138
        device =  &_ux_system_slave -> ux_system_slave_device;
124
125
        /* As long as the device is in the CONFIGURED state.  */
126
5238
        while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
127
        {
128
129
            /* We are activated. We need the interface to the class.  */
130
5141
            interface_ptr =  storage -> ux_slave_class_storage_interface;
131
132
            /* We assume the worst situation.  */
133
5141
            status =  UX_ERROR;
134
135
            /* Locate the endpoints.  */
136
5141
            endpoint_in =  interface_ptr -> ux_slave_interface_first_endpoint;
137
138
            /* Check the endpoint direction, if IN we have the correct endpoint.  */
139
5141
            if ((endpoint_in -> ux_slave_endpoint_descriptor.bEndpointAddress & UX_ENDPOINT_DIRECTION) != UX_ENDPOINT_IN)
140
            {
141
142
                /* Wrong direction, we found the OUT endpoint first.  */
143
976
                endpoint_out =  endpoint_in;
144
145
                /* So the next endpoint has to be the IN endpoint.  */
146
976
                endpoint_in =  endpoint_out -> ux_slave_endpoint_next_endpoint;
147
            }
148
            else
149
            {
150
151
                /* We found the endpoint IN first, so next endpoint is OUT.  */
152
4165
                endpoint_out =  endpoint_in -> ux_slave_endpoint_next_endpoint;
153
            }
154
155
#if UX_DEVICE_ENDPOINT_BUFFER_OWNER == 1
156
157
            /* Assign endpoint buffers.  */
158
            endpoint_out -> ux_slave_endpoint_transfer_request.
159
                    ux_slave_transfer_request_data_pointer =
160
                            UX_DEVICE_CLASS_STORAGE_BULKOUT_BUFFER(storage);
161
            endpoint_in -> ux_slave_endpoint_transfer_request.
162
                    ux_slave_transfer_request_data_pointer =
163
                            UX_DEVICE_CLASS_STORAGE_BULKIN_BUFFER(storage);
164
#endif
165
166
            /* All SCSI commands are on the endpoint OUT, from the host.  */
167
5141
            transfer_request =  &endpoint_out -> ux_slave_endpoint_transfer_request;
168
169
            /* Check state, they must be both RESET.  */
170
5141
            if (endpoint_out -> ux_slave_endpoint_state == UX_ENDPOINT_RESET &&
171
2977
                (UCHAR)storage -> ux_slave_class_storage_csw_status != UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR)
172
            {
173
174
                /* Send the request to the device controller.  */
175
2713
                status =  _ux_device_stack_transfer_request(transfer_request, 64, 64);
176
177
            }
178
179
            /* Check the status. Our status is UX_ERROR if one of the endpoint was STALLED. We must wait for the host
180
               to clear the mess.   */
181
5107
            if (status == UX_SUCCESS)
182
            {
183
184
                /* Obtain the length of the transaction.  */
185
2554
                length =  transfer_request -> ux_slave_transfer_request_actual_length;
186
187
                /* Obtain the buffer address containing the SCSI command.  */
188
2554
                scsi_command =  transfer_request -> ux_slave_transfer_request_data_pointer;
189
190
                /* Obtain the lun from the CBW.  */
191
2554
                lun =  (ULONG) *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_LUN);
192
2554
                storage -> ux_slave_class_storage_cbw_lun = (UCHAR)lun;
193
194
                /* We have to memorize the SCSI command tag for the CSW phase.  */
195
2554
                storage -> ux_slave_class_storage_scsi_tag =  _ux_utility_long_get(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_TAG);
196
197
                /* Get dCBWDataTransferLength: number of bytes to transfer.  */
198
2554
                storage -> ux_slave_class_storage_host_length = _ux_utility_long_get(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_DATA_LENGTH);
199
200
                /* Save bmCBWFlags.  */
201
2554
                storage -> ux_slave_class_storage_cbw_flags = *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_FLAGS);
202
203
                /* Reset CSW status.  */
204
2554
                storage -> ux_slave_class_storage_csw_residue = 0;
205
2554
                storage -> ux_slave_class_storage_csw_status = 0;
206
207
                /* Ensure the LUN number is within our declared values and check the command
208
                   content and format. First we make sure we have a complete CBW.  */
209

2554
                if ((lun < storage -> ux_slave_class_storage_number_lun) && (length == UX_SLAVE_CLASS_STORAGE_CBW_LENGTH))
210
                {
211
212
                    /* The length of the CBW is correct, analyze the header.  */
213
4592
                    if (_ux_utility_long_get(scsi_command) == UX_SLAVE_CLASS_STORAGE_CBW_SIGNATURE_MASK)
214
                    {
215
216
                        /* Get the length of the CBWCB.  */
217
2297
                        cbwcb_length =  (ULONG) *(scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_CB_LENGTH);
218
219
                        /* Check the length of the CBWCB to ensure there is at least a command.  */
220
2297
                        if (cbwcb_length != 0)
221
                        {
222
223
                            /* Analyze the command stored in the CBWCB.  */
224
2296
                            cbw_cb = scsi_command + UX_SLAVE_CLASS_STORAGE_CBW_CB;
225




2296
                            switch (*(cbw_cb))
226
                            {
227
228
369
                            case UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY:
229
230
369
                                _ux_device_class_storage_test_ready(storage, lun, endpoint_in, endpoint_out, cbw_cb);
231
369
                                break;
232
233
148
                            case UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE:
234
235
148
                                _ux_device_class_storage_request_sense(storage, lun, endpoint_in, endpoint_out, cbw_cb);
236
148
                                break;
237
238
1
                            case UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT:
239
240
1
                                _ux_device_class_storage_format(storage, lun, endpoint_in, endpoint_out, cbw_cb);
241
1
                                break;
242
243
191
                            case UX_SLAVE_CLASS_STORAGE_SCSI_INQUIRY:
244
245
191
                                _ux_device_class_storage_inquiry(storage, lun, endpoint_in, endpoint_out, cbw_cb);
246
191
                                break;
247
248
4
                            case UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP:
249
250
4
                                _ux_device_class_storage_start_stop(storage, lun, endpoint_in, endpoint_out, cbw_cb);
251
4
                                break;
252
253
1
                            case UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL:
254
255
1
                                _ux_device_class_storage_prevent_allow_media_removal(storage, lun, endpoint_in, endpoint_out, cbw_cb);
256
1
                                break;
257
258
355
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ_FORMAT_CAPACITY:
259
260
355
                                _ux_device_class_storage_read_format_capacity(storage, lun, endpoint_in, endpoint_out, cbw_cb);
261
355
                                break;
262
263
184
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ_CAPACITY:
264
265
184
                                _ux_device_class_storage_read_capacity(storage, lun, endpoint_in, endpoint_out, cbw_cb);
266
184
                                break;
267
268
1
                            case UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY:
269
270
1
                                _ux_device_class_storage_verify(storage, lun, endpoint_in, endpoint_out, cbw_cb);
271
1
                                break;
272
273
2
                            case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT:
274
275
2
                                _ux_device_class_storage_mode_select(storage, lun, endpoint_in, endpoint_out, cbw_cb);
276
2
                                break;
277
278
11
                            case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT:
279
                            case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE:
280
281
11
                                _ux_device_class_storage_mode_sense(storage, lun, endpoint_in, endpoint_out, cbw_cb);
282
11
                                break;
283
284
1
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
285
286
1
                                _ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbw_cb,
287
                                                                UX_SLAVE_CLASS_STORAGE_SCSI_READ32);
288
1
                                break;
289
290
617
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
291
292
617
                                _ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbw_cb,
293
                                                                UX_SLAVE_CLASS_STORAGE_SCSI_READ16);
294
616
                                break;
295
296
1
                            case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
297
298
1
                                _ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbw_cb,
299
                                                                UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32);
300
1
                                break;
301
302
394
                            case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
303
304
394
                                _ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbw_cb,
305
                                                                UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16);
306
394
                                break;
307
308
11
                            case UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE:
309
310
11
                                _ux_device_class_storage_synchronize_cache(storage, lun, endpoint_in, endpoint_out, cbw_cb, *(cbw_cb));
311
11
                                break;
312
313
#ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
314
                            case UX_SLAVE_CLASS_STORAGE_SCSI_GET_STATUS_NOTIFICATION:
315
316
                                _ux_device_class_storage_get_status_notification(storage, lun, endpoint_in, endpoint_out, cbw_cb);
317
                                break;
318
319
                            case UX_SLAVE_CLASS_STORAGE_SCSI_GET_CONFIGURATION:
320
321
                                _ux_device_class_storage_get_configuration(storage, lun, endpoint_in, endpoint_out, cbw_cb);
322
                                break;
323
324
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DISK_INFORMATION:
325
326
                                _ux_device_class_storage_read_disk_information(storage, lun, endpoint_in, endpoint_out, cbw_cb);
327
                                break;
328
329
                            case UX_SLAVE_CLASS_STORAGE_SCSI_REPORT_KEY:
330
331
                                _ux_device_class_storage_report_key(storage, lun, endpoint_in, endpoint_out, cbw_cb);
332
                                break;
333
334
                            case UX_SLAVE_CLASS_STORAGE_SCSI_GET_PERFORMANCE:
335
336
                                _ux_device_class_storage_get_performance(storage, lun, endpoint_in, endpoint_out, cbw_cb);
337
                                break;
338
339
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DVD_STRUCTURE:
340
341
                                _ux_device_class_storage_read_dvd_structure(storage, lun, endpoint_in, endpoint_out, cbw_cb);
342
                                break;
343
344
                            case UX_SLAVE_CLASS_STORAGE_SCSI_READ_TOC:
345
346
                                status = _ux_device_class_storage_read_toc(storage, lun, endpoint_in, endpoint_out, cbw_cb);
347
348
                                /* Special treatment of TOC command. If error, default to Stall endpoint.  */
349
                                if (status == UX_SUCCESS)
350
                                    break;
351
#endif
352
353
                            /* fall through */
354
5
                            default:
355
356
                                /* The command is unknown or unsupported, so we stall the endpoint.  */
357
358
5
                                if (storage -> ux_slave_class_storage_host_length > 0 &&
359
2
                                    ((storage -> ux_slave_class_storage_cbw_flags & 0x80) == 0))
360
361
                                    /* Data-Out from host to device, stall OUT.  */
362
1
                                    _ux_device_stack_endpoint_stall(endpoint_out);
363
                                else
364
365
                                    /* Data-In from device to host, stall IN.  */
366
4
                                    _ux_device_stack_endpoint_stall(endpoint_in);
367
368
                                /* Initialize the request sense keys.  */
369
5
                                storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status =
370
                                    UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST,
371
                                                                         UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND,0);
372
373
                                /* This is the tricky part of the SCSI state machine. We must send the CSW BUT need to wait
374
                                   for the endpoint_in to be reset by the host.  */
375
193721
                                while (device -> ux_slave_device_state == UX_DEVICE_CONFIGURED)
376
                                {
377
378
                                    /* Check the endpoint state.  */
379
193720
                                    if (endpoint_in -> ux_slave_endpoint_state == UX_ENDPOINT_RESET)
380
                                    {
381
382
                                        /* Now we set the CSW with failure.  */
383
4
                                        storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
384
4
                                        break;
385
                                    }
386
387
                                    else
388
389
                                        /* We must therefore wait a while.  */
390
193716
                                        _ux_device_thread_relinquish();
391
                                }
392
5
                                break;
393
                            }
394
395
                            /* Send CSW if not SYNC_CACHE.  */
396
2295
                            status = _ux_device_class_storage_csw_send(storage, lun, endpoint_in, 0 /* Don't care */);
397
398
                            /* Check error code. */
399
2292
                            if (status != UX_SUCCESS)
400
401
                                /* Error trap. */
402
3
                                _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, status);
403
                        }
404
                        else
405
406
                            /* Phase error!  */
407
1
                            storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
408
                    }
409
410
                    else
411
412
                        /* Phase error!  */
413
1
                        storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
414
                }
415
                else
416
417
                    /* Phase error!  */
418
256
                    storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
419
            }
420
            else
421
            {
422
423
2553
                if ((UCHAR)storage -> ux_slave_class_storage_csw_status == UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR)
424
                {
425
426
                    /* We should keep the endpoints stalled.  */
427
1804
                    _ux_device_stack_endpoint_stall(endpoint_out);
428
1804
                    _ux_device_stack_endpoint_stall(endpoint_in);
429
                }
430
431
                /* We must therefore wait a while.  */
432
2553
                _ux_utility_delay_ms(2);
433
            }
434
        }
435
436
        /* We need to suspend ourselves. We will be resumed by the
437
           device enumeration module.  */
438
97
        _ux_device_thread_suspend(&class_ptr -> ux_slave_class_thread);
439
    }
440
}
441
#endif