GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: fx_media_open.c Lines: 299 299 100.0 %
Date: 2026-03-06 18:49:02 Branches: 88 88 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
/** FileX Component                                                       */
17
/**                                                                       */
18
/**   Media                                                               */
19
/**                                                                       */
20
/**************************************************************************/
21
/**************************************************************************/
22
23
#define FX_SOURCE_CODE
24
25
26
/* Include necessary system files.  */
27
28
#include "fx_api.h"
29
#include "fx_system.h"
30
#include "fx_media.h"
31
#include "fx_utility.h"
32
33
34
/**************************************************************************/
35
/*                                                                        */
36
/*  FUNCTION                                               RELEASE        */
37
/*                                                                        */
38
/*    _fx_media_open                                      PORTABLE C      */
39
/*                                                           6.2.0        */
40
/*  AUTHOR                                                                */
41
/*                                                                        */
42
/*    William E. Lamie, Microsoft Corporation                             */
43
/*                                                                        */
44
/*  DESCRIPTION                                                           */
45
/*                                                                        */
46
/*    This function opens the specified media with the supplied device    */
47
/*    driver.  The specified media must conform to the FAT compatible     */
48
/*    file format, which is verified during the media open process.  In   */
49
/*    addition, the supplied FileX device driver must also conform to     */
50
/*    the FileX device driver specification.                              */
51
/*                                                                        */
52
/*    The FAT boot sector (512 bytes) that is verified by this            */
53
/*    function must look like the following:                              */
54
/*                                                                        */
55
/*          Byte Offset         Meaning             Size                  */
56
/*                                                                        */
57
/*            0x000         Jump Instructions        3                    */
58
/*            0x003         OEM Name                 8                    */
59
/*            0x00B        *Bytes per Sector         2                    */
60
/*            0x00D        *Sectors per Cluster      1                    */
61
/*            0x00E        *Reserved Sectors         2                    */
62
/*            0x010        *Number of FATs           1                    */
63
/*            0x011        *Max Root Dir Entries     2                    */
64
/*            0x013        *Number of Sectors        2                    */
65
/*            0x015         Media Type               1                    */
66
/*            0x016        *Sectors per FAT          2                    */
67
/*            0x018        *Sectors per Track        2                    */
68
/*            0x01A        *Number of Heads          2                    */
69
/*            0x01C        *Hidden Sectors           4                    */
70
/*            0x020        *Huge Sectors             4                    */
71
/*            0x024         Drive Number             1                    */
72
/*            0x025         Reserved                 1                    */
73
/*            0x026         Boot Signature           1                    */
74
/*            0x027         Volume ID                4                    */
75
/*            0x02B         Volume Label             11                   */
76
/*            0x036         File System Type         8                    */
77
/*             ...              ...                 ...                   */
78
/*            0x1FE       **Signature (0x55aa)       2                    */
79
/*                                                                        */
80
/*            * Denotes which elements of the boot record                 */
81
/*              FileX uses.                                               */
82
/*                                                                        */
83
/*            **Denotes the element is checked by the I/O                 */
84
/*              driver.  This eliminates the need for a minimum           */
85
/*              512-byte buffer for FileX.                                */
86
/*                                                                        */
87
/*  Note: All values above are in little endian format, i.e. the LSB is   */
88
/*        in the lowest address.                                          */
89
/*                                                                        */
90
/*  INPUT                                                                 */
91
/*                                                                        */
92
/*    media_ptr                             Media control block pointer   */
93
/*    media_name                            Pointer to media name string  */
94
/*    media_driver                          Media driver entry function   */
95
/*    driver_info_ptr                       Optional information pointer  */
96
/*                                            supplied to media driver    */
97
/*    memory_ptr                            Pointer to memory used by the */
98
/*                                            FileX for this media.       */
99
/*    memory_size                           Size of media memory - must   */
100
/*                                            at least 512 bytes and      */
101
/*                                            one sector size.            */
102
/*                                                                        */
103
/*  OUTPUT                                                                */
104
/*                                                                        */
105
/*    return status                                                       */
106
/*                                                                        */
107
/*  CALLS                                                                 */
108
/*                                                                        */
109
/*    I/O Driver                                                          */
110
/*    _fx_utility_16_unsigned_read          Read 16-bit unsigned value    */
111
/*    _fx_utility_32_unsigned_read          Read 32-bit unsigned value    */
112
/*    _fx_utility_logical_sector_flush      Invalidate log sector cache   */
113
/*    _fx_media_boot_info_extract           Extract media information     */
114
/*    _fx_utility_FAT_entry_read            Pickup FAT entry contents     */
115
/*    tx_mutex_create                       Create protection mutex       */
116
/*                                                                        */
117
/*  CALLED BY                                                             */
118
/*                                                                        */
119
/*    Application Code                                                    */
120
/*                                                                        */
121
/**************************************************************************/
122
7254
UINT  _fx_media_open(FX_MEDIA *media_ptr, CHAR *media_name,
123
                     VOID (*media_driver)(FX_MEDIA *), VOID *driver_info_ptr,
124
                     VOID *memory_ptr, ULONG memory_size)
