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

Last change on this file since 625 was 625, checked in by alain, 2 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

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