source: trunk/kernel/fs/fatfs.c @ 627

Last change on this file since 627 was 627, checked in by alain, 5 years ago

Replace the queuelock protectingthe FAT by a rwlock in the FATFS.

File size: 100.1 KB
Line 
1/*
2 * fatfs.c - FATFS file system API implementation.
3 *
4 * Author    Alain Greiner (2016,2017,2018,2019)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24
25#include <hal_kernel_types.h>
26#include <hal_special.h>
27#include <printk.h>
28#include <thread.h>
29#include <kmem.h>
30#include <ppm.h>
31#include <vfs.h>
32#include <string.h>
33#include <rpc.h>
34#include <mapper.h>
35#include <cluster.h>
36#include <dev_ioc.h>
37#include <fatfs.h>
38
39#define LITTLE_ENDIAN  1
40
41//////////////////////////////////////////////////////////////////////////////////////////
42//          Extern  variables         
43//////////////////////////////////////////////////////////////////////////////////////////
44
45extern vfs_ctx_t     fs_context[FS_TYPES_NR];   // allocated in kernel_init.c file
46
47//////////////////////////////////////////////////////////////////////////////////////////
48//              FATFS specific static functions
49//////////////////////////////////////////////////////////////////////////////////////////
50
51//////////////////////////////////////////////////////////////////////////////////////////
52// These functions return the "offset" and "length" values of an
53// [offset,length] constant defined in the fatfs.h file.
54//////////////////////////////////////////////////////////////////////////////////////////
55
56static inline int get_length( int offset __attribute__((unused)), int length ) { return length; }
57
58static inline int get_offset( int offset, int length __attribute__((unused)) ) { return offset; }
59
60//////////////////////////////////////////////////////////////////////////////////////////
61// This static function returns the LBA of the first sector of a FAT cluster.
62// This function can be called by any thread running in any cluster.
63//////////////////////////////////////////////////////////////////////////////////////////
64// @ ctx          :     pointer on FATFS context.
65// @ cluster  : cluster index in FATFS.
66// @ return the lba value.
67//////////////////////////////////////////////////////////////////////////////////////////
68static inline uint32_t fatfs_lba_from_cluster( fatfs_ctx_t * ctx,
69                                               uint32_t      cluster )
70{
71    return (ctx->cluster_begin_lba + ((cluster - 2) << 3));
72}
73
74//////////////////////////////////////////////////////////////////////////////////////////
75// This function return an integer record value (one, two, or four bytes) from a local
76// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
77// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
78//////////////////////////////////////////////////////////////////////////////////////////
79// @ offset        : first byte in array.
80// @ nbytes        : record length in bytes (1/2/4).
81// @ buffer        : local pointer on byte array.
82// @ return the integer value in a 32 bits word.
83//////////////////////////////////////////////////////////////////////////////////////////
84static uint32_t fatfs_get_record( uint32_t    offset,
85                                  uint32_t    nbytes,
86                                  uint8_t   * buffer )
87{
88    uint32_t i;
89    uint32_t res = 0;
90
91    if ( LITTLE_ENDIAN )
92    {
93        for( i = nbytes ; i > 0 ; i-- ) res = (res<<8) | buffer[offset+i-1];
94    }
95    else 
96    {
97        for( i = 0 ; i < nbytes ; i++ ) res = (res<<8) | buffer[offset+i];
98    }
99    return res;
100
101}  // end fatfs_get_record()
102
103//////////////////////////////////////////////////////////////////////////////////////////
104// This function return an integer record value (one, two, or four bytes) from a remote
105// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
106// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
107//////////////////////////////////////////////////////////////////////////////////////////
108// @ offset        : first byte in array.
109// @ nbytes        : record length in bytes (1/2/4).
110// @ buffer_xp     : extended pointer on byte array.
111// @ return the integer value in a 32 bits word.
112//////////////////////////////////////////////////////////////////////////////////////////
113static uint32_t fatfs_get_remote_record( uint32_t   offset,
114                                         uint32_t   nbytes,
115                                         xptr_t     buffer_xp )
116{
117    uint32_t i;
118    uint32_t res = 0;
119
120    if ( LITTLE_ENDIAN )
121    {
122        for( i = nbytes ; i > 0 ; i-- )
123        {
124            res = (res<<8) | hal_remote_lb( buffer_xp+offset+i-1 );
125        }
126    }
127    else 
128    {
129        for( i = 0 ; i < nbytes ; i++ )
130        {
131            res = (res<<8) | hal_remote_lb( buffer_xp+offset+i );
132        }
133    }
134    return res;
135
136}  // end fatfs_get_remote_record()
137
138//////////////////////////////////////////////////////////////////////////////////////////
139// This function writes one, two, or four bytes from a 32 bits integer to a local
140// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
141// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
142//////////////////////////////////////////////////////////////////////////////////////////
143// @ offset        : first byte in array.
144// @ nbytes        : record length in bytes (1/2/4).
145// @ buffer        : local pointer on byte array.
146// @ value         : 32 bits integer value.
147//////////////////////////////////////////////////////////////////////////////////////////
148static void fatfs_set_record( uint32_t    offset,
149                              uint32_t    nbytes,
150                              uint8_t   * buffer,
151                              uint32_t    value )
152{
153    uint32_t i;
154
155    if ( LITTLE_ENDIAN )
156    {
157        for( i = nbytes ; i > 0 ; i-- ) buffer[offset+i-1] = (uint8_t)(value>>((i-1)<<3));
158    }
159    else
160    {
161        for( i = 0 ; i < nbytes ; i++ ) buffer[offset+i] = (uint8_t)(value>>((nbytes-1-i)<<3));
162    }
163
164}  // end fatfs_set_record()
165
166//////////////////////////////////////////////////////////////////////////////////////////
167// This function writes one, two, or four bytes from a 32 bits integer to a remote
168// array of bytes, taking into account the global LITTLE_ENDIAN parameter:
169// if LITTLE_ENDIAN is true, the most significant byte has the highest address.
170//////////////////////////////////////////////////////////////////////////////////////////
171// @ offset        : first byte in array.
172// @ nbytes        : record length in bytes (1/2/4).
173// @ buffer_xp     : extended pointer on byte array.
174// @ value         : 32 bits integer value.
175//////////////////////////////////////////////////////////////////////////////////////////
176static void fatfs_set_remote_record( uint32_t    offset,
177                                     uint32_t    nbytes,
178                                     xptr_t      buffer_xp,
179                                     uint32_t    value )
180{
181    uint32_t i;
182
183    if ( LITTLE_ENDIAN )
184    {
185        for( i = nbytes ; i > 0 ; i-- )
186        {
187            hal_remote_sb( (buffer_xp+offset+i-1) , (uint8_t)(value>>((i-1)<<3)) );
188        }
189    }
190    else
191    {
192        for( i = 0 ; i < nbytes ; i++ )
193        {
194            hal_remote_sb( (buffer_xp+offset+i) , (uint8_t)(value>>((nbytes-1-i)<<3)) );
195        }
196    }
197
198}  // end fatfs_set_record()
199
200//////////////////////////////////////////////////////////////////////////////////////////
201// This static function retun in the <name> buffer a short name stored in
202// a SFN FATFS directory entry.
203/////////////////////////i////////////////////////////////////////////////////////////////
204// @ buffer   : pointer on buffer containing the directory entry.
205// @ name     : [out] buffer allocated by the caller.
206//////////////////////////////////////////////////////////////////////////////////////////
207static void fatfs_get_name_from_short( uint8_t * buffer,
208                                       char    * name )
209{
210    uint32_t i;
211    uint32_t j = 0;
212
213    // get name
214    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
215    {
216        name[j] = to_lower( buffer[i] );
217        j++;
218    }
219
220    // get extension
221    for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ )
222    {
223        // we entered the loop so there is an extension. add the dot
224        if ( i == 8 )
225        {
226            name[j] = '.';
227            j++;
228        }
229
230        name[j] = to_lower( buffer[i] );
231        j++;
232    }
233
234    name[j] = '\0';
235
236}  // fatfs_get_name_from_short()
237
238//////////////////////////////////////////////////////////////////////////////////////////
239// This static function retun in the <name> buffer a partial name stored in
240// a LFN FATFS directory entry.
241/////////////////////////i////////////////////////////////////////////////////////////////
242// @ buffer   : pointer on buffer containing the directory entry.
243// @ name     : [out] buffer allocated by the caller.
244//////////////////////////////////////////////////////////////////////////////////////////
245static void fatfs_get_name_from_long( uint8_t * buffer,
246                                      char    * name )
247{
248    uint32_t   name_offset   = 0;
249    uint32_t   buffer_offset = get_length(LDIR_ORD);
250    uint32_t   l_name_1      = get_length(LDIR_NAME_1);
251    uint32_t   l_name_2      = get_length(LDIR_NAME_2);
252    uint32_t   l_name_3      = get_length(LDIR_NAME_3);
253    uint32_t   l_attr        = get_length(LDIR_ATTR);
254    uint32_t   l_type        = get_length(LDIR_TYPE);
255    uint32_t   l_chksum      = get_length(LDIR_CHKSUM);
256    uint32_t   l_rsvd        = get_length(LDIR_RSVD);
257
258    uint32_t   j             = 0;
259    uint32_t   eof           = 0;
260
261    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
262    {
263        while (j != l_name_1 && !eof )
264        {
265            if ( (buffer[buffer_offset] == 0x00) || 
266                 (buffer[buffer_offset] == 0xFF) )
267            {
268                eof = 1;
269                continue;
270            }
271            name[name_offset] = buffer[buffer_offset];
272            buffer_offset += 2;
273            j += 2;
274            name_offset++;
275        }
276
277        buffer_offset += (l_attr + l_type + l_chksum);
278        j = 0;
279
280        while (j != l_name_2 && !eof )
281        {
282            if ( (buffer[buffer_offset] == 0x00) || 
283                 (buffer[buffer_offset] == 0xFF) )
284            {
285                eof = 1;
286                continue;
287            }
288            name[name_offset] = buffer[buffer_offset];
289            buffer_offset += 2;
290            j += 2;
291            name_offset++;
292        }
293
294        buffer_offset += l_rsvd;
295        j = 0;
296
297        while (j != l_name_3 && !eof )
298        {
299            if ( (buffer[buffer_offset] == 0x00) || 
300                 (buffer[buffer_offset] == 0xFF) )
301            {
302                eof = 1;
303                continue;
304            }
305            name[name_offset] = buffer[buffer_offset];
306            buffer_offset += 2;
307            j += 2;
308            name_offset++;
309        }
310    }
311    name[name_offset] = 0;
312
313} // end fatfs_get_name_from_long()
314
315//////////////////////////////////////////////////////////////////////////////////////////
316// This static function analyse the <name> input argument, and returns in other
317// output arguments various informations required to store the name in FATFS directory.
318// The <name> length cannot be larger than 31 characters :
319// - Short name (less than 13 characters) require 1 LFN entry.
320// - Medium names (from 14 to 26 characters require 2 LFN entries.
321// - Large names (up to 31 characters) require 3 LFN entries.
322//////////////////////////////////////////////////////////////////////////////////////////
323// @ name     : [in]  complete directory entry name.
324// @ length   : [out] total number of characters in name.
325// @ nb_lfn   : [out] number of LFN entries required to store the name.
326// @ sfn      : [out] a legal SFN name extracted from name / upper case and 8-3 format.
327// @ checksum : [out] checksum to be stored in SFN.
328// @ returns 0 on success / returns 1 if the name length is larger than 31 characters.
329//////////////////////////////////////////////////////////////////////////////////////////
330static error_t fatfs_name_format( const char  * name,
331                                  uint32_t    * length,
332                                  uint32_t    * nb_lfn,
333                                  char        * sfn,
334                                  uint8_t     * checksum )
335{
336    // compute name length
337    uint32_t name_length = strlen( name );
338    *length = name_length;
339
340    uint32_t suffix_length = 0;
341    uint32_t prefix_length = 0;
342    uint32_t dot_found     = 0;
343    uint32_t i;
344
345    // compute prefix and suffix length
346    // only the last '.' is taken into account
347    for ( i=0 ; i<name_length ; i++ )
348    {
349        if (name[i] == '.' )
350        {
351            if ( dot_found ) 
352            {
353                prefix_length += suffix_length + 1;
354                suffix_length =  0;
355            }
356            else
357            {
358                dot_found = 1;
359            }
360        }
361        else
362        { 
363            if ( dot_found)  suffix_length++;
364            else             prefix_length++;
365        }
366    } 
367
368    // build SFN prefix (8bits)
369    if (prefix_length <= 8)
370    {
371        for( i=0 ; i<8 ; i++)
372        {
373            if ( i<prefix_length ) sfn[i] = to_upper( name[i] );
374            else                   sfn[i] = 0x20;
375        }
376    }
377    else
378    {
379        for( i=0 ; i<6 ; i++)
380        {
381            sfn[i] = to_upper( name[i] );
382        }
383        sfn[6] = 0x7E;
384        sfn[7] = 0x31;
385    }
386
387    // build SFN suffix (3 bits)
388    if ( suffix_length == 0 )
389    {
390        sfn[8]  = 0x20;
391        sfn[9]  = 0x20;
392        sfn[10] = 0x20;
393    }
394    else if ( suffix_length == 1 )
395    {
396        sfn[8]  = to_upper( name[name_length-1] );
397        sfn[9]  = 0x20;
398        sfn[10] = 0x20;
399    }
400    else if ( suffix_length == 2 )
401    {
402        sfn[8]  = to_upper( name[name_length-2] );
403        sfn[9]  = to_upper( name[name_length-1] );
404        sfn[10] = 0x20;
405    }
406    else
407    {
408        sfn[8]  = to_upper( name[name_length-suffix_length] );
409        sfn[9]  = to_upper( name[name_length-suffix_length+1] );
410        sfn[10] = to_upper( name[name_length-suffix_length+2] );
411    }
412
413    // compute 8 bits checksum
414    uint8_t sum = 0;
415    for ( i=0 ; i<11 ; i++ )
416    {
417        sum = (((sum & 0x01)<<7) | ((sum & 0xFE)>>1)) + sfn[i];
418    }
419    *checksum = sum;
420
421    // set nb_lfn and length values
422    if      ( name_length <= 13 )
423    {
424        *nb_lfn  = 1;
425        return 0;
426    }
427    else if ( name_length <= 26 )
428    {
429        *nb_lfn  = 2;
430        return 0;
431    }
432    else if ( name_length <= 31 )
433    {
434        *nb_lfn  = 3;
435        return 0;
436    }
437    else
438    {
439        return 1;
440    }
441}   // end fatfs_name_format() 
442
443//////////////////////////////////////////////////////////////////////////////////////////
444// This static function is called by both the fatfs_free_clusters_increment(),
445// and the fatfs_free_cluster_decrement() functions defined below.
446// It synchronously updates the  "free_clusters" and "free_cluster_hint" variables
447// in FS_INFO sector on the IOC device, each times these variables are modified.
448//////////////////////////////////////////////////////////////////////////////////////////
449// @ fatfs_ctx_xp      : extended pointer on fatfs context in FAT cluster.
450// @ free_clusters     : new free_clusters value.
451// @ free_cluster_hint : new free_cluster_hint value.
452// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
453//////////////////////////////////////////////////////////////////////////////////////////
454static error_t fatfs_free_clusters_update_ioc( xptr_t    fatfs_ctx_xp,
455                                               uint32_t  free_clusters,
456                                               uint32_t  free_cluster_hint )
457{
458    cxy_t         fat_cxy;             // FAT cluster identifier
459    fatfs_ctx_t * fatfs_ctx_ptr;       // local pointer on fatfs context in FAT cluster
460    uint8_t     * fs_info_buffer_ptr;  // local pointer on FS_INFO buffer in FAT cluster
461    xptr_t        fs_info_buffer_xp;   // extended pointer on FS_INFO buffer in FAT cluster
462    uint32_t      fs_info_lba;         // FS_INFO sector lba on IOC device
463
464    // get cluster and local pointer on FAT cluster context
465    fat_cxy       = GET_CXY( fatfs_ctx_xp ); 
466    fatfs_ctx_ptr = GET_PTR( fatfs_ctx_xp ); 
467
468    // get pointers on FS_INFO buffer in FAT cluster
469    fs_info_buffer_ptr = hal_remote_lpt( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_buffer ) );
470    fs_info_buffer_xp  = XPTR( fat_cxy , fs_info_buffer_ptr );
471
472    // get lba of FS_INFO sector on IOC device from fatfs context
473    fs_info_lba = hal_remote_l32( XPTR( fat_cxy , &fatfs_ctx_ptr->fs_info_lba ) );
474
475    // update the FS_INFO buffer in FAT cluster
476    fatfs_set_remote_record( FS_FREE_CLUSTERS     , fs_info_buffer_xp , free_clusters );
477    fatfs_set_remote_record( FS_FREE_CLUSTER_HINT , fs_info_buffer_xp , free_cluster_hint );
478   
479    // update the FS_INFO sector on IOC device
480    return dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 );
481 
482}  // fatfs_free_clusters_update_ioc()
483
484//////////////////////////////////////////////////////////////////////////////////////////
485// This static function decrements the  "free_clusters" variable, and updates the
486// "free_cluster_hint" variable in the FATFS context in FAT cluster, identified
487// by the <fat_ctx_xp> argument, when a new <cluster> has been allocated from FAT.
488// It scan all slots in the FAT mapper seen as an array of 32 bits words, looking for the
489// first free slot larger than the <cluster> argument, to update "free_cluster_hint".
490// It calls the fatfs_free_clusters_update_ioc() function to synchronously update the
491// FS_INFO sector on the IOC device. It can be called by a thead running in any cluster.
492//
493// WARNING : The lock protecting exclusive access to these variables
494//           must be taken by the calling function.
495//////////////////////////////////////////////////////////////////////////////////////////
496// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
497// @ cluster       : recently allocated cluster index in FAT.
498// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
499//////////////////////////////////////////////////////////////////////////////////////////
500static error_t fatfs_free_clusters_decrement( xptr_t    fatfs_ctx_xp,
501                                              uint32_t  cluster )
502{
503    error_t       error;
504    cxy_t         fat_cxy;      // FAT cluster identifier
505    fatfs_ctx_t * fat_ctx_ptr;  // local pointer on fatfs context in FAT cluster
506    xptr_t        mapper_xp;    // extended pointer on FAT mapper
507    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
508    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
509    uint32_t      numb;         // "free_clusters" variable current value
510    uint32_t      hint;         // "free_cluster_hint" variable current value
511    uint32_t      page_id;      // page index in FAT mapper
512    uint32_t      slot_id;      // slot index in one page of FAT (1024 slots per page)
513    uint32_t      page_max;     // max number of pages in FAT mapper
514    xptr_t        page_xp;      // extended pointer on current page in FAT mapper
515    xptr_t        base_xp;      // extended pointer on current page base
516    xptr_t        slot_xp;      // extended pointer on current slot in FAT mapper
517
518#if DEBUG_FATFS_FREE_CLUSTERS
519uint32_t   cycle = (uint32_t)hal_get_cycles();
520thread_t * this  = CURRENT_THREAD;
521if( DEBUG_FATFS_FREE_CLUSTERS < cycle )
522printk("\n[%s] thread[%x,%x] enter for allocated cluster %x / cycle %d\n",
523__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
524#endif
525
526    // get FAT cluster an local pointer on fatfs context in FAT cluster
527    fat_cxy      = GET_CXY( fatfs_ctx_xp );
528    fat_ctx_ptr  = GET_PTR( fatfs_ctx_xp );
529   
530    // build extended pointers on free_clusters, and free_cluster_hint in fatfs context
531    hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint );
532    numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters );
533
534    // update "free_clusters" value
535    numb = hal_remote_l32( numb_xp ) - 1;
536    hal_remote_s32( numb_xp , numb );
537
538    // get extended pointer on FAT mapper
539    mapper_xp = hal_remote_l64( XPTR( fat_cxy , &fat_ctx_ptr->fat_mapper_xp ) );
540
541    // initialise variables to scan the FAT mapper
542    // and find the first free slot > cluster
543    page_id  = (cluster + 1) >> 10;
544    slot_id  = (cluster + 1) & 0x3FF;
545    page_max = hal_remote_l32( XPTR( fat_cxy, &fat_ctx_ptr->fat_sectors_count ) ) >> 3;
546
547    // scan FAT mapper / loop on pages
548    while ( page_id < page_max )           
549    {
550        // get current page from mapper
551        page_xp = mapper_remote_get_page( mapper_xp , page_id );
552
553        if( page_xp == XPTR_NULL )
554        {
555            printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
556            return -1;
557        }
558
559        // get extended pointer on page
560        base_xp = ppm_page2base( page_xp );
561
562        // scan FAT mapper / loop on slots
563        while ( slot_id < 1024 )
564        {
565            // get extended pointer on current slot
566            slot_xp = base_xp + (slot_id << 2);
567
568            // test slot value
569            if ( hal_remote_l32( slot_xp ) == FREE_CLUSTER )
570            {
571                // update "free_cluster_hint" value
572                hint = (page_id << 10) + slot_id - 1;
573                hal_remote_s32( hint_xp , hint );
574
575                // update FS_INFO sector on IOC device
576                error = fatfs_free_clusters_update_ioc( fatfs_ctx_xp , numb , hint );
577
578                if( error ) 
579                {
580                    printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
581                    return -1;
582                }
583
584#if DEBUG_FATFS_FREE_CLUSTERS
585cycle = (uint32_t)hal_get_cycles();
586if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
587printk("\n[%s] thread[%x,%x] updated free cluster info  / hint %x / number %x\n",
588__FUNCTION__, this->process->pid, this->trdid, 
589hal_remote_l32(hint_xp), hal_remote_l32(numb_xp) );
590#endif
591                return 0;
592            }
593
594            // update slot_id
595            slot_id = 0;
596
597        }  // end loop on slots
598
599        // update page_id & slot_id variables
600        page_id++;
601        slot_id = 0;
602
603    }  // end loop on pages
604
605    // return error if no free cluster found
606    printk("\n[ERROR] in %s : No free cluster found\n", __FUNCTION__ );
607    return -1;
608   
609}  // end fatfs_free_clusters_decrement()
610
611//////////////////////////////////////////////////////////////////////////////////////////
612// This static function increments the "free_clusters" variable, and updates the
613// "free_cluster_hint" variables in the FATFS context in FAT cluster, identified
614// by the <fat_ctx_xp> argument, when a cluster is released to FAT.
615// If the released cluster index is smaller than the current (hint) value,
616// it set "free_cluster_hint" <= cluster.
617// It calls the fatfs_free_clusters_update_ioc() function to synchronously update the
618// FS_INFO sector on the IOC device. It can be called by a thead running in any cluster.
619//
620// WARNING : The lock protecting exclusive access to these variables
621//           must be taken by the calling function.
622//////////////////////////////////////////////////////////////////////////////////////////
623// @ fatfs_ctx_xp  : extended pointer on FATFS context in FAT cluster.
624// @ cluster       : recently released cluster index in FAT.
625// @ return 0 if success, return -1 if the FS_INFO sector cannot be updated.
626//////////////////////////////////////////////////////////////////////////////////////////
627static error_t fatfs_free_clusters_increment( xptr_t   fatfs_ctx_xp,
628                                              uint32_t cluster )
629{
630    error_t       error;
631    cxy_t         fat_cxy;      // FAT cluster identifier
632    fatfs_ctx_t * fat_ctx_ptr;  // local pointer on fatfs context in FAT cluster
633    xptr_t        hint_xp;      // extended pointer on "free_cluster_hint" shared variable
634    xptr_t        numb_xp;      // extended pointer on "free_clusters" shared variable
635    uint32_t      hint;         // "free_cluster_hint" variable current value
636    uint32_t      numb;         // "free_clusters" variable current value
637
638#if DEBUG_FATFS_FREE_CLUSTERS
639uint32_t   cycle = (uint32_t)hal_get_cycles();
640thread_t * this  = CURRENT_THREAD;
641if( DEBUG_FATFS_FREE_CLUSTERS < cycle )
642printk("\n[%s] thread[%x,%x] enter for released cluster %x / cycle %d\n",
643__FUNCTION__, this->process->pid, this->trdid, cluster , cycle );
644#endif
645
646    // get FAT cluster an local pointer on fatfs context in FAT cluster
647    fat_cxy      = GET_CXY( fatfs_ctx_xp );
648    fat_ctx_ptr  = GET_PTR( fatfs_ctx_xp );
649   
650    // build extended pointers on free_clusters, and free_cluster_hint
651    hint_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_cluster_hint );
652    numb_xp = XPTR( fat_cxy , &fat_ctx_ptr->free_clusters );
653
654    // get current value of free_cluster_hint and free_clusters
655    hint = hal_remote_l32( hint_xp );
656    numb = hal_remote_l32( numb_xp );
657
658    // update "numb" and "hint" variables as required
659    numb++;
660    if ( (cluster - 1) < hint ) hint = cluster - 1;
661
662    // update free_clusters
663    hal_remote_s32( numb_xp , numb );
664    hal_remote_s32( hint_xp , hint );
665
666    // update FS_INFO sector on IOC device
667    error = fatfs_free_clusters_update_ioc( fatfs_ctx_xp , numb , hint );
668
669    if( error ) 
670    {
671        printk("\n[ERROR] in %s : cannot update FS_INFO on IOC\n", __FUNCTION__ );
672        return -1;
673    }
674
675#if DEBUG_FATFS_FREE_CLUSTERS
676thread_t * this = CURRENT_THREAD;
677if( DEBUG_FATFS_FREE_CLUSTERS < (uint32_t)hal_get_cycles() )
678printk("\n[%s] thread[%x,%x] updated free cluster info : hint %x / number %x\n",
679__FUNCTION__, this->process->pid, this->trdid,
680hal_remote_l32( hint_xp ), hal_remote_l32( numb_xp ) );
681#endif
682
683    return 0;
684
685}  // end fatfs_free_clusters_increment()
686
687//////////////////////////////////////////////////////////////////////////////////////////
688// This recursive function is called by the generic function fatfs_release_all_clusters()
689// It release all clusters allocated to a given inode in the FAT mapper.
690// The removal is done in reverse order of the linked list (from last to first).
691// It does NOT update the FS on the IOC device.
692//////////////////////////////////////////////////////////////////////////////////////////
693// @ mapper_cxy : FAT mapper cluster identifier.
694// @ mapper_ptr : local pointer on FAT mapper.
695// @ fatfs_ctx  : local pointer on FATFS context in FAT cluster.
696// @ cluster    : index of cluster to be released from FAT mapper.
697// @ return 0 if success / return -1 if error (cannot access FAT)
698//////////////////////////////////////////////////////////////////////////////////////////
699static error_t fatfs_recursive_release( cxy_t         mapper_cxy,
700                                        mapper_t    * mapper_ptr,
701                                        fatfs_ctx_t * fatfs_ctx,
702                                        uint32_t      cluster )
703{
704    uint32_t next;
705
706    // build extended pointer on FAT mapper
707    xptr_t mapper_xp = XPTR( mapper_cxy , mapper_ptr );
708
709    // get next cluster index from FAT mapper
710    if ( mapper_remote_get_32( mapper_xp,
711                               cluster,
712                               &next ) ) return -1;
713
714#if (DEBUG_FATFS_RELEASE_INODE & 1)
715thread_t * this = CURRENT_THREAD;
716if ( DEBUG_FATFS_RELEASE_INODE < (uint32_t)hal_get_cycles() )
717printk("\n[%s] thread[%x,%x] access FAT for cluster %x / next %x\n",
718__FUNCTION__, this->process->pid, this->trdid, cluster, next );
719#endif
720
721    if ( next < END_OF_CHAIN_CLUSTER_MIN )  // non terminal case
722    {
723        // call fatfs_recursive_release() on next cluster
724        if ( fatfs_recursive_release( mapper_cxy,
725                                      mapper_ptr,
726                                      fatfs_ctx,
727                                      next ) ) return -1;
728    }       
729
730    // update current cluster in FAT mapper
731    if ( mapper_remote_set_32( mapper_xp, 
732                               cluster,
733                               FREE_CLUSTER ) ) return -1;
734
735    // Update free_cluster info in FATFS context and in FS_INFO sector
736    return fatfs_free_clusters_increment( XPTR( mapper_cxy , fatfs_ctx ) , cluster );
737
738}  // end fatfs_recursive_release()
739
740
741//////////////////////////////////////////////////////////////////////////////////////////
742//              FATFS specific extern functions
743//////////////////////////////////////////////////////////////////////////////////////////
744
745///////////////////////////////////
746void fatfs_display_ctx( cxy_t cxy )
747{
748    // get pointer on local FATFS context
749    vfs_ctx_t   * vfs_ctx = &fs_context[FS_TYPE_FATFS];
750        fatfs_ctx_t * ctx     = hal_remote_lpt( XPTR( cxy , &vfs_ctx->extend ) );
751
752    uint32_t fat_sectors       = hal_remote_l32( XPTR( cxy , &ctx->fat_sectors_count ) );
753    uint32_t sector_size       = hal_remote_l32( XPTR( cxy , &ctx->bytes_per_sector ) );
754    uint32_t sec_per_clus      = hal_remote_l32( XPTR( cxy , &ctx->sectors_per_cluster ) );
755    uint32_t fat_lba           = hal_remote_l32( XPTR( cxy , &ctx->fat_begin_lba ) );
756    uint32_t data_lba          = hal_remote_l32( XPTR( cxy , &ctx->cluster_begin_lba ) );
757    uint32_t fsinfo_lba        = hal_remote_l32( XPTR( cxy , &ctx->fs_info_lba ) );
758    uint32_t root_dir_clus     = hal_remote_l32( XPTR( cxy , &ctx->root_dir_cluster ) );
759    uint32_t free_clusters     = hal_remote_l32( XPTR( cxy , &ctx->free_clusters ) );
760    uint32_t free_cluster_hint = hal_remote_l32( XPTR( cxy , &ctx->free_cluster_hint ) );
761    xptr_t   mapper_xp         = hal_remote_l64( XPTR( cxy , &ctx->fat_mapper_xp ) );
762    void   * fs_info_buffer    = hal_remote_lpt( XPTR( cxy , &ctx->fs_info_buffer ) );
763
764    printk("\n*** FAT context in cluster %x\n" 
765           "- fat_sectors       = %d\n"
766           "- sector size       = %d\n"
767           "- cluster size      = %d\n"
768           "- fat_lba           = %x\n"
769           "- data_lba          = %x\n"
770           "- fsinfo_lba        = %x\n"
771           "- root_dir_cluster  = %x\n"
772           "- free_clusters     = %x\n"
773           "- free_cluster_hint = %x\n"
774           "- fat_mapper_ptr    = %x\n"
775           "- fs_info_buffer    = %x\n",
776           cxy,
777           fat_sectors,
778           sector_size,
779           sector_size * sec_per_clus,
780           fat_lba,
781           data_lba,
782           fsinfo_lba,
783           root_dir_clus,
784           free_clusters,
785           free_cluster_hint,
786           GET_PTR( mapper_xp ),
787           fs_info_buffer );
788
789}  // end fatfs_ctx_display()
790
791//////////////////////////////////////////
792void fatfs_display_fat( uint32_t  page_id,
793                        uint32_t  nentries )
794{
795    uint32_t line;
796    uint32_t maxline;
797
798    // compute number of lines to display
799    maxline = nentries >> 3;
800    if( nentries & 0x7 ) maxline++;
801
802    // get pointer on local FATFS context
803    vfs_ctx_t   * vfs_ctx       = &fs_context[FS_TYPE_FATFS];
804    fatfs_ctx_t * loc_fatfs_ctx = (fatfs_ctx_t *)vfs_ctx->extend;
805
806    // get extended pointer on FAT mapper
807    xptr_t fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
808
809    // get FAT cluster identifier
810    cxy_t  fat_cxy = GET_CXY( fat_mapper_xp );
811
812    // get pointer on FATFS context in FAT cluster
813    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
814 
815    // get current value of hint and free_clusters
816    uint32_t hint = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint ) );
817    uint32_t free = hal_remote_l32( XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters ) );
818 
819    // get extended pointer on requested page in FAT mapper
820    xptr_t     page_xp  = mapper_remote_get_page( fat_mapper_xp , page_id );
821
822    // get extended pointer on requested page base
823    xptr_t     base_xp  = ppm_page2base( page_xp );
824    void     * base     = GET_PTR( base_xp );
825
826    printk("\n***** FAT mapper / cxy %x / page_id %d / base %x / free_clusters %x / hint %x\n",
827    fat_cxy, page_id, base, free, hint );
828
829    for( line = 0 ; line < maxline ; line++ )
830    {
831        printk("%x : %X | %X | %X | %X | %X | %X | %X | %X\n", (line<<3),
832        hal_remote_l32( base_xp + ((line<<5)      ) ),
833        hal_remote_l32( base_xp + ((line<<5) + 4  ) ),
834        hal_remote_l32( base_xp + ((line<<5) + 8  ) ),
835        hal_remote_l32( base_xp + ((line<<5) + 12 ) ),
836        hal_remote_l32( base_xp + ((line<<5) + 16 ) ),
837        hal_remote_l32( base_xp + ((line<<5) + 20 ) ),
838        hal_remote_l32( base_xp + ((line<<5) + 24 ) ),
839        hal_remote_l32( base_xp + ((line<<5) + 28 ) ) );
840    }
841
842}  // end fatfs_display_fat()
843
844///////////////////////////////////////////////////////
845error_t fatfs_get_cluster( uint32_t   first_cluster_id,
846                           uint32_t   searched_page_index,
847                           uint32_t * searched_cluster_id )
848{
849    xptr_t     current_page_xp;        // pointer on current page descriptor
850    uint32_t * buffer;                 // pointer on current page (array of uint32_t)
851    uint32_t   current_page_index;     // index of current page in FAT
852    uint32_t   current_slot_index;     // index of slot in current page
853    uint32_t   page_count_in_file;     // index of page in file (index in linked list)
854    uint32_t   next_cluster_id;        // content of current FAT slot
855    xptr_t     lock_xp;                // extended pointer on FAT lock
856
857assert( (searched_page_index > 0) ,
858"no FAT access required for first page\n");
859
860#if DEBUG_FATFS_GET_CLUSTER
861uint32_t   cycle = (uint32_t)hal_get_cycles();
862thread_t * this  = CURRENT_THREAD;
863if( DEBUG_FATFS_GET_CLUSTER < cycle )
864printk("\n[%s] thread[%x,%x] enter / first_cluster_id %d / searched_index %d / cycle %d\n",
865__FUNCTION__, this->process->pid, this->trdid, first_cluster_id, searched_page_index, cycle );
866#endif
867
868    // get local pointer on VFS context (same in all clusters)
869    vfs_ctx_t * vfs_ctx = &fs_context[FS_TYPE_FATFS];
870
871    // get local pointer on local FATFS context
872    fatfs_ctx_t * loc_fatfs_ctx = vfs_ctx->extend;
873
874    // get extended pointer and cluster on FAT mapper
875    xptr_t fat_mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
876    cxy_t  fat_cxy        = GET_CXY( fat_mapper_xp );
877
878    // get local pointer on FATFS context in FAT cluster
879    fatfs_ctx_t * fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
880
881    // build extended pointer on FAT lock in FAT cluster
882    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
883
884    // take FAT lock in read mode
885    remote_rwlock_rd_acquire( lock_xp );
886
887    // initialize loop variable (1024 slots per page)
888    current_page_index  = first_cluster_id >> 10;
889    current_slot_index  = first_cluster_id & 0x3FF;
890    page_count_in_file  = 0;
891    next_cluster_id     = 0xFFFFFFFF;
892
893    // scan FAT mapper (i.e. traverse FAT linked list)
894    while( page_count_in_file < searched_page_index )
895    {
896        // get pointer on current page descriptor in FAT mapper
897        current_page_xp = mapper_remote_get_page( fat_mapper_xp , current_page_index );
898
899        if( current_page_xp == XPTR_NULL )
900        {
901            printk("\n[ERROR] in %s : cannot get next page from FAT mapper\n", __FUNCTION__);
902            remote_rwlock_rd_release( lock_xp );
903            return -1;
904        }
905
906        // get pointer on buffer for current page
907        xptr_t base_xp = ppm_page2base( current_page_xp );
908        buffer = (uint32_t *)GET_PTR( base_xp );
909
910        // get FAT slot content
911        next_cluster_id = hal_remote_l32( XPTR( fat_cxy, &buffer[current_slot_index] ) );
912
913#if (DEBUG_FATFS_GET_CLUSTER & 1)
914if( DEBUG_FATFS_GET_CLUSTER < cycle )
915printk("\n[%s] traverse FAT / current_page_index = %d\n"
916"current_slot_index = %d / next_cluster_id = %d\n",
917__FUNCTION__, current_page_index, current_slot_index , next_cluster_id );
918#endif
919        // update loop variables
920        current_page_index = next_cluster_id >> 10;
921        current_slot_index = next_cluster_id & 0x3FF;
922        page_count_in_file++;
923    }
924
925    if( next_cluster_id == 0xFFFFFFFF )
926    {
927        printk("\n[ERROR] in %s : searched_cluster_id not found in FAT\n", __FUNCTION__ );
928        remote_rwlock_rd_release( lock_xp );
929        return -1;
930    }
931   
932    // release FAT lock
933    remote_rwlock_rd_release( lock_xp );
934
935#if DEBUG_FATFS_GET_CLUSTER
936cycle = (uint32_t)hal_get_cycles();
937if( DEBUG_FATFS_GET_CLUSTER < cycle )
938printk("\n[%s] thread[%x,%x] exit / searched_cluster_id = %d / cycle %d\n",
939__FUNCTION__, this->process->pid, this->trdid, next_cluster_id / cycle );
940#endif
941
942    *searched_cluster_id = next_cluster_id;
943    return 0;
944
945}  // end fatfs_get_cluster()
946
947
948
949///////////////////////////////////////////////////////////////////////////////////////
950// Generic API : the following functions are called by the kernel VFS
951//               and must be defined by all supported file systems.
952///////////////////////////////////////////////////////////////////////////////////////
953
954/////////////////////////////////////
955fatfs_ctx_t * fatfs_ctx_alloc( void )
956{
957    kmem_req_t    req;
958        req.type    = KMEM_FATFS_CTX;
959        req.size    = sizeof(fatfs_ctx_t);
960    req.flags   = AF_KERNEL | AF_ZERO;
961
962        return (fatfs_ctx_t *)kmem_alloc( &req );
963}
964
965//////////////////////////////////////////////
966void fatfs_ctx_init( fatfs_ctx_t * fatfs_ctx )
967{
968    error_t       error;
969    kmem_req_t    req;
970    uint8_t     * buffer;
971    xptr_t        buffer_xp;
972
973#if DEBUG_FATFS_CTX_INIT
974uint32_t   cycle = (uint32_t)hal_get_cycles();
975thread_t * this  = CURRENT_THREAD;
976if( DEBUG_FATFS_CTX_INIT < cycle )
977printk("\n[%s] thread[%x,%x] enter for fatfs_ctx = %x / cycle %d\n",
978__FUNCTION__ , this->process->pid, this->trdid, fatfs_ctx , cycle );
979#endif
980
981// check argument
982assert( (fatfs_ctx != NULL) , "pointer on FATFS context is NULL" );
983
984// check only cluster 0 does FATFS initialization
985assert( (local_cxy == 0) , "only cluster 0 can initialize FATFS");
986
987    // allocate a permanent 512 bytes buffer to store
988    // - temporarily the BOOT sector
989    // - permanently the FS_INFO sector
990        req.type    = KMEM_512_BYTES;
991    req.flags   = AF_KERNEL | AF_ZERO;
992        buffer      = (uint8_t *)kmem_alloc( &req );
993    buffer_xp   = XPTR( local_cxy , buffer );
994
995    if( buffer == NULL ) 
996    {
997        printk("\n[PANIC] in %s : cannot allocate buffer\n", __FUNCTION__ );
998        hal_core_sleep();
999    }
1000     
1001    // load the BOOT record from device
1002    error = dev_ioc_sync_read( buffer_xp , 0 , 1 );
1003
1004    if ( error )
1005    {
1006        printk("\n[PANIC] in %s : cannot access boot record\n", __FUNCTION__ );
1007        hal_core_sleep();
1008    }
1009
1010#if (DEBUG_FATFS_CTX_INIT & 0x1)
1011if( DEBUG_FATFS_CTX_INIT < cycle )
1012putb( "boot record", buffer , 256 );
1013#endif
1014
1015    // get sector size from boot record
1016    uint32_t sector_size = fatfs_get_record( BPB_BYTSPERSEC , buffer );
1017    if ( sector_size != 512 )
1018    {
1019        printk("\n[PANIC] in %s : sector size must be 512 bytes\n", __FUNCTION__ );
1020        hal_core_sleep();
1021    }
1022
1023    // get cluster size from boot record
1024    uint32_t nb_sectors = fatfs_get_record( BPB_SECPERCLUS , buffer );
1025    if ( nb_sectors != 8 )
1026    {
1027        printk("\n[PANIC] in %s : cluster size must be 8 sectors\n", __FUNCTION__ );
1028        hal_core_sleep();
1029    }
1030
1031    // get number of FAT copies from boot record
1032    uint32_t nb_fats = fatfs_get_record( BPB_NUMFATS , buffer );
1033    if ( nb_fats != 1 )
1034    {
1035        printk("\n[PANIC] in %s : number of FAT copies must be 1\n", __FUNCTION__ );
1036        hal_core_sleep();
1037    }
1038
1039    // get number of sectors in FAT from boot record
1040    uint32_t fat_sectors = fatfs_get_record( BPB_FAT32_FATSZ32 , buffer );
1041    if ( (fat_sectors & 0xF) != 0 )
1042    {
1043        printk("\n[PANIC] in %s : FAT size not multiple of 16 sectors\n", __FUNCTION__ );
1044        hal_core_sleep();
1045    }
1046
1047    // get root cluster from boot record
1048    uint32_t root_cluster = fatfs_get_record( BPB_FAT32_ROOTCLUS , buffer );
1049    if ( root_cluster != 2 ) 
1050    {
1051        printk("\n[PANIC] in %s : root cluster index must be 2\n", __FUNCTION__ );
1052        hal_core_sleep();
1053    }
1054
1055    // get FAT lba from boot record
1056    uint32_t fat_lba = fatfs_get_record( BPB_RSVDSECCNT , buffer );
1057
1058    // get FS_INFO sector lba from boot record
1059    uint32_t fs_info_lba = fatfs_get_record( BPB_FAT32_FSINFO , buffer );
1060
1061    // load the FS_INFO record from device
1062    error = dev_ioc_sync_read( buffer_xp , fs_info_lba , 1 );
1063
1064    if ( error )
1065    {
1066        printk("\n[PANIC] in %s : cannot access FS_INFO record\n", __FUNCTION__ );
1067        hal_core_sleep();
1068    }
1069
1070    // get free_clusters number from FS_INFO record
1071    uint32_t free_clusters = fatfs_get_record( FS_FREE_CLUSTERS , buffer );
1072    if ( free_clusters >= fat_sectors << 7 )
1073    {
1074        printk("\n[PANIC] in %s : unconsistent free_clusters\n", __FUNCTION__ );
1075        hal_core_sleep();
1076    }
1077
1078    // get free_cluster_hint from FS_INFO record
1079    uint32_t free_cluster_hint = fatfs_get_record( FS_FREE_CLUSTER_HINT , buffer );
1080
1081    if ( free_cluster_hint >= fat_sectors << 7 )
1082    {
1083        printk("\n[PANIC] in %s : unconsistent free_cluster_hint\n", __FUNCTION__ );
1084        hal_core_sleep();
1085    }
1086
1087    // allocate a mapper for the FAT itself
1088    mapper_t * fat_mapper = mapper_create( FS_TYPE_FATFS );
1089    if ( fat_mapper == NULL )
1090    {
1091        printk("\n[PANIC] in %s : no memory for FAT mapper\n", __FUNCTION__ );
1092        hal_core_sleep();
1093    }
1094
1095    // the inode field is NULL for the FAT mapper
1096    fat_mapper->inode = NULL;
1097
1098    // initialize the FATFS context
1099    fatfs_ctx->fat_begin_lba         = fat_lba;
1100    fatfs_ctx->fat_sectors_count     = fat_sectors; 
1101    fatfs_ctx->bytes_per_sector      = sector_size;
1102    fatfs_ctx->sectors_per_cluster   = nb_sectors;
1103    fatfs_ctx->cluster_begin_lba     = fat_lba + fat_sectors;
1104    fatfs_ctx->root_dir_cluster      = 2;
1105    fatfs_ctx->fat_mapper_xp         = XPTR( local_cxy , fat_mapper );
1106    fatfs_ctx->fs_info_lba           = fs_info_lba;
1107    fatfs_ctx->free_clusters         = free_clusters;
1108    fatfs_ctx->free_cluster_hint     = free_cluster_hint;
1109    fatfs_ctx->fs_info_buffer        = buffer;
1110
1111    remote_rwlock_init( XPTR( local_cxy , &fatfs_ctx->lock ) , LOCK_FATFS_FREE );
1112
1113#if (DEBUG_FATFS_CTX_INIT & 0x1)
1114if( DEBUG_FATFS_CTX_INIT < cycle )
1115fatfs_ctx_display( fatfs_ctx );
1116#endif
1117
1118#if DEBUG_FATFS_CTX_INIT
1119cycle = (uint32_t)hal_get_cycles();
1120if( DEBUG_FATFS_CTX_INIT < cycle )
1121printk("\n[%s]  thread[%x,%x] exit for fatfs_ctx = %x / cycle %d\n",
1122__FUNCTION__, this->process->pid, this->trdid, fatfs_ctx, cycle );
1123#endif
1124
1125}  // end fatfs_ctx_init()
1126
1127/////////////////////////////////////////////////
1128void fatfs_ctx_destroy( fatfs_ctx_t * fatfs_ctx )
1129{
1130    kmem_req_t    req;
1131    req.type = KMEM_FATFS_CTX;
1132    req.ptr  = fatfs_ctx;
1133    kmem_free( &req );
1134}
1135
1136///////////////////////////////////////////////
1137error_t fatfs_add_dentry( vfs_inode_t  * inode,
1138                          vfs_dentry_t * dentry )
1139{
1140    error_t       error;
1141    uint32_t      length;        // dentry name length
1142    uint32_t      nb_lfn;        // number or required LFN
1143    char          sfn[11];       // buffer for SFN name
1144    uint8_t       checksum;      // name checksum
1145    mapper_t    * mapper;        // loal pointer on parent inode mapper
1146    xptr_t        mapper_xp;     // extended pointer on parent inode mapper
1147    xptr_t        child_xp;      // extended pointer on child inode
1148    cxy_t         child_cxy;     // child inode cluster
1149    vfs_inode_t * child_ptr;     // child inode local pointer
1150    uint32_t      size;          // child inode size
1151    uint32_t      type;          // child inode type
1152    uint32_t      cluster;       // child inode cluster index
1153
1154#if DEBUG_FATFS_ADD_DENTRY
1155char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1156uint32_t   cycle = (uint32_t)hal_get_cycles();
1157thread_t * this  = CURRENT_THREAD;
1158vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1159if( DEBUG_FATFS_ADD_DENTRY < cycle )
1160printk("\n[%s]  thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1161__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1162#endif
1163
1164// check arguments
1165assert( (inode != NULL) , "inode pointer is NULL\n" );
1166assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1167assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1168 
1169    // get pointers on directory mapper
1170    mapper    = inode->mapper;
1171    mapper_xp = XPTR( local_cxy , mapper );
1172
1173    // get extended pointers on remote child inode
1174    child_xp  = dentry->child_xp;
1175    child_cxy = GET_CXY( child_xp );
1176    child_ptr = GET_PTR( child_xp );
1177
1178    // get relevant infos from child inode
1179    type    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->type ) );
1180    size    =                     hal_remote_l32( XPTR( child_cxy , &child_ptr->size ) );
1181    cluster = (uint32_t)(intptr_t)hal_remote_lpt( XPTR( child_cxy , &child_ptr->extend ) );
1182
1183    // analyse dentry name
1184    error = fatfs_name_format( dentry->name,
1185                               &length,
1186                               &nb_lfn,
1187                               sfn,
1188                               &checksum );
1189    if ( error )
1190    {
1191        printk("\n[ERROR] in %s : dentry name > 31 bytes\n", __FUNCTION__ );
1192        return -1;
1193    }
1194                               
1195    // Search end of directory with two embedded loops:
1196    // - scan the pages in the mapper
1197    // - scan the entries in each page to find NO_MORE_ENTRY
1198
1199    xptr_t     page_xp;                 // extended pointer on page descriptor
1200    xptr_t     base_xp;                 // extended pointer on page base
1201    uint8_t  * base;                    // local pointer on page base (array of bytes)
1202    uint32_t   page_id = 0;             // page index in mapper
1203    uint32_t   offset  = 0;             // position in page
1204    uint32_t   found   = 0;             // NO_MORE_ENTRY found
1205
1206    // loop on pages in mapper
1207    while ( found == 0 )
1208    {
1209        // get extended pointer on page descriptor in mapper
1210        page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1211
1212        if ( page_xp == XPTR_NULL )
1213        {
1214            printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1215            return -1;
1216        }
1217       
1218        // get pointer on page base
1219        base_xp = ppm_page2base( page_xp );
1220        base = GET_PTR( base_xp );
1221
1222        // loop on directory entries in this page
1223        while ( (offset < 4096) && (found == 0) )
1224        {
1225            if ( fatfs_get_record( LDIR_ORD, (base + offset) ) == NO_MORE_ENTRY )
1226            {
1227                found = 1;
1228            } 
1229            else
1230            {
1231                offset = offset + 32;
1232            }
1233        }  // end loop on entries
1234
1235        if ( found == 0 )
1236        {
1237            page_id++;
1238            offset = 0;
1239        }
1240    }  // end loop on pages
1241
1242    // Modify the directory mapper: depending on the name length,
1243    // the new child requires to write (3, 4, or 5) directory entries.
1244    // To actually register the new child, we use a 5 steps FSM
1245    // (one state per entry to be written), that is traversed as:
1246    // LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1247    // At most two pages are modified:
1248    // - the page containing the NO_MORE_ENTRY is always modified
1249    // - the following page can be modified if the name spread on to pages.
1250
1251    char * name = dentry->name;
1252
1253    uint32_t step;          // FSM state
1254
1255    if      ( nb_lfn == 1 ) step = 3;
1256    else if ( nb_lfn == 2 ) step = 4;
1257    else if ( nb_lfn == 3 ) step = 5;
1258   
1259    uint8_t  * entry;       // pointer on directory entry to be written
1260    uint32_t   i;           // byte index in one 32 bytes directory
1261    uint32_t   c;           // character index in name
1262
1263    while ( step )   
1264    {
1265        // when the new child is split on two pages,
1266        // we need to access a new page in mapper
1267        if ( offset >= 4096 )
1268        {
1269            // copy the modified page to IOC device
1270            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1271
1272            // get the next page in FAT mapper
1273            page_xp  = mapper_remote_get_page( mapper_xp , page_id + 1 );
1274
1275            if ( page_xp == XPTR_NULL )
1276            {
1277                printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1278                return -1;
1279            }
1280       
1281            // get pointer on page base
1282            base_xp = ppm_page2base( page_xp );
1283            base = GET_PTR( base_xp );
1284           
1285            // update offset
1286            offset = 0;
1287        }
1288
1289        // compute directory entry address
1290        entry = base + offset;
1291
1292#if (DEBUG_FATFS_ADD_DENTRY & 1)
1293if( DEBUG_FATFS_ADD_DENTRY < cycle )
1294printk("\n[%s] FSM step = %d / offset = %x / nb_lfn = %d\n",
1295__FUNCTION__, step, offset, nb_lfn );
1296#endif
1297
1298        // write 32 bytes (one directory entry) per iteration
1299        switch ( step )
1300        {
1301            case 5:   // write LFN3 entry
1302            {
1303                c = 26;
1304                // scan the 32 bytes in dir_entry
1305                for ( i = 0 ; i < 32 ; i++ )
1306                {
1307                    if (i == 0)
1308                    {
1309                        if ( nb_lfn == 3) entry[i] = 0x43;
1310                        else              entry[i] = 0x03;
1311                    }
1312                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1313                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1314                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1315                              ( c < length ) )
1316                    {
1317                                          entry[i] = name[c];
1318                                          c++;
1319                    }
1320                    else if (i == 11)     entry[i] = 0x0F;
1321                    else if (i == 13)     entry[i] = checksum;
1322                    else                  entry[i] = 0x00;
1323                }
1324                step--;
1325                break;
1326            }
1327            case 4:   // write LFN2 entry 
1328            {
1329                c = 13;
1330                // scan the 32 bytes in dir_entry
1331                for ( i = 0 ; i < 32 ; i++ )
1332                {
1333                    if (i == 0)
1334                    {
1335                        if ( nb_lfn == 2) entry[i] = 0x42;
1336                        else              entry[i] = 0x02;
1337                    }
1338                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1339                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1340                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1341                              ( c < length ) )
1342                    {
1343                                          entry[i] = name[c];
1344                                          c++;
1345                    }
1346                    else if (i == 11)     entry[i] = 0x0F;
1347                    else if (i == 13)     entry[i] = checksum;
1348                    else                  entry[i] = 0x00;
1349                }
1350                step--;
1351                break;
1352            }
1353            case 3:   // Write LFN1 entry   
1354            {
1355                c = 0;
1356                // scan the 32 bytes in dir_entry
1357                for ( i = 0 ; i < 32 ; i++ )
1358                {
1359                    if (i == 0)
1360                    {
1361                        if ( nb_lfn == 1) entry[i] = 0x41;
1362                        else              entry[i] = 0x01;
1363                    }
1364                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1365                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1366                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1367                              ( c < length ) )
1368                    {
1369                                          entry[i] = name[c];
1370                                          c++;
1371                    }
1372                    else if (i == 11)     entry[i] = 0x0F;
1373                    else if (i == 13)     entry[i] = checksum;
1374                    else                  entry[i] = 0x00;
1375                }
1376                step--;
1377                break;
1378            }
1379            case 2:   // write NORMAL entry     
1380            {
1381                // scan the 32 bytes in dir_entry
1382                for ( i = 0 ; i < 32 ; i++ )
1383                {
1384                    if      ( i < 11 )                              // 8.3 SFN
1385                    {
1386                                          entry[i] = sfn[i];
1387                    }
1388                    else if (i == 11)                               // ATTR
1389                    {
1390                        if (type == INODE_TYPE_DIR)  entry[i] = 0x10;
1391                        else                         entry[i] = 0x20;
1392                    }
1393                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1394                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1395                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1396                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1397                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1398                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1399                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1400                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1401                    else                  entry[i] = 0x00;
1402                }
1403
1404                // update the "extend" field in dentry descriptor
1405                dentry->extend = (void*)(intptr_t)(((page_id<<12) + offset)>>5);
1406
1407                step--;
1408                break;
1409            }
1410            case 1:   // write NOMORE entry 
1411            {
1412                entry [0] = 0x00;
1413                step--;
1414                break;
1415            }
1416        } // end switch step
1417
1418        offset += 32;
1419
1420    } // exit while     
1421
1422    // copy the modified page to the IOC device
1423    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1424
1425#if DEBUG_FATFS_ADD_DENTRY
1426cycle = (uint32_t)hal_get_cycles();
1427if( DEBUG_FATFS_ADD_DENTRY < cycle )
1428printk("\n[%s]  thread[%x,%x] exit / parent <%s> / child <%s> / cycle %d\n",
1429__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1430#endif
1431
1432    return 0;
1433
1434}  // end fatfs_add_dentry()
1435
1436//////////////////////////////////////////////////
1437error_t fatfs_remove_dentry( vfs_inode_t  * inode,
1438                             vfs_dentry_t * dentry )
1439{
1440    xptr_t     mapper_xp;  // extended pointer on mapper
1441    mapper_t * mapper;     // local pointer on mapper
1442    xptr_t     page_xp;    // extended pointer on mapper page descriptor
1443    xptr_t     base_xp;    // extended pointer on mapper page base
1444    uint8_t  * base;       // local pointer on mapper page base
1445
1446#if DEBUG_FATFS_REMOVE_DENTRY
1447char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1448uint32_t   cycle = (uint32_t)hal_get_cycles();
1449thread_t * this  = CURRENT_THREAD;
1450vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1451if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1452printk("\n[%s] thread[%x,%x] enter / parent <%s> / child <%s> / cycle %d\n",
1453__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1454#endif
1455
1456// check arguments
1457assert( (inode != NULL) , "inode pointer is NULL\n" );
1458assert( (dentry != NULL) , "dentry pointer is NULL\n" );
1459assert( (inode->type == INODE_TYPE_DIR) , "inode is not a directory\n" );
1460assert( (inode->mapper != NULL ) , "mapper pointer is NULL\n" );
1461
1462    // get pointers on directory mapper
1463    mapper    = inode->mapper;
1464    mapper_xp = XPTR( local_cxy , mapper );
1465
1466    // compute number of LFN entries
1467    uint32_t nb_lfn;
1468    uint32_t name_length = strlen( dentry->name );
1469
1470    if      ( name_length <= 13 ) nb_lfn  = 1;
1471    else if ( name_length <= 26 ) nb_lfn  = 2;
1472    else                          nb_lfn  = 3;
1473
1474    // we must invalidate (2, 3 or 4) 32 bytes entries:
1475    // the NORMAL entry (registered in dentry->extend) and all preceding LFN entries
1476    // At most two pages are modified:
1477    // - the page containing the NORMAL entry is always modified.
1478    // - the preceding page is modified when the name spread on two pages.
1479
1480    // get 32 bytes directory entry index from dentry->extend
1481    uint32_t  dentry_id  = (uint32_t)(intptr_t)dentry->extend; 
1482
1483    // get page index and offset in parent directory mapper
1484    uint32_t  page_id    = dentry_id >> 7;
1485    uint32_t  offset     = (dentry_id & 0x7F)<<5;
1486
1487#if DEBUG_FATFS_REMOVE_DENTRY & 1
1488if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1489printk("\n[%s] dentry_id %x / page_id %x / offset %x\n",
1490__FUNCTION__, dentry_id, page_id, offset );
1491#endif
1492
1493    // get extended pointer on page descriptor from parent directory mapper
1494    page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1495
1496    if ( page_xp == XPTR_NULL )
1497    {
1498        printk("\n[ERROR] in %s : cannot extend directory mapper\n", __FUNCTION__ );
1499        return -1;
1500    }
1501       
1502    // get pointers on page base
1503    base_xp = ppm_page2base( page_xp );
1504    base    = GET_PTR( base_xp );
1505
1506    // invalidate NORMAL entry in directory cache
1507    base[offset] = 0xE5;
1508
1509    // invalidate LFN entries
1510    while ( nb_lfn )
1511    {
1512        if (offset == 0)  // we must load page (page_id - 1)
1513        {
1514
1515// check page_id
1516assert( (page_id > 0), "page_id and offset cannot be both 0\n" );
1517
1518            // copy the modified page to the IOC device
1519            fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1520
1521            // get extended pointer on page descriptor from parent directory mapper
1522            page_xp  = mapper_remote_get_page( mapper_xp , page_id );
1523
1524            if ( page_xp == XPTR_NULL )
1525            {
1526                printk("\n[ERROR] in %s : cannot access directory mapper\n", __FUNCTION__ );
1527                return -1;
1528            }
1529       
1530            // get pointers on page base
1531            base_xp = ppm_page2base( page_xp );
1532            base    = GET_PTR( base_xp );
1533
1534            // update offset
1535            offset = 4096;
1536        }
1537
1538        offset = offset - 32;
1539
1540// check for LFN entry
1541assert( (fatfs_get_record( DIR_ATTR, base + offset ) == ATTR_LONG_NAME_MASK ),
1542"this directory entry must be a LFN\n");
1543
1544        // invalidate LFN entry
1545        base[offset] = 0xE5;
1546
1547        nb_lfn--;
1548    }     
1549
1550    // copy the modified page to the IOC device
1551    fatfs_move_page( page_xp , IOC_SYNC_WRITE );   
1552   
1553
1554#if DEBUG_FATFS_REMOVE_DENTRY
1555cycle = (uint32_t)hal_get_cycles();
1556if( DEBUG_FATFS_REMOVE_DENTRY < cycle )
1557printk("\n[%s] thread[%x,%x] exit / parent %s / child %s / cycle %d\n",
1558__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1559#endif
1560
1561    return 0;
1562
1563}  // end fatfs_remove_dentry
1564
1565
1566//////////////////////////////////////////////////////////////////////////////////////////////
1567// This static function scan the pages of a mapper containing a FAT32 directory, identified
1568// by the <mapper> argument, to find the directory entry identified by the <name> argument,
1569// and return a pointer on the directory entry, described as and array of 32 bytes, and the
1570// incex of this entry in the FAT32 mapper, seen as an array of 32 bytes entries.
1571// It is called by the fatfs_new_dentry() and fatfs_update_dentry() functions.
1572// It must be called by a thread running in the cluster containing the mapper.
1573//////////////////////////////////////////////////////////////////////////////////////////////
1574// @ mapper    : [in]  local pointer on directory mapper.
1575// @ name      : [in]  searched directory entry name.
1576// @ entry     : [out] buffer for the pointer on the 32 bytes directory entry (when found).
1577// @ index     : [out] buffer for the directory entry index in mapper.
1578// @ return 0 if found / return 1 if not found / return -1 if mapper access error.
1579//////////////////////////////////////////////////////////////////////////////////////////////
1580error_t fatfs_scan_directory( mapper_t *  mapper,
1581                              char     *  name,
1582                              uint8_t  ** entry,
1583                              uint32_t *  index )
1584{
1585    // Two embedded loops to scan the directory mapper:
1586    // - scan the parent directory mapper pages
1587    // - scan the directory entries in each 4 Kbytes page
1588
1589// check parent_inode and child_inode
1590assert( (mapper != NULL) , "mapper pointer is NULL\n" );
1591assert( (name   != NULL ), "child name is undefined\n" );
1592assert( (entry  != NULL ), "entry buffer undefined\n" );
1593
1594#if DEBUG_FATFS_SCAN_DIRECTORY
1595char       parent_name[CONFIG_VFS_MAX_NAME_LENGTH];
1596uint32_t   cycle = (uint32_t)hal_get_cycles();
1597thread_t * this  = CURRENT_THREAD;
1598vfs_inode_get_name( XPTR( local_cxy , mapper->inode ) , parent_name );
1599if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1600printk("\n[%s]  thread[%x,%x] enter to search child <%s> in parent <%s> / cycle %d\n",
1601__FUNCTION__, this->process->pid, this->trdid, name , parent_name , cycle );
1602#endif
1603
1604    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each directory entry
1605
1606    char       lfn1[16];         // buffer for one partial cname
1607    char       lfn2[16];         // buffer for one partial cname
1608    char       lfn3[16];         // buffer for one partial cname
1609    xptr_t     mapper_xp;        // extended pointer on mapper descriptor
1610    xptr_t     page_xp;          // extended pointer on page descriptor
1611    xptr_t     base_xp;          // extended pointer on page base
1612    uint8_t  * base;             // local pointer on page base
1613    uint8_t    attr;             // directory entry ATTR field
1614    uint8_t    ord;              // directory entry ORD field
1615    uint32_t   seq;              // sequence index
1616    uint32_t   lfn       = 0;    // LFN entries number
1617    int32_t    found     = 0;    // not yet = 0 / success = 1 / not found = 2 / error = -1
1618    uint32_t   page_id   = 0;    // page index in mapper
1619    uint32_t   offset    = 0;    // byte offset in page
1620
1621    mapper_xp = XPTR( local_cxy , mapper );
1622
1623    // scan the mapper pages
1624    while ( found == 0 )
1625    {
1626        // get one page
1627        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1628
1629        if( page_xp == XPTR_NULL)
1630        {
1631            found = -1;
1632        }
1633
1634        // get page base
1635        base_xp = ppm_page2base( page_xp );
1636        base    = (uint8_t *)GET_PTR( base_xp );
1637
1638#if (DEBUG_FATFS_SCAN_DIRECTORY & 0x1)
1639if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1640mapper_display_page( mapper_xp , page_id , 256 );
1641#endif
1642        // scan this page until end of directory, end of page, or name found
1643        while( (offset < 4096) && (found == 0) )
1644        {
1645            attr = fatfs_get_record( DIR_ATTR , base + offset );   
1646            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
1647
1648            if (ord == NO_MORE_ENTRY)                 // no more entry => break
1649            {
1650                found = 2;
1651            }
1652            else if ( ord == FREE_ENTRY )             // free entry => skip
1653            {
1654                offset = offset + 32;
1655            }
1656            else if ( attr == 0x28 )                  // volune_id => skip
1657            {
1658                offset = offset + 32;
1659            }
1660            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial cname
1661            {
1662                seq = ord & 0x3;
1663                lfn = (seq > lfn) ? seq : lfn;   
1664                if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
1665                else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
1666                else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
1667                offset = offset + 32;
1668            }
1669            else                                 // NORMAL entry
1670            {
1671                // build the extracted name
1672                if      ( lfn == 0 )
1673                {
1674                    fatfs_get_name_from_short( base + offset , cname );
1675                }
1676                else if ( lfn == 1 )
1677                {
1678                    strcpy( cname      , lfn1 );
1679                }   
1680                else if ( lfn == 2 ) 
1681                {
1682                    strcpy( cname      , lfn1 );
1683                    strcpy( cname + 13 , lfn2 );
1684                }
1685                else if ( lfn == 3 ) 
1686                {
1687                    strcpy( cname      , lfn1 );
1688                    strcpy( cname + 13 , lfn2 );
1689                    strcpy( cname + 26 , lfn3 );
1690                }
1691
1692                // get dentry arguments if extracted cname == searched name
1693                if ( strcmp( name , cname ) == 0 )
1694                {
1695                    *entry = base + offset;
1696                    *index = ((page_id<<12) + offset)>>5; 
1697                    found     = 1;
1698                }
1699                offset = offset + 32;
1700                lfn    = 0;
1701            }
1702        }  // end loop on directory entries in page
1703
1704        page_id++;
1705        offset = 0;
1706
1707    }  // end loop on pages
1708
1709    if( found == 1 )
1710    {
1711
1712#if DEBUG_FATFS_SCAN_DIRECTORY
1713cycle = (uint32_t)hal_get_cycles();
1714if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1715printk("\n[%s]  thread[%x,%x] exit / found child <%s> in <%s>\n",
1716__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
1717#endif
1718        return 0;
1719    }
1720    else if( found == 2 )
1721    {
1722
1723#if DEBUG_FATFS_SCAN_DIRECTORY
1724cycle = (uint32_t)hal_get_cycles();
1725if( DEBUG_FATFS_SCAN_DIRECTORY < cycle )
1726printk("\n[%s]  thread[%x,%x] exit / child <%s> in <%s> not found\n",
1727__FUNCTION__, this->process->pid, this->trdid, name, parent_name );
1728#endif
1729        return 1;
1730    }
1731    else
1732    {
1733        printk("\n[ERROR] in %s : cannot get page %d from mapper\n",
1734        __FUNCTION__, page_id );
1735
1736        return -1;
1737    }
1738}  // end fatfs_scan_directory()
1739
1740
1741
1742/////////////////////////////////////////////////////
1743error_t fatfs_new_dentry( vfs_inode_t * parent_inode,
1744                          char        * name,
1745                          xptr_t        child_inode_xp )
1746{
1747    uint8_t      * entry;            // pointer on FAT32 directory entry (array of 32 bytes)
1748    uint32_t       index;            // index of FAT32 directory entry in mapper
1749    mapper_t     * mapper;           // pointer on directory mapper
1750    uint32_t       cluster;          // directory entry cluster
1751    uint32_t       size;             // directory entry size
1752    bool_t         is_dir;           // directory entry type (file/dir)
1753    xptr_t         root_xp;          // extended pointer on root of parent dentries
1754    xptr_t         iter_xp;          // iterator for this list
1755    cxy_t          child_inode_cxy;  // child inode cluster 
1756    vfs_inode_t  * child_inode_ptr;  // child inode local pointer
1757    xptr_t         dentry_xp;        // extended pointer on searched dentry descriptor
1758    cxy_t          dentry_cxy;       // cluster identifier of dentry (must be local_cxy)
1759    vfs_dentry_t * dentry_ptr;       // local pointer
1760    error_t        error;
1761
1762    char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1763
1764// check arguments
1765assert( (parent_inode   != NULL)       , "parent_inode is NULL\n" );
1766assert( (name           != NULL)       , "name is NULL\n" );
1767assert( (child_inode_xp != XPTR_NULL ) , "child_inode is NULL\n" );
1768
1769    // get child inode cluster and local pointer
1770    child_inode_cxy = GET_CXY( child_inode_xp );
1771    child_inode_ptr = GET_PTR( child_inode_xp );
1772
1773    // build extended pointer on root of list of parent dentries
1774    root_xp = XPTR( child_inode_cxy , &child_inode_ptr->parents );
1775
1776// check child inode has at least one parent
1777assert( (xlist_is_empty( root_xp ) == false ), "child inode must have one parent\n");
1778
1779#if DEBUG_FATFS_GET_DENTRY
1780uint32_t   cycle = (uint32_t)hal_get_cycles();
1781thread_t * this  = CURRENT_THREAD;
1782vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name );
1783if( DEBUG_FATFS_GET_DENTRY < cycle )
1784printk("\n[%s]  thread[%x,%x] enter for child <%s> in parent <%s> / cycle %d\n",
1785__FUNCTION__, this->process->pid, this->trdid, name , dir_name , cycle );
1786#endif
1787
1788    // get local pointer on parent mapper
1789    mapper = parent_inode->mapper;
1790
1791    // get pointer and index in mapper for searched directory entry
1792    error  = fatfs_scan_directory( mapper, name , &entry , &index );
1793
1794    // return non fatal error if not found
1795    if( error ) return -1;
1796
1797    // get relevant infos from FAT32 directory entry
1798    cluster = (fatfs_get_record( DIR_FST_CLUS_HI , entry ) << 16) |
1799              (fatfs_get_record( DIR_FST_CLUS_LO , entry )      ) ;
1800    is_dir  = (fatfs_get_record( DIR_ATTR        , entry ) & ATTR_DIRECTORY);
1801    size    =  fatfs_get_record( DIR_FILE_SIZE   , entry );
1802
1803    // scan list of parent dentries to search the parent_inode
1804    bool_t found = false;
1805    XLIST_FOREACH( root_xp , iter_xp )
1806    {
1807        // get pointers on dentry
1808        dentry_xp  = XLIST_ELEMENT( iter_xp , vfs_dentry_t , parents );
1809        dentry_cxy = GET_CXY( dentry_xp );
1810        dentry_ptr = GET_PTR( dentry_xp );
1811
1812        // get local pointer on current parent directory inode
1813        vfs_inode_t * current = hal_remote_lpt( XPTR( dentry_cxy , &dentry_ptr->parent ) );
1814
1815        // check if current parent is the searched parent
1816        if( XPTR( dentry_cxy , current ) == XPTR( local_cxy , parent_inode ) )
1817        {
1818            found = true;
1819            break;
1820        }
1821    }
1822
1823    if( found == false )
1824    { 
1825        vfs_inode_get_name( XPTR( local_cxy , parent_inode ) , dir_name );
1826        printk("\n[ERROR] in %s : cannot find <%s> directory in list of parents for <%s>\n",
1827        __FUNCTION__, dir_name, name );
1828        return -1;
1829    }
1830
1831    // update the child inode "type", "size", and "extend" fields
1832    vfs_inode_type_t type = (is_dir) ? INODE_TYPE_DIR : INODE_TYPE_FILE;
1833
1834    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->type   ) , type );
1835    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->size   ) , size );
1836    hal_remote_s32( XPTR( child_inode_cxy , &child_inode_ptr->extend ) , cluster );
1837
1838    // update the dentry "extend" field
1839    dentry_ptr->extend = (void *)(intptr_t)index;
1840
1841#if DEBUG_FATFS_GET_DENTRY
1842cycle = (uint32_t)hal_get_cycles();
1843if( DEBUG_FATFS_GET_DENTRY < cycle )
1844printk("\n[%s]  thread[%x,%x] exit / intialised inode & dentry for <%s> in <%s> / cycle %d\n",
1845__FUNCTION__, this->process->pid, this->trdid, name, dir_name, cycle );
1846#endif
1847
1848    return 0;
1849
1850}  // end fatfs_new_dentry()
1851
1852//////////////////////////////////////////////////
1853error_t fatfs_update_dentry( vfs_inode_t  * inode,
1854                             vfs_dentry_t * dentry,
1855                             uint32_t       size )
1856{
1857    uint8_t  * entry;    // pointer on FAT32 directory entry (array of 32 bytes)
1858    uint32_t   index;    // index of FAT32 directory entry in mapper
1859    mapper_t * mapper;   // pointer on directory mapper
1860    error_t    error;
1861
1862    char       dir_name[CONFIG_VFS_MAX_NAME_LENGTH];
1863
1864// check arguments
1865assert( (inode  != NULL) , "inode is NULL\n" );
1866assert( (dentry != NULL) , "dentry is NULL\n" );
1867assert( (size   != 0   ) , "size is 0\n" );
1868
1869#if DEBUG_FATFS_UPDATE_DENTRY
1870uint32_t   cycle = (uint32_t)hal_get_cycles();
1871thread_t * this  = CURRENT_THREAD;
1872vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1873if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
1874printk("\n[%s]  thread[%x,%x] enter for <%s/%s> / size %d / cycle %d\n",
1875__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, size, cycle );
1876#endif
1877
1878    // get local pointer on mapper
1879    mapper = inode->mapper;
1880
1881    // get pointer and index in mapper for searched directory entry
1882    error  = fatfs_scan_directory( mapper, dentry->name , &entry , &index );
1883
1884    if( error )
1885    { 
1886        vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1887        printk("\n[ERROR] in %s : cannot find <%s> in parent mapper <%s>\n",
1888        __FUNCTION__, dentry->name, dir_name );
1889        return -1;
1890    }
1891
1892    // set size in FAT32 directory entry
1893    fatfs_set_record( DIR_FILE_SIZE , entry , size );
1894
1895    // get local pointer on modified page base
1896    void * base = (void *)((intptr_t)entry & (~CONFIG_PPM_PAGE_MASK)); 
1897
1898    // get extended pointer on modified page descriptor
1899    xptr_t page_xp = ppm_base2page( XPTR( local_cxy , base ) );
1900
1901    // synchronously update the modified page on device
1902    error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
1903
1904    if( error )
1905    { 
1906        vfs_inode_get_name( XPTR( local_cxy , inode ) , dir_name );
1907        printk("\n[ERROR] in %s : cannot update parent directory <%s> on device\n",
1908        __FUNCTION__, dir_name );
1909        return -1;
1910    }
1911
1912#if DEBUG_FATFS_UPDATE_DENTRY
1913cycle = (uint32_t)hal_get_cycles();
1914if( DEBUG_FATFS_UPDATE_DENTRY < cycle )
1915printk("\n[%s]  thread[%x,%x] exit / updated size for <%s/%s> / cycle %d\n",
1916__FUNCTION__, this->process->pid, this->trdid, dir_name, dentry->name, cycle );
1917#endif
1918
1919    return 0;
1920
1921}  // end fatfs_update_dentry()
1922
1923///////////////////////////////////////////////////////
1924error_t fatfs_get_user_dir( struct vfs_inode_s * inode,
1925                            struct dirent      * array, 
1926                            uint32_t             max_dirent,
1927                            uint32_t             min_dentry,
1928                            bool_t               detailed,
1929                            uint32_t           * entries,
1930                            bool_t             * done )
1931{
1932    // Two embedded loops to scan the directory mapper:
1933    // - scan the parent directory mapper pages starting always from page 0
1934    // - scan the 32 bytes NORMAL/LFN directory entries in each page
1935    // Only valid dentries are copied : dentry_id >= min_dentry && dirent_id < dirent_max
1936
1937#if DEBUG_FATFS_GET_USER_DIR
1938char       inode_name[CONFIG_VFS_MAX_NAME_LENGTH];
1939uint32_t   cycle = (uint32_t)hal_get_cycles();
1940thread_t * this  = CURRENT_THREAD;
1941vfs_inode_get_name( XPTR( local_cxy , inode ) , inode_name );
1942if( DEBUG_FATFS_GET_USER_DIR < cycle )
1943printk("\n[%s]  thread[%x,%x] enter for inode <%s> / cycle %d\n",
1944__FUNCTION__, this->process->pid, this->trdid, inode_name , cycle );
1945#endif
1946
1947    mapper_t * mapper    = inode->mapper;
1948    xptr_t     mapper_xp = XPTR( local_cxy , mapper );
1949
1950// check mapper pointer
1951assert( (mapper != NULL) , "mapper is NULL\n");
1952   
1953// TODO handle the detailed flag
1954assert( (detailed == false), "detailed argument not supported/n");
1955
1956    char       cname[CONFIG_VFS_MAX_NAME_LENGTH];  // name extracted from each dentry
1957
1958    char       lfn1[16];           // buffer for one partial cname
1959    char       lfn2[16];           // buffer for one partial cname
1960    char       lfn3[16];           // buffer for one partial cname
1961    xptr_t     page_xp;            // extended pointer on page descriptor
1962    xptr_t     base_xp;            // extended pointer on page base
1963    uint8_t  * base;               // local pointer on page base
1964    uint8_t    attr;               // directory entry ATTR field
1965    uint8_t    ord;                // directory entry ORD field
1966    uint32_t   seq;                // sequence index
1967    uint32_t   lfn       = 0;      // LFN entries number
1968    uint32_t   offset    = 0;      // byte offset in page
1969    uint32_t   page_id   = 0;      // page index in mapper
1970    uint32_t   dentry_id = 0;      // valid (i.e. copied) dentry index in mapper
1971    uint32_t   dirent_id = 0;      // slot index in dirent array to initialize
1972    bool_t     end       = false;  // true if end of directory found
1973
1974    // loop on mapper pages
1975    while ( (end == false) && (dirent_id < max_dirent) )
1976    {
1977        // get one page from mapper
1978        page_xp = mapper_remote_get_page( mapper_xp , page_id );
1979
1980        if( page_xp == XPTR_NULL) return -1;
1981
1982        // get page base
1983        base_xp = ppm_page2base( page_xp );
1984        base    = (uint8_t *)GET_PTR( base_xp );
1985
1986#if (DEBUG_FATFS_GET_USER_DIR & 0x1)
1987if( DEBUG_FATFS_GET_USER_DIR < cycle )
1988mapper_display_page( mapper_xp , page_id , 256 );
1989#endif
1990        // loop on NORMAL/LFN (32 bytes) directory entries in this page
1991        while( (end == false) && (offset < 4096) )
1992        {
1993            // compute condition to copy one dentry to dirent array
1994            bool_t valid = (dentry_id >= min_dentry) && (dirent_id <  max_dirent );
1995
1996            attr = fatfs_get_record( DIR_ATTR , base + offset );   
1997            ord  = fatfs_get_record( LDIR_ORD , base + offset );   
1998
1999            if (ord == NO_MORE_ENTRY)                 // no more entry => break
2000            {
2001                end = true;
2002            }
2003            else if ( ord == FREE_ENTRY )             // free entry => skip
2004            {
2005                offset = offset + 32;
2006            }
2007            else if ( attr == 0x28 )                  // volune_id => skip
2008            {
2009                offset = offset + 32;
2010            }
2011            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry
2012            {
2013                if( valid )
2014                {
2015                    // get partial cname
2016                    seq = ord & 0x3;
2017                    lfn = (seq > lfn) ? seq : lfn;   
2018                    if      ( seq == 1 ) fatfs_get_name_from_long( base + offset, lfn1 );
2019                    else if ( seq == 2 ) fatfs_get_name_from_long( base + offset, lfn2 );
2020                    else if ( seq == 3 ) fatfs_get_name_from_long( base + offset, lfn3 );
2021                }
2022                offset = offset + 32;
2023            }
2024            else                                     // NORMAL entry
2025            {
2026                // increment dentry_id
2027                dentry_id++;
2028
2029                if( valid )
2030                {
2031                    // build the complete cname
2032                    if      ( lfn == 0 )
2033                    {
2034                        fatfs_get_name_from_short( base + offset , cname );
2035                    }
2036                    else if ( lfn == 1 )
2037                    {
2038                        strcpy( cname      , lfn1 );
2039                    }   
2040                    else if ( lfn == 2 ) 
2041                    {
2042                        strcpy( cname      , lfn1 );
2043                        strcpy( cname + 13 , lfn2 );
2044                    }
2045                    else if ( lfn == 3 ) 
2046                    {
2047                        strcpy( cname      , lfn1 );
2048                        strcpy( cname + 13 , lfn2 );
2049                        strcpy( cname + 26 , lfn3 );
2050                    }
2051                   
2052                    // copy cname into dirent array
2053                    strcpy( array[dirent_id].d_name , cname ); 
2054
2055                    // increment dirent_id
2056                    dirent_id++;
2057                }
2058                offset = offset + 32;
2059                lfn    = 0;
2060            }
2061        }  // end loop on directory entries in page
2062
2063        page_id++;
2064        offset = 0;
2065
2066    }  // end loop on pages
2067
2068    // return result of scan
2069    *done    = end;
2070    *entries = dirent_id;
2071
2072#if DEBUG_FATFS_GET_USER_DIR
2073cycle = (uint32_t)hal_get_cycles();
2074if( DEBUG_FATFS_GET_USER_DIR < cycle )
2075printk("\n[%s]  thread[%x,%x] exit for inode <%s> / %d entries / cycle %d\n",
2076__FUNCTION__, this->process->pid, this->trdid, inode_name, dirent_id, cycle );
2077#endif
2078
2079    return 0;
2080
2081}  // end fatfs_get_user_dir()
2082
2083///////////////////////////////////////////////
2084error_t fatfs_sync_inode( vfs_inode_t * inode )
2085{
2086
2087// check inode pointer and cluster index
2088assert( (inode != NULL)                  , "inode pointer undefined\n" );
2089assert( (inode->mapper != NULL )         , "mapper pointer undefined\n" );
2090assert( (inode->type == INODE_TYPE_FILE) , "inode must be a file\n" );     
2091
2092#if DEBUG_FATFS_SYNC_INODE
2093char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2094uint32_t   cycle = (uint32_t)hal_get_cycles();
2095thread_t * this  = CURRENT_THREAD;
2096vfs_inode_get_name( XPTR( local_cxy , inode ) , name );
2097if( DEBUG_FATFS_SYNC_INODE < cycle )
2098printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
2099__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2100#endif
2101
2102    error_t    error;
2103    mapper_t * mapper;
2104    page_t   * page;
2105    uint32_t   page_id;
2106
2107    // get mapper from inode
2108    mapper = inode->mapper;
2109
2110    // compute max number of pages in mapper from file size
2111    uint32_t size  = inode->size;
2112    uint32_t pages = size >> CONFIG_PPM_PAGE_SHIFT;
2113    if( size & CONFIG_PPM_PAGE_MASK ) pages++; 
2114         
2115    // get pointer on mapper radix tree
2116    grdxt_t * rt = &mapper->rt;
2117
2118    // scan all pages
2119    for( page_id = 0 ; page_id < pages ; page_id++ )
2120    {
2121        // get page descriptor from mapper
2122        page = grdxt_lookup( rt , page_id );
2123
2124        // check all existing pages
2125        if ( page != NULL )
2126        {
2127            if ( page->flags & PG_DIRTY )
2128            {
2129
2130#if (DEBUG_FATFS_SYNC_INODE & 1)
2131if( DEBUG_FATFS_SYNC_INODE < cycle )
2132printk("\n[%s] thread[%x,%x] synchronizes page %d from <%s> mapper to IOC device\n",
2133__FUNCTION__, page_id, name );
2134#endif
2135                // build extended pointer on page descriptor
2136                xptr_t page_xp = XPTR( local_cxy , page );
2137
2138                // move page from mapper to device
2139                error = fatfs_move_page( page_xp , IOC_WRITE );
2140
2141                if ( error )  return -1;
2142
2143                // reset page dirty flag
2144                ppm_page_undo_dirty( page_xp );
2145            }
2146        }
2147    }  // end loop on pages
2148
2149#if DEBUG_FATFS_SYNC_INODE
2150cycle = (uint32_t)hal_get_cycles();
2151if( DEBUG_FATFS_SYNC_INODE < cycle )
2152printk("\n[%s] thread[%x,%x] exit for <%s> / cycle %d\n",
2153__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2154#endif
2155
2156    return 0;
2157
2158}  // end fatfs_sync_inode()
2159
2160//////////////////////////////
2161error_t fatfs_sync_fat( void )
2162{
2163
2164#if DEBUG_FATFS_SYNC_FAT
2165uint32_t   cycle = (uint32_t)hal_get_cycles();
2166thread_t * this  = CURRENT_THREAD;
2167if( DEBUG_FATFS_SYNC_FAT < cycle )
2168printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2169__FUNCTION__ , this->process->pid, this->trdid, cycle );
2170#endif
2171
2172    uint32_t   page_id;
2173    error_t    error;
2174
2175    // get FAT mapper pointers an cluster
2176    fatfs_ctx_t * fatfs_ctx  = fs_context[FS_TYPE_FATFS].extend;
2177    xptr_t        mapper_xp  = fatfs_ctx->fat_mapper_xp;
2178    cxy_t         mapper_cxy = GET_CXY( mapper_xp );
2179    mapper_t    * mapper_ptr = GET_PTR( mapper_xp );
2180
2181    // compute max number of 4 Kbytes pages in FAT mapper
2182    // TODO : this could be improved (see fatfs.h) [AG]
2183    uint32_t   pages = fatfs_ctx->fat_sectors_count >> 3;
2184         
2185    // get pointers on remote FAT mapper radix tree
2186    grdxt_t  * rt_ptr = &mapper_ptr->rt;
2187    xptr_t     rt_xp  = XPTR( mapper_cxy , rt_ptr );
2188
2189    // scan all pages
2190    for( page_id = 0 ; page_id < pages ; page_id++ )
2191    {
2192        // get extended pointer on page descriptor from FAT mapper
2193        xptr_t page_xp = grdxt_remote_lookup( rt_xp , page_id );
2194
2195        // check all existing pages
2196        if ( page_xp != XPTR_NULL )
2197        {
2198            page_t * page_ptr = GET_PTR( page_xp );
2199            uint32_t flags    = hal_remote_l32( XPTR( mapper_cxy , &page_ptr->flags ) );
2200
2201            if ( flags & PG_DIRTY )
2202            {
2203
2204#if (DEBUG_FATFS_SYNC_FAT & 1)
2205if( DEBUG_FATFS_SYNC_FAT < cycle )
2206printk("\n[%s] thread[%x,%x] synchronizes page %d from FAT mapper to IOC device\n",
2207__FUNCTION__, page_id );
2208#endif
2209                // move page from mapper to device
2210                error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
2211
2212                if ( error )  return -1;
2213
2214                // reset page dirty flag
2215                ppm_page_undo_dirty( page_xp );
2216            }
2217        }
2218    }  // end loop on pages
2219
2220#if DEBUG_FATFS_SYNC_FAT
2221cycle = (uint32_t)hal_get_cycles();
2222if( DEBUG_FATFS_SYNC_FAT < cycle )
2223printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2224__FUNCTION__ , this->process->pid, this->trdid, cycle );
2225#endif
2226
2227    return 0;
2228
2229}  // end fatfs_sync_fat()
2230
2231////////////////////////////////////
2232error_t fatfs_sync_free_info( void )
2233{
2234    error_t       error;
2235    fatfs_ctx_t * fatfs_ctx_ptr;              // local pointer on fatfs context in cluster 0
2236    uint32_t      ctx_free_clusters;          // number of free clusters from fatfs context
2237    uint32_t      ctx_free_cluster_hint;      // free cluster hint from fatfs context
2238    uint32_t      ioc_free_clusters;          // number of free clusters from fatfs context
2239    uint32_t      ioc_free_cluster_hint;      // free cluster hint from fatfs context
2240    uint32_t      fs_info_lba;                // lba of FS_INFO sector on IOC device
2241    uint8_t     * fs_info_buffer;             // local pointer on FS_INFO buffer in cluster 0
2242    xptr_t        fs_info_buffer_xp;          // extended pointer on FS_INFO buffer in cluster 0
2243    uint8_t       tmp_buf[512];               // 512 bytes temporary buffer
2244    xptr_t        tmp_buf_xp;                 // extended pointer on temporary buffer
2245
2246#if DEBUG_FATFS_SYNC_FSINFO
2247uint32_t   cycle = (uint32_t)hal_get_cycles();
2248thread_t * this  = CURRENT_THREAD;
2249if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2250printk("\n[%s] thread[%x,%x] enter / cycle %d\n",
2251__FUNCTION__ , this->process->pid, this->trdid, cycle );
2252#endif
2253
2254    // get pointer on fatfs context in cluster 0
2255    fatfs_ctx_ptr = hal_remote_lpt( XPTR( 0 , &fs_context[FS_TYPE_FATFS].extend ) );
2256
2257    // get "free_clusters" and "free_cluster_hint" from fatfs context in cluster 0
2258    ctx_free_clusters     = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_clusters ) );
2259    ctx_free_cluster_hint = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->free_cluster_hint ) );
2260
2261    // get fs_info_lba
2262    fs_info_lba = hal_remote_l32( XPTR( 0 , &fatfs_ctx_ptr->fs_info_lba ) );
2263
2264    // build extended pointer on temporary buffer
2265    tmp_buf_xp = XPTR( local_cxy , tmp_buf );
2266
2267    // copy FS_INFO sector from IOC to local buffer
2268    error = dev_ioc_sync_read( tmp_buf_xp , fs_info_lba , 1 );
2269
2270    if ( error )
2271    {
2272        printk("\n[ERROR] in %s : cannot access FS_INFO on IOC device\n", __FUNCTION__ );
2273        return -1;
2274    }
2275
2276    // get current values of "free_clusters" and "free_cluster_hint" from FS_INFO on IOC
2277    ioc_free_clusters     = fatfs_get_remote_record( FS_FREE_CLUSTERS     , tmp_buf_xp );
2278    ioc_free_cluster_hint = fatfs_get_remote_record( FS_FREE_CLUSTER_HINT , tmp_buf_xp );
2279
2280    // check values
2281    if( (ioc_free_clusters     != ctx_free_clusters) || 
2282        (ioc_free_cluster_hint != ctx_free_cluster_hint) )
2283    {
2284        printk("\n[WARNING] in %s : unconsistent free clusters info\n"
2285        " ioc_free %x / ctx_free %x / ioc_hint %x / ctx_hint %x\n",
2286        __FUNCTION__, ioc_free_clusters, ctx_free_clusters,
2287        ioc_free_cluster_hint, ctx_free_cluster_hint );
2288
2289        // get pointers on FS_INFO buffer in cluster 0
2290        fs_info_buffer    = hal_remote_lpt( XPTR( 0 , &fatfs_ctx_ptr->fs_info_buffer ) );
2291        fs_info_buffer_xp = XPTR( 0 , fs_info_buffer );
2292
2293        // update FS_INFO buffer in cluster 0
2294        fatfs_set_remote_record(FS_FREE_CLUSTERS    ,fs_info_buffer_xp,ctx_free_clusters );
2295        fatfs_set_remote_record(FS_FREE_CLUSTER_HINT,fs_info_buffer_xp,ctx_free_cluster_hint);
2296
2297        // update the FS_INFO sector on IOC device
2298        error = dev_ioc_sync_write( fs_info_buffer_xp , fs_info_lba , 1 );
2299
2300        if ( error )
2301        {
2302            printk("\n[ERROR] in %s : cannot update FS_INFO on IOC device\n", __FUNCTION__ );
2303            return -1;
2304        }
2305    }
2306
2307#if DEBUG_FATFS_SYNC_FSINFO
2308cycle = (uint32_t)hal_get_cycles();
2309if( DEBUG_FATFS_SYNC_FSINFO < cycle )
2310printk("\n[%s] thread[%x,%x] exit / cycle %d\n",
2311__FUNCTION__ , this->process->pid, this->trdid, cycle );
2312#endif
2313
2314    return 0;
2315
2316}  // end fatfs_sync_free_info()
2317
2318//////////////////////////////////////////////////////////
2319error_t fatfs_cluster_alloc( uint32_t * searched_cluster )
2320{
2321    error_t       error;
2322    uint32_t      page_id;        // page index in FAT mapper
2323    uint32_t      slot_id;        // slot index in page (1024 slots per page)
2324    uint32_t      cluster;        // first free cluster index in FAT
2325    uint32_t      free_clusters;  // total number of free clusters
2326    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters)
2327    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2328    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
2329    xptr_t        mapper_xp;      // extended pointer on FAT mapper
2330    cxy_t         fat_cxy;        // Fat mapper cluster identifier
2331    xptr_t        page_xp;        // extended pointer on current page descriptor in mapper
2332    xptr_t        slot_xp;        // extended pointer on FAT slot defined by hint
2333    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info
2334    xptr_t        hint_xp;        // extended pointer on free_cluster_hint in FAT cluster
2335    xptr_t        free_xp;        // extended pointer on free_clusters_number in FAT cluster
2336
2337#if DEBUG_FATFS_CLUSTER_ALLOC
2338uint32_t   cycle = (uint32_t)hal_get_cycles();
2339thread_t * this  = CURRENT_THREAD;
2340if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2341printk("\n[%s] thread[%x,%x] enter / cycle = %d\n",
2342__FUNCTION__, this->process->pid, this->trdid, cycle );
2343#endif
2344
2345    // get local pointer on VFS context (same in all clusters)
2346    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2347
2348    // get local pointer on local FATFS context
2349    loc_fatfs_ctx = vfs_ctx->extend;
2350
2351    // get extended pointer on FAT mapper
2352    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2353
2354    // get FAT cluster
2355    fat_cxy = GET_CXY( mapper_xp );
2356   
2357    // get local pointer on FATFS context in FAT cluster
2358    fat_fatfs_ctx = hal_remote_lpt( XPTR( fat_cxy , &vfs_ctx->extend ) );
2359
2360    // build relevant extended pointers on free clusters info in mapper cluster
2361    lock_xp = XPTR( fat_cxy , &fat_fatfs_ctx->lock );
2362    hint_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_cluster_hint );
2363    free_xp = XPTR( fat_cxy , &fat_fatfs_ctx->free_clusters );
2364
2365    // take the FAT lock in write mode
2366    remote_rwlock_wr_acquire( lock_xp );
2367
2368    // get hint and free_clusters values from FATFS context in FAT cluster
2369    cluster       = hal_remote_l32( hint_xp ) + 1;
2370    free_clusters = hal_remote_l32( free_xp );
2371       
2372#if (DEBUG_FATFS_CLUSTER_ALLOC & 1)
2373if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2374printk("\n[%s] thread[%x,%x] get free info : hint %x / free_clusters %x\n",
2375__FUNCTION__, this->process->pid, this->trdid, (cluster - 1), free_clusters );
2376#endif
2377
2378    // check "free_clusters"
2379    if ( free_clusters == 0 )
2380    {
2381        printk("\n[ERROR] in %s : no more free FATFS clusters\n", __FUNCTION__ );
2382        remote_rwlock_wr_release( lock_xp );
2383        return -1;
2384    }
2385    else if ( free_clusters < CONFIG_VFS_FREE_CLUSTERS_MIN )
2386    {
2387        printk("\n[WARNING] in %s : only %n free FATFS clusters\n", 
2388        __FUNCTION__, CONFIG_VFS_FREE_CLUSTERS_MIN );
2389    }
2390
2391    // get page index & slot index for selected cluster
2392    page_id  = cluster >> 10;
2393    slot_id  = cluster & 0x3FF;
2394
2395    // get relevant page descriptor from FAT mapper
2396    page_xp = mapper_remote_get_page( mapper_xp , page_id );
2397
2398    if( page_xp == XPTR_NULL )
2399    {
2400        printk("\n[ERROR] in %s : cannot acces FAT mapper\n", __FUNCTION__ );
2401        remote_rwlock_wr_release( lock_xp );
2402        return -1;
2403    }
2404
2405    // build extended pointer on selected cluster slot in FAT mapper
2406    slot_xp = ppm_page2base( page_xp ) + (slot_id << 2);
2407         
2408    // check selected cluster actually free
2409    if( hal_remote_l32( slot_xp ) != FREE_CLUSTER )
2410    { 
2411        printk("\n[ERROR] in %s : selected cluster %x not free\n", __FUNCTION__, cluster );
2412        remote_rwlock_wr_release( lock_xp );
2413        return -1;
2414    }
2415
2416    // update free cluster info in FATFS context and in FS_INFO sector
2417    error = fatfs_free_clusters_decrement( XPTR( fat_cxy , fat_fatfs_ctx ) , cluster );
2418
2419    if( error )
2420    { 
2421        printk("\n[ERROR] in %s : cannot update free cluster info\n", __FUNCTION__ );
2422        remote_rwlock_wr_release( lock_xp );
2423        return -1;
2424    }
2425
2426    // update FAT mapper
2427    hal_remote_s32( slot_xp , END_OF_CHAIN_CLUSTER_MAX );
2428
2429    // synchronously update FAT on device
2430    error = fatfs_move_page( page_xp , IOC_SYNC_WRITE );
2431
2432    if( error )
2433    { 
2434        printk("\n[ERROR] in %s : cannot update FAT on IOC device\n", __FUNCTION__ );
2435        remote_rwlock_wr_release( lock_xp );
2436        return -1;
2437    }
2438
2439    // release FAT lock
2440    remote_rwlock_wr_release( lock_xp );
2441
2442#if DEBUG_FATFS_CLUSTER_ALLOC
2443cycle = (uint32_t)hal_get_cycles();
2444if( DEBUG_FATFS_CLUSTER_ALLOC < cycle )
2445printk("\n[%s] thread[%x,%x] exit / allocated cluster %x in FAT / cycle %d\n",
2446__FUNCTION__, this->process->pid, this->trdid, cluster, cycle );
2447#endif
2448
2449    *searched_cluster = cluster;
2450    return 0;
2451
2452}  // end fat_cluster_alloc()
2453
2454//////////////////////////////////////////////
2455error_t fatfs_release_inode( xptr_t inode_xp )
2456{
2457    vfs_ctx_t   * vfs_ctx;        // local pointer on VFS context (same in all clusters).
2458    fatfs_ctx_t * loc_fatfs_ctx;  // local pointer on local FATFS context
2459    fatfs_ctx_t * fat_fatfs_ctx;  // local pointer on FATFS context in FAT cluster
2460    xptr_t        mapper_xp;      // extended pointer on FAT mapper
2461    cxy_t         mapper_cxy;     // Fat mapper cluster identifier
2462    mapper_t    * mapper_ptr;     // local pointer on FAT mapper
2463    xptr_t        lock_xp;        // extended pointer on lock protecting free clusters info.
2464    xptr_t        first_xp;       // extended pointer on inode extension
2465    uint32_t      first_cluster;  // first cluster index for released inode
2466    vfs_inode_t * inode_ptr;      // local pointer on target inode
2467    cxy_t         inode_cxy;      // target inode cluster identifier
2468
2469// check inode pointer
2470assert( (inode_xp != XPTR_NULL) , "inode pointer is NULL\n" );
2471
2472    // get inode cluster and local pointer
2473    inode_ptr     = GET_PTR( inode_xp );
2474    inode_cxy     = GET_CXY( inode_xp );
2475
2476    // get first_cluster from inode extension
2477    first_xp      = XPTR( inode_cxy , &inode_ptr->extend );
2478    first_cluster = (uint32_t)(intptr_t)hal_remote_lpt( first_xp );
2479
2480// check first cluster index
2481assert( (first_cluster != 0) , "inode extend is NULL\n" );
2482
2483#if DEBUG_FATFS_RELEASE_INODE
2484char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2485uint32_t   cycle = (uint32_t)hal_get_cycles();
2486thread_t * this  = CURRENT_THREAD;
2487vfs_inode_get_name( inode_xp , name );
2488if( DEBUG_FATFS_RELEASE_INODE < cycle )
2489printk("\n[%s] thread[%x,%x] enter for <%s> / first_cluster %x / cycle %d\n",
2490__FUNCTION__ , this->process->pid, this->trdid, name, first_cluster, cycle );
2491#endif
2492
2493#if (DEBUG_FATFS_RELEASE_INODE & 1)
2494fatfs_display_fat( 0 , 512 );
2495#endif
2496
2497    // get local pointer on VFS context (same in all clusters)
2498    vfs_ctx = &fs_context[FS_TYPE_FATFS];
2499
2500    // get local pointer on local FATFS context
2501    loc_fatfs_ctx = vfs_ctx->extend;
2502
2503    // get pointers and cluster on FAT mapper
2504    mapper_xp  = loc_fatfs_ctx->fat_mapper_xp;
2505    mapper_cxy = GET_CXY( mapper_xp );
2506    mapper_ptr = GET_PTR( mapper_xp );
2507   
2508    // get local pointer on FATFS context in FAT cluster
2509    fat_fatfs_ctx = hal_remote_lpt( XPTR( mapper_cxy , &vfs_ctx->extend ) );
2510
2511    // get extended pointer on FAT lock in FAT cluster
2512    lock_xp = XPTR( mapper_cxy , &fat_fatfs_ctx->lock );
2513
2514    // take FAT lock in write mode
2515    remote_rwlock_wr_acquire( lock_xp );
2516
2517    // call the recursive function to release all clusters from FAT mapper
2518    if ( fatfs_recursive_release( mapper_cxy,
2519                                  mapper_ptr,
2520                                  fat_fatfs_ctx,
2521                                  first_cluster ) )
2522    {
2523        printk("\n[ERROR] in %s : cannot update FAT mapper\n", __FUNCTION__ );
2524        remote_rwlock_wr_release( lock_xp );
2525        return -1;
2526    }
2527
2528#if (DEBUG_FATFS_RELEASE_INODE & 1)
2529if( DEBUG_FATFS_RELEASE_INODE < cycle )
2530printk("\n[%s] inode <%s> removed from FAT mapper\n", __FUNCTION__, name );
2531#endif
2532
2533    // update FAT on IOC device (from FAT mapper)
2534    if ( fatfs_sync_fat() )
2535    {
2536        printk("\n[ERROR] in %s : cannot update FAT on device\n", __FUNCTION__ );
2537        remote_rwlock_wr_release( lock_xp );
2538        return -1;
2539    }
2540
2541#if (DEBUG_FATFS_RELEASE_INODE & 1)
2542if( DEBUG_FATFS_RELEASE_INODE < cycle )
2543printk("\n[%s] inode <%s> removed from FAT on IOC device\n", __FUNCTION__, name );
2544#endif
2545
2546    // update FS-INFO sector on IOC device (from FATFS context)
2547    if ( fatfs_sync_free_info() )
2548    {
2549        printk("\n[ERROR] in %s: cannot update FS_INFO on device\n", __FUNCTION__ );
2550        remote_rwlock_wr_release( lock_xp );
2551        return -1;
2552    }
2553
2554    // release FAT lock
2555    remote_rwlock_wr_release( lock_xp );
2556
2557#if DEBUG_FATFS_RELEASE_INODE
2558cycle = (uint32_t)hal_get_cycles();
2559if( DEBUG_FATFS_RELEASE_INODE < cycle )
2560printk("\n[%s] thread[%x,%x] removed <%s> inode from FATFS / cycle %d\n",
2561__FUNCTION__ , this->process->pid, this->trdid, name, cycle );
2562#endif
2563
2564    return 0;
2565
2566}  // end fatfs_release_inode()
2567
2568////////////////////////////////////////////
2569error_t fatfs_move_page( xptr_t     page_xp,
2570                         cmd_type_t cmd_type )
2571{
2572    error_t       error;
2573    vfs_inode_t * inode_ptr;
2574    mapper_t    * mapper_ptr;     
2575    uint32_t      page_id;     // page index in mapper
2576
2577#if DEBUG_FATFS_MOVE_PAGE
2578uint32_t   cycle = (uint32_t)hal_get_cycles();
2579thread_t * this  = CURRENT_THREAD;
2580char       name[CONFIG_VFS_MAX_NAME_LENGTH];
2581#endif
2582
2583    // get page cluster an local pointer
2584    cxy_t    page_cxy = GET_CXY( page_xp );
2585    page_t * page_ptr = GET_PTR( page_xp );
2586
2587    // get mapper pointer and page index from page descriptor
2588    mapper_ptr = hal_remote_lpt( XPTR( page_cxy , &page_ptr->mapper ) );
2589    page_id    = hal_remote_l32( XPTR( page_cxy , &page_ptr->index ) );
2590
2591    // get pointer on local FATFS context
2592    fatfs_ctx_t * fatfs_ctx = fs_context[FS_TYPE_FATFS].extend;
2593
2594    // get page base address
2595    xptr_t    buffer_xp  = ppm_page2base( page_xp );
2596    uint8_t * buffer_ptr = (uint8_t *)GET_PTR( buffer_xp );
2597 
2598    // get inode pointer from mapper
2599    inode_ptr  = hal_remote_lpt( XPTR( page_cxy , &mapper_ptr->inode ) );
2600
2601#if DEBUG_FATFS_MOVE_PAGE
2602if( DEBUG_FATFS_MOVE_PAGE < cycle )
2603printk("\n[%s] thread[%x,%x] enters : %s / cxy %x / mapper %x / inode %x / page %x\n",
2604__FUNCTION__, this->process->pid, this->trdid,
2605dev_ioc_cmd_str( cmd_type ), page_cxy, mapper_ptr, inode_ptr, buffer_ptr );
2606#endif
2607
2608    //////////////////////////////  FAT mapper
2609    if( inode_ptr == NULL )
2610    {
2611        // get lba from FATFS context and page_id
2612        uint32_t      lba = fatfs_ctx->fat_begin_lba + (page_id << 3);
2613 
2614        // access device
2615        if     (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp  , lba , 8 );
2616        else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp  , lba , 8 );
2617        else if(cmd_type == IOC_READ      ) error = dev_ioc_read      ( buffer_ptr , lba , 8 );
2618        else if(cmd_type == IOC_WRITE     ) error = dev_ioc_write     ( buffer_ptr , lba , 8 );
2619        else                                error = -1;
2620
2621        if( error )
2622        {
2623            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2624            return -1;
2625        }
2626
2627#if DEBUG_FATFS_MOVE_PAGE
2628if( DEBUG_FATFS_MOVE_PAGE < cycle )
2629{
2630    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
2631        printk("\n[%s] thread[%x,%x] load FAT mapper page %d from IOC / cycle %d\n",
2632        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2633    else
2634        printk("\n[%s] thread[%x,%x] sync FAT mapper page %d to IOC / cycle %d\n",
2635        __FUNCTION__, this->process->pid, this->trdid, page_id, cycle );
2636}
2637#endif
2638
2639    }
2640    /////////////////////////  inode mapper
2641    else                       
2642    {
2643
2644#if DEBUG_FATFS_MOVE_PAGE
2645vfs_inode_get_name( XPTR( page_cxy , inode_ptr ) , name );
2646#endif
2647
2648        uint32_t  searched_cluster;
2649        uint32_t  first_cluster;
2650
2651        // get first_cluster from inode extension
2652        void * extend = hal_remote_lpt( XPTR( page_cxy , &inode_ptr->extend ) );
2653        first_cluster = (uint32_t)(intptr_t)extend;
2654
2655        // compute searched_cluster
2656        if( page_id == 0 )            // no need to access FAT mapper
2657        {
2658            // searched cluster is first cluster
2659            searched_cluster = first_cluster;
2660        }
2661        else                        // FAT mapper access required
2662        {
2663            // access FAT mapper to get searched cluster
2664            error = fatfs_get_cluster( first_cluster,
2665                                       page_id,
2666                                       &searched_cluster );
2667            if( error )
2668            {
2669                printk("\n[ERROR] in %s : cannot access FAT mapper\n", __FUNCTION__ );
2670                return -1;
2671            }
2672        }
2673
2674        // get lba for searched_cluster
2675        uint32_t lba = fatfs_lba_from_cluster( fatfs_ctx , searched_cluster );
2676
2677        // access device
2678        if     (cmd_type == IOC_SYNC_READ ) error = dev_ioc_sync_read ( buffer_xp  , lba , 8 );
2679        else if(cmd_type == IOC_SYNC_WRITE) error = dev_ioc_sync_write( buffer_xp  , lba , 8 );
2680        else if(cmd_type == IOC_READ      ) error = dev_ioc_read      ( buffer_ptr , lba , 8 );
2681        else if(cmd_type == IOC_WRITE     ) error = dev_ioc_write     ( buffer_ptr , lba , 8 );
2682        else                                error = -1;
2683
2684        if( error )
2685        {
2686            printk("\n[ERROR] in %s : cannot access device\n", __FUNCTION__ );
2687            return -1;
2688        }
2689
2690#if DEBUG_FATFS_MOVE_PAGE
2691if( DEBUG_FATFS_MOVE_PAGE < cycle )
2692{
2693    if ( (cmd_type == IOC_READ) || (cmd_type == IOC_SYNC_READ) )
2694    printk("\n[%s] thread[%x,%x] load page %d of <%s> / cluster_id %x / cycle %d\n",
2695    __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle );
2696    else
2697    printk("\n[%s] thread[%x,%x] sync page %d of <%s> / cluster_id %x / cycle %d\n",
2698    __FUNCTION__, this->process->pid, this->trdid, page_id, name, searched_cluster, cycle );
2699}
2700#endif
2701
2702    }
2703
2704    return 0;
2705
2706}  // end fatfs_move_page()
2707
2708
Note: See TracBrowser for help on using the repository browser.