125
{
126
127
FX_MEDIA_PTR      tail_ptr;
128
ULONG             cluster_number;
129
ULONG             FAT_entry, FAT_sector, FAT_read_sectors;
130
ULONG             i, j;
131
#ifndef FX_DISABLE_CACHE
132
FX_CACHED_SECTOR *cache_entry_ptr;
133
#endif /* FX_DISABLE_CACHE */
134
UINT              status;
135
UINT              additional_info_sector;
136
UCHAR            *original_memory_ptr;
137
ULONG             bytes_in_buffer;
138
FX_INT_SAVE_AREA
139
140
141
#ifndef FX_DISABLE_BUILD_OPTIONS
142
    /* Reference the version ID and option words to ensure they are linked in.  */
143
7254
    if ((_fx_system_build_options_1 | _fx_system_build_options_2 | _fx_system_build_options_3) == 0 ||
144
7253
        _fx_version_id[0] == 0)
145
    {
146
147
        /* We should never get here!  */
148
2
        return(FX_NOT_IMPLEMENTED);
149
    }
150
#endif /* FX_DISABLE_BUILD_OPTIONS */
151
152
#ifdef FX_DISABLE_FORCE_MEMORY_OPERATION
153
    _fx_utility_memory_set((UCHAR *)media_ptr, 0, sizeof(FX_MEDIA));
154
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
155
#ifdef FX_DISABLE_CACHE
156
    media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
157
#endif /* FX_DISABLE_CACHE */
158
159
    /* Save the basic information in the media control block.  */
160
7252
    media_ptr -> fx_media_name =                        media_name;
161
7252
    media_ptr -> fx_media_driver_entry =                media_driver;
162
7252
    media_ptr -> fx_media_memory_buffer =               (UCHAR *)memory_ptr;
163
7252
    media_ptr -> fx_media_memory_size =                 memory_size;
164
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
165
7252
    media_ptr -> fx_media_disable_burst_cache =         FX_FALSE;
166
7252
    media_ptr -> fx_media_FAT_type =                    0;
167
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
168
169
    /* Save the original memory pointer.  */
170
7252
    original_memory_ptr =  (UCHAR *)memory_ptr;
171
172
#ifndef FX_MEDIA_STATISTICS_DISABLE
173
174
    /* Clear the optional media statistics.  */
175
7252
    media_ptr -> fx_media_directory_attributes_reads =  0;
176
7252
    media_ptr -> fx_media_directory_attributes_sets =  0;
177
7252
    media_ptr -> fx_media_directory_creates =  0;
178
7252
    media_ptr -> fx_media_directory_default_gets =  0;
179
7252
    media_ptr -> fx_media_directory_default_sets =  0;
180
7252
    media_ptr -> fx_media_directory_deletes =  0;
181
7252
    media_ptr -> fx_media_directory_first_entry_finds =  0;
182
7252
    media_ptr -> fx_media_directory_first_full_entry_finds =  0;
183
7252
    media_ptr -> fx_media_directory_information_gets =  0;
184
7252
    media_ptr -> fx_media_directory_local_path_clears =  0;
185
7252
    media_ptr -> fx_media_directory_local_path_gets =  0;
186
7252
    media_ptr -> fx_media_directory_local_path_restores =  0;
187
7252
    media_ptr -> fx_media_directory_local_path_sets =  0;
188
7252
    media_ptr -> fx_media_directory_name_tests =  0;
189
7252
    media_ptr -> fx_media_directory_next_entry_finds =  0;
190
7252
    media_ptr -> fx_media_directory_next_full_entry_finds =  0;
191
7252
    media_ptr -> fx_media_directory_renames =  0;
192
7252
    media_ptr -> fx_media_file_allocates =  0;
193
7252
    media_ptr -> fx_media_file_attributes_reads =  0;
194
7252
    media_ptr -> fx_media_file_attributes_sets =  0;
195
7252
    media_ptr -> fx_media_file_best_effort_allocates =  0;
196
7252
    media_ptr -> fx_media_file_closes =  0;
197
7252
    media_ptr -> fx_media_file_creates =  0;
198
7252
    media_ptr -> fx_media_file_deletes =  0;
199
7252
    media_ptr -> fx_media_file_opens =  0;
200
7252
    media_ptr -> fx_media_file_reads =  0;
201
7252
    media_ptr -> fx_media_file_relative_seeks =  0;
202
7252
    media_ptr -> fx_media_file_renames =  0;
203
7252
    media_ptr -> fx_media_file_seeks =  0;
204
7252
    media_ptr -> fx_media_file_truncates =  0;
205
7252
    media_ptr -> fx_media_file_truncate_releases =  0;
206
7252
    media_ptr -> fx_media_file_writes =  0;
207
7252
    media_ptr -> fx_media_aborts =  0;
208
7252
    media_ptr -> fx_media_flushes =  0;
209
7252
    media_ptr -> fx_media_reads =  0;
210
7252
    media_ptr -> fx_media_writes =  0;
211
7252
    media_ptr -> fx_media_directory_entry_reads =  0;
212
7252
    media_ptr -> fx_media_directory_entry_writes =  0;
213
7252
    media_ptr -> fx_media_directory_searches =  0;
214
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
215
7252
    media_ptr -> fx_media_directory_search_cache_hits =  0;
216
#endif
217
7252
    media_ptr -> fx_media_directory_free_searches =  0;
218
7252
    media_ptr -> fx_media_fat_entry_reads =  0;
219
7252
    media_ptr -> fx_media_fat_entry_writes =  0;
220
7252
    media_ptr -> fx_media_fat_entry_cache_read_hits =  0;
221
7252
    media_ptr -> fx_media_fat_entry_cache_read_misses =  0;
222
7252
    media_ptr -> fx_media_fat_entry_cache_write_hits =  0;
223
7252
    media_ptr -> fx_media_fat_entry_cache_write_misses =  0;
224
7252
    media_ptr -> fx_media_fat_cache_flushes =  0;
225
7252
    media_ptr -> fx_media_fat_sector_reads =  0;
226
7252
    media_ptr -> fx_media_fat_sector_writes =  0;
227
7252
    media_ptr -> fx_media_logical_sector_reads =  0;
228
7252
    media_ptr -> fx_media_logical_sector_writes =  0;
229
7252
    media_ptr -> fx_media_logical_sector_cache_read_hits =  0;
230
7252
    media_ptr -> fx_media_logical_sector_cache_read_misses =  0;
231
7252
    media_ptr -> fx_media_driver_read_requests =  0;
232
7252
    media_ptr -> fx_media_driver_write_requests =  0;
233
7252
    media_ptr -> fx_media_driver_boot_read_requests =  0;
234
7252
    media_ptr -> fx_media_driver_boot_write_requests =  0;
235
7252
    media_ptr -> fx_media_driver_release_sectors_requests =  0;
236
7252
    media_ptr -> fx_media_driver_flush_requests =  0;
237
#endif
238
#ifdef FX_ENABLE_FAULT_TOLERANT
239
    media_ptr -> fx_media_fault_tolerant_enabled = FX_FALSE;
240
    media_ptr -> fx_media_fault_tolerant_state = 0;
241
#endif /* FX_ENABLE_FAULT_TOLERANT */
242
243
    /* If trace is enabled, insert this event into the trace buffer.  */
244
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_OPEN, media_ptr, media_driver, memory_ptr, memory_size, FX_TRACE_MEDIA_EVENTS, 0, 0)
245
246
    /* Initialize the supplied media I/O driver.  First, build the
247
       initialize driver request. Set the fx_media_driver_status to FX_MEDIA_NOT_OPEN
248
       to let the driver understand that the request is issued from a fx_media_open() call.
249
    */
