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: 2024-12-12 17:16:36 Branches: 47 47 100.0 %

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