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 /** FileX Component                                                       */
16 /**                                                                       */
17 /**   Media                                                               */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define FX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "fx_api.h"
28 #include "fx_media.h"
29 #include "fx_utility.h"
30 
31 
32 /* Define global variables necessary for formatting.  */
33 
34 /* Define OEM Name. This name must be 8 characters long and be blank padded.
35    The default may be changed by modifying this file or calling the
36    fx_media_format_oem_name_set utility prior to calling fx_media_format.  */
37 
38 UCHAR   _fx_media_format_oem_name[8] = "EL FILEX";
39 
40 
41 /* Define the default media type.  This default may be changed by modifying
42    this file or calling the fx_media_format_type_set utility prior to calling
43    fx_media_format.  */
44 
45 UCHAR _fx_media_format_media_type =  0xF8;
46 
47 
48 /* Define the default volume ID.  This default may be changed by modifying
49    this file or calling the fx_media_format_volume_id_set utility prior to calling
50    fx_media_format.  */
51 
52 ULONG _fx_media_format_volume_id =  1;
53 
54 
55 /**************************************************************************/
56 /*                                                                        */
57 /*  FUNCTION                                               RELEASE        */
58 /*                                                                        */
59 /*    _fx_media_format                                    PORTABLE C      */
60 /*                                                           6.1.11       */
61 /*  AUTHOR                                                                */
62 /*                                                                        */
63 /*    William E. Lamie, Microsoft Corporation                             */
64 /*                                                                        */
65 /*  DESCRIPTION                                                           */
66 /*                                                                        */
67 /*    This function creates a FAT12/16/32 format with raw calls to the    */
68 /*    I/O driver. It can and must be called before the fx_media_open      */
69 /*    and is designed to utilize the same underlying FileX driver.        */
70 /*                                                                        */
71 /*  INPUT                                                                 */
72 /*                                                                        */
73 /*    media_ptr                             Pointer to media control block*/
74 /*                                            (does not need to be opened)*/
75 /*    driver                                Pointer to FileX driver (must */
76 /*                                            be able to field requests   */
77 /*                                            prior to opening)           */
78 /*    driver_info_ptr                       Optional information pointer  */
79 /*    memory_ptr                            Pointer to memory used by the */
80 /*                                            FileX for this media.       */
81 /*    memory_size                           Size of media memory - must   */
82 /*                                            at least 512 bytes and      */
83 /*                                            one sector size.            */
84 /*    volume_name                           Name of the volume            */
85 /*    number_of_fats                        Number of FAT tables          */
86 /*    directory_entries                     Number of directory entries   */
87 /*    hidden_sectors                        Number of hidden sectors      */
88 /*    total_sectors                         Total number of sectors       */
89 /*    bytes_per_sector                      Number of bytes per sector    */
90 /*    sectors_per_cluster                   Number of sectors per cluster */
91 /*    heads                                 Number of heads               */
92 /*    sectors_per_track                     Number of sectors per track   */
93 /*                                                                        */
94 /*  OUTPUT                                                                */
95 /*                                                                        */
96 /*    Completion Status                                                   */
97 /*                                                                        */
98 /*  CALLS                                                                 */
99 /*                                                                        */
100 /*    Media driver                                                        */
101 /*    _fx_utility_16_unsigned_write         Write 16-bit unsigned         */
102 /*    _fx_utility_32_unsigned_write         Write 32-bit unsigned         */
103 /*                                                                        */
104 /*  CALLED BY                                                             */
105 /*                                                                        */
106 /*    Application Code                                                    */
107 /*                                                                        */
108 /*  RELEASE HISTORY                                                       */
109 /*                                                                        */
110 /*    DATE              NAME                      DESCRIPTION             */
111 /*                                                                        */
112 /*  05-19-2020     William E. Lamie         Initial Version 6.0           */
113 /*  09-30-2020     William E. Lamie         Modified comment(s), and      */
114 /*                                            added conditional to        */
115 /*                                            disable force memset,       */
116 /*                                            resulting in version 6.1    */
117 /*  03-02-2021     William E. Lamie         Modified comment(s),          */
118 /*                                            resulting in version 6.1.5  */
119 /*  08-02-2021     Bhupendra Naphade        Modified comment(s), and      */
120 /*                                            updated boot write logic,   */
121 /*                                            resulting in version 6.1.8  */
122 /*  04-25-2022     Bhupendra Naphade        Modified comment(s), and      */
123 /*                                            updated reserved FAT entry  */
124 /*                                            value,                      */
125 /*                                            resulting in version 6.1.11 */
126 /*                                                                        */
127 /**************************************************************************/
_fx_media_format(FX_MEDIA * media_ptr,VOID (* driver)(FX_MEDIA * media),VOID * driver_info_ptr,UCHAR * memory_ptr,UINT memory_size,CHAR * volume_name,UINT number_of_fats,UINT directory_entries,UINT hidden_sectors,ULONG total_sectors,UINT bytes_per_sector,UINT sectors_per_cluster,UINT heads,UINT sectors_per_track)128 UINT  _fx_media_format(FX_MEDIA *media_ptr, VOID (*driver)(FX_MEDIA *media), VOID *driver_info_ptr, UCHAR *memory_ptr, UINT memory_size,
129                        CHAR *volume_name, UINT number_of_fats, UINT directory_entries, UINT hidden_sectors,
130                        ULONG total_sectors, UINT bytes_per_sector, UINT sectors_per_cluster,
131                        UINT heads, UINT sectors_per_track)
132 {
133 
134 UCHAR *byte_ptr;
135 UINT   reserved_sectors, i, j, root_sectors, total_clusters, bytes_needed;
136 UINT   sectors_per_fat, f, s;
137 
138 
139     /* Create & write bootrecord from drive geometry information.  */
140 
141     /* If trace is enabled, insert this event into the trace buffer.  */
142     FX_TRACE_IN_LINE_INSERT(FX_TRACE_MEDIA_FORMAT, media_ptr, directory_entries, total_sectors, sectors_per_cluster, FX_TRACE_MEDIA_EVENTS, 0, 0)
143 
144     /* Validate bytes per sector value: greater than zero and no more than 4096.  */
145     if((bytes_per_sector == 0) || (bytes_per_sector > 4096))
146         return(FX_SECTOR_INVALID);
147 
148     /* Validate sectors per cluster value: greater than zero and no more than 128.  */
149     if((sectors_per_cluster == 0) || (sectors_per_cluster > 128))
150         return(FX_SECTOR_INVALID);
151 
152     /* Setup driver pointer and memory information.  */
153     media_ptr -> fx_media_driver_entry =                driver;
154     media_ptr -> fx_media_memory_buffer =               (UCHAR *)memory_ptr;
155     media_ptr -> fx_media_memory_size =                 memory_size;
156 
157     /* Store geometry information in media record - driver needs this.  */
158     media_ptr -> fx_media_bytes_per_sector =            bytes_per_sector;
159     media_ptr -> fx_media_sectors_per_track =           sectors_per_track;
160     media_ptr -> fx_media_heads =                       heads;
161     media_ptr -> fx_media_hidden_sectors =              hidden_sectors;
162 
163     /* Initialize the supplied media I/O driver.  First, build the
164        initialize driver request.  */
165     media_ptr -> fx_media_driver_request =              FX_DRIVER_INIT;
166     media_ptr -> fx_media_driver_status =               FX_IO_ERROR;
167     media_ptr -> fx_media_driver_info =                 driver_info_ptr;
168     media_ptr -> fx_media_driver_write_protect =        FX_FALSE;
169     media_ptr -> fx_media_driver_free_sector_update =   FX_FALSE;
170     media_ptr -> fx_media_driver_data_sector_read =     FX_FALSE;
171 
172     /* If trace is enabled, insert this event into the trace buffer.  */
173     FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_INIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
174 
175     /* Call the specified I/O driver with the initialize request.  */
176     (media_ptr -> fx_media_driver_entry) (media_ptr);
177 
178     /* Determine if the I/O driver initialized successfully.  */
179     if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
180     {
181 
182         /* Return the driver error status.  */
183         return(FX_IO_ERROR);
184     }
185 
186     /* Setup driver buffer memory.  */
187     media_ptr -> fx_media_driver_buffer =  memory_ptr;
188 
189     /* Move the buffer pointer into a local copy.  */
190     byte_ptr =  media_ptr -> fx_media_driver_buffer;
191 
192 #ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
193     /* Clear the buffer record out, assuming it is large enough for one sector.   */
194     for (i = 0; i < bytes_per_sector; i++)
195     {
196 
197         /* Clear each byte of the boot record.  */
198         byte_ptr[i] =  (UCHAR)0;
199     }
200 #else
201     _fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
202 #endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
203 
204     /* Set jump instruction at the beginning of the sector.  */
205     byte_ptr[0] =  (UCHAR)0xEB;
206     byte_ptr[1] =  (UCHAR)0x34;
207     byte_ptr[2] =  (UCHAR)0x90;
208 
209     /* Set the OEM name in the boot record.  */
210     for (i = 0; i < 8; i++)
211     {
212 
213         /* Copy a character from the OEM name.  */
214         byte_ptr[i + 3] =  _fx_media_format_oem_name[i];
215     }
216 
217     /* Set the media type in the boot record.  */
218     byte_ptr[FX_MEDIA_TYPE] =  _fx_media_format_media_type;
219 
220     /* Set the number of bytes per sector.  */
221     _fx_utility_16_unsigned_write(&byte_ptr[FX_BYTES_SECTOR], bytes_per_sector);
222 
223     /* Set the number of sectors per track.  */
224     _fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS_PER_TRK], sectors_per_track);
225 
226     /* Set the number of heads.  */
227     _fx_utility_16_unsigned_write(&byte_ptr[FX_HEADS], heads);
228 
229 #ifdef FX_FORCE_512_BYTE_BOOT_SECTOR
230 
231     /* Calculate the number of reserved sectors. If sector size is smaller than 512 bytes, there will be
232        reserved sectors, otherwise assumed that only the sector containing bootrecord is reserved.  */
233     if (bytes_per_sector < 512)
234     {
235         reserved_sectors =  512 / bytes_per_sector;
236     }
237     else
238     {
239         reserved_sectors =  1;
240     }
241 #else
242 
243     /* The boot sector is the only reserved sector.  */
244     reserved_sectors =  1;
245 #endif
246 
247 
248     /* Calculate the maximum clusters.... This is actually greater than the actual since the FAT
249        sectors have yet to be accounted for.  */
250     total_clusters =  (total_sectors - reserved_sectors - ((directory_entries * FX_DIR_ENTRY_SIZE) + (bytes_per_sector - 1)) / bytes_per_sector) / sectors_per_cluster;
251 
252     /* Calculate the maximum number of FAT sectors necessary for FAT12.  */
253     if (total_clusters % 2)
254     {
255         bytes_needed = (total_clusters + total_clusters / 2) + 1;
256     }
257     else
258     {
259         bytes_needed = (total_clusters + total_clusters / 2);
260     }
261     sectors_per_fat =  bytes_needed / bytes_per_sector;
262     if (bytes_needed % bytes_per_sector)
263     {
264         sectors_per_fat++;
265     }
266 
267     /* Now adjust the total clusters by the number of sectors per FAT.  */
268     total_clusters =  total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
269 
270     /* Is the total cluster count greater than the FAT12 maximum?  */
271     if (total_clusters >= FX_12_BIT_FAT_SIZE)
272     {
273 
274         /* Yes, too big for FAT12, we need to evaluate for FAT16.  */
275 
276         /* Reset the maximum clusters.... This is actually greater than the actual since the FAT
277            sectors have yet to be accounted for.  */
278         total_clusters =  (total_sectors - reserved_sectors -  ((directory_entries * FX_DIR_ENTRY_SIZE) + (bytes_per_sector - 1)) / bytes_per_sector) / sectors_per_cluster;
279 
280         /* Calculate 16-bit FAT is present. Each cluster requires a 2 byte entry in the FAT table.  */
281         sectors_per_fat =  (total_clusters * 2) / bytes_per_sector;
282         if ((total_clusters * 2) % bytes_per_sector)
283         {
284             sectors_per_fat++;
285         }
286 
287         /* Now adjust the total clusters by the number of sectors per FAT.  */
288         total_clusters =  total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
289 
290         /* Is the total cluster count greater than the FAT16 maximum?  */
291         if (total_clusters >= FX_16_BIT_FAT_SIZE)
292         {
293 
294             /* Yes, FAT32 is present.  */
295 
296             /* Allocate room for the FAT32 additional information sector. This contains useful information
297                such as the number of available clusters between successive mounting of the media.  */
298             if (bytes_per_sector == 512)
299             {
300 
301                 /* Write sector number 1 to the additional information sector.  */
302                 _fx_utility_16_unsigned_write(&byte_ptr[48], 1);
303 
304                 /* Increment the reserved sectors count, since this will count as a reserved sector.  */
305                 reserved_sectors++;
306             }
307             else
308             {
309 
310                 /* Write value to indicate there is no additional information sector.  */
311                 _fx_utility_16_unsigned_write(&byte_ptr[48], 0xFFFF);
312             }
313 
314             /* Allocate the first cluster to the root directory.  */
315             _fx_utility_32_unsigned_write(&byte_ptr[FX_ROOT_CLUSTER_32], FX_FAT_ENTRY_START);
316 
317             /* Determine if the number of root directory entries should be modified.  */
318             directory_entries =  (sectors_per_cluster * bytes_per_sector) / FX_DIR_ENTRY_SIZE;
319 
320             /* Reset the total_clusters for the FAT32 calculation.  */
321             total_clusters =  (total_sectors - reserved_sectors) / sectors_per_cluster;
322 
323             /* 32-bit FAT is present. Each cluster requires a 4 byte entry in the FAT table.  */
324             sectors_per_fat =  (total_clusters * 4) / bytes_per_sector;
325             if ((total_clusters * 4) % bytes_per_sector)
326             {
327                 sectors_per_fat++;
328             }
329 
330             /* Now adjust the total clusters by the number of sectors per FAT.  */
331             total_clusters =  total_clusters - ((sectors_per_fat * number_of_fats) + (sectors_per_cluster - 1)) / sectors_per_cluster;
332         }
333     }
334 
335     /* Set sectors per FAT type.  */
336     if (total_clusters < FX_16_BIT_FAT_SIZE)
337     {
338 
339         /* Set the number of sectors per FAT12/16.  */
340         _fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS_PER_FAT], sectors_per_fat);
341 
342         /* Set the signature.  */
343         byte_ptr[FX_BOOT_SIG] =  0x29;
344 
345         /* Setup the volume ID.  */
346         _fx_utility_32_unsigned_write(&byte_ptr[FX_VOLUME_ID], _fx_media_format_volume_id);
347     }
348     else
349     {
350 
351         /* Set the number of sectors per FAT32.  */
352         _fx_utility_32_unsigned_write(&byte_ptr[FX_SECTORS_PER_FAT_32], sectors_per_fat);
353 
354         /* Set the signature.  */
355         byte_ptr[FX_BOOT_SIG_32] =  0x29;
356 
357         /* Setup the volume ID.  */
358         _fx_utility_32_unsigned_write(&byte_ptr[FX_VOLUME_ID_32], _fx_media_format_volume_id);
359     }
360 
361     /* Set the total number of sectors.  */
362     if (total_sectors < (ULONG)0xFFFF)
363     {
364 
365         /* Write the 16-bit total sector field.  */
366         _fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS], (UINT)(total_sectors));
367 
368         /* Set the number of huge sectors.  */
369         _fx_utility_32_unsigned_write(&byte_ptr[FX_HUGE_SECTORS], 0);
370     }
371     else
372     {
373 
374         /* Write the 16-bit total sector field as 0.  */
375         _fx_utility_16_unsigned_write(&byte_ptr[FX_SECTORS], (UINT)0);
376 
377         /* Set the number of huge sectors.  */
378         _fx_utility_32_unsigned_write(&byte_ptr[FX_HUGE_SECTORS], total_sectors);
379     }
380 
381     /* Set the number of reserved sectors.  */
382     _fx_utility_16_unsigned_write(&byte_ptr[FX_RESERVED_SECTORS], reserved_sectors);
383 
384     /* Set the number of sectors per cluster */
385     byte_ptr[FX_SECTORS_CLUSTER] =  (UCHAR)sectors_per_cluster;
386 
387     /* Set the number of FATs.  */
388     byte_ptr[FX_NUMBER_OF_FATS] =  (UCHAR)number_of_fats;
389 
390     /* Set the number of hidden sectors.  */
391     _fx_utility_32_unsigned_write(&byte_ptr[FX_HIDDEN_SECTORS], hidden_sectors);
392 
393     /* Determine if a FAT12 or FAT16 is present.  If FAT32 is present, these fields are left alone!   */
394     if (total_clusters < FX_16_BIT_FAT_SIZE)
395     {
396 
397         /* Yes, set the number of root directory entries.  */
398         _fx_utility_16_unsigned_write(&byte_ptr[FX_ROOT_DIR_ENTRIES], directory_entries);
399     }
400 
401     /* Now setup the volume label. */
402     if (total_clusters < FX_16_BIT_FAT_SIZE)
403     {
404 
405         /* FAT12/16 volume label offset.  */
406         j =  FX_VOLUME_LABEL;
407     }
408     else
409     {
410 
411         /* FAT32 volume label offset.  */
412         j =  FX_VOLUME_LABEL_32;
413     }
414 
415     i = 0;
416     while (i < 11)
417     {
418 
419         /* Determine if it is NULL.  */
420         if (volume_name[i] == 0)
421         {
422 
423             /* Yes, the copying is finished.  */
424             break;
425         }
426 
427         /* Otherwise, copy byte of volume name into boot record.  */
428         byte_ptr[j + i] =  (UCHAR)volume_name[i];
429 
430         /* Increment byte position.  */
431         i++;
432     }
433 
434     /* Now blank-pad the remainder of the volume name.  */
435 #ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
436     while (i < 11)
437     {
438 
439         byte_ptr[j + i] =  (UCHAR)' ';
440         i++;
441     }
442 #else
443     _fx_utility_memory_set(&byte_ptr[j + i], ' ', (11 - i));
444 #endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
445 
446 
447 #ifdef FX_FORCE_512_BYTE_BOOT_SECTOR
448 
449     /* Set bootrecord signature.  */
450     byte_ptr[510] = 0x55;
451     byte_ptr[511] = 0xAA;
452 #else
453 
454     /* Set bootrecord signature.  */
455     byte_ptr[bytes_per_sector - 2] = 0x55;
456     byte_ptr[bytes_per_sector - 1] = 0xAA;
457 #endif
458 
459     /* Select the boot record write command.  */
460     media_ptr -> fx_media_driver_request =       FX_DRIVER_BOOT_WRITE;
461     media_ptr -> fx_media_driver_system_write =  FX_TRUE;
462     media_ptr -> fx_media_driver_sectors =       1;
463     media_ptr -> fx_media_driver_sector_type =   FX_BOOT_SECTOR;
464 
465     /* If trace is enabled, insert this event into the trace buffer.  */
466     FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_BOOT_WRITE, media_ptr, memory_ptr, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
467 
468     /* Write out the bootrecord */
469     (driver)(media_ptr);
470 
471     /* Clear the write flag.  */
472     media_ptr -> fx_media_driver_system_write =  FX_FALSE;
473 
474     /* Determine if it was successful.  */
475     if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
476     {
477         return(FX_IO_ERROR);
478     }
479 
480     /* Calculate the number of root sectors.  */
481     root_sectors =    ((directory_entries * FX_DIR_ENTRY_SIZE) + bytes_per_sector - 1) / bytes_per_sector;
482 
483     /* Determine if FAT32 is present AND if the bytes per sector is large enough to have
484        a FSINFO sector.  */
485     if ((total_clusters >= FX_16_BIT_FAT_SIZE) && (bytes_per_sector == 512))
486     {
487 
488 #ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
489         /* Clear sector buffer.  */
490         for (i = 0; i < bytes_per_sector; i++)
491         {
492             byte_ptr[i] =  (CHAR)0;
493         }
494 #else
495         _fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
496 #endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
497 
498         /* Build the FSINFO fields.  */
499 
500         /* Build first signature word, used to help verify this is a FSINFO sector.  */
501         byte_ptr[0] =  0x52;
502         byte_ptr[1] =  0x52;
503         byte_ptr[2] =  0x61;
504         byte_ptr[3] =  0x41;
505 
506         /* Build the next signature word, this too is used to help verify that this is a FSINFO sector.  */
507         byte_ptr[484] =  0x72;
508         byte_ptr[485] =  0x72;
509         byte_ptr[486] =  0x41;
510         byte_ptr[487] =  0x61;
511 
512         /* Build the final signature word, this too is used to help verify that this is a FSINFO sector.  */
513         byte_ptr[508] =  0x55;
514         byte_ptr[509] =  0xAA;
515 
516         /* Setup the total available clusters on the media. We need to subtract 1 for the FAT32 root directory.  */
517         _fx_utility_32_unsigned_write(&byte_ptr[488], (total_clusters - 1));
518 
519         /* Setup the starting free cluster to 3, since cluster 2 is reserved for the FAT32 root directory.  */
520         _fx_utility_32_unsigned_write(&byte_ptr[492], 3);
521 
522         /* Now write the FSINFO sector to the media.  */
523         media_ptr -> fx_media_driver_logical_sector =  1;
524         media_ptr -> fx_media_driver_request =         FX_DRIVER_WRITE;
525         media_ptr -> fx_media_driver_sectors =         1;
526         media_ptr -> fx_media_driver_system_write =    FX_TRUE;
527         media_ptr -> fx_media_driver_sector_type =     FX_BOOT_SECTOR;
528 
529         /* If trace is enabled, insert this event into the trace buffer.  */
530         FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, 1, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
531 
532         /* Write out the sector.  */
533         (driver)(media_ptr);
534 
535         /* Clear the system write flag.  */
536         media_ptr -> fx_media_driver_system_write =  FX_FALSE;
537 
538         /* Determine if it was successful.  */
539         if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
540         {
541             return(FX_IO_ERROR);
542         }
543     }
544 
545     /* At this point we need set up first to FAT entries and clear the remaining FAT sectors area.  */
546 
547     /* Loop through number of FATs. The first is the only one used.  */
548     for (f = 0; f < number_of_fats; f++)
549     {
550 
551         /* Loop through all the sectors in this FAT.  */
552         for (s = 0; s < sectors_per_fat; s++)
553         {
554 
555             if (s == 0)
556             {
557 
558                 /* Reserve the first two FAT table entries.  */
559                 if (total_clusters < FX_12_BIT_FAT_SIZE)
560                 {
561 
562                     /* Reserve the first two FAT-12 entries.  */
563                     byte_ptr[0] =  _fx_media_format_media_type;
564                     byte_ptr[1] =  (UCHAR)0xFF;
565                     byte_ptr[2] =  (UCHAR)0xFF;
566 
567                     /* Start clearing at FAT entry 3.  */
568                     i =  3;
569                 }
570                 else if (total_clusters < FX_16_BIT_FAT_SIZE)
571                 {
572 
573                     /* Reserve the first two FAT-16 entries.  */
574                     byte_ptr[0] =  _fx_media_format_media_type;
575                     byte_ptr[1] =  (UCHAR)0xFF;
576                     byte_ptr[2] =  (UCHAR)0xFF;
577                     byte_ptr[3] =  (UCHAR)0xFF;
578 
579                     /* Start clearing at FAT entry 3.  */
580                     i =  4;
581                 }
582                 else
583                 {
584 
585                     /* Reserve the first two FAT-32 entries.   */
586                     byte_ptr[0] =  _fx_media_format_media_type;
587                     byte_ptr[1] =  (UCHAR)0xFF;
588                     byte_ptr[2] =  (UCHAR)0xFF;
589                     byte_ptr[3] =  (UCHAR)0x0F;
590                     byte_ptr[4] =  (UCHAR)0xFF;
591                     byte_ptr[5] =  (UCHAR)0xFF;
592                     byte_ptr[6] =  (UCHAR)0xFF;
593                     byte_ptr[7] =  (UCHAR)0x0F;
594 
595                     /* Preallocate the first cluster for the root directory.  */
596                     byte_ptr[8] =   (UCHAR)0xFF;
597                     byte_ptr[9] =   (UCHAR)0xFF;
598                     byte_ptr[10] =  (UCHAR)0xFF;
599                     byte_ptr[11] =  (UCHAR)0x0F;
600 
601                     /* Start clearing at FAT entry 3.  */
602                     i =  12;
603                 }
604             }
605             else
606             {
607                 i = 0;
608             }
609 
610 #ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
611             /* Clear remainder of sector buffer.  */
612             for (; i < bytes_per_sector; i++)
613             {
614                 byte_ptr[i] =  (CHAR)0;
615             }
616 #else
617             _fx_utility_memory_set(&byte_ptr[i], 0, (bytes_per_sector - i));
618 #endif  /* FX_DISABLE_FORCE_MEMORY_OPERATION */
619 
620             /* Build sector write command.  */
621             media_ptr -> fx_media_driver_logical_sector =  reserved_sectors + (f * sectors_per_fat) + s;
622             media_ptr -> fx_media_driver_request =         FX_DRIVER_WRITE;
623             media_ptr -> fx_media_driver_sectors =         1;
624             media_ptr -> fx_media_driver_system_write =    FX_TRUE;
625             media_ptr -> fx_media_driver_sector_type =     FX_FAT_SECTOR;
626 
627             /* If trace is enabled, insert this event into the trace buffer.  */
628             FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_driver_logical_sector, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
629 
630             /* Write out the sector.  */
631             (driver)(media_ptr);
632 
633             /* Clear the system write flag.  */
634             media_ptr -> fx_media_driver_system_write =  FX_FALSE;
635 
636             /* Determine if it was successful.  */
637             if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
638             {
639                 return(FX_IO_ERROR);
640             }
641         }
642     }
643 
644 #ifndef FX_DISABLE_FORCE_MEMORY_OPERATION
645     /* Clear sector buffer.  */
646     for (i = 0; i < bytes_per_sector; i++)
647     {
648         byte_ptr[i] =  (CHAR)0;
649     }
650 #else
651     _fx_utility_memory_set(byte_ptr, 0, bytes_per_sector);
652 #endif /* FX_DISABLE_FORCE_MEMORY_OPERATION */
653 
654     /* Now clear the root directory sectors.  */
655     for (s = 0; s < root_sectors; s++)
656     {
657 
658         /* Build sector write command.  */
659         media_ptr -> fx_media_driver_logical_sector =  reserved_sectors + (number_of_fats * sectors_per_fat) + s;
660         media_ptr -> fx_media_driver_request =         FX_DRIVER_WRITE;
661         media_ptr -> fx_media_driver_sectors =         1;
662         media_ptr -> fx_media_driver_system_write =    FX_TRUE;
663         media_ptr -> fx_media_driver_sector_type =     FX_DIRECTORY_SECTOR;
664 
665         /* If trace is enabled, insert this event into the trace buffer.  */
666         FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_WRITE, media_ptr, media_ptr -> fx_media_driver_logical_sector, 1, memory_ptr, FX_TRACE_INTERNAL_EVENTS, 0, 0)
667 
668         /* Write out the sector.  */
669         (driver)(media_ptr);
670 
671         /* Clear the write flag.  */
672         media_ptr -> fx_media_driver_system_write =  FX_FALSE;
673 
674         /* Determine if it was successful.  */
675         if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
676         {
677             return(FX_IO_ERROR);
678         }
679     }
680 
681     /* Build the "uninitialize" I/O driver request.  */
682     media_ptr -> fx_media_driver_request =      FX_DRIVER_UNINIT;
683     media_ptr -> fx_media_driver_status =       FX_IO_ERROR;
684 
685     /* If trace is enabled, insert this event into the trace buffer.  */
686     FX_TRACE_IN_LINE_INSERT(FX_TRACE_INTERNAL_IO_DRIVER_UNINIT, media_ptr, 0, 0, 0, FX_TRACE_INTERNAL_EVENTS, 0, 0)
687 
688     /* Call the specified I/O driver with the uninitialize request.  */
689     (media_ptr -> fx_media_driver_entry) (media_ptr);
690 
691     /* Return success!  */
692     return(media_ptr -> fx_media_driver_status);
693 }
694 
695