250
7252
    media_ptr -> fx_media_driver_request =              FX_DRIVER_INIT;
251
7252
    media_ptr -> fx_media_driver_status =               FX_MEDIA_NOT_OPEN;
252
7252
    media_ptr -> fx_media_driver_info =                 driver_info_ptr;
253
7252
    media_ptr -> fx_media_driver_write_protect =        FX_FALSE;
254
7252
    media_ptr -> fx_media_driver_free_sector_update =   FX_FALSE;
255
7252
    media_ptr -> fx_media_driver_data_sector_read =     FX_FALSE;
256
257
    /* If trace is enabled, insert this event into the trace buffer.  */
258
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_INIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
259
260
    /* Call the specified I/O driver with the initialize request.  */
261
7252
    (media_ptr -> fx_media_driver_entry) (media_ptr);
262
263
    /* Determine if the I/O driver initialized successfully.  */
264
7252
    if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
265
    {
266
267
        /* Return the driver error status.  */
268
836
        return(FX_IO_ERROR);
269
    }
270
271
#ifndef FX_MEDIA_STATISTICS_DISABLE
272
273
    /* Increment the number of driver boot read requests.  */
274
6416
    media_ptr -> fx_media_driver_boot_read_requests++;
275
#endif
276
277
    /* Read the boot sector from the device.  Build the read boot sector
278
       command.  */
279
6416
    media_ptr -> fx_media_driver_request =          FX_DRIVER_BOOT_READ;
280
6416
    media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
281
6416
    media_ptr -> fx_media_driver_buffer =           memory_ptr;
282
6416
    media_ptr -> fx_media_driver_sectors =          1;
283
6416
    media_ptr -> fx_media_driver_sector_type =      FX_BOOT_SECTOR;
284
285
    /* If trace is enabled, insert this event into the trace buffer.  */
286
    FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_READ, media_ptr, memory_ptr, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
287
288
    /* Invoke the driver to read the boot sector.  */
289
6416
    (media_ptr -> fx_media_driver_entry) (media_ptr);
290
291
    /* Determine if the boot sector was read correctly. */
292
6416
    if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
293
    {
294
295
        /* Build the "uninitialize" I/O driver request.  */
296
388
        media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
297
388
        media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
298
299
        /* If trace is enabled, insert this event into the trace buffer.  */
300
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
301
302
        /* Call the specified I/O driver with the uninitialize request.  */
303
388
        (media_ptr -> fx_media_driver_entry) (media_ptr);
304
305
        /* Return the boot sector error status.  */
306
388
        return(FX_BOOT_ERROR);
307
    }
308
309
    /* Extract and validate the media parameters from the boot sector.  */
310
6028
    if (_fx_media_boot_info_extract(media_ptr) != FX_SUCCESS)
311
    {
312
313
        /* Build the "uninitialize" I/O driver request.  */
314
6
        media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
315
6
        media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
316
317
        /* If trace is enabled, insert this event into the trace buffer.  */
318
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
319
320
        /* Call the specified I/O driver with the uninitialize request.  */
321
6
        (media_ptr -> fx_media_driver_entry) (media_ptr);
322
323
        /* Return the invalid media error status.  */
324
6
        return(FX_MEDIA_INVALID);
325
    }
326
327
    /* Pickup the additional info sector number. This will only be used in FAT32 situations.  */
328
6022
    additional_info_sector =  _fx_utility_16_unsigned_read(&media_ptr -> fx_media_driver_buffer[48]);
329
330
    /* Is there at least one?  */
331
6022
    if (memory_size < media_ptr -> fx_media_bytes_per_sector)
332
    {
333
334
        /* Build the "uninitialize" I/O driver request.  */
335
1
        media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
336
1
        media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
337
338
        /* If trace is enabled, insert this event into the trace buffer.  */
339
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
340
341
        /* Call the specified I/O driver with the uninitialize request.  */
342
1
        (media_ptr -> fx_media_driver_entry) (media_ptr);
343
344
        /* Error in the buffer size supplied by user.  */
345
1
        return(FX_BUFFER_ERROR);
346
    }
347
348
#ifndef FX_DISABLE_CACHE
349
    /* Determine how many logical sectors can be cached with user's supplied
350
       buffer area - there must be at least enough for one sector!  */
351
6021
    media_ptr -> fx_media_sector_cache_size =  memory_size / media_ptr -> fx_media_bytes_per_sector;
352
353
    /* If trace is enabled, register this object.  */
354
    FX_TRACE_OBJECT_REGISTER(FX_TRACE_OBJECT_TYPE_MEDIA, media_ptr, media_name, FX_MAX_FAT_CACHE, media_ptr -> fx_media_sector_cache_size)
355
356
    /* Adjust the internal cache to fit the fixed number of sector cache control blocks
357
       built into the media control block.  */
