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

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

Introducing a major release, to suppoort the tsar_generic_leti platform
and the various (external or internal) peripherals configurations.
The map.xml format has been modified, in order to support the new
vci_iopic componentand a new policy for peripherals initialisation.
The IRQs are nom described in the XICU and IOPIC components
(and not anymore in the processors).
To enforce this major change, the map.xml file signature changed:
The signature value must be: 0xDACE2014

This new release has been tested on the tsar_generic_leti platform
for the following mappings:

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