GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usbx_host_classes/src/ux_host_class_storage_thread_entry.c Lines: 73 73 100.0 %
Date: 2026-03-06 18:57:10 Branches: 49 49 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
/**   Storage Class                                                       */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
24
/* Include necessary system files.  */
25
26
#define UX_SOURCE_CODE
27
28
#include "ux_api.h"
29
#include "ux_host_class_storage.h"
30
#include "ux_host_stack.h"
31
32
33
#if !defined(UX_HOST_STANDALONE)
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _ux_host_class_storage_thread_entry                 PORTABLE C      */
39
/*                                                           6.1.11       */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    Chaoqiong Xiao, Microsoft Corporation                               */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function is awaken every 2 seconds to check if there was a     */
47
/*    device insertion on a specific media. This is the only way we can   */
48
/*    remount a media after the storage instance has opened the media to  */
49
/*    UX_MEDIA (default FileX) and the media is either not present        */
50
/*    or was removed and is being re-inserted.                            */
51
/*                                                                        */
52
/*    It's for RTOS mode.                                                 */
53
/*                                                                        */
54
/*  INPUT                                                                 */
55
/*                                                                        */
56
/*    class_address                         Class address                 */
57
/*                                                                        */
58
/*  OUTPUT                                                                */
59
/*                                                                        */
60
/*    None                                                                */
61
/*                                                                        */
62
/*  CALLS                                                                 */
63
/*                                                                        */
64
/*    ux_media_close                        Close media                   */
65
/*    _ux_host_class_storage_device_reset   Reset device                  */
66
/*    _ux_host_class_storage_media_mount    Mount the media               */
67
/*    _ux_host_class_storage_unit_ready_test                              */
68
/*                                          Test for unit ready           */
69
/*    _ux_host_class_storage_media_characteristics_get                    */
70
/*                                          Get media characteristics     */
71
/*    _ux_host_class_storage_media_format_capacity_get                    */
72
/*                                          Get media format capacity     */
73
/*    _ux_utility_memory_free               Free memory block             */
74
/*    _ux_host_semaphore_get                Get a semaphore               */
75
/*    _ux_host_semaphore_put                Put a semaphore               */
76
/*    _ux_utility_delay_ms                  Thread sleep                  */
77
/*                                                                        */
78
/*  CALLED BY                                                             */
79
/*                                                                        */
80
/*    ThreadX                                                             */
81
/*                                                                        */
82
/**************************************************************************/
83
43
VOID  _ux_host_class_storage_thread_entry(ULONG class_address)
84
{
85
86
UX_HOST_CLASS                   *class_inst;
87
UX_HOST_CLASS_STORAGE           *storage;
88
UINT                            status;
89
ULONG                           lun_index;
90
UX_HOST_CLASS_STORAGE_MEDIA     *storage_media;
91
UINT                            media_index;
92
#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
93
UX_MEDIA                        *media;
94
UCHAR                           *memory;
95
#endif
96
97
98
    /* Setup pointer to class.  */
99
43
    UX_THREAD_EXTENSION_PTR_GET(class_inst, UX_HOST_CLASS, class_address)
100
101
    /* This thread goes on forever once started.  */
102
    while(1)
103
    {
104
105
        /* We need to wake every 2 seconds or so.  */
106
354
        _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
107
108
        /* We need to parse all the storage instances and check for a removable
109
           media flag.  */
110
311
        storage =  (UX_HOST_CLASS_STORAGE *) class_inst -> ux_host_class_first_instance;
111
112
518
        while (storage != UX_NULL)
113
        {
114
115
            /* Check if the instance is live and the device is removable.  */
116
278
            if ((storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE))
117
            {
118
119
                /* We need to ensure nobody is accessing this storage instance. We use
120
                   the storage class instance semaphore to protect.  */
121
253
                status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
122
253
                if (status != UX_SUCCESS)
123
71
                    break;
124
125
                /* Each LUN must be parsed and mounted.  */
126
368
                for (lun_index = 0; lun_index <= storage -> ux_host_class_storage_max_lun; lun_index++)
127
                {
128
129
190
                    if (storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] != UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE)
130
20
                        continue;
131
132
                    /* Check the type of LUN, we only deal with the ones we know how to mount.  */
133
170
                    if ((storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) ||
134
133
                        (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK) ||
135
131
                        (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK))
136
                    {
137
138
                        /* Set the LUN into the storage instance.  */
139
168
                        storage -> ux_host_class_storage_lun =  lun_index;
140
141
                        /* Check if the device is now ready.  */
142
168
                        status =  _ux_host_class_storage_unit_ready_test(storage);
143
144
                        /* If we have an transport failure here, we are in trouble! The storage device
145
                           is in an unstable state and should be reset completely.  */
146
168
                        if (status != UX_SUCCESS)
147
                        {
148
149
                            /* Reset device.  */
150
4
                            _ux_host_class_storage_device_reset(storage);
151
4
                            break;
152
                        }
153
154
                        /* Process relative to device status.  */
155
164
                        switch(storage -> ux_host_class_storage_sense_code >> 16)
156
                        {
157
158
26
                        case UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY:
159
160
                            /* We may need to unmount this partition if it was mounted before.
161
                               To do so, we need to parse the existing media instance and find out
162
                               if this partition was already mounted.  */
163
164
26
                            storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
165
166
                            /* Scan all instances of media.  */
167
72
                            for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
168
46
                                storage_media++, media_index++)
169
                            {
170
#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
171
                                /* Get the UX_MEDIA (default FileX) Media attached to this media.  */
172
49
                                media =  &storage_media -> ux_host_class_storage_media;
173
174
                                /* Check for the storage instance and lun number.  */
175

49
                                if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
176
13
                                    (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
177
                                {
178
179
                                    /* We preserve the memory used by this media.  */
180
12
                                    memory =  storage_media -> ux_host_class_storage_media_memory;
181
182
                                    /* Let UX_MEDIA (default FileX) use this instance.  */
183
12
                                    _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
184
185
                                    /* Ask UX_MEDIA (default FileX) to unmount the partition.  */
186
12
                                    ux_media_close(media);
187
188
                                    /* This device is now unmounted.  */
189
12
                                    storage_media -> ux_host_class_storage_media_status = UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
190
191
                                    /* Reset the media ID.  */
192
12
                                    ux_media_id_set(media, 0);
193
194
                                    /* Now, we protect the storage instance.  */
195
12
                                    status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
196
12
                                    if (status != UX_SUCCESS)
197
3
                                        break;
198
199
                                    /* Free the memory block used for data transfer on behalf of UX_MEDIA (default FileX).  */
200
9
                                    _ux_utility_memory_free(memory);
201
                                }
202
#else
203
204
                                /* Check storage instance and lun number.  */
205
                                if (storage_media -> ux_host_class_storage_media_status != UX_USED)
206
                                    continue;
207
                                if (storage_media -> ux_host_class_storage_media_storage != storage)
208
                                    continue;
209
                                if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
210
                                    continue;
211
212
                                /* Release the instance.  */
213
                                status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
214
215
                                /* Free the storage media.  */
216
                                storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
217
218
                                /* Invoke callback for media removal.  */
219
                                if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
220
                                {
221
222
                                    /* Call system change function.  */
223
                                    _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
224
                                                        storage -> ux_host_class_storage_class, (VOID *) storage_media);
225
                                }
226
227
                                /* Now, we protect the storage instance.  */
228
                                status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
229
                                if (status != UX_SUCCESS)
230
                                    break;
231
#endif
232
                            }
233
26
                            break;
234
235
34
                            case UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION:
236
237
                                /* We may need to unmount this partition if it was mounted before.
238
                                   To do so, we need to parse the existing media instance and find out
239
                                   if this partition was already mounted.  */
240
34
                                storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
241
242
                                /* Scan all instances of media.   */
243
96
                                for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
244
62
                                    storage_media++, media_index++)
245
                                {
246
247
#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
248
                                    /* Get the UX_MEDIA (default FileX) Media attached to this media.  */
249
65
                                    media = &storage_media -> ux_host_class_storage_media;
250
251
                                    /* Check for the storage instance and lun number. */
252

65
                                    if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
253
18
                                            (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
254
                                    {
255
256
                                        /* We preserve the memory used by this media.  */
257
17
                                        memory =  storage_media -> ux_host_class_storage_media_memory;
258
259
                                        /* Let UX_MEDIA (default FileX) use this instance.  */
260
17
                                        _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
261
262
                                        /* Ask UX_MEDIA (default FileX) to unmount the partition.  */
263
17
                                        ux_media_close(media);
264
265
                                        /* This device is now unmounted.  */
266
17
                                        storage_media -> ux_host_class_storage_media_status =  UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
267
268
                                        /* Reset the media ID.  */
269
17
                                        ux_media_id_set(media, 0);
270
271
                                        /* Now, we protect the storage instance.  */
272
17
                                        status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
273
17
                                        if (status != UX_SUCCESS)
274
3
                                            break;
275
276
                                        /* Free the memory block used for data transfer on behalf of FileX.  */
277
14
                                        _ux_utility_memory_free(memory);
278
                                    }
279
#else
280
281
                                    /* Check storage instance and lun number.  */
282
                                    if (storage_media -> ux_host_class_storage_media_status != UX_USED)
283
                                        continue;
284
                                    if (storage_media -> ux_host_class_storage_media_storage != storage)
285
                                        continue;
286
                                    if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
287
                                        continue;
288
289
                                    /* Release the instance.  */
290
                                    status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
291
292
                                    /* Free the storage media.  */
293
                                    storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
294
295
                                    /* Invoke callback for media removal.  */
296
                                    if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
297
                                    {
298
299
                                        /* Call system change function.  */
300
                                        _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
301
                                                            storage -> ux_host_class_storage_class, (VOID *) storage_media);
302
                                    }
303
304
                                    /* Now, we protect the storage instance.  */
305
                                    status =  _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
306
                                    if (status != UX_SUCCESS)
307
                                        break;
308
#endif
309
                                }
310
311
                                /* Now, we need to retest the media to see if it is there.  */
312
34
                                status =  _ux_host_class_storage_unit_ready_test(storage);
313
314
                                /* If we have an transport failure here, we are in trouble! The storage device
315
                                   is in an unstable state and should be reset completely.  */
316
34
                                if (status != UX_SUCCESS)
317
                                {
318
319
                                    /* Reset device.  */
320
3
                                    _ux_host_class_storage_device_reset(storage);
321
3
                                    break;
322
                                }
323
324
31
                                if (storage -> ux_host_class_storage_sense_code == 0)
325
                                {
326
327
                                    /* Get the media type supported by this storage device.  */
328
30
                                    status =  _ux_host_class_storage_media_characteristics_get(storage);
329
30
                                    if (status != UX_SUCCESS)
330
1
                                        break;
331
332
                                    /* Get the format capacity of this storage device.  */
333
29
                                    status =  _ux_host_class_storage_media_format_capacity_get(storage);
334
29
                                    if (status != UX_SUCCESS)
335
1
                                        break;
336
337
                                    /* Let UX_MEDIA (default FileX) use this instance.  */
338
28
                                    _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
339
340
#if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
341
342
                                    /* The device seems to have been inserted, try to mount it.  */
343
28
                                    _ux_host_class_storage_media_mount(storage, 0);
344
#else
345
346
                                    /* Find a free media slot for inserted media.  */
347
                                    storage_media =  (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
348
                                    for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
349
                                        storage_media ++, media_index ++)
350
                                    {
351
352
                                        /* Skip used storage media slots.  */
353
                                        if (storage_media -> ux_host_class_storage_media_status == UX_USED)
354
                                            continue;
355
356
                                        /* Use this free storage media slot.  */
357
                                        storage_media -> ux_host_class_storage_media_status = UX_USED;
358
                                        storage_media -> ux_host_class_storage_media_storage = storage;
359
360
                                        /* Save media information.  */
361
                                        storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun;
362
                                        storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size;
363
                                        storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1;
364
365
                                        /* Invoke callback for media insertion.  */
366
                                        if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
367
                                        {
368
369
                                            /* Call system change function.  */
370
                                            _ux_system_host ->  ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION,
371
                                                                storage -> ux_host_class_storage_class, (VOID *) storage_media);
372
                                        }
373
                                    }
374
#endif
375
376
                                    /* Now, we protect the storage instance.  */
377
28
                                    _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
378
                                }
379
29
                                break;
380
381
104
                            default:
382
104
                                break;
383
                        }
384
                    }
385
                }
386
387
                /* Other threads are now allowed to access this storage instance.  */
388
182
                _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
389
            }
390
391
            /* Move to the next entry in the storage instances link.  */
392
207
            storage =  storage -> ux_host_class_storage_next_instance;
393
        }
394
    }
395
}
396
#endif