358
6021
    if (media_ptr -> fx_media_sector_cache_size > FX_MAX_SECTOR_CACHE)
359
    {
360
361
        /* Adjust the number of cache sectors downward.  If this is insufficient,
362
           the FX_MAX_SECTOR_CACHE constant in FX_API.H must be changed and the FileX
363
           library must be rebuilt.  */
364
1
        media_ptr -> fx_media_sector_cache_size =  FX_MAX_SECTOR_CACHE;
365
    }
366
367
    /* Otherwise, everything is okay.  Initialize the data structures for managing the
368
       logical sector cache.  */
369
6021
    i =  (UINT)media_ptr -> fx_media_sector_cache_size;
370
6021
    cache_entry_ptr =  media_ptr -> fx_media_sector_cache;
371
21611
    while (i--)
372
    {
373
374
        /* Initialize each of the cache entries.  */
375
15590
        cache_entry_ptr -> fx_cached_sector_memory_buffer =  (UCHAR *)memory_ptr;
376
15590
        cache_entry_ptr -> fx_cached_sector =                (~(ULONG64)0);
377
15590
        cache_entry_ptr -> fx_cached_sector_buffer_dirty =   FX_FALSE;
378
15590
        cache_entry_ptr -> fx_cached_sector_valid =          FX_FALSE;
379
15590
        cache_entry_ptr -> fx_cached_sector_next_used =      cache_entry_ptr + 1;
380
381
        /* Move to the next cache sector entry.  */
382
15590
        cache_entry_ptr++;
383
384
        /* Update the memory pointer to the next buffer slot.  */
385
15590
        memory_ptr =  (VOID *)(((UCHAR *)memory_ptr) + media_ptr -> fx_media_bytes_per_sector);
386
    }
387
388
    /* Backup to the last cache entry to set its next pointer to NULL.  */
389
6021
    cache_entry_ptr--;
390
6021
    cache_entry_ptr -> fx_cached_sector_next_used =  FX_NULL;
391
392
    /* Remember the last memory address used by the caching logic.  */
393
6021
    media_ptr -> fx_media_sector_cache_end =  ((UCHAR *)memory_ptr) - 1;
394
395
    /* Setup the head pointer of the list.  */
396
6021
    media_ptr -> fx_media_sector_cache_list_ptr =  media_ptr -> fx_media_sector_cache;
397
398
    /* Setup the bit map that keeps track of the valid hashed cache logical sectors.  */
399
6021
    media_ptr -> fx_media_sector_cache_hashed_sector_valid =  0;
400
401
    /* Clear the counter of the number of outstanding dirty sectors.  */
402
6021
    media_ptr -> fx_media_sector_cache_dirty_count =  0;
403
404
    /* Determine if the logical sector cache should be managed by the hash function
405
       instead of the linear search. The cache must be a power of 2 that is between the
406
       minimum and maximum cache size.  */
407
6021
    if ((media_ptr -> fx_media_sector_cache_size >= FX_SECTOR_CACHE_HASH_ENABLE) &&
408
138
        ((media_ptr -> fx_media_sector_cache_size ^ (media_ptr -> fx_media_sector_cache_size - 1)) ==
409
138
         (media_ptr -> fx_media_sector_cache_size | (media_ptr -> fx_media_sector_cache_size - 1))))
410
    {
411
412
413
        /* Set the logical sector cache hash flag. When this flag is set, the logical
414
           sector cache is accessed with a hash function instead of a linear search.  */
415
136
        media_ptr -> fx_media_sector_cache_hashed =  FX_TRUE;
416
136
        media_ptr -> fx_media_sector_cache_hash_mask =
417
136
            ((media_ptr -> fx_media_sector_cache_size / FX_SECTOR_CACHE_DEPTH) - 1);
418
    }
419
    else
420
    {
421
422
        /* Clear the logical sector cache flag.  */
423
5885
        media_ptr -> fx_media_sector_cache_hashed =  FX_FALSE;
424
    }
425
#else
426
    media_ptr -> fx_media_memory_buffer = memory_ptr;
427
#endif /* FX_DISABLE_CACHE */
428
429
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
430
    /* Initialize the FAT cache entry array.  */
431
391365
    for (i = 0; i < FX_MAX_FAT_CACHE; i++)
432
    {
433
434
        /* Clear entry in the FAT cache.  */
435
385344
        media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_cluster =   0;
436
385344
        media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_value   =   0;
437
385344
        media_ptr -> fx_media_fat_cache[i].fx_fat_cache_entry_dirty   =   0;
438
    }
439
440
    /* Initialize the secondary FAT update map.  */
441
12042
    for (i = 0; i < FX_FAT_MAP_SIZE; i++)
442
    {
443
444
        /* Clear bit map entry for secondary FAT update.  */
445
6021
        media_ptr -> fx_media_fat_secondary_update_map[i] =  0;
446
    }
447
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
448
449
450
    /* Root_sector_start has been computed */
451
6021
    media_ptr -> fx_media_root_sector_start =  media_ptr -> fx_media_reserved_sectors +
452
6021
        (media_ptr -> fx_media_number_of_FATs *
453
6021
         media_ptr -> fx_media_sectors_per_FAT);
454
455
    /* Calculate the number of directory sectors.  */
456
6021
    media_ptr -> fx_media_root_sectors =
457
6021
        ((media_ptr -> fx_media_root_directory_entries * FX_DIR_ENTRY_SIZE) +
458
6021
         media_ptr -> fx_media_bytes_per_sector - 1) /
459
6021
        media_ptr -> fx_media_bytes_per_sector;
460
461
    /* Calculate the starting data sector.  */
462
6021
    media_ptr -> fx_media_data_sector_start =  media_ptr -> fx_media_root_sector_start +
463
6021
        media_ptr -> fx_media_root_sectors;
464
465
    /* Calculate the total number of clusters.  */
