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

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

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