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

Last change on this file since 623 was 623, checked in by alain, 6 years ago

Introduce three new types of vsegs (KCODE,KDATA,KDEV)
to map the kernel vsegs in the process VSL and GPT.
This now used by both the TSAR and the I86 architectures.

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