source: soft/giet_vm/giet_fat32/fat32.c @ 530

Last change on this file since 530 was 530, checked in by alain, 9 years ago

1) The FAT library supports now only two modes to access the block device:

  • synchronous: the calling task detect transfer completion by polling the block device status. This mode is used by the boot code.
  • descheduling: The calling task is descheduled, and transfer completion is signaled by an IRQ. This mode is used by the kernel code to handle user system calls.

2) The generic IOC driver has been integrate in the FAT library: the _fat_ioc_access() function

select the proper driver (BDV,HBA,SDC,RDK), with the requested access mode.

  • Property svn:executable set to *
File size: 65.4 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : fat32.c
3// Date     : 01/09/2013
4// Authors  : Marco Jankovic, Cesar Fuguet & Alain Greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////
7// The fat.h and fat_common.c files define a library of access functions
8// to a FAT32 disk on a block device. It is intended to be used
9// by the GIET_VM nano-kernel for both the boot code and the kernel code.
10//////////////////////////////////////////////////////////////////////////////////
11// Implementation notes:
12// 1. the "lba" (Logical Block Address) is the physical sector index on
13//    the block device. The physical sector size is supposed to be 512 bytes.
14// 2. the "cluster" variable is actually a cluster index. A cluster contains
15//    typically 8 sectors (4K bytes) and the cluster index is a 32 bits word.
16// 3. This FAT32 library uses a FAT cache whose storage capacity is one
17//    sector (512 bytes = 128 cluster indexes in FAT)
18//////////////////////////////////////////////////////////////////////////////////
19
20#include <giet_config.h>
21#include <hard_config.h>
22#include <fat32.h>
23#include <utils.h>
24#include <vmem.h>
25#include <bdv_driver.h>
26#include <hba_driver.h>
27#include <sdc_driver.h>
28#include <rdk_driver.h>
29#include <mmc_driver.h>
30#include <tty0.h>
31
32//////////////////////////////////////////////////////////////////////////////////
33//      Global variable : internal FAT representation
34//////////////////////////////////////////////////////////////////////////////////
35
36extern fat32_fs_t _fat;
37
38extern unsigned int _ptabs_vaddr[GIET_NB_VSPACE_MAX][X_SIZE][Y_SIZE];
39 
40//////////////////////////////////////////////////////////////////////////////
41// This function computes the memory buffer physical address, and calls
42// the proper IOC driver depending on the subtype (BDV / HBA / SDC /RDK).
43// The use_irq argument allows to activate the descheduling mode, if it
44// supported by the IOC driver subtype
45//////////////////////////////////////////////////////////////////////////////
46// Return 0 in case of success, return -1 in case of error
47//////////////////////////////////////////////////////////////////////////////
48static
49int _fat_ioc_access( unsigned int use_irq,
50                     unsigned int to_mem,
51                     unsigned int lba,
52                     unsigned int buf_vaddr,
53                     unsigned int count ) 
54{
55    // compute memory buffer physical address
56    unsigned int       flags;         // for _v2p_translate
57    unsigned long long buf_paddr;     // buffer physical address
58
59    if ( ((_get_mmu_mode() & 0x4) == 0 ) || USE_IOC_RDK )  // identity
60    {
61        buf_paddr = (unsigned long long)buf_vaddr;
62    }
63    else                                // V2P translation required
64    {
65        buf_paddr = _v2p_translate( buf_vaddr , &flags );
66    }
67
68#if (GIET_DEBUG_FAT > 1)
69unsigned int procid  = _get_procid();
70unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
71unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
72unsigned int p       = procid & ((1<<P_WIDTH)-1);
73_printf("\n[DEBUG FAT] P[%d,%d,%d] enters _fat_ioc_access() at cycle %d\n"
74        "  to_mem = %d / vaddr = %x / paddr = %l / sectors = %d / lba = %x\n",
75        x, y , p, _get_proctime(), to_mem, buf_vaddr, buf_paddr, count, lba );
76#endif
77
78    // cache coherence for both L1 & L2 caches
79    if ( to_mem ) // memory write 
80    {
81        // L1 cache (only if L1 cache coherence not guaranteed by hardware)
82        if ( GIET_NO_HARD_CC ) _dcache_buf_invalidate( buf_vaddr, count<<9 );
83
84        // L2 cache (only if we use an IO-Bridge component in architecture))
85        if ( USE_IOB ) _mmc_inval( buf_paddr, count<<9 );
86    }
87    else         // memory read
88    {
89        // L1 cache : nothing to do for L1 write-through
90
91        // L2 cache (only if we use an IO-Bridge component in architecture))
92        if ( USE_IOB ) _mmc_sync( buf_paddr, count<<9 );
93    }
94
95    // call the proper descheduling physical device driver
96 
97#if   ( USE_IOC_BDV )
98    return( _bdv_access( use_irq , to_mem , lba , buf_paddr , count ) ); 
99#elif ( USE_IOC_HBA )
100    return( _hba_access( use_irq , to_mem , lba , buf_paddr , count ) );
101#elif ( USE_IOC_SPI )
102    return( _sdc_access( use_irq , to_mem , lba , buf_paddr , count ) );
103#elif ( USE_IOC_RDK )
104    return( _rdk_access( use_irq , to_mem , lba , buf_paddr , count ) );
105#else
106    _printf("\n[FAT ERROR] in _fat_ioc_access() : no IOC driver\n");
107    _exit();
108#endif
109
110}  // end _fat_ioc_access()
111
112
113//////////////////////////////////////////////////////////////////////////////////
114// This function displays the content of the FAT cache
115//////////////////////////////////////////////////////////////////////////////////
116#if (GIET_DEBUG_FAT > 1)
117static
118void _display_fat_cache()
119{
120    unsigned int line;
121    unsigned int word;
122    unsigned int temp[9];
123
124    temp[8] = 0;
125
126    _puts("\n*********************** fat_cache_lba = ");
127    _putx( _fat.cache_lba );
128    _puts(" *****************************\n");
129
130    for ( line = 0 ; line < 16 ; line++ )
131    {
132        // display line index
133        _putx( line );
134        _puts(" : ");
135
136        // display 8*4 bytes hexa
137        for ( word=0 ; word<8 ; word++ )
138        {
139            unsigned int byte  = (line<<5) + (word<<2);
140            unsigned int hexa  = (_fat.fat_cache[byte  ]<<24) |
141                                 (_fat.fat_cache[byte+1]<<16) |
142                                 (_fat.fat_cache[byte+2]<< 8) |
143                                 (_fat.fat_cache[byte+3]);
144            _putx( hexa );
145            _puts(" | ");
146
147            // prepare display ascii
148            temp[word] = _fat.fat_cache[byte]         |
149                         (_fat.fat_cache[byte+1]<<8)  |
150                         (_fat.fat_cache[byte+2]<<16) |
151                         (_fat.fat_cache[byte+3]<<24) ;
152        }
153       
154        // display data ascii
155        _puts( (char*)temp );
156        _puts("\n");
157    }
158    _puts("***************************************************************************\n");
159
160} // end _display_fat_cache() 
161#endif
162
163//////////////////////////////////////////////////////////////////////////////////
164// This function displays the FAT descriptor.
165//////////////////////////////////////////////////////////////////////////////////
166#if GIET_DEBUG_FAT
167static
168void _fat_print()
169{
170    _printf("\n########################## FAT32 ################################" 
171            "\nFAT initialised                  %x"
172            "\nSector Size  (bytes)             %x"
173            "\nSectors per cluster              %x"
174            "\nFAT region first lba             %x"
175            "\nData region first lba            %x"
176            "\nNumber of sectors for one FAT    %x"
177            "\nNumber of free clusters          %x"
178            "\nLast allocated cluster           %x" 
179            "\n#################################################################\n",
180            _fat.initialised,
181            _fat.sector_size,
182            _fat.sectors_per_cluster,
183            _fat.fat_lba,
184            _fat.data_lba,
185            _fat.fat_sectors,
186            _fat.number_free_cluster,
187            _fat.last_cluster_allocated );
188} // end _fat_print()
189#endif
190
191//////////////////////////////////////////////////////////////////////////////////
192// This function returns the length of a FAT field. This field is identified
193// by an (offset,length) mnemonic defined in fat32.h file.
194//////////////////////////////////////////////////////////////////////////////////
195static inline 
196int get_length( int offset, 
197                int length )
198{
199    return length;
200}
201
202//////////////////////////////////////////////////////////////////////////////
203// Write one 32 bits word "value" in a char[] buffer.
204// The modified field in buffer is defined by the offset and size arguments.
205//////////////////////////////////////////////////////////////////////////////
206static 
207void _write_entry( unsigned int   offset,
208                   unsigned int   size,
209                   char*          buffer,
210                   unsigned int   value )
211{
212    unsigned int turn = 0;
213    unsigned int res  = value;
214    unsigned int mask = 0x000000ff;
215
216    while( turn != size - 1 )
217    {
218        buffer[ offset + turn ] = res & mask;
219        res = res >> 8;
220        turn++;
221    }
222    buffer[offset + turn] = res & mask;
223}
224
225//////////////////////////////////////////////////////////////////////////////
226// Read one 32 bits word in a char[] buffer, taking endianness into account.
227// The analysed field in buffer is defined by the offset and size arguments.
228//////////////////////////////////////////////////////////////////////////////
229static 
230unsigned int _read_entry( unsigned int   offset,
231                          unsigned int   size,
232                          char*          buffer,
233                          unsigned int   little_indian )
234{
235    unsigned int turn;
236    unsigned int res  = 0;
237    unsigned int mask = 0x000000ff;
238
239    if( little_indian )
240    {
241        turn = size;
242        while( turn != 1 )
243        {
244            res = res | (buffer[offset + (turn-1)] & mask);
245            res = res << 8;
246            turn--;
247        }
248        res = (buffer[offset + (turn-1)] & mask) | res;
249    }
250    else
251    {
252        turn = 0;
253        while( turn != size - 1 )
254        {
255
256            res = res  | (buffer[ offset + turn ] & mask );
257            res = res << 8;
258            turn++;
259        }
260        res = res | (buffer[offset + turn] & mask);
261    }
262    return res;
263}
264
265//////////////////////////////////////////////////////////////////////////////////
266// This function retuns the cluster index from the lba of a DATA sector.
267// The lba must be larger than the lba of the first DATA sector.
268// The DATA region indexing starts a cluster 2.
269//////////////////////////////////////////////////////////////////////////////////
270static inline 
271unsigned int lba_to_cluster( unsigned int lba )                   
272{
273   if (lba < _fat.data_lba ) return 0;
274
275   return ( (lba - _fat.data_lba) / _fat.sectors_per_cluster) + 2; 
276}
277
278//////////////////////////////////////////////////////////////////////////////////
279// This function retuns the lba of first sector in DATA region
280// from the cluster index. The cluster index must be larger than 2.
281//////////////////////////////////////////////////////////////////////////////////
282static inline 
283unsigned int cluster_to_lba( unsigned int cluster )       
284{
285   if ( cluster < 2 ) return 0; 
286
287   return  (_fat.sectors_per_cluster * (cluster - 2)) + _fat.data_lba;
288}
289
290/////////////////////////////////////////////////////////////////////////////////
291// This function search the FAT (using the FAT cache), and returns
292// the next cluster index from the current cluster index in the FAT.
293// remark: a sector of FAT contains 128 cluster indexes.
294/////////////////////////////////////////////////////////////////////////////////
295static 
296unsigned int _get_next_cluster( unsigned int use_irq,
297                                unsigned int cluster )
298{
299    // compute lba of the sector containing the cluster index
300    unsigned int lba = _fat.fat_lba + (cluster / 128);
301
302    if ( lba != _fat.cache_lba )      // miss in fat_cache
303    {
304        // access fat
305        if( _fat_ioc_access( use_irq,
306                             1,               // read
307                             lba, 
308                             (unsigned int)_fat.fat_cache,
309                             1 ) )            // one sector
310        {
311            _printf("[FAT_ERROR] in get_next_cluster_id() : cannot read block %x", 
312                    lba );
313            return 1;
314        }
315        _fat.cache_lba = lba;
316    }
317
318    unsigned int next = _read_entry( ((cluster % 128) * 4), 
319                                     4, 
320                                     _fat.fat_cache,
321                                     1 );
322#if (GIET_DEBUG_FAT > 1)
323unsigned int procid  = _get_procid();
324unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
325unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
326unsigned int p       = procid & ((1<<P_WIDTH)-1);
327_printf("\n[DEBUG FAT] P[%d,%d,%d] in _get_next_cluster() :  next = %x\n",
328        x , y , p , next );
329_display_fat_cache();
330#endif
331
332    return next;
333}
334
335//////////////////////////////////////////////////////
336static inline unsigned char to_upper(unsigned char c)
337{
338   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
339   else                      return c;
340}
341
342////////////////////////////////////////////////////////////////
343// This function is a filter:
344// Return the c character if c is a legal short name character
345// Return the '_' character if c is illegal
346////////////////////////////////////////////////////////////////
347static 
348unsigned char illegal_short(unsigned char c)
349{
350   const unsigned char illegal_char [] =";+=[]’,\"*\\<>/?:|\0";
351   short i = 0;
352   while (illegal_char[i]!='\0')
353   {
354      if (c == illegal_char[i])
355         return '_';
356      i++;
357   }
358   return c;
359}
360
361/////////////////////////////////////////////////////////////////////////////////
362// This function test if the string argument is a legal SFN (Short File Name)
363// and copies this name (removing the .) in the sfn_string argument.
364// Criteria for a Short File Name are:
365// - separator is '.' (extension is not mandatory)
366// - 1 <= name length <= 8
367// - 0 <= extension length <= 3
368// - no illegal character (see illega_short() function)
369// Return 1 if it string is a legal SFN
370// Return 0 if not legal SFN
371/////////////////////////////////////////////////////////////////////////////////
372static 
373int is_short( char* string, 
374              char* sfn_string)
375{
376    int s_size   = 0;
377    int dot_ext  = 0;       // dot offset in the filename
378    int name_len = 0;       // length of file name
379    int ext_len  = 0;       // length of extension
380    int i        = 0;
381    int sc_i     = 0;
382    char ch;
383
384    if(string[0] == '.' && string[1] == '\0')
385    {
386        sfn_string[0] = '.';
387        return 1;
388    }
389    if(string[0] == '.' && string[1] == '.' && string[2] == '\0')
390    {
391        sfn_string[0] = '.';
392        sfn_string[1] = '.';
393        return 1;
394    }
395    sfn_string[11] = '\0';
396    while (string[s_size] != '\0')
397    {
398        if (string[s_size] == '.')
399        {
400            dot_ext = s_size;
401            ext_len = -1;
402        }
403        ext_len++;
404        s_size++;
405    }
406    if (dot_ext != 0)
407    {
408        name_len = s_size - ext_len - 1;
409    }
410    else
411    {
412        name_len = s_size;
413        ext_len = 0;
414    }
415    if ( ext_len > 3 || ( name_len > 8))
416    {
417        return 0;
418    }
419    if (dot_ext != 0)
420    {
421        while (i != ext_len)
422        {
423            ch = to_upper(string[dot_ext + 1 + i]);
424            ch = illegal_short(ch);
425            sfn_string[8+i] = ch;
426            i++;
427        } 
428    }
429    i = 0;
430    sc_i = 0;
431    while (i!= name_len)
432    {
433        ch = to_upper(string[i]);
434        ch = illegal_short(ch);
435        if (ch != '.') sfn_string[sc_i++] = ch;
436        i++;
437    }
438    return 1;
439}
440
441///////////////////////////////////////////////////////////////////////
442// This function analyses the pathname argument, from the character
443// defined by the *nb_read argument.
444// It copies the found name (between '/') in the name[] buffer,
445// and updates the nb_read argument.
446// Return 1 if name found, Return 0 if NUL character found,
447///////////////////////////////////////////////////////////////////////
448static 
449int get_name_from_path( char*          pathname,
450                        char*          name,
451                        unsigned int*  nb_read )       
452{
453    if ( pathname[*nb_read] == 0 ) return 0;
454
455    int i = (pathname[*nb_read] == '/')? (*nb_read) + 1 : *nb_read;
456    int j = 0;
457   
458    while(pathname[i] != '/' && pathname[i] != '\0')
459    {
460        name[j] = pathname[i];   
461        j++;
462        i++;
463    }
464    name[j] = 0;
465
466    if ( pathname[i] == '/' ) *nb_read += j+1;
467    else                      *nb_read += j;
468
469    return 1;
470}
471
472////////////////////////////////////////////////////////////////////////////////
473static int get_name_from_short( char* dir_entry,     // input:  SFN dir_entry
474                                char* entry_name )   // output: name
475{
476    unsigned int i   = 0;
477    unsigned int length = get_length(DIR_NAME);
478
479    while ( i < length )
480    {
481        entry_name[i] = dir_entry[i];
482        i++;
483    }
484    entry_name[i] = '\0';
485
486    return i;
487}
488
489///////////////////////////////////////////////////////////////////////////////
490static int get_name_from_long( char *dir_entry,     // input : LFN dir_entry
491                               char *entry_name )   // output : name
492{
493    unsigned int   entry_name_offset   = 0;
494    unsigned int   dir_entry_offset    = get_length(LDIR_ORD);
495    unsigned int   l_name_1            = get_length(LDIR_NAME_1);
496    unsigned int   l_name_2            = get_length(LDIR_NAME_2);
497    unsigned int   l_name_3            = get_length(LDIR_NAME_3);
498    unsigned int   l_attr              = get_length(LDIR_ATTR);
499    unsigned int   l_type              = get_length(LDIR_TYPE);
500    unsigned int   l_chksum            = get_length(LDIR_CHKSUM);
501    unsigned int   l_rsvd              = get_length(LDIR_RSVD);
502
503    unsigned int j            = 0;
504    unsigned int eof          = 0;
505
506    while ( (dir_entry_offset != DIR_ENTRY_SIZE)  && (!eof) )
507    {
508        while (j != l_name_1 && !eof )
509        {
510            if ( (dir_entry[dir_entry_offset] == 0x00) || 
511                 (dir_entry[dir_entry_offset] == 0xFF) )
512            {
513                eof = 1;
514                continue;
515            }
516            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
517            dir_entry_offset += 2;
518            j += 2;
519            entry_name_offset++;
520        }
521
522        dir_entry_offset += (l_attr + l_type + l_chksum);
523        j = 0;
524
525        while (j != l_name_2 && !eof )
526        {
527            if ( (dir_entry[dir_entry_offset] == 0x00) || 
528                 (dir_entry[dir_entry_offset] == 0xFF) )
529            {
530                eof = 1;
531                continue;
532            }
533            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
534            dir_entry_offset += 2;
535            j += 2;
536            entry_name_offset++;
537        }
538
539        dir_entry_offset += l_rsvd;
540        j = 0;
541
542        while (j != l_name_3 && !eof )
543        {
544            if ( (dir_entry[dir_entry_offset] == 0x00) || 
545                 (dir_entry[dir_entry_offset] == 0xFF) )
546            {
547                eof = 1;
548                continue;
549            }
550            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
551            dir_entry_offset += 2;
552            j += 2;
553            entry_name_offset++;
554        }
555    }
556    entry_name[entry_name_offset] = '\0';
557
558    return entry_name_offset;
559} // end get_name_from_long()
560
561///////////////////////////////////////////////////////////////////////////////////
562// This function update a DIR_ENTRY, write a new value into a specific field
563// (ex : DIR_FILE_SIZE, when we want update the file size after a fat_write)
564// Return 0 in case of success, > 0 if failure.
565///////////////////////////////////////////////////////////////////////////////////
566// TODO : make this function less complex
567///////////////////////////////////////////////////////////////////////////////////
568static inline 
569unsigned int _update_entry( unsigned int use_irq,
570                            unsigned int fd_id, 
571                            unsigned int field,
572                            unsigned int size,
573                            unsigned int value )
574{
575    char dir_entry[32];   // buffer to store a full directory_entry
576    char name_entry[14];  // buffer to store a 13 characters (partial) name
577    char file_name[256];  // buffer to store the name (not pathname) of the file
578
579    char sfn_string[12]  = {[0 ... 10] = ' ', '\0'};     // buffer Short File Name
580    unsigned int lba     = _fat.fd[fd_id].lba_dir_entry;  // Lba of file dir_entry
581    unsigned int is_sfn;         
582    unsigned int attr    = 0;                            // dir entry attribute
583    unsigned int ord     = 0;                            // dir entry sequence
584    unsigned int found   = 0;                            // name found
585    unsigned int offset  = 0;                            // offset in fat_cache
586    unsigned int i       = 0;
587    unsigned int nb_read = 0;
588
589    for ( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
590    for ( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
591   
592    // Get the name of the file.
593    while ( get_name_from_path( _fat.fd[fd_id].name, file_name, &nb_read ) )
594    {
595    }
596
597    // Format file_name to SFN format
598    is_sfn = is_short( file_name, sfn_string );
599
600    // access FAT
601    if ( _fat_ioc_access( use_irq,
602                          1,               // read
603                          lba, 
604                          (unsigned int)_fat.fat_cache,
605                          1 ) )            // one sector
606    {
607        _printf("\n[FAT ERROR] in _update_entry() cannot read sector %x\n", 
608                lba );
609        return 1;
610    }
611    _fat.cache_lba = lba;
612
613    // - the offset increment is an integer number of directory entry (32 bytes)
614    // - the exit condition is success (name found) or failure (end of directory)
615    while ( !found )
616    {
617        attr = _read_entry( DIR_ATTR, _fat.fat_cache + offset, 0 );
618        ord  = _read_entry( LDIR_ORD, _fat.fat_cache + offset, 0 );
619
620        if ( is_sfn == 1 )                                     // searched name is short
621        {
622            if      ( (ord != FREE_ENTRY ) &&
623                    (ord != NO_MORE_ENTRY) &&
624                    (attr == ATTR_LONG_NAME_MASK) )    // LFN entry : skipped
625            {
626                offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
627                continue;
628            }
629            else if ( (attr != ATTR_LONG_NAME_MASK) && 
630                    (ord  != FREE_ENTRY) && 
631                    (ord  != NO_MORE_ENTRY ) )         // SFN entry : checked
632            {
633                memcpy( dir_entry, _fat.fat_cache + offset, DIR_ENTRY_SIZE );   
634            }
635            else if (ord == NO_MORE_ENTRY )            // end of directory : return
636            {
637                _printf("\n[FAT ERROR] in _update_entry() : reaches end\n");
638                return 1;
639            }
640            else                                                                           // free entry : skipped
641            {
642                offset = offset + DIR_ENTRY_SIZE;
643                continue;
644            }
645        }
646        else                                           // searched name is long
647        {
648            if      ( (attr == ATTR_LONG_NAME_MASK) && 
649                    (ord != FREE_ENTRY) &&
650                    (ord != NO_MORE_ENTRY) )           // LFN entry : checked
651            {
652                memcpy( dir_entry, _fat.fat_cache + offset, DIR_ENTRY_SIZE );   
653            }
654            else if ( (attr != ATTR_LONG_NAME_MASK) && 
655                    (ord  != FREE_ENTRY) && 
656                    (ord  != NO_MORE_ENTRY))               // SFN entry : skipped
657            {
658                offset = offset + DIR_ENTRY_SIZE;
659                continue;
660            }
661            else if (ord == NO_MORE_ENTRY )                        // end of directory : return
662            {
663                _printf("\n[FAT ERROR] in _update_entry() reaches end\n");
664                return 1;
665            }
666            else                                       // free entry : skipped
667            {
668                offset = offset + DIR_ENTRY_SIZE;
669                continue;
670            }
671        }
672
673        // testing the name extracted from dir entry
674
675        if ( is_sfn == 1 )                             // searched name is short
676        {
677            get_name_from_short( dir_entry, name_entry );
678
679            if ( _strncmp( (char*)sfn_string, (char*)name_entry, 13 ) == 0 )
680            {
681                _write_entry(offset + field, size, _fat.fat_cache, value);
682                found = 1;
683            }
684            else                                                                       // no matching : skip
685            {
686                offset = offset + DIR_ENTRY_SIZE;
687            }
688        }
689        else                                           // searched name is long
690        {
691            get_name_from_long( dir_entry, name_entry );
692
693            unsigned shift = ((ord & 0xf) - 1) * 13;
694            if ( _strncmp( (char*)(file_name + shift), 
695                           (char*)name_entry, 13 ) == 0 )
696            {
697                if ( (ord & 0xf) == 1 )
698                {
699                    offset = offset + DIR_ENTRY_SIZE;
700                    _write_entry(offset + field, size, _fat.fat_cache, value);
701                    found = 1;
702                }
703                offset = offset + DIR_ENTRY_SIZE;
704                continue;
705            }
706            else                                                                       // no matching : skip
707            {
708                offset = offset + ((ord & 0xf) * DIR_ENTRY_SIZE) + DIR_ENTRY_SIZE;
709            }
710        }
711    }
712
713    // write block to FAT
714    if ( _fat_ioc_access( use_irq,
715                          0,                // write
716                          lba, 
717                          (unsigned int)_fat.fat_cache, 
718                          1 ) )             // one sector
719    {
720        _printf("\n[FAT ERROR] in _update_entry() cannot write sector %x\n", 
721                lba );
722        return 1;
723    }
724
725    return 0;
726} // end _update_entry()
727
728
729//////////////////////////////////////////////////////////////////////////////////
730// This function update the FS_INFO block:
731// last cluster allocated and number of free cluster.
732// Return 0 in case of success, > 0 if failure.
733//////////////////////////////////////////////////////////////////////////////////
734static inline 
735unsigned int _update_fs_info( unsigned int use_irq )
736{
737    unsigned int lba = _fat.fs_info_lba;
738
739#if GIET_DEBUG_FAT
740_printf("\n[DEBUG FAT] _update_fs_info()\n");
741#endif
742
743    // update FAT cache in case of miss
744    if ( lba != _fat.cache_lba )
745    {
746        if ( _fat_ioc_access( use_irq,
747                              1,                 // read
748                              lba, 
749                              (unsigned int)_fat.fat_cache, 
750                              1 ) )              // one sector
751        {
752            _printf("\n[FAT_ERROR] in _update_fs_info() cannot read block\n");
753            return 1;
754        }
755        _fat.cache_lba = lba;
756    }
757
758    _write_entry( FS_FREE_CLUSTER     , _fat.fat_cache, _fat.number_free_cluster );
759    _write_entry( FS_FREE_CLUSTER_HINT, _fat.fat_cache, _fat.last_cluster_allocated );
760   
761    // write bloc to FAT
762    if ( _fat_ioc_access( use_irq,
763                          0,                // write
764                          lba,
765                          (unsigned int)_fat.fat_cache, 
766                          1 ) )             // one sector
767    {
768        _printf("\n[FAT_ERROR] in _update_fs_info() cannot write block\n");
769        return 1;
770    }
771
772    return 0;
773}  // end _update_fs_info()
774
775//////////////////////////////////////////////////////////////////////////////////
776// This function update FAT, write a new value into cluster index.
777// Used by the function _fat_allocate to update the chaining of clusters.
778// Return 0 in case of success, > 0 if failure.
779//////////////////////////////////////////////////////////////////////////////////
780static inline 
781unsigned int _update_fat( unsigned int use_irq,
782                          unsigned int cluster, 
783                          unsigned int value  )
784{
785    unsigned int lba = _fat.fat_lba + (cluster / 128);
786
787#if GIET_DEBUG_FAT
788_printf("\n[DEBUG FAT] _update_fat() : cluster = %x / value = %x\n", 
789        cluster, value );
790#endif
791
792    // update FAT cache in case of miss
793    if ( lba != _fat.cache_lba ) 
794    {
795        if ( _fat_ioc_access( use_irq,
796                              1,                 // read
797                              lba, 
798                              (unsigned int)_fat.fat_cache, 
799                              1 ) )              // one sector
800        {
801            _printf("\n[FAT_ERROR] in _update_fat() cannot read block %x\n",
802                    lba );
803            return 1;
804        }
805        _fat.cache_lba = lba;
806    }
807
808    _write_entry( ((cluster % 128) << 2), 4, _fat.fat_cache, value );
809
810    // write bloc to FAT
811    if ( _fat_ioc_access( use_irq,
812                          0,                // write
813                          lba,
814                          (unsigned int)_fat.fat_cache,
815                          1 ) )             // one sector
816    {
817        _printf("\n[FAT_ERROR] in _update_fat() cannot write block %x\n",
818                lba );
819        return 1;
820    }
821
822    return 0;
823} // end update_fat()
824
825//////////////////////////////////////////////////////////////////////////////////
826// This function allocate count clusters to a file by calling the
827// _update_fat function that takes care to update the chaining of clusters.
828// return 0 if success, -1 if failure
829//////////////////////////////////////////////////////////////////////////////////
830static inline 
831int _fat_allocate( unsigned int use_irq,
832                   unsigned int fd_id, 
833                   unsigned int count )
834{
835    unsigned int next_cluster = _fat.fd[fd_id].first_cluster;    // first cluster
836    unsigned int cluster_to_allocate = count;                   // to allocate
837    unsigned int last_cluster_file;                             // Last cluster
838    unsigned int free_cluster = _fat.last_cluster_allocated + 1; // First free
839
840    // Check if free_cluster is really free (must be true)
841    if ( _get_next_cluster( use_irq , free_cluster ) != FREE_CLUSTER)
842    {
843        _printf("\n[FAT ERROR] in _fat_allocate() : first free cluster not free\n");
844        return -1;
845    }
846    // Check if FAT contains enough cluster free for this allocation
847    if ( count > _fat.number_free_cluster )
848    {
849        _printf("\n[FAT ERROR] in _fat_allocate() : Not enough free cluster(s)\n");
850        return -1;
851    }
852
853#if GIET_DEBUG_FAT
854_printf("\n[DEBUG FAT] _fat_allocate() for fd = %d\n", fd_id );
855#endif
856
857    // Get the last cluster allocated for the file (seek END_OF_CHAIN_CLUSTER).
858    do 
859    {
860        last_cluster_file = next_cluster;
861        next_cluster      = _get_next_cluster( use_irq , next_cluster );
862    }
863    while ( next_cluster < END_OF_CHAIN_CLUSTER );
864
865    // Loop on the number of clusters to be allocated
866    while ( cluster_to_allocate > 0 )
867    {
868
869#if GIET_DEBUG_FAT
870_printf("\n[DEBUG FAT] cluster to update = %x / free cluster = %x / count = %d\n",
871        last_cluster_file , free_cluster , cluster_to_allocate );
872#endif
873
874        // update, in the FAT, the value of last cluster allocated by the index
875        // of free cluster.
876        if ( _update_fat( use_irq , last_cluster_file , free_cluster ) )
877        {
878            _printf("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
879            return -1;
880        }
881
882        cluster_to_allocate = cluster_to_allocate - 1;
883        // Last cluster allocated is then free_cluster
884        last_cluster_file = free_cluster;
885
886        // Last cluster to allocate done, then we must close the chain of clusters
887        if ( cluster_to_allocate == 0 )
888        {
889            // update, in the FAT, the value of the last cluster allocated by
890            // END_OF_CHAIN_CLUSTER
891            if ( _update_fat( use_irq , last_cluster_file , END_OF_CHAIN_CLUSTER ) )
892            {
893                _printf("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
894                return -1;
895            }
896        }
897
898        free_cluster = free_cluster + 1;
899
900        // Check if free_cluster is really free (must be true)
901        if ( _get_next_cluster( use_irq , free_cluster ) != FREE_CLUSTER)
902        {
903            _printf("\n[FAT ERROR] in _fat_allocate() : free_cluster not free\n");
904            return -1;
905        }
906    }
907
908    // Update field number_free_cluster and last_cluster_allocated
909    // of structure fat for next fat_allocate
910    _fat.last_cluster_allocated = last_cluster_file;
911    _fat.number_free_cluster    = _fat.number_free_cluster - count;
912
913    if ( _update_fs_info( use_irq ) )
914    {
915        _printf("\n[FAT ERROR] in _fat_allocate() : update fs_info failed\n");
916        return -1;
917    }
918
919    return 0;
920}  // end _fat_allocate()
921
922//////////////////////////////////////////////////////////////////////////////////
923// This function read the blocks defined by the cluster index argument, in a data
924// region containing a directory to search the name of a file/firectory.
925// It returns the cluster index of the file/directory when the name has been found,
926// as well as the file size, and the lba.
927// We consider 3 types of directory entries:
928// - SFN : directory entry associated to a Short File Name (8.3)
929// - LFN : directory entry associated to a Long File Name
930// - XTN : directory entry containing only a name extension for a Long File Name
931// The cluster index is always stored in a SFN or LFN entry.
932// Return cluster index if name found / Return -1 if not found.
933//////////////////////////////////////////////////////////////////////////////////
934static 
935int _scan_directory( unsigned int   use_irq,         // use descheduling mode
936                     unsigned int   cluster,         // cluster of dir_entry
937                     char*          file_name,       // searched file/dir name
938                     unsigned int*  file_size,       // file size
939                     unsigned int*  lba_dir_entry )  // lba of dir_entry
940{
941    char dir_entry[32];   // buffer to store a full directory_entry
942    char name_entry[14];  // buffer to store a 13 characters (partial) name
943
944    char sfn_string[12]    = {[0 ... 10] = ' ', '\0'};  // buffer Short File Name
945    unsigned int  is_sfn   = is_short(file_name, sfn_string); // file_name is short
946    unsigned int  offset   = 0;                         // byte offset in block
947    unsigned int  block_id = _fat.sectors_per_cluster;   // sector index
948    unsigned int  lba      = cluster_to_lba(cluster);   // lba of cluster
949    unsigned int  attr     = 0;                         // dir entry attribute
950    unsigned int  ord      = 0;                         // dir entry sequence
951    unsigned int  found    = 0;                         // searched name found
952    unsigned int  long_name_found = 0;                  // matching XTN found
953    unsigned int  searched_cluster;                     // searched cluster index
954
955#if GIET_DEBUG_FAT
956unsigned int procid  = _get_procid();
957unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
958unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
959unsigned int p       = procid & ((1<<P_WIDTH)-1);
960
961_printf("\n[DEBUG FAT] P[%d,%d,%d] enters _scan_directory() for %s\n",
962      x, y, p, file_name );
963#endif
964
965    unsigned int  i;
966    for( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
967    for( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
968
969    // load first sector from DATA region into FAT cache
970    // other sectors will be loaded inside loop as required
971    if( _fat_ioc_access( use_irq,
972                         1,               // read
973                         lba,
974                         (unsigned int)_fat.fat_cache,
975                         1 ) )            // one sector
976    {
977        _printf("[\nFAT ERROR] in _scan_directory() : cannot read sector %x\n",
978                lba );
979        return -1;
980    }
981    _fat.cache_lba = lba;
982
983#if ( GIET_DEBUG_FAT > 1 )
984_display_fat_cache();
985#endif
986
987    // in this loop we scan all names in the directory identified by cluster index
988    // - the offset increment is an integer number of directory entry (32 bytes)
989    // - the exit condition is success (name found) or failure (end of directory)
990    while( found == 0 )
991    {
992        // load a new sector if required
993        if (offset >= 512)             
994        {
995            if ( block_id )           // not a new cluster
996            {
997                lba += 1;
998                block_id --;
999            }
1000            else                                          // get next cluster
1001            {
1002                cluster = _get_next_cluster( use_irq , cluster );
1003
1004                if ( cluster >= END_OF_CHAIN_CLUSTER  ) return END_OF_CHAIN_CLUSTER;
1005
1006                lba      = cluster_to_lba(cluster);
1007                block_id = _fat.sectors_per_cluster;
1008            }
1009            if( _fat_ioc_access( use_irq,
1010                                 1,               // read
1011                                 lba, 
1012                                 (unsigned int)_fat.fat_cache,
1013                                 1 ) )            // one sector
1014            {
1015                _printf("\n[FAT ERROR] in _scan_directory() : cannot read sector %x\n",
1016                        lba);
1017                return -1;
1018            }
1019            _fat.cache_lba = lba;
1020            block_id--;
1021            offset = offset % 512;
1022        }
1023
1024        // store the directory entry pointed by offset in dir_entry buffer,
1025        // if it a possible candidate for the searched name
1026
1027        attr = _read_entry( DIR_ATTR, _fat.fat_cache + offset, 0);   
1028        ord  = _read_entry( LDIR_ORD, _fat.fat_cache + offset, 0);
1029
1030        if ( is_sfn == 1 )                                // searched name is short
1031        {
1032            if      ( (ord != FREE_ENTRY ) &&
1033                      (ord != NO_MORE_ENTRY) &&
1034                      (attr == ATTR_LONG_NAME_MASK) )    // EXT entry : skipped
1035            {
1036                offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
1037            }
1038            else if ( (attr != ATTR_LONG_NAME_MASK) && 
1039                      (ord  != FREE_ENTRY) && 
1040                      (ord  != NO_MORE_ENTRY ) )         // SFN entry : to be checked
1041            {
1042                memcpy( dir_entry, _fat.fat_cache + offset, DIR_ENTRY_SIZE );   
1043
1044                get_name_from_short( dir_entry, name_entry );
1045
1046                if ( _strncmp( (char*)sfn_string, 
1047                               (char*)name_entry, 13 ) == 0 )  // short name found
1048                {
1049                    found = 1;
1050                }
1051                else
1052                {
1053                    offset = offset + DIR_ENTRY_SIZE;
1054                }
1055            }
1056            else if (ord == NO_MORE_ENTRY )              // end of directory : return
1057            {
1058                return END_OF_CHAIN_CLUSTER;
1059            }
1060        }
1061        else                                      // searched name is long
1062        {
1063            if( (attr == ATTR_LONG_NAME_MASK) && 
1064                (ord != FREE_ENTRY) &&
1065                (ord != NO_MORE_ENTRY) )                 // EXT entry : to be checked
1066            {
1067                memcpy( dir_entry, _fat.fat_cache + offset, DIR_ENTRY_SIZE );
1068
1069                get_name_from_long( dir_entry, name_entry );
1070
1071                unsigned shift = ((ord & 0xf) - 1) * 13;
1072                if ( _strncmp( (char*)(file_name + shift), 
1073                               (char*)name_entry, 13 ) == 0 )  // matching EXT
1074                {
1075                    if( (ord & 0xf) == 1 )                    // long name found
1076                    {
1077                        long_name_found = 1;
1078                    }
1079                }
1080                offset = offset + DIR_ENTRY_SIZE;
1081            }
1082            else if( (attr != ATTR_LONG_NAME_MASK) && 
1083                     (ord  != FREE_ENTRY) && 
1084                     (ord  != NO_MORE_ENTRY) )
1085            {
1086                if ( long_name_found )                   // LFN entry
1087                {
1088                    memcpy( dir_entry, _fat.fat_cache + offset, DIR_ENTRY_SIZE );
1089                    found = 1;
1090                }
1091                else                                     // SFN entry: must be skipped
1092                {
1093                    offset = offset + DIR_ENTRY_SIZE;
1094                }
1095            }
1096            else if (ord == NO_MORE_ENTRY )                              // end of directory : return
1097            {
1098                return END_OF_CHAIN_CLUSTER;
1099            }
1100        }
1101    }  // end while
1102
1103    // returns cluster index
1104    *file_size       = _read_entry( DIR_FILE_SIZE, dir_entry, 1 );
1105    *lba_dir_entry   = lba;
1106    searched_cluster = (_read_entry( DIR_FST_CLUS_HI, dir_entry, 1 ) << 16) |
1107                       (_read_entry( DIR_FST_CLUS_LO, dir_entry, 1 )      ) ;
1108
1109#if GIET_DEBUG_FAT
1110_printf("\n[DEBUG FAT] _scan_directory() : P[%d,%d,%d] found %s"
1111        " : cluster = %x\n", x, y, p, file_name, searched_cluster );
1112#endif
1113
1114    return searched_cluster;
1115} // end _scan_directory()
1116
1117
1118//////////////////////////////////////////////////////////////////////
1119// This function create a new entry in a directory identified
1120// by "dir_cluster". The name is defined by "name".
1121// The type (dir/file) is defined by "is_file".
1122// Returns cluster index if success, Returns -1 if error.
1123//////////////////////////////////////////////////////////////////////
1124static int _fat_create( char*           name,
1125                        unsigned int    is_file,
1126                        unsigned int    dir_cluster )
1127{
1128    _printf("\n[FAT ERROR] _fat_create() not implemented\n");
1129    return 0;
1130}  //end _fat_create()
1131
1132
1133
1134////////////// Extern functions //////////////////////////////////////////
1135
1136//////////////////////////////////////////////////////////////////////////
1137// This function initializes the FAT structure, including the open
1138// files descriptors array and the lock protecting the FAT,
1139// from informations found in the boot record.
1140// This should be done only once.
1141//////////////////////////////////////////////////////////////////////////
1142// Return 0 if success, exit if failure
1143//////////////////////////////////////////////////////////////////////////
1144int _fat_init( unsigned int use_irq ) 
1145{
1146
1147#if GIET_DEBUG_FAT
1148unsigned int procid  = _get_procid();
1149unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1150unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1151unsigned int p       = procid & ((1<<P_WIDTH)-1);
1152_printf("\n[DEBUG FAT] P[%d,%d,%d] enters _fat_init\n",x,y,p);
1153#endif
1154
1155    // FAT initialisation should be done only once
1156    if ( _fat.initialised == FAT_INITIALISED )
1157    {
1158        _printf("\n[FAT ERROR] Strange, FAT already initialised...\n");
1159        _exit();
1160    }
1161
1162    // load Boot Record (VBR) into fat cache
1163    if ( _fat_ioc_access( use_irq,
1164                          1,                   // read
1165                          0,                   // sector index
1166                          (unsigned int)_fat.fat_cache,
1167                          1 ) )                // one sector
1168    {
1169        _printf("\n[FAT ERROR] in _fat_init() cannot load VBR\n");
1170        _exit();
1171    }
1172    _fat.cache_lba = 0;
1173
1174#if GIET_DEBUG_FAT > 1
1175_printf("\n[DEBUG FAT] _fat_init() : Boot Sector Loaded\n");
1176_display_fat_cache();
1177#endif
1178
1179    // checking various FAT32 assuptions from boot sector
1180    if( _read_entry( BPB_BYTSPERSEC, _fat.fat_cache, 1 ) != 512 )
1181    {
1182        _printf("\n[FAT ERROR] The sector size must be 512 bytes\n");
1183        _exit();
1184    }
1185    if( _read_entry( BPB_NUMFATS, _fat.fat_cache, 1 ) != 1 )
1186    {
1187        _printf("\n[FAT ERROR] The number of FAT copies in FAT region must be 1\n");
1188        _exit();
1189    }
1190    if( (_read_entry( BPB_FAT32_FATSZ32, _fat.fat_cache, 1 ) & 0xF) != 0 )
1191    {
1192        _printf("\n[FAT ERROR] The FAT region must be multiple of 32 sectors\n");
1193        _exit();
1194    }
1195    if( _read_entry( BPB_FAT32_ROOTCLUS, _fat.fat_cache, 1 ) != 2 )
1196    {
1197        _printf("\n[FAT ERROR] The first cluster index must be 2\n");
1198        _exit();
1199    }
1200    // FS Info always in sector 1
1201    _fat.fs_info_lba         = _read_entry( BPB_FAT32_FSINFO, _fat.fat_cache, 1 );
1202
1203    // initialise fat descriptor from VBR
1204    _fat.sectors_per_cluster = _read_entry( BPB_SECPERCLUS, _fat.fat_cache, 1 );
1205    _fat.sector_size         = _read_entry( BPB_BYTSPERSEC, _fat.fat_cache, 1 );
1206    _fat.cluster_size        = _fat.sectors_per_cluster * 512;
1207    _fat.fat_sectors         = _read_entry( BPB_FAT32_FATSZ32, _fat.fat_cache, 1 );
1208    _fat.fat_lba             = _read_entry( BPB_RSVDSECCNT, _fat.fat_cache, 1 );
1209    _fat.data_lba            = _fat.fat_lba + _fat.fat_sectors;
1210    _fat.initialised         = FAT_INITIALISED;
1211
1212    // initalise the lock protecting the FAT
1213    _spin_lock_init( &_fat.fat_lock );
1214
1215    // initialise file descriptor array
1216    unsigned int   n;
1217    for( n = 0 ; n < GIET_OPEN_FILES_MAX ; n++ ) _fat.fd[n].used = 0;
1218
1219#if GIET_DEBUG_FAT
1220_printf("\n[DEBUG FAT] _fat_init() : FS_INFO Sector = %x\n", _fat.fs_info_lba );
1221#endif
1222
1223    // load FS_INFO into fat cache
1224    if ( _fat_ioc_access( use_irq,
1225                          1,                  // read
1226                          _fat.fs_info_lba,   
1227                          (unsigned int)_fat.fat_cache,
1228                          1 ) )               // one sector
1229    { 
1230        _printf("\n[FAT ERROR] in _fat_init() cannot load FS_INFO Sector\n"); 
1231        _exit();
1232    }
1233    _fat.cache_lba = _fat.fs_info_lba;
1234
1235    _fat.number_free_cluster    = _read_entry( FS_FREE_CLUSTER     , _fat.fat_cache, 1);
1236    _fat.last_cluster_allocated = _read_entry( FS_FREE_CLUSTER_HINT, _fat.fat_cache, 1);
1237
1238#if GIET_DEBUG_FAT
1239_fat_print();
1240_printf("\n[DEBUG FAT] P[%d,%d,%d] exit _fat_init()\n", x,y,p );
1241#endif
1242
1243    return 0;
1244}  // end _fat_init()
1245
1246///////////////////////////////////////////////////////////////////////////////
1247// This function checks that the kernel FAT structure has been initialised.
1248// It searches a file identified by the "pathname" argument.
1249// It starts from root (cluster 2) to scan successively each subdirectory.
1250// When the file is not found, but the path is found, and "creat" is set,
1251// a new file is created and introduced in the directory.
1252// Finally, it sets a new open file in the file descriptors array.
1253// The same file can be open several times by differents tasks.
1254///////////////////////////////////////////////////////////////////////////////
1255// Returns file descriptor index if success, returns -1 if error.
1256///////////////////////////////////////////////////////////////////////////////
1257int _fat_open( unsigned int use_irq,       // use descheduling mode if possible
1258               char*        pathname,
1259               unsigned int creat )
1260{
1261    char                 name[256];        // buffer for one name in pathname
1262    unsigned int         nb_read;              // number of characters written in name[]
1263    unsigned int         cluster;          // current cluster index when scanning FAT
1264    unsigned int         dir_cluster;      // previous cluster index when scanning FAT
1265    unsigned int         fd_id;            // index when scanning file descriptors array
1266    unsigned int         file_size = 0;    // number of bytes
1267    unsigned int         last_name = 0;    // directory containing file name is reached
1268    unsigned int         lba       = 0;    // lba of dir_entry for this file
1269   
1270#if GIET_DEBUG_FAT
1271unsigned int procid  = _get_procid();
1272unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1273unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1274unsigned int p       = procid & ((1<<P_WIDTH)-1);
1275_printf("\n[DEBUG FAT] P[%d,%d,%d] enters _fat_open() for path %s\n",
1276        x, y, p, pathname );
1277#endif
1278
1279    // checking creat argument
1280    if ( creat )
1281    {
1282        _printf("\n[FAT ERROR] in _fat_open() : create not supported yet\n");
1283        return -1;
1284    }
1285
1286    // checking FAT initialised
1287    if( _fat.initialised != FAT_INITIALISED )
1288    {
1289        _printf("\n[FAT ERROR] in _fat_open() : FAT not initialised\n");
1290        return -1;
1291    }
1292    // takes the FAT lock for exclusive access
1293    _spin_lock_acquire( &_fat.fat_lock );
1294
1295#if GIET_DEBUG_FAT
1296_printf("\n[DEBUG FAT] _fat_open() : P[%d,%d,%d] takes the FAT lock\n",
1297        x, y, p );
1298#endif
1299 
1300    // Scan the directories, starting from the root directory (cluster 2)
1301    // - The get_name_from_path() function extracts (successively)
1302    //   each directory name from the pathname, and store it in name[] buffer
1303    // - The _scan_directory() function scan one (or several) cluster(s) containing
1304    //   a directory looking for name[], and return the cluster index
1305    //   corresponding to the directory/file found.
1306    nb_read     = 0;
1307    cluster     = 2;
1308    last_name   = 0;
1309    while ( get_name_from_path( pathname, name, &nb_read) )
1310    {
1311
1312#if GIET_DEBUG_FAT
1313_printf("\n[DEBUG FAT] _fat_open() : P[%d,%d,%d] search file/dir %s\n",
1314        x, y, p, name );
1315#endif
1316
1317        // test if we reach the last name (file name)
1318        if( pathname[nb_read] == 0 ) 
1319        {
1320            last_name   = 1;
1321            dir_cluster = cluster;
1322        }
1323
1324        // scan current directory
1325        cluster = _scan_directory( use_irq , cluster , name , &file_size , &lba );
1326
1327        if( cluster == END_OF_CHAIN_CLUSTER && last_name && creat )
1328        {
1329            cluster = _fat_create( name, 1, dir_cluster );
1330        }
1331        else if ( cluster == END_OF_CHAIN_CLUSTER )
1332        {
1333            _printf("\n[FAT ERROR] in _fat_open() cannot found %s\n", name );
1334            _spin_lock_release( &_fat.fat_lock );
1335            return -1;
1336        }
1337    }
1338
1339#if GIET_DEBUG_FAT
1340_printf("\n[DEBUG FAT] P[%d,%d,%d] in _fat_open() : cluster for %s = %x\n",
1341       x, y, p, pathname, cluster );
1342#endif
1343
1344    // check the next value for cluster index found
1345    unsigned next = _get_next_cluster( use_irq , cluster );
1346
1347    if ( (next != BAD_CLUSTER) && (next != FREE_CLUSTER) )
1348    {
1349        // Search an empty slot scanning open file descriptors array
1350        fd_id = 0;
1351        while ( _fat.fd[fd_id].used != 0 && fd_id < GIET_OPEN_FILES_MAX )
1352        {
1353            fd_id++;
1354        }
1355
1356        // set file descriptor if found empty slot
1357        if ( fd_id < GIET_OPEN_FILES_MAX )
1358        {
1359            _fat.fd[fd_id].used          = 1;
1360            _fat.fd[fd_id].first_cluster = cluster;
1361            _fat.fd[fd_id].file_size     = file_size;
1362            _fat.fd[fd_id].lba_dir_entry = lba;
1363            _strcpy( _fat.fd[fd_id].name, pathname );
1364
1365#if GIET_DEBUG_FAT
1366_printf("\n[DEBUG FAT] _fat_open() : P[%d,%d,%d] exit : fd = %d for file %s\n",
1367        x, y, p, fd_id, pathname );
1368#endif
1369
1370            // release FAT lock
1371            _spin_lock_release( &_fat.fat_lock );
1372
1373            return fd_id;
1374        }
1375        else
1376        {
1377            _printf("\n[FAT ERROR] in _fat_open() for file %s : fd array full\n", 
1378                    pathname );
1379            _spin_lock_release( &_fat.fat_lock );
1380            return -1;
1381        }
1382    }
1383    else
1384    {
1385        _printf("\n[FAT ERROR] in _fat_open() for file %s : bad cluster\n",
1386                pathname );
1387        _spin_lock_release( &_fat.fat_lock );
1388        return -1;
1389    }
1390} // end _fat_open()
1391
1392///////////////////////////////////////////////////////////////////////////////
1393// For an open file, identified by the file descriptor index, transfer
1394// an integer number of sectors from block device to a memory buffer.
1395// If the number of requested sectors exceeds the file size, it is reduced.
1396///////////////////////////////////////////////////////////////////////////////
1397// Returns number of sectors transfered if success, < 0 if error.
1398///////////////////////////////////////////////////////////////////////////////
1399int _fat_read( unsigned int use_irq,    // use descheduling mode if possible
1400               unsigned int fd_id,      // file descriptor
1401               void*        buffer,     // target buffer base address
1402               unsigned int count,      // number of sector to read
1403               unsigned int offset )    // nuber of sectors to skip in file
1404{
1405    unsigned int spc = _fat.sectors_per_cluster;
1406
1407    unsigned int file_size;         // number of bytes in file
1408    unsigned int file_sectors;      // number of sectors in file
1409    unsigned int total_sectors;     // actual number of sectors to be transfered
1410    unsigned int cluster;           // cluster index
1411    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1412    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1413
1414    // arguments checking
1415    if ( fd_id >= GIET_OPEN_FILES_MAX )
1416    { 
1417        _printf("\n[FAT ERROR] in _fat_read() : illegal file descriptor index\n");
1418        return -1;
1419    }
1420    if ( _fat.fd[fd_id].used != 1 )
1421    {
1422        _printf("\n[FAT ERROR] in _fat_read() : file not open\n");
1423        return -1;
1424    }
1425    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1426    {
1427        _printf("\n[FAT ERROR] in _fat_read() : memory buffer not sector aligned\n");
1428        return -1;
1429    }
1430
1431    // compute file size as a number of sectors
1432    file_size    = _fat.fd[fd_id].file_size;
1433    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1434    else                     file_sectors = (file_size >> 9); 
1435
1436    if ( offset >= file_sectors )
1437    {
1438        _printf("\n[FAT ERROR] offset larger than number of sectors\n");
1439        return -1;
1440    }
1441
1442    // compute total number of sectors to read
1443    if ( file_sectors < (offset + count) ) total_sectors = file_sectors - offset;
1444    else                                   total_sectors = count;
1445
1446    // compute clusters and sectors to be skipped
1447    clusters_to_skip = offset / spc;
1448    sectors_to_skip  = offset % spc;
1449   
1450    // get first cluster index
1451    cluster = _fat.fd[fd_id].first_cluster;
1452
1453#if GIET_DEBUG_FAT
1454unsigned int procid  = _get_procid();
1455unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1456unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1457unsigned int p       = procid & ((1<<P_WIDTH)-1);
1458_printf("\n[DEBUG FAT] _fat_read() : P[%d,%d,%d] enters for file %s\n"
1459        " - buffer vbase     = %x\n"
1460        " - skipped sectors  = %x\n"
1461        " - read sectors     = %x\n"
1462        " - first cluster    = %x\n"
1463        " - skipped clusters = %x\n",
1464        x, y, p, _fat.fd[fd_id].name, (unsigned int)buffer,
1465        offset, count, cluster, clusters_to_skip );
1466#endif
1467
1468    // compute index of first cluster to be loaded
1469    while ( clusters_to_skip )
1470    {
1471        cluster = _get_next_cluster( use_irq , cluster );
1472        clusters_to_skip--;
1473    }
1474
1475    // variables used in the loop on clusters
1476    int             todo_sectors;   // number of sectors still to be loaded
1477    unsigned int    lba;            // first sector index on device
1478    unsigned int    iter_sectors;   // number of sectors to load in iteration
1479    unsigned int    dst;            // pointer on target buffer
1480
1481    // initialize these variables for the first iteration
1482    todo_sectors  = total_sectors;
1483    dst           = (unsigned int)buffer;
1484    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1485    if( total_sectors < (spc - sectors_to_skip) ) iter_sectors = total_sectors;
1486    else                                          iter_sectors = spc - sectors_to_skip; 
1487
1488    // loop on the clusters: one IOC access per cluster
1489    while ( todo_sectors > 0 )
1490    {
1491
1492#if GIET_DEBUG_FAT
1493_printf("\n[DEBUG FAT] _fat_read() : P[%d,%d,%d] makes an IOC read\n"
1494        "  cluster = %x / buffer = %x / lba = %x / sectors = %d\n",
1495        x, y, p, cluster, dst, lba, iter_sectors );
1496#endif
1497
1498        if( _fat_ioc_access( use_irq,
1499                             1,                 // read
1500                             lba, 
1501                             dst,               // buffer address
1502                             iter_sectors ) )   // number of sectors
1503        {
1504            _printf("\n[FAT ERROR] in _fat_read() cannot load block %x", lba );
1505            return -1;
1506        }
1507         
1508        // update variables for next iteration
1509        cluster      = _get_next_cluster( use_irq , cluster );
1510        todo_sectors = todo_sectors - iter_sectors;
1511        dst          = dst + (iter_sectors << 9);
1512        lba          = cluster_to_lba(cluster);
1513        if ( todo_sectors > spc ) iter_sectors = spc;
1514        else                      iter_sectors = todo_sectors;
1515    }
1516         
1517    // returns number of sectors actually transfered
1518    return total_sectors;
1519
1520}  // end _fat_read()
1521
1522///////////////////////////////////////////////////////////////////////////////
1523// For an open file, identified by the file descriptor index, transfer
1524// an integer number of sectors from a memory buffer to block device.
1525// Allocate new clusters if the offset+count larger than current file size,
1526// but the offset should be smaller than the current file size...
1527///////////////////////////////////////////////////////////////////////////////
1528// Returns number of sectors written if success, < 0 if error.
1529///////////////////////////////////////////////////////////////////////////////
1530int _fat_write( unsigned int use_irq,    // use descheduling mode if possible
1531                unsigned int fd_id,      // file descriptor
1532                void*        buffer,     // target buffer base address
1533                unsigned int count,      // number of sector to write
1534                unsigned int offset )    // nuber of sectors to skip in file
1535{
1536
1537    unsigned int spc = _fat.sectors_per_cluster;
1538
1539    unsigned int file_size;         // number of bytes in file
1540    unsigned int file_sectors;      // number of sectors in file
1541    unsigned int cluster;           // cluster index
1542    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1543    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1544    unsigned int allocate;          // need allocate or not
1545    unsigned int current_cluster;   // number of cluster allocated to the file
1546    unsigned int required_cluster;  // number of cluster needed for the write
1547
1548    // compute file size as a number of sectors
1549    file_size    = _fat.fd[fd_id].file_size;
1550    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1551    else                     file_sectors = (file_size >> 9); 
1552
1553    // Compute the number of clusters occupied by the file
1554    current_cluster = file_sectors / spc;
1555
1556    // Compute the number of clusters that will occupy the file (after fat_write)
1557    required_cluster = (count + offset) / spc;
1558
1559    // Check if we need to allocate new cluster(s) for the file 
1560    allocate = ( required_cluster > current_cluster );
1561
1562#if GIET_DEBUG_FAT
1563unsigned int procid  = _get_procid();
1564unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1565unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1566unsigned int p       = procid & ((1<<P_WIDTH)-1);
1567
1568_printf("\n[DEBUG FAT] _fat_write() : P[%d,%d,%d] enters for file %s\n"
1569        " - buffer vbase    = %x\n"
1570        " - skipped sectors = %x\n"
1571        " - write sectors   = %x\n"
1572        " - file sectors    = %x\n"
1573        " - need_allocate   = %d\n",
1574        x, y, p, _fat.fd[fd_id].name, (unsigned int)buffer,
1575        offset, count, file_sectors, allocate );
1576#endif
1577
1578    // arguments checking
1579    if ( fd_id >= GIET_OPEN_FILES_MAX )
1580    { 
1581        _printf("\n[FAT ERROR] in _fat_write() : illegal file descriptor index\n");
1582        return -1;
1583    }
1584    if ( _fat.fd[fd_id].used != 1 )
1585    {
1586        _printf("\n[FAT ERROR] in _fat_write() : file not open\n");
1587        return -1;
1588    }
1589    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1590    {
1591        _printf("\n[FAT ERROR] in _fat_write() : memory buffer not sector aligned\n");
1592        return -1;
1593    }
1594
1595    if ( allocate  )
1596    {
1597        if ( _fat_allocate( use_irq , fd_id, (required_cluster-current_cluster) ) )
1598        {
1599            _printf("\n[FAT ERROR] in _fat_write() : fat_allocate failed\n");
1600            return -1;
1601        }
1602    }
1603
1604    // compute clusters and sectors to be skipped
1605    clusters_to_skip = offset / spc;
1606    sectors_to_skip  = offset % spc;
1607   
1608    // get first cluster index
1609    cluster = _fat.fd[fd_id].first_cluster;
1610
1611#if GIET_DEBUG_FAT
1612_printf("\n[DEBUG FAT] _fat_write() : P[%d,%d,%d] get cluster %x\n",
1613        x, y, p, cluster );
1614#endif
1615
1616    // compute index of first cluster to be loaded
1617    while ( clusters_to_skip )
1618    {
1619        cluster = _get_next_cluster( use_irq , cluster );
1620        clusters_to_skip--;
1621    }
1622
1623    // variables used in the loop on clusters
1624    int             todo_sectors;   // number of sectors still to be loaded
1625    unsigned int    lba;            // first sector index on device
1626    unsigned int    iter_sectors;   // number of sectors to load in iteration
1627    unsigned int    src;            // pointer on target buffer
1628
1629    // initialize these variables for the first iteration
1630    todo_sectors  = count;
1631    src           = (unsigned int)buffer;
1632    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1633    if( count < (spc - sectors_to_skip) ) iter_sectors = count;
1634    else                                  iter_sectors = spc - sectors_to_skip; 
1635
1636    // loop on the clusters
1637    while ( todo_sectors > 0 )
1638    {
1639
1640#if GIET_DEBUG_FAT
1641_printf("\n[DEBUG FAT] _fat_write() : P[%d,%d,%d] makes an IOC write"
1642        "  cluster = %x / buffer = %x / lba = %x / sectors = %d\n",
1643        x, y, p, cluster, src, lba, iter_sectors );
1644#endif
1645
1646        if( _fat_ioc_access( use_irq,
1647                             0,                 // write
1648                             lba, 
1649                             src,               // source buffer address
1650                             iter_sectors ) )   // number of sectors
1651        {
1652            _printf("\n[FAT ERROR] in _fat_write() cannot write block %x\n", lba );
1653            return -1;
1654        }
1655         
1656        // update variables for next iteration
1657        cluster      = _get_next_cluster( use_irq , cluster );
1658        todo_sectors = todo_sectors - iter_sectors;
1659        src          = src + (iter_sectors << 9);
1660        lba          = cluster_to_lba(cluster);
1661        if ( todo_sectors > spc ) iter_sectors = spc;
1662        else                      iter_sectors = todo_sectors;
1663    }
1664
1665    // Update structure file descriptor, field file_size with
1666    // the new file size if the file is bigger than the previous file
1667    if ( ( offset + count ) > file_sectors )
1668    {
1669        _fat.fd[fd_id].file_size = (count + offset) << 9;
1670    }
1671
1672    // Update entry of directory with the new value
1673    // of file size (Field : DIR_FILE_SIZE)
1674    if ( _update_entry( use_irq, fd_id , DIR_FILE_SIZE , _fat.fd[fd_id].file_size ) )
1675    {
1676        _printf("\n[FAT ERROR] in _fat_write() update entry failed\n");
1677        return -1;
1678    }
1679         
1680    // returns number of sectors actually transfered
1681    return count;
1682}  // end _fat_write()
1683
1684/////////////////////////////////////////////////////////////////////////////////
1685// Return stats of a file identified by "fd".
1686// (Only the file_size in sectors for this moment)
1687/////////////////////////////////////////////////////////////////////////////////
1688// Returns file size (on sectors) on success, -1 on failure.
1689/////////////////////////////////////////////////////////////////////////////////
1690int _fat_fstat( unsigned int fd_id )
1691{
1692    unsigned int file_size    = 0;
1693    unsigned int file_sectors = 0;
1694
1695    if( (fd_id < GIET_OPEN_FILES_MAX) )
1696    {
1697        file_size = _fat.fd[fd_id].file_size;
1698
1699        if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1700        else                     file_sectors = (file_size >> 9); 
1701
1702        return file_sectors;
1703    }
1704    else
1705    {
1706        _printf("\n[FAT ERROR] in _fat_fstat() : illegal file descriptor index\n");
1707        return -1;
1708    } 
1709} // end _fat_fstat()
1710
1711/////////////////////////////////////////////////////////////////////////////////
1712// Close the file identified by the file_descriptor index.
1713/////////////////////////////////////////////////////////////////////////////////
1714// Returns 0 on success, -1 on failure.
1715/////////////////////////////////////////////////////////////////////////////////
1716int _fat_close( unsigned int fd_id )
1717{
1718    if( (fd_id < GIET_OPEN_FILES_MAX) )
1719    {
1720        _fat.fd[fd_id].used = 0;
1721        return 0;
1722    }
1723    else
1724    {
1725        _printf("\n[FAT ERROR] in _fat_close() : illegal file descriptor index\n");
1726        return -1;
1727    } 
1728} // end fat_close()
1729
1730/////////////////////////////////////////////////////////////////////////////////
1731// The following function implement the user_level system call.
1732// The flags argument is not used, as file access modes are not implemented yet.
1733/////////////////////////////////////////////////////////////////////////////////
1734// Return the file descriptor index if success / return -1 if failure
1735/////////////////////////////////////////////////////////////////////////////////
1736int _fat_user_open( char*  pathname,         // absolute pathname from root
1737                    unsigned int flags )     // unused: TODO
1738{
1739    return _fat_open( 1,        // use descheduling mode if possible
1740                      pathname, 
1741                      0 );      // no creation if not found
1742}
1743
1744/////////////////////////////////////////////////////////////////////////////////
1745// The following function implement the user_level system call.
1746// This function should be modified to respect the UNIX specification.
1747/////////////////////////////////////////////////////////////////////////////////
1748// Return number of sectors actually transfered if success / return -1 if failure
1749/////////////////////////////////////////////////////////////////////////////////
1750int _fat_user_read( unsigned int fd,        // file descriptor index
1751                    void*        buffer,    // destination buffer
1752                    unsigned int count,     // number of sectors to read
1753                    unsigned int offset )   // number of sectors to skip
1754{
1755    return _fat_read( 1,        // use descheduling mode if possible
1756                      fd,
1757                      buffer, 
1758                      count, 
1759                      offset );
1760}
1761
1762/////////////////////////////////////////////////////////////////////////////////
1763// The following function implement the user_level system call.
1764// This function should be modified to respect the UNIX specification.
1765/////////////////////////////////////////////////////////////////////////////////
1766// Return number of sectors actually transfered if success / return -1 if failure
1767/////////////////////////////////////////////////////////////////////////////////
1768int _fat_user_write( unsigned int fd,       // file descriptor
1769                     void*        buffer,   // source buffer
1770                     unsigned int count,    // number of sectors to write
1771                     unsigned int offset )  // number of sectors to skip on file
1772{
1773    return _fat_write( 1,       // use descheduling mode if possible
1774                       fd,
1775                       buffer, 
1776                       count, 
1777                       offset );
1778}
1779
1780/////////////////////////////////////////////////////////////////////////////////
1781int _fat_user_lseek( unsigned int fd_id,
1782                     unsigned int offset,
1783                     unsigned int whence )
1784{
1785    _printf("\n[GIET ERROR] _fat_user_lseek() not implemented\n");
1786    _exit();
1787    return 0;
1788}
1789
1790
1791// Local Variables:
1792// tab-width: 4
1793// c-basic-offset: 4
1794// c-file-offsets:((innamespace . 0)(inline-open . 0))
1795// indent-tabs-mode: nil
1796// End:
1797// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1798
Note: See TracBrowser for help on using the repository browser.