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

Last change on this file since 580 was 569, checked in by alain, 10 years ago

Improving debug: debug activated only if _get_proctime() > GIET_DEBUG_FAT

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