466
6021
    media_ptr -> fx_media_total_clusters =  (ULONG)((media_ptr -> fx_media_total_sectors - media_ptr -> fx_media_data_sector_start) /
467
6021
                                                        media_ptr -> fx_media_sectors_per_cluster);
468
469
    /* Determine if a 12-bit FAT is in use.  */
470
6021
    if (media_ptr -> fx_media_total_clusters < FX_12_BIT_FAT_SIZE)
471
    {
472
473
        /* Yes, 12-bit FAT is present.  Set flag accordingly.  */
474
106
        media_ptr -> fx_media_12_bit_FAT = FX_TRUE;
475
106
        media_ptr -> fx_media_32_bit_FAT = FX_FALSE;
476
477
        /* No additional information sector in FAT12.  */
478
106
        media_ptr -> fx_media_FAT32_additional_info_sector =  0;
479
480
        /* Set FAT last and FAT reserved. */
481
106
        media_ptr -> fx_media_fat_reserved = FX_RESERVED_1;
482
106
        media_ptr -> fx_media_fat_last = FX_LAST_CLUSTER_2;
483
    }
484
5915
    else if (media_ptr -> fx_media_total_clusters < FX_16_BIT_FAT_SIZE)
485
    {
486
487
        /* A 16-bit FAT is present.  Set flag accordingly.  */
488
2083
        media_ptr -> fx_media_12_bit_FAT =  FX_FALSE;
489
2083
        media_ptr -> fx_media_32_bit_FAT =  FX_FALSE;
490
491
        /* No additional information sector in FAT16.  */
492
2083
        media_ptr -> fx_media_FAT32_additional_info_sector =  0;
493
494
        /* Set FAT last and FAT reserved. */
495
2083
        media_ptr -> fx_media_fat_reserved = FX_RESERVED_1;
496
2083
        media_ptr -> fx_media_fat_last = FX_LAST_CLUSTER_2;
497
    }
498
    else
499
    {
500
501
        /* Yes, a 32-bit FAT is present.  */
502
3832
        media_ptr -> fx_media_12_bit_FAT =  FX_FALSE;
503
3832
        media_ptr -> fx_media_32_bit_FAT =  FX_TRUE;
504
505
        /* Save the additional information sector FAT32. This was read from the boot
506
           sector earlier in this routine. */
507
3832
        media_ptr -> fx_media_FAT32_additional_info_sector =  additional_info_sector;
508
509
        /* Set FAT last and FAT reserved. */
510
3832
        media_ptr -> fx_media_fat_reserved = FX_RESERVED_1_32;
511
3832
        media_ptr -> fx_media_fat_last = FX_LAST_CLUSTER_2_32;
512
    }
513
514
    /* Determine if a 32-bit FAT is present. If so, calculate the size of the root directory (since
515
       it is variable in FAT32.  */
516
6021
    if (media_ptr -> fx_media_32_bit_FAT == FX_TRUE)
517
    {
518
519
        /* Root First cluster starts from at least cluster 2, or higher. */
520
3832
        if (media_ptr -> fx_media_root_cluster_32 < FX_FAT_ENTRY_START)
521
        {
522
1
            return(FX_MEDIA_INVALID);
523
        }
524
525
        /* Calculate logical number of root dir sector.  */
526
3831
        media_ptr -> fx_media_root_sector_start = media_ptr -> fx_media_data_sector_start +
527
3831
            (media_ptr -> fx_media_root_cluster_32 - FX_FAT_ENTRY_START) *
528
3831
            media_ptr -> fx_media_sectors_per_cluster;
529
530
        /* Calculate maximum possible value for fx_media_root_directory_entries */
531
3831
        i = 0;
532
3831
        for (cluster_number = media_ptr -> fx_media_root_cluster_32;;)
533
        {
534
535
73290
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster_number, &FAT_entry);
536
73290
            i++;
537
            /* Determine if the read was successful.  */
538
73290
            if (status != FX_SUCCESS)
539
            {
540
541
                /* Build the "uninitialize" I/O driver request.  */
542
376
                media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
543
376
                media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
544
545
                /* If trace is enabled, insert this event into the trace buffer.  */
546
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
547
548
                /* Call the specified I/O driver with the uninitialize request.  */
549
376
                (media_ptr -> fx_media_driver_entry) (media_ptr);
550
551
376
                return(FX_FAT_READ_ERROR);
552
            }
553
554

72914
            if ((cluster_number == FAT_entry) || (i > media_ptr -> fx_media_total_clusters))
555
            {
556
557
                /* Build the "uninitialize" I/O driver request.  */
558
2
                media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
559
2
                media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
560
561
                /* If trace is enabled, insert this event into the trace buffer.  */
562
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
563
564
                /* Call the specified I/O driver with the uninitialize request.  */
565
2
                (media_ptr -> fx_media_driver_entry) (media_ptr);
566
567
2
                return(FX_FAT_READ_ERROR);
568
            }
569
72912
            if (FAT_entry >= FX_RESERVED_1_32)
570
            {
571
3453
                break;
572
            }
573
69459
            cluster_number = FAT_entry;
574
        }
575
576
        /* Calculate the number of directory entries.  */
577
3453
        media_ptr -> fx_media_root_directory_entries =  (i * media_ptr -> fx_media_sectors_per_cluster *
578
3453
                                                         media_ptr -> fx_media_bytes_per_sector) / FX_DIR_ENTRY_SIZE;
579
    }
580
581
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
582
    /* Calculate the number of available clusters.  */
583
5642
    media_ptr -> fx_media_available_clusters =  0;
584
585
    /* Set the cluster search start to an invalid value.  */
586
5642
    media_ptr -> fx_media_cluster_search_start =  0;
587
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
588
589
    /* Determine if there is 32-bit FAT additional information sector. */
590
5642
    if (media_ptr -> fx_media_FAT32_additional_info_sector)
591
    {
592
593
    UCHAR *buffer_ptr;
594
    ULONG  signature;
595
596
597
        /* Yes, read the FAT32 additional information sector to get the available cluster count and
598
           the hint for the first available cluster.  */
599
600
#ifndef FX_DISABLE_CACHE
601
        /* Setup a pointer to the first cached entry's buffer.  */
602
3453
        buffer_ptr =  (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_memory_buffer;
603
604
        /* Invalidate this cache entry.  */
605
3453
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector =  (~((ULONG64) 0));
606
3453
        (media_ptr -> fx_media_sector_cache_list_ptr) -> fx_cached_sector_valid =  FX_FALSE;
607
#else
608
        buffer_ptr =  media_ptr -> fx_media_memory_buffer;
609
        media_ptr -> fx_media_memory_buffer_sector = (ULONG64)-1;
610
#endif /* FX_DISABLE_CACHE */
611
612
        /* Read the FAT32 additional information sector from the device.  */
613
3453
        media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
614
3453
        media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
615
3453
        media_ptr -> fx_media_driver_buffer =           buffer_ptr;
616
3453
        media_ptr -> fx_media_driver_logical_sector =   media_ptr -> fx_media_FAT32_additional_info_sector;
617
3453
        media_ptr -> fx_media_driver_sectors =          1;
618
3453
        media_ptr -> fx_media_driver_sector_type =      FX_DIRECTORY_SECTOR;
619
620
#ifndef FX_MEDIA_STATISTICS_DISABLE
621
622
        /* Increment the number of driver read sector(s) requests.  */
623
3453
        media_ptr -> fx_media_driver_read_requests++;
624
#endif
625
626
        /* If trace is enabled, insert this event into the trace buffer.  */
627
        FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, media_ptr -> fx_media_FAT32_additional_info_sector, 1, buffer_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
628
629
        /* Invoke the driver to read the FAT32 additional information sector.  */
630
3453
        (media_ptr -> fx_media_driver_entry) (media_ptr);
631
632
        /* Determine if the FAT32 sector was read correctly. */
633
3453
        if (media_ptr -> fx_media_driver_status == FX_SUCCESS)
634
        {
635
636
            /* Yes, setup a pointer into the FAT32 additional information sector.  */
637
3063
            buffer_ptr =  media_ptr -> fx_media_driver_buffer;
638
639
            /* Pickup the first signature long word.  */
640
3063
            signature =  _fx_utility_32_unsigned_read(&buffer_ptr[0]);
641
642
            /* Determine if the signature is correct.  */
643
3063
            if (signature == 0x41615252)
644
            {
645
646
                /* Yes, the first signature is correct, now pickup the next signature.  */
647
2025
                signature =  _fx_utility_32_unsigned_read(&buffer_ptr[484]);
648
649
                /* Determine if this signature is correct.  */
650
2025
                if (signature == 0x61417272)
651
                {
652
653
                    /* Yes, we have a good FAT32 additional information sector.  */
654
655
                    /* Pickup the current available cluster count on the media.  */
656
2024
                    media_ptr -> fx_media_available_clusters =  _fx_utility_32_unsigned_read(&buffer_ptr[488]);
657
658
                    /* Initialize the last reported available cluster count to the same value.  */
659
2024
                    media_ptr -> fx_media_FAT32_additional_info_last_available =  media_ptr -> fx_media_available_clusters;
660
661
                    /* Pickup the hint for the starting free cluster search.  */
662
2024
                    media_ptr -> fx_media_cluster_search_start =  _fx_utility_32_unsigned_read(&buffer_ptr[492]);
663
664
                    /* Perform a quick sanity check on the available cluster count and the starting free
665
                       cluster search.  */
666
2024
                    if ((media_ptr -> fx_media_available_clusters > media_ptr -> fx_media_total_clusters) ||
667
2023
                        (media_ptr -> fx_media_cluster_search_start > media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START) ||
668
2022
                        (media_ptr -> fx_media_cluster_search_start < FX_FAT_ENTRY_START))
669
                    {
670
671
                        /* Something is wrong, clear the available cluster count and search so the regular processing
672
                           is used.  */
673
3
                        media_ptr -> fx_media_available_clusters =    0;
674
3
                        media_ptr -> fx_media_cluster_search_start =  0;
675
676
                        /* We don't invalidate the additional info sector here because only the data is bad.  */
677
                    }
678
                }
679
                else
680
                {
681
682
                    /* Signature is bad, invalidate the additional info sector.  */
683
1
                    media_ptr -> fx_media_FAT32_additional_info_sector =  0;
684
                }
685
            }
686
            else
687
            {
688
689
                /* Signature is bad, invalidate the additional info sector.  */
690
1038
                media_ptr -> fx_media_FAT32_additional_info_sector =  0;
691
            }
692
        }
693
        else
694
        {
695
696
            /* IO error trying to read additional information sector, invalidate the additional info sector.  */
697
390
            media_ptr -> fx_media_FAT32_additional_info_sector =  0;
698
        }
699
    }
700
701
    /* Search the media to find the first available cluster as well as the total
702
       available clusters.  */
703
704
    /* Determine what type of FAT is present.  */
705
5642
    if (media_ptr -> fx_media_12_bit_FAT)
706
    {
707
708
        /* A 12-bit FAT is present.  Utilize the FAT entry read utility to pickup
709
           each FAT entry's contents.  */
710
711
        /* Loop to read each cluster entry in the first FAT.  */
712
106
        for (cluster_number =  FX_FAT_ENTRY_START;
713
80329
             cluster_number < (media_ptr -> fx_media_total_clusters) + FX_FAT_ENTRY_START;
714
80223
             cluster_number++)
715
        {
716
717
            /* Read a FAT entry.  */
718
80224
            status =  _fx_utility_FAT_entry_read(media_ptr, cluster_number, &FAT_entry);
719
720
            /* Determine if the read was successful.  */
721
80224
            if (status != FX_SUCCESS)
722
            {
723
724
                /* Build the "uninitialize" I/O driver request.  */
725
1
                media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
726
1
                media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
727
728
                /* If trace is enabled, insert this event into the trace buffer.  */
729
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
730
731
                /* Call the specified I/O driver with the uninitialize request.  */
732
1
                (media_ptr -> fx_media_driver_entry) (media_ptr);
733
734
1
                return(FX_FAT_READ_ERROR);
735
            }
736
737
            /* Now determine if the FAT entry is available.  */
738
80223
            if (FAT_entry == FX_FREE_CLUSTER)
739
            {
740
741
                /* Increment the number of available clusters.  */
742
79652
                media_ptr -> fx_media_available_clusters++;
743
744
                /* Determine if the starting free cluster has been found yet.  */
745
79652
                if (media_ptr -> fx_media_cluster_search_start == 0)
746
                {
747
748
                    /* Remember the first free cluster to start further searches from.  */
749
105
                    media_ptr -> fx_media_cluster_search_start =  cluster_number;
750
                }
751
            }
752
        }
753
    }
754
5536
    else if (media_ptr -> fx_media_available_clusters == 0)
755
    {
756
757
        /* A 16 or 32-bit FAT is present. Read directly into the logical sector
758
           cache memory to optimize I/O on larger devices. Since we are looking for
759
           values of zero, endian issues are not important.  */
760
761
        /* Invalidate the current logical sector cache.  */
762
3515
        _fx_utility_logical_sector_flush(media_ptr, ((ULONG64) 1), (ULONG64) (media_ptr -> fx_media_total_sectors), FX_TRUE);
763
764
        /* Reset the memory pointer.  */
765
3515
        media_ptr -> fx_media_memory_buffer =  original_memory_ptr;
766
767
        /* Loop through all FAT sectors in the primary FAT.  The first two entries are
768
           examined in this loop, but they are always unavailable.  */
769
3515
        cluster_number =  0;
770
#ifndef FX_DISABLE_CACHE
771
2512506
        for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i = i + media_ptr -> fx_media_sector_cache_size)
772
        {
773
774
            /* Calculate the starting next FAT sector.  */
775
2508992
            FAT_sector =  media_ptr -> fx_media_reserved_sectors + i;
776
777
            /* Calculate how many sectors to read.  */
778
2508992
            FAT_read_sectors =  media_ptr -> fx_media_sectors_per_FAT - i;
779
780
            /* Determine if there is not enough memory to read the remaining FAT sectors.  */
781
2508992
            if (FAT_read_sectors > media_ptr -> fx_media_sector_cache_size)
782
            {
783
2507932
                FAT_read_sectors =  media_ptr -> fx_media_sector_cache_size;
784
            }
785
#else
786
        for (i = 0; i < media_ptr -> fx_media_sectors_per_FAT; i++)
787
        {
788
789
            /* Calculate the starting next FAT sector.  */
790
            FAT_sector =  media_ptr -> fx_media_reserved_sectors + i;
791
792
            /* Calculate how many sectors to read.  */
793
            FAT_read_sectors =  1;
794
#endif /* FX_DISABLE_CACHE */
795
796
            /* Read the FAT sectors directly from the driver.  */
797
2508992
            media_ptr -> fx_media_driver_request =          FX_DRIVER_READ;
798
2508992
            media_ptr -> fx_media_driver_status =           FX_IO_ERROR;
799
2508992
            media_ptr -> fx_media_driver_buffer =           media_ptr -> fx_media_memory_buffer;
800
2508992
            media_ptr -> fx_media_driver_logical_sector =   FAT_sector;
801
2508992
            media_ptr -> fx_media_driver_sectors =          FAT_read_sectors;
802
2508992
            media_ptr -> fx_media_driver_sector_type =      FX_FAT_SECTOR;
803
804
            /* If trace is enabled, insert this event into the trace buffer.  */
805
            FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_READ, media_ptr, FAT_sector, FAT_read_sectors, media_ptr -> fx_media_memory_buffer, FX_TRACE_INTERNAL_EVENTS, 0, 0)
806
807
            /* Invoke the driver to read the FAT sectors.  */
808
2508992
            (media_ptr -> fx_media_driver_entry) (media_ptr);
809
810
            /* Determine if the read was successful.  */
811
2508992
            if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
812
            {
813
814
                /* Build the "uninitialize" I/O driver request.  */
815
1
                media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
816
1
                media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
817
818
                /* If trace is enabled, insert this event into the trace buffer.  */
819
                FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
820
821
                /* Call the specified I/O driver with the uninitialize request.  */
822
1
                (media_ptr -> fx_media_driver_entry) (media_ptr);
823
824
1
                return(FX_FAT_READ_ERROR);
825
            }
826
827
            /* Calculate the number of bytes in the buffer.  */
828
2508991
            bytes_in_buffer =  (media_ptr -> fx_media_bytes_per_sector * FAT_read_sectors);
829
830
            /* Walk through the sector cache memory to search for available clusters and the first
831
               available if not already found.  */
832
113190054
            for (j = 0; j < bytes_in_buffer;)
833
            {
834
835
                /* Check for a 32-bit FAT.  */
836
110684577
                if (media_ptr -> fx_media_32_bit_FAT)
837
                {
838
839
                    /* Pickup 32-bit FAT entry.  */
840
98092567
                    FAT_entry =  *((ULONG *)&(media_ptr -> fx_media_memory_buffer[j]));
841
842
                    /* Advance to next FAT entry.  */
843
98092567
                    j = j + 4;
844
                }
845
                else
846
                {
847
848
                    /* Process a 16-bit FAT entry.  */
849
12592010
                    FAT_entry =  (((ULONG)(media_ptr -> fx_media_memory_buffer[j])) & 0xFF) |
850
12592010
                        ((((ULONG)(media_ptr -> fx_media_memory_buffer[j + 1])) & 0xFF) << 8);
851
852
                    /* Advance to next FAT entry.  */
853
12592010
                    j =  j + 2;
854
                }
855
856
                /* Determine if the FAT entry is free.  */
857
110684577
                if (FAT_entry == FX_FREE_CLUSTER)
858
                {
859
860
                    /* Entry is free, increment available clusters.  */
861
110657298
                    media_ptr -> fx_media_available_clusters++;
862
863
                    /* Determine if the starting free cluster has been found yet.  */
864
110657298
                    if (media_ptr -> fx_media_cluster_search_start == 0)
865
                    {
866
867
                        /* Remember the first free cluster to start further searches from.  */
868
3516
                        media_ptr -> fx_media_cluster_search_start =  cluster_number;
869
                    }
870
                }
871
872
                /* Increment the cluster number.  */
873
110684577
                cluster_number++;
874
875
                /* Determine if we have reviewed all FAT entries.  */
876
110684577
                if (cluster_number >= (media_ptr -> fx_media_total_clusters + FX_FAT_ENTRY_START))
877
                {
878
879
                    /* Yes, we have looked at all the FAT entries.  */
880
881
                    /* Ensure that the outer loop terminates as well.  */
882
3514
                    i = media_ptr -> fx_media_sectors_per_FAT;
883
3514
                    break;
884
                }
885
            }
886
        }
887
    }
888
889
    /* If there were no free clusters, just set the search pointer to the
890
       first cluster number.  */
891
5640
    if (media_ptr -> fx_media_cluster_search_start == 0)
892
    {
893
1
        media_ptr -> fx_media_cluster_search_start =  FX_FAT_ENTRY_START;
894
    }
895
896
    /* Setup the current working directory fields to default to the root
897
       directory.  */
898
5640
    media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name =
899
5640
        media_ptr -> fx_media_default_path.fx_path_name_buffer;
900
5640
    media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_short_name[0] =  0;
901
5640
    media_ptr -> fx_media_default_path.fx_path_directory.fx_dir_entry_name[0] =        0;
902
5640
    media_ptr -> fx_media_default_path.fx_path_string[0] =                      (CHAR)0;
903
5640
    media_ptr -> fx_media_default_path.fx_path_string[FX_MAXIMUM_PATH - 1] =      (CHAR)0;
904
5640
    media_ptr -> fx_media_default_path.fx_path_current_entry =                         0;
905
906
#ifndef FX_MEDIA_DISABLE_SEARCH_CACHE
907
908
    /* Invalidate the previously found directory entry.  */
909
5640
    media_ptr -> fx_media_last_found_name[0] =  0;
910
#endif
911
912
#ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
913
    /* Initialize the opened file linked list and associated counter.  */
914
5640
    media_ptr -> fx_media_opened_file_list =      FX_NULL;
915
5640
    media_ptr -> fx_media_opened_file_count =     0;
916
#endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
917
918
    /* Create the media protection structure if FX_SINGLE_THREAD is not
919
       defined.  */
920
#ifndef FX_SINGLE_THREAD
921
922
#ifndef FX_DONT_CREATE_MUTEX
923
924
    /* Create ThreadX mutex for protection.  */
925
5640
    tx_mutex_create(&(media_ptr -> fx_media_protect), "FileX Media Mutex", TX_NO_INHERIT);
926
#endif
927
928
#endif
929
930
#ifdef FX_DONT_CREATE_MUTEX
931
932
    /* Load the media ID field in the media control block.  This allows the FX_PROTECT
933
       call to succeed.  */
934
    media_ptr -> fx_media_id =  (ULONG)FX_MEDIA_ID;
935
936
    /* Protect against other threads accessing the media.  */
937
    FX_PROTECT
938
#endif
939
940
    /* Lockout interrupts.  */
941
5640
    FX_DISABLE_INTS
942
943
    /* At this point, the media has been opened successfully.  Place the
944
       media on the linked list of currently opened media.  */
945
946
    /* Load the media ID field in the media control block.  */
947
5640
    media_ptr -> fx_media_id =  (ULONG)FX_MEDIA_ID;
948
949
    /* Place the thread on the list of opened media.  First,
950
       check for an empty list.  */
951
5640
    if (_fx_system_media_opened_ptr)
952
    {
953
954
        /* Pickup tail pointer.  */
955
5
        tail_ptr =  _fx_system_media_opened_ptr -> fx_media_opened_previous;
956
957
        /* Place the new media in the list.  */
958
5
        _fx_system_media_opened_ptr -> fx_media_opened_previous =  media_ptr;
959
5
        tail_ptr -> fx_media_opened_next =  media_ptr;
960
961
        /* Setup this media's opened links.  */
962
5
        media_ptr -> fx_media_opened_previous =  tail_ptr;
963
5
        media_ptr -> fx_media_opened_next =      _fx_system_media_opened_ptr;
964
    }
965
    else
966
    {
967
968
        /* The opened media list is empty.  Add the media to empty list.  */
969
5635
        _fx_system_media_opened_ptr =           media_ptr;
970
5635
        media_ptr -> fx_media_opened_next =     media_ptr;
971
5635
        media_ptr -> fx_media_opened_previous = media_ptr;
972
    }
973
974
    /* Increment the opened media counter.  */
975
5640
    _fx_system_media_opened_count++;
976
977
    /* Invoke media open callback. */
978
5640
    if (media_ptr -> fx_media_open_notify)
979
    {
980
1
        media_ptr -> fx_media_open_notify(media_ptr);
981
    }
982
983
    /* Restore interrupts.  */
984
5640
    FX_RESTORE_INTS
985
986
#ifdef FX_DONT_CREATE_MUTEX
987
988
    /* Release media protection.  */
989
    FX_UNPROTECT
990
#endif
991
992
    /* Return a successful status.  */
993
5640
    return(FX_SUCCESS);
994
}
995