Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers usbhost_fat.c Source File

usbhost_fat.c

00001 /*
00002 **************************************************************************************************************
00003 *                                                 NXP USB Host Stack
00004 *
00005 *                                     (c) Copyright 2008, NXP SemiConductors
00006 *                                     (c) Copyright 2008, OnChip  Technologies LLC
00007 *                                                 All Rights Reserved
00008 *
00009 *                                                  www.nxp.com
00010 *                                               www.onchiptech.com
00011 *
00012 * File           : usbhost_fat.c
00013 * Programmer(s)  : Ravikanth.P
00014 * Version        :
00015 *
00016 **************************************************************************************************************
00017 */
00018 
00019 /*
00020 **************************************************************************************************************
00021 *                                           INCLUDE HEADER FILES
00022 **************************************************************************************************************
00023 */
00024 
00025 #include  "usbhost_fat.h"
00026 
00027 /*
00028 **************************************************************************************************************
00029 *                                              GLOBAL VARIABLES
00030 **************************************************************************************************************
00031 */
00032 
00033 #define MAX_FILE_DESCRIPTORS 2
00034 static  BOOT_SEC    FAT_BootSec;
00035 static  FILE_ENTRY  FAT_FileEntry[MAX_FILE_DESCRIPTORS];
00036 
00037 /*
00038 **************************************************************************************************************
00039 *                                         INITIALIZE THE FILE SYSTEM
00040 *
00041 * Description: This function initializes the FAT16 file system
00042 *
00043 * Arguments  : None
00044 *
00045 * Returns    : OK                     if Success
00046 *              ERR_INVALID_BOOTSIG    if Failed
00047 *
00048 **************************************************************************************************************
00049 */
00050 
00051 USB_INT32S  FAT_Init (void)
00052 {
00053     USB_INT16U  boot_sig;
00054     USB_INT32S  rc, i;
00055     FILE_ENTRY  *entry;
00056 
00057     for (i=0;i<MAX_FILE_DESCRIPTORS;i++) {
00058         entry = &FAT_FileEntry[i];
00059         entry->CurrClus       = 0;
00060         entry->CurrClusOffset = 0;
00061         entry->FileSize       = 0;
00062         entry->EntrySec       = 0;
00063         entry->EntrySecOffset = 0;
00064         entry->FileStatus     = 0;
00065     }
00066 
00067     MS_BulkRecv(0, 1, FATBuffer);
00068     boot_sig = ReadLE16U(&FATBuffer[510]);
00069     if (boot_sig != 0xAA55) {
00070         rc = ERR_INVALID_BOOT_SIG;
00071     } else {
00072         if (FATBuffer[0] != 0xEB && FATBuffer[0] != 0xE9) {
00073             FAT_BootSec.BootSecOffset = ReadLE32U(&FATBuffer[454]);
00074             MS_BulkRecv(FAT_BootSec.BootSecOffset, 1, FATBuffer);
00075         }
00076         FAT_BootSec.BytsPerSec      = ReadLE16U(&FATBuffer[11]);          /* Bytes per cluster              */
00077         FAT_BootSec.SecPerClus      = FATBuffer[13];                      /* Sectors per cluster            */
00078                                                                           /* Reserved sector count          */
00079         FAT_BootSec.RsvdSecCnt      = ReadLE16U(&FATBuffer[14]) + FAT_BootSec.BootSecOffset;
00080         FAT_BootSec.NumFATs         = FATBuffer[16];                      /* Number of FAT copies           */
00081         FAT_BootSec.RootEntCnt      = ReadLE16U(&FATBuffer[17]);          /* Root entry count               */
00082         FAT_BootSec.TotSec16        = ReadLE16U(&FATBuffer[19]);          /* Total FAT16 sectors            */
00083         FAT_BootSec.TotSec32        = ReadLE32U(&FATBuffer[32]);          /* Total FAT32 sectors            */
00084         FAT_BootSec.FATSz16         = ReadLE16U(&FATBuffer[22]);          /* Size of the FAT table          */
00085                                                                           /* Bytes per cluster              */
00086         FAT_BootSec.BytsPerClus     = (FAT_BootSec.BytsPerSec * FAT_BootSec.SecPerClus);
00087                                                                           /* Root directory starting sector */
00088         FAT_BootSec.RootDirStartSec = FAT_BootSec.RsvdSecCnt + (FAT_BootSec.FATSz16 * FAT_BootSec.NumFATs);
00089                                                                       /* Sectors occupied by root directory */
00090         FAT_BootSec.RootDirSec      = ((FAT_BootSec.RootEntCnt * 32) + (FAT_BootSec.BytsPerSec - 1)) /
00091                                        (FAT_BootSec.BytsPerSec);
00092                                                                           /* First data sector              */
00093         FAT_BootSec.FirstDataSec    = FAT_BootSec.RootDirStartSec + FAT_BootSec.RootDirSec;
00094         FAT_BootSec.FATType         = FAT_GetFATType();                   /* Type of FAT                    */
00095         if (FAT_BootSec.FATType == FAT_16) {
00096             rc = OK;
00097         } else {
00098             rc = ERR_FAT_NOT_SUPPORTED;
00099             PRINT_Err(rc);
00100         }
00101     }
00102     return (rc);
00103 }
00104 
00105 /*
00106 **************************************************************************************************************
00107 *                                         GET FILE SYSTEM TYPE
00108 *
00109 * Description: This function returns the file system type with which the disk is formatted
00110 *
00111 * Arguments  : None
00112 *
00113 * Returns    : FAT16           On Success
00114 *              ERR_FAT_TYPE    On Failure
00115 *
00116 **************************************************************************************************************
00117 */
00118 
00119 USB_INT08U  FAT_GetFATType (void)
00120 {
00121     USB_INT08U  fat_type;
00122     USB_INT32U  tot_sec;
00123     USB_INT32U  tot_data_clus;
00124 
00125 
00126     if (FAT_BootSec.TotSec16 != 0) {                             /* Get total sectors in the disk           */
00127         tot_sec = FAT_BootSec.TotSec16;
00128     } else {
00129         tot_sec = FAT_BootSec.TotSec32;
00130     }
00131 
00132     tot_data_clus = tot_sec / (FAT_BootSec.SecPerClus);          /* Get total data clusters in the disk     */
00133                                                                  /* If total data clusters >= 4085 and      */
00134                                                                  /* < 65525, then it is FAT16 file system   */
00135     if (tot_data_clus >= 4085 && tot_data_clus < 65525) {
00136         fat_type = FAT_16;
00137     } else {
00138         fat_type = 0;
00139     }
00140 
00141     return (fat_type);
00142 }
00143 
00144 /*
00145 **************************************************************************************************************
00146 *                                                OPENING A FILE
00147 *
00148 * Description: This function stores the attributes of a file, such as starting cluster, file size, 
00149 *              sector where the file entry is stored and offset of the entry in that sector
00150 *
00151 * Arguments  : file_name    Name of the file. The file must be in root directory.
00152 *
00153 * Returns    : pointer to the entry    On Success
00154 *              NULL                    On Failure
00155 * 
00156 * Modifed 6/9/08 WCB returns a file descriptor which is the INDEX+1 to the entry.
00157 * returning the entry address itself could be interpreted as a negative number --
00158 * and thus an error -- for memory locations of 0x80000000 and above.  We return
00159 * INDEX+1 instead of just the index to avoid returning a file descriptor of zero,
00160 * which could be potentially confused with an error.
00161 *
00162 **************************************************************************************************************
00163 */
00164 
00165 USB_INT32S  FILE_Open (USB_INT08U  *file_name,
00166                        USB_INT08U   flags)
00167 {
00168     USB_INT32S   rc;
00169     FILE_ENTRY  *entry = 0;
00170     USB_INT32S  fd = -1;
00171 
00172     do {
00173         if (FAT_FileEntry[++fd].FileStatus == 0)
00174             entry = &FAT_FileEntry[fd];
00175     } while ((entry == 0) && (fd < MAX_FILE_DESCRIPTORS-1));
00176     if (entry == 0) {
00177         return (ERR_OPEN_LIMIT_REACHED);
00178     }
00179     if (flags == RDONLY) {                       /* Search for a file. If it doesn't exist, don't create it */
00180         rc = FAT_FindEntry(file_name, entry);
00181         if (rc == MATCH_FOUND) {
00182             entry->FileStatus = 1;
00183             rc = fd+1;
00184         }
00185     } else {                                     /* Search for a file. If it doesn't exist, create it       */
00186         rc = FAT_CreateEntry(file_name, entry);
00187         if (rc == MATCH_FOUND) {
00188             entry->FileStatus = 1;
00189             rc = fd+1;
00190         }
00191     }
00192     return (rc);
00193 }
00194 
00195 /*
00196 **************************************************************************************************************
00197 *                                                 FINDING AN ENTRY
00198 *
00199 * Description: This function searches for a file name in the root directory
00200 *
00201 * Arguments  : ent_name_given    Pointer to the file name to be searched.
00202 *              entry             Pointer to the entry structure. The attributes of the file are stored in this
00203 *                                structure if the file was found in the root directory.
00204 *
00205 * Returns    : MATCH_FOUND       if the file was found in the root directory.
00206 *              MATCH_NOT_FOUND   if the file was not found in the root directory.
00207 *
00208 **************************************************************************************************************
00209 */
00210 
00211 USB_INT32S  FAT_FindEntry (USB_INT08U  *ent_name_given,
00212                            FILE_ENTRY  *entry)
00213 {
00214               USB_INT32U   sec_num;
00215     volatile  USB_INT08U  *buf;
00216               USB_INT08U   ent_type;
00217               USB_INT08U   ent_name_read[13];
00218 
00219 
00220     for (sec_num = FAT_BootSec.RootDirStartSec;              /* For all the sectors in root directory       */
00221          sec_num < (FAT_BootSec.RootDirStartSec + FAT_BootSec.RootDirSec);
00222          sec_num++) {
00223            
00224 
00225         MS_BulkRecv(sec_num, 1, FATBuffer);                  /* Read one sector                             */
00226         buf = FATBuffer;
00227         while (buf < (FATBuffer + FAT_BootSec.BytsPerSec)) {
00228             ent_type = FAT_ChkEntType(buf);                  /* Check for the entry type                    */
00229             if (ent_type == SFN_ENTRY) {                     /* If it is short entry get short file name    */
00230                 FAT_GetSFN(buf, ent_name_read);
00231                                                     /* Compare given name with this name case insensitively */
00232                 if (FAT_StrCaseCmp(ent_name_given, ent_name_read) == MATCH_FOUND) {
00233                     entry->CurrClus = ReadLE16U(&buf[26]);   /* If they are same, get starting cluster      */
00234                     entry->FileSize  = ReadLE32U(&buf[28]);  /* Get file size                               */
00235                     entry->EntrySec = sec_num;           /* Get sector number where the filename is located */
00236                                                  /* Get offset in this sector where the filename is located */
00237                     entry->EntrySecOffset = buf - FATBuffer;
00238                     return (MATCH_FOUND);
00239                 }
00240             }
00241             if (ent_type == LAST_ENTRY) {    /* If it is the last entry, no more entries will exist. Return */
00242                 return (MATCH_NOT_FOUND);
00243             }
00244             buf = buf + 32;                                  /* Move to the next entry                      */
00245         }
00246     }
00247     return (MATCH_NOT_FOUND);
00248 }
00249 
00250 /*
00251 **************************************************************************************************************
00252 *                                       GET SHORT FILE NAME AND EXTENSION OF A FILE
00253 *
00254 * Description: This function reads the short file name and extension corresponding to a file
00255 *
00256 * Arguments  : ent_buf    buffer which contains the 32 byte entry of a file
00257 *              name       buffer to store the file name and extension of a file
00258 *
00259 * Returns    : None
00260 *
00261 **************************************************************************************************************
00262 */
00263 
00264 void  FAT_GetSFN (volatile  USB_INT08U  *entry,
00265                             USB_INT08U  *name)
00266 {
00267     USB_INT08U   ext[4];                          /* Buffer to store the extension of a file                */
00268     USB_INT08U  *ext_ptr;
00269 
00270 
00271     ext_ptr = ext;
00272 
00273     FAT_GetSfnName(entry, name);                  /* Get file name into "name" buffer                       */
00274     FAT_GetSfnExt(entry, ext_ptr);                /* Get extension into "ext" buffer                        */
00275 
00276     while (*name) {                               /* Goto the end of the filename                           */
00277         name++;
00278     }
00279     if (*ext_ptr) {                               /* If the extension exists, put a '.' charecter           */
00280         *name = '.';
00281         name++;
00282     }
00283     while (*ext_ptr) {                            /* Append the extension to the file name                  */
00284         *name = *ext_ptr;
00285         name++;
00286         ext_ptr++;
00287     }
00288     *name = '\0';
00289 }
00290 
00291 /*
00292 **************************************************************************************************************
00293 *                                          GET SHORT FILE NAME OF A FILE
00294 *
00295 * Description: This function reads the short file name of a file
00296 *
00297 * Arguments  : ent_buf  buffer which contains the 32 byte entry of a file
00298 *              name     buffer to store the short file name of a file
00299 *
00300 * Returns    : None
00301 *
00302 **************************************************************************************************************
00303 */
00304 
00305 void  FAT_GetSfnName (volatile  USB_INT08U  *entry,
00306                                 USB_INT08U  *name)
00307 {
00308     USB_INT32U  cnt;
00309 
00310 
00311     cnt = 0;
00312     while (cnt < 8) {
00313         *name = *entry;                     /* Get first 8 charecters of an SFN entry                       */
00314         name++;
00315         entry++;
00316         cnt++;
00317     }
00318     *name = 0;
00319     name--;
00320     while (*name == 0x20) {                 /* If any spaces exist after the file name, replace them with 0 */
00321         *name = 0;
00322         name--;
00323     }
00324 }
00325 
00326 /*
00327 **************************************************************************************************************
00328 *                                       GET EXTENSION OF A FILE
00329 *
00330 * Description: This function reads the extension of a file
00331 *
00332 * Arguments  : ent_buf    buffer which contains the 32 byte entry of a file
00333 *              ext_ptr    buffer to store the extension of a file       
00334 *
00335 * Returns    : None
00336 *
00337 **************************************************************************************************************
00338 */
00339 
00340 void  FAT_GetSfnExt (volatile  USB_INT08U  *entry,
00341                                USB_INT08U  *ext_ptr)
00342 {
00343     USB_INT32U  cnt;
00344 
00345 
00346     cnt = 0;
00347     while (cnt < 8) {                  /* Goto the beginning of the file extension                          */
00348         entry++;
00349         cnt++;
00350     }
00351     cnt = 0;
00352     while (cnt < 3) {                  /* Get 3 charecters from there                                       */
00353         *ext_ptr = *entry;
00354         ext_ptr++;
00355         entry++;
00356         cnt++;
00357     }
00358     *ext_ptr = 0;
00359     ext_ptr--;
00360     while (*ext_ptr == ' ') {          /* If any spaces exist after the file extension, replace them with 0 */
00361         *ext_ptr = 0;
00362         ext_ptr--;
00363     }
00364 }
00365 
00366 /*
00367 **************************************************************************************************************
00368 *                                       CASE INSENSITIVE COMPARISION OF STRINGS
00369 *
00370 * Description: This function compares two strings case insensitively
00371 *
00372 * Arguments  : str1               Pointer to the first string
00373 *              str2               Pointer to the second string
00374 *
00375 * Returns    : MATCH_FOUND        if both the strings are same
00376 *              NATCH_NOT_FOUND    if both the strings are different
00377 *
00378 **************************************************************************************************************
00379 */
00380 
00381 USB_INT32S  FAT_StrCaseCmp (USB_INT08U  *str1,
00382                             USB_INT08U  *str2)
00383 {
00384     while (*str1 && *str2) {
00385         if (*str1 == *str2 || *str1 == (*str2 + 32) || *str1 == (*str2 - 32)) {
00386             str1++;
00387             str2++;
00388             continue;
00389         } else {
00390             return (MATCH_NOT_FOUND);
00391         }
00392     }
00393     if (*str1 == 0 && *str2 == 0) {
00394         return (MATCH_FOUND);
00395     } else {
00396         return (MATCH_NOT_FOUND);
00397     }
00398 }
00399 
00400 /*
00401 **************************************************************************************************************
00402 *                                       CHECK TYPE OF THE ENTRY
00403 *
00404 * Description: This function checks the type of file entry.
00405 *
00406 * Arguments  : ent           Pointer to the buffer containing the entry
00407 *
00408 * Returns    : LAST_ENTRY    if the entry is last entry
00409 *              FREE_ENTRY    if the entry is free entry
00410 *              LFN_ENTRY     if the entry is long file name entry
00411 *              SFN_ENTRY     if the entry is short file name entry
00412 *
00413 **************************************************************************************************************
00414 */
00415 
00416 USB_INT32U  FAT_ChkEntType (volatile  USB_INT08U  *ent)
00417 {
00418     if (ent[0] == 0x00) {                              /* First byte is 0 means it is the last entry        */
00419         return (LAST_ENTRY);
00420     }
00421 
00422     if (ent[0] == 0xE5) {                              /* First byte is 0xE5 means it is the free entry     */
00423         return (FREE_ENTRY);
00424     }
00425 
00426     if (0x0F == ent[11]) {                             /* If 11th byte of an entry is 0x0F, it is LFN       */
00427         return (LFN_ENTRY);
00428 
00429     } else {
00430         return (SFN_ENTRY);                            /* Else it is the SFN                                */
00431     }
00432 }
00433 
00434 /*
00435 **************************************************************************************************************
00436 *                                       READ DATA REQUESTED BY THE USER
00437 *
00438 * Description: This function reads data requested by the application from the file pointed by file descriptor.
00439 *
00440 * Arguments  : fd                  file descriptor that points to a file
00441 *              buffer              buffer into which the data is to be read
00442 *              num_bytes           number of bytes requested by the application
00443 *
00444 * Returns    : total_bytes_read    Total bytes actually read.
00445 *
00446 **************************************************************************************************************
00447 */
00448 
00449 USB_INT32U  FILE_Read (          USB_INT32S  fd,
00450                        volatile  USB_INT08U  *buffer,
00451                                  USB_INT32U   num_bytes)
00452 {
00453     USB_INT32U   total_bytes_to_read;            /* Total bytes requested by the application                */
00454     USB_INT32U   total_bytes_read;               /* Total bytes read                                        */
00455     USB_INT32U   bytes_read;                     /* Bytes read from one cluster                             */
00456     USB_INT32U   bytes_to_read;                  /* Bytes to be read in one cluster                         */
00457     FILE_ENTRY  *entry;                          /* Entry that contains the file attribute information      */
00458     USB_INT16U   next_clus;                     /* Next cluster of the current cluster in the cluster chain */
00459 
00460     entry = &FAT_FileEntry[fd-1];                /* Get file entry from file descriptor                     */
00461     total_bytes_read = 0;
00462 
00463     if (entry->FileSize == 0) {
00464         return (0);
00465     }
00466     if (num_bytes < entry->FileSize) {
00467         total_bytes_to_read = num_bytes;
00468     } else {
00469         total_bytes_to_read = entry->FileSize;
00470     }
00471     do {
00472         next_clus = FAT_GetNextClus(entry->CurrClus);     /* Get next cluster                               */
00473         if (next_clus == 0) {                             /* If the current cluster is the last cluster     */
00474                                                           /* If the offset is at the end of the file        */
00475             if (entry->CurrClusOffset == (entry->FileSize % FAT_BootSec.BytsPerClus)) {
00476                 return (0);                               /* No more bytes to read                          */
00477             }                               /* If requested number is > remaining bytes in the last cluster */
00478             if (total_bytes_to_read > ((entry->FileSize % FAT_BootSec.BytsPerClus) - entry->CurrClusOffset)) {
00479                 total_bytes_to_read = (entry->FileSize % FAT_BootSec.BytsPerClus) - entry->CurrClusOffset;
00480             }
00481             bytes_to_read = total_bytes_to_read;
00482                                          /* If requested number is > remaining bytes in the current cluster */
00483         } else if (total_bytes_to_read > (FAT_BootSec.BytsPerClus - entry->CurrClusOffset)) {
00484             bytes_to_read = FAT_BootSec.BytsPerClus - entry->CurrClusOffset;
00485         } else {
00486             bytes_to_read = total_bytes_to_read;
00487         }
00488         bytes_read = FAT_ClusRead(entry->CurrClus,       /* Read bytes from a single cluster                */
00489                                   entry->CurrClusOffset,
00490                                   buffer,
00491                                   bytes_to_read);
00492         buffer              += bytes_read;
00493         total_bytes_read    += bytes_read;
00494         total_bytes_to_read -= bytes_read;
00495                                              /* If the cluster offset reaches end of the cluster, make it 0 */
00496         if (entry->CurrClusOffset + bytes_read == FAT_BootSec.BytsPerClus) {
00497             entry->CurrClusOffset = 0;
00498         } else {
00499             entry->CurrClusOffset += bytes_read;        /* Else increment the cluster offset                */
00500         }
00501         if (entry->CurrClusOffset == 0) {
00502             entry->CurrClus = (next_clus > 0) ? next_clus : entry->CurrClus;
00503         }
00504     } while (total_bytes_to_read);
00505     return (total_bytes_read);
00506 }
00507 
00508 /*
00509 **************************************************************************************************************
00510 *                                                 READ FROM ONE CLUSTER
00511 *
00512 * Description: This function reads the data from a single cluster.
00513 *
00514 * Arguments  : curr_clus         Current cluster from which the data has to read
00515 *              clus_offset       Position in the current cluster from which the data has to read
00516 *              buffer            Buffer into which the data has to read
00517 *              num_bytes         Number of bytes to read
00518 *
00519 * Returns    : tot_bytes_read    Total bytes read from the current cluster
00520 *
00521 **************************************************************************************************************
00522 */
00523 
00524 USB_INT32U  FAT_ClusRead (          USB_INT16U   curr_clus,
00525                                     USB_INT32U   clus_offset,
00526                           volatile  USB_INT08U  *buffer,
00527                                     USB_INT32U   num_bytes)
00528 {
00529     USB_INT32U  tot_bytes_read;                              /* total bytes read in the current cluster     */
00530     USB_INT32U  n_bytes;                                     /* Bytes to read in the current sector         */
00531     USB_INT32U  start_sec;                                   /* Starting sector of the current cluster      */
00532     USB_INT32U  sec_num;                                     /*Current sector number                        */
00533     USB_INT16U  num_sec;                                     /* Number of sectors to be read                */
00534     USB_INT32U  sec_offset;                                  /* Offset in the current sector                */
00535     USB_INT32U  cnt;
00536 
00537 
00538     tot_bytes_read = 0;
00539     start_sec  = ((curr_clus - 2) * FAT_BootSec.SecPerClus) + FAT_BootSec.FirstDataSec;
00540     sec_num    = start_sec + (clus_offset / FAT_BootSec.BytsPerSec);
00541     num_sec    = num_bytes / FAT_BootSec.BytsPerSec;
00542     sec_offset = clus_offset % FAT_BootSec.BytsPerSec;
00543 
00544     if (sec_offset) {                                 /* If the sector offset is at the middle of a sector  */
00545         MS_BulkRecv(sec_num, 1, FATBuffer);           /* Read the first sector                              */
00546         n_bytes = (FAT_BootSec.BytsPerSec - sec_offset <= num_bytes) ?
00547                   (FAT_BootSec.BytsPerSec - sec_offset) : num_bytes;
00548         for (cnt = sec_offset; cnt < sec_offset + n_bytes; cnt++) {
00549             *buffer = FATBuffer[cnt];                 /* Copy the required bytes to user buffer             */
00550              buffer++;
00551         }
00552         tot_bytes_read += n_bytes;
00553         clus_offset    += n_bytes;
00554         num_bytes      -= n_bytes;
00555         sec_num++;
00556     }
00557 
00558     if (num_bytes / FAT_BootSec.BytsPerSec) {         /* Read all the remaining full sectors                */
00559 
00560         num_sec = num_bytes / FAT_BootSec.BytsPerSec;
00561         MS_BulkRecv(sec_num, num_sec, buffer);
00562         buffer         += (num_sec * FAT_BootSec.BytsPerSec);
00563         tot_bytes_read += (num_sec * FAT_BootSec.BytsPerSec);
00564         clus_offset    += (num_sec * FAT_BootSec.BytsPerSec);
00565         num_bytes      -= (num_sec * FAT_BootSec.BytsPerSec);
00566         sec_num        += num_sec;
00567     }
00568 
00569     if (num_bytes) {                                  /* Read the last sector for the remaining bytes       */
00570         MS_BulkRecv(sec_num, 1, FATBuffer);
00571         for (cnt = 0; cnt < num_bytes; cnt++) {
00572             *buffer = FATBuffer[cnt];                 /* Copy the required bytes to user buffer             */
00573              buffer++;
00574         }
00575         tot_bytes_read += num_bytes;
00576     }
00577 
00578     return (tot_bytes_read);
00579 }
00580 
00581 /*
00582 **************************************************************************************************************
00583 *                                       WRITE THE DATA REQUESTED BY THE USER
00584 *
00585 * Description: This function writes data requested by the application to the file pointed by file descriptor
00586 *
00587 * Arguments  : fd                     file descriptor that points to a file
00588 *              buffer                 buffer from which the data is to be written
00589 *              num_bytes              number of bytes requested by the application
00590 *
00591 * Returns    : total_bytes_written    Total bytes actually written
00592 *
00593 **************************************************************************************************************
00594 */
00595 
00596 USB_INT32U  FILE_Write (          USB_INT32S  fd,
00597                         volatile  USB_INT08U  *buffer,
00598                                   USB_INT32U   num_bytes)
00599 {
00600     USB_INT32U   total_bytes_to_write;                      /* Total bytes requested by application         */
00601     USB_INT32U   total_bytes_written;                       /* Total bytes written                          */
00602     USB_INT32U   bytes_written;                             /* Bytes written in a single cluster            */
00603     USB_INT32U   bytes_to_write;                            /* Bytes to write in a single cluster           */
00604     FILE_ENTRY  *entry;                               /* Entry that contains the file attribute information */
00605     USB_INT16U   free_clus;                                 /* Free cluster available in the disk           */
00606 
00607 
00608     entry = &FAT_FileEntry[fd-1];                           /* Get file entry from file descriptor                     */
00609     total_bytes_written  = 0;
00610     total_bytes_to_write = num_bytes;
00611 
00612     if (num_bytes) {
00613         if (entry->FileSize == 0) {
00614             free_clus = FAT_GetFreeClus();
00615             FAT_UpdateFAT(free_clus, 0xFFFF);
00616             entry->CurrClus  = free_clus;
00617             MS_BulkRecv(entry->EntrySec, 1, FATBuffer);
00618             WriteLE16U(&FATBuffer[(entry->EntrySecOffset) + 26], free_clus);
00619             MS_BulkSend(entry->EntrySec, 1, FATBuffer);
00620         }
00621     } else {
00622         return (0);
00623     }
00624     entry->CurrClus = FAT_GetEndClus(entry->CurrClus);           /* Make the current cluster as end cluster */
00625     entry->CurrClusOffset = entry->FileSize % FAT_BootSec.BytsPerClus;   /* Move cluster offset to file end */
00626     do {
00627         if (total_bytes_to_write > FAT_BootSec.BytsPerClus - entry->CurrClusOffset) {
00628             bytes_to_write = FAT_BootSec.BytsPerClus - entry->CurrClusOffset;
00629         } else {
00630             bytes_to_write = total_bytes_to_write;
00631         }
00632         bytes_written = FAT_ClusWrite(entry->CurrClus,
00633                                       entry->CurrClusOffset,
00634                                       buffer,
00635                                       bytes_to_write);
00636         buffer               += bytes_written;
00637         total_bytes_written  += bytes_written;
00638         total_bytes_to_write -= bytes_written;
00639         entry->FileSize      += bytes_written;
00640         if (entry->CurrClusOffset + bytes_written == FAT_BootSec.BytsPerClus) {
00641             entry->CurrClusOffset = 0;
00642         } else {
00643             entry->CurrClusOffset += bytes_written;
00644         }
00645         if (entry->CurrClusOffset == 0) {
00646             free_clus = FAT_GetFreeClus();
00647             if (free_clus == 0) {
00648                 return (total_bytes_written);
00649             }
00650             FAT_UpdateFAT(entry->CurrClus, free_clus);
00651             FAT_UpdateFAT(free_clus, 0xFFFF);
00652             entry->CurrClus = free_clus;
00653         }
00654     } while (total_bytes_to_write);
00655     return (total_bytes_written);
00656 }
00657 
00658 /*
00659 **************************************************************************************************************
00660 *                                               WRITE TO ONE CLUSTER
00661 *
00662 * Description: This function writes the data to a single cluster.
00663 *
00664 * Arguments  : curr_clus         Current cluster into which the data has to write
00665 *              clus_offset       Position in the current cluster from which the data has to write
00666 *              buffer            Buffer from which the data has to write
00667 *              num_bytes         Number of bytes to write
00668 *
00669 * Returns    : tot_bytes_read    Total bytes written into the current cluster
00670 *
00671 **************************************************************************************************************
00672 */
00673 
00674 USB_INT32U  FAT_ClusWrite (          USB_INT16U   curr_clus,
00675                                      USB_INT32U   clus_offset,
00676                            volatile  USB_INT08U  *buffer,
00677                                      USB_INT32U   num_bytes)
00678 {
00679     USB_INT32U  tot_bytes_written;
00680     USB_INT32U  n_bytes;
00681     USB_INT32U  start_sec;
00682     USB_INT32U  sec_num;
00683     USB_INT16U  num_sec;
00684     USB_INT32U  sec_offset;
00685     USB_INT32U  cnt;
00686 
00687 
00688     tot_bytes_written = 0;
00689     start_sec  = ((curr_clus - 2) * FAT_BootSec.SecPerClus) + FAT_BootSec.FirstDataSec;
00690     sec_num    = start_sec + (clus_offset / FAT_BootSec.BytsPerSec);
00691     num_sec    = num_bytes / FAT_BootSec.BytsPerSec;
00692     sec_offset = clus_offset % FAT_BootSec.BytsPerSec;
00693 
00694     if (sec_offset) {
00695         MS_BulkRecv(sec_num, 1, FATBuffer);
00696         n_bytes = (FAT_BootSec.BytsPerSec - sec_offset <= num_bytes) ?
00697                   (FAT_BootSec.BytsPerSec - sec_offset) : num_bytes;
00698         for (cnt = sec_offset; cnt < (sec_offset + n_bytes); cnt++) {
00699             FATBuffer[cnt] = *buffer;
00700             buffer++;
00701         }
00702         MS_BulkSend(sec_num, 1, FATBuffer);
00703         tot_bytes_written += n_bytes;
00704         clus_offset       += n_bytes;
00705         num_bytes         -= n_bytes;
00706         sec_num++;
00707     }
00708     if (num_bytes / FAT_BootSec.BytsPerSec) {
00709         num_sec = num_bytes / FAT_BootSec.BytsPerSec;
00710         MS_BulkSend(sec_num, num_sec, buffer);
00711         buffer            += (num_sec * FAT_BootSec.BytsPerSec);
00712         tot_bytes_written += (num_sec * FAT_BootSec.BytsPerSec);
00713         clus_offset       += (num_sec * FAT_BootSec.BytsPerSec);
00714         num_bytes         -= (num_sec * FAT_BootSec.BytsPerSec);
00715         sec_num           += num_sec;
00716     }
00717     if (num_bytes) {
00718         MS_BulkRecv(sec_num, 1, FATBuffer);
00719 
00720         for (cnt = 0; cnt < num_bytes; cnt++) {
00721             FATBuffer[cnt] = *buffer;
00722             buffer++;
00723         }
00724         MS_BulkSend(sec_num, 1, FATBuffer);
00725         tot_bytes_written += num_bytes;
00726     }
00727     return (tot_bytes_written);
00728 }
00729 
00730 /*
00731 **************************************************************************************************************
00732 *                                              GET NEXT CLUSTER
00733 *
00734 * Description: This function returns next cluster of the current cluster in the cluster chain. If the current
00735 *              cluster is the last cluster then this function returns 0
00736 *
00737 * Arguments  : clus_no    The cluster number for which the next cluster to be found
00738 *
00739 * Returns    : next_clus  if the current cluster is not the last cluster
00740 *              0          if the current cluster is the last cluster
00741 *                         Note: In practical cluster number 0 doesn't exist
00742 *
00743 **************************************************************************************************************
00744 */
00745 
00746 USB_INT16U  FAT_GetNextClus (USB_INT16U  clus_no)
00747 {
00748     USB_INT32U  sec_num;
00749     USB_INT32U  ent_offset;
00750     USB_INT16U  next_clus;
00751 
00752                                           /* Get the sector number in the FAT that contains current cluster */
00753     sec_num = FAT_BootSec.RsvdSecCnt + ((clus_no * 2) / FAT_BootSec.BytsPerSec);
00754                                    /* Get the sector offset in the FAT where the current cluster is located */
00755     ent_offset = (clus_no * 2) % FAT_BootSec.BytsPerSec; 
00756     MS_BulkRecv(sec_num, 1, FATBuffer);                          /* Read that sector                        */
00757     next_clus = ReadLE16U(&FATBuffer[ent_offset]);               /* Read the next cluster                   */
00758     if (next_clus >= 0xFFF8 && next_clus <= 0xFFFF) {      /* If that value is in between 0xFFF8 and 0xFFFF */ 
00759         next_clus = 0;                                     /* Current cluster is the end cluster            */
00760     }
00761     return (next_clus);
00762 
00763 }
00764 
00765 /*
00766 **************************************************************************************************************
00767 *                                               GET FREE CLUSTER
00768 *
00769 * Description: This function returns the free cluster if available
00770 *
00771 * Arguments  : None
00772 *
00773 * Returns    : free_clus    if available
00774 *              0            if not available(means the disk is full)
00775 *
00776 **************************************************************************************************************
00777 */
00778 
00779 USB_INT16U  FAT_GetFreeClus (void)
00780 {
00781     USB_INT32U  num_sec;
00782     USB_INT32U  cnt;
00783     USB_INT32U  sec_num;
00784     USB_INT16U  free_clus;
00785 
00786 
00787     sec_num = FAT_BootSec.RsvdSecCnt;
00788     num_sec = FAT_BootSec.FATSz16;
00789     while (sec_num < (FAT_BootSec.RsvdSecCnt + num_sec)) {
00790         MS_BulkRecv(sec_num, 1, FATBuffer);
00791         for (cnt = 0; cnt < FAT_BootSec.BytsPerSec; cnt += 2) {
00792             if (ReadLE16U(&FATBuffer[cnt]) == 0) {
00793                 free_clus = (((sec_num - FAT_BootSec.RsvdSecCnt) * FAT_BootSec.BytsPerSec) + cnt) / 2;
00794                 return (free_clus);
00795             }
00796         }
00797         sec_num++;
00798     }
00799     return (0);
00800 }
00801 
00802 /*
00803 **************************************************************************************************************
00804 *                                       UPDATE FILE ALLOCATION TABLE
00805 *
00806 * Description: This function updates the file allocation table
00807 *
00808 * Arguments  : curr_clus    Offset of the current cluster number in the file allocation table
00809 *              value        Value with which this offset to be updated
00810 *
00811 * Returns    : None
00812 *
00813 **************************************************************************************************************
00814 */
00815 
00816 void  FAT_UpdateFAT (USB_INT16U  curr_clus,
00817                      USB_INT16U  value)
00818 {
00819     USB_INT32U  sec_num;
00820     USB_INT32U  sec_offset;
00821     
00822     sec_num = FAT_BootSec.RsvdSecCnt + (curr_clus * 2) / FAT_BootSec.BytsPerSec;
00823     sec_offset = (curr_clus * 2) % FAT_BootSec.BytsPerSec;
00824     
00825     MS_BulkRecv(sec_num, 1, FATBuffer);
00826     WriteLE16U(&FATBuffer[sec_offset], value);
00827     MS_BulkSend(sec_num, 1, FATBuffer);
00828 }
00829 
00830 /*
00831 **************************************************************************************************************
00832 *                                              UPDATE THE FILE ENTRY
00833 *
00834 * Description: This function updates the file entry that is located in the root directory
00835 *
00836 * Arguments  : entry    Pointer to the FILE ENTRY structure which contains the information about the file
00837 *
00838 * Returns    : None
00839 *
00840 **************************************************************************************************************
00841 */
00842 
00843 void  FAT_UpdateEntry (FILE_ENTRY  *entry)
00844 {
00845     USB_INT32U  sec_num;
00846     USB_INT32U  offset;
00847     
00848     sec_num = entry->EntrySec;
00849     offset  = entry->EntrySecOffset;
00850     MS_BulkRecv(sec_num, 1, FATBuffer);
00851     WriteLE32U(&FATBuffer[offset + 28], entry->FileSize);
00852     MS_BulkSend(sec_num, 1, FATBuffer);
00853 }
00854 
00855 /*
00856 **************************************************************************************************************
00857 *                                              CREATING AN ENTRY
00858 *
00859 * Description: This function creates a file entry in the root directory if the file does not exist
00860 *
00861 * Arguments  : ent_name_given    The file name with which the entry is to be created
00862 *              entry             Pointer to FILE ENTRY structure
00863 *
00864 * Returns    : OK                If the entry already exists or successfully created if it doesn't exists
00865 *              ERROR             If failed to create the entry
00866 *
00867 **************************************************************************************************************
00868 */
00869 
00870 USB_INT32S  FAT_CreateEntry (USB_INT08U  *ent_name_given,
00871                              FILE_ENTRY  *entry)
00872 {
00873     USB_INT32S  rc;
00874 
00875 
00876     rc = FAT_FindEntry(ent_name_given, entry);        /* Find for the given file name in the root directory */
00877     if (rc == MATCH_FOUND) {                          /* If match found, return                             */
00878         return (rc);
00879     } else {
00880         rc = FAT_GetFreeEntry(entry);                 /* Else get a free entry from the root directory      */
00881         if (rc != OK) {
00882             return (rc);
00883         } else {
00884             FAT_PutSFN(ent_name_given, entry);        /* Store the given short file name in that entry      */
00885             return (rc);
00886         }
00887     }
00888 }
00889 
00890 /*
00891 **************************************************************************************************************
00892 *                                                GET GREE ENTRY
00893 *
00894 * Description: This function searches for a free entry in the root directory. If a free entry is found, the
00895 *              sector number and sector offset where the entry is located will be stored
00896 *
00897 * Arguments  : entry    Pointer to FILE_ENTRY structure
00898 *
00899 * Returns    : OK       If a free entry is found
00900 *              ERROR    If no free entry is found
00901 *
00902 **************************************************************************************************************
00903 */
00904 
00905 USB_INT32S  FAT_GetFreeEntry (FILE_ENTRY  *entry)
00906 {
00907               USB_INT32U   sec_num;
00908     volatile  USB_INT08U  *buf;
00909               USB_INT08U   ent_type;
00910 
00911 
00912     for (sec_num = FAT_BootSec.RootDirStartSec; 
00913          sec_num < (FAT_BootSec.RootDirStartSec + FAT_BootSec.RootDirSec);
00914          sec_num++) {
00915 
00916         MS_BulkRecv(sec_num, 1, FATBuffer);
00917         buf = FATBuffer;
00918         while (buf < (FATBuffer + FAT_BootSec.BytsPerSec)) {
00919             ent_type = FAT_ChkEntType(buf);
00920             if (ent_type == FREE_ENTRY) {
00921                 entry->EntrySec       = sec_num;
00922                 entry->EntrySecOffset = buf - FATBuffer;
00923                 return (OK);
00924             }
00925             if (ent_type == LAST_ENTRY) {
00926                 return (ERR_ROOT_DIR_FULL);
00927             } else {
00928                 buf += 32;
00929             }
00930         }
00931     }
00932     return (ERR_ROOT_DIR_FULL);
00933 }
00934 
00935 /*
00936 **************************************************************************************************************
00937 *                                              PUT SHORT FILE NAME
00938 *
00939 * Description: This function fills the file entry with the short file name given by the user
00940 *
00941 * Arguments  : ent_name_given    File name given by the user
00942 *              entry             Pointer to the FILE_ENTRY structure
00943 *
00944 * Returns    : None
00945 *
00946 **************************************************************************************************************
00947 */
00948 
00949 void  FAT_PutSFN (USB_INT08U  *ent_name_given,
00950                   FILE_ENTRY  *entry)
00951 {
00952     USB_INT32U  idx;
00953 
00954                                            /* Read the sector from root directory containing the free entry */
00955     MS_BulkRecv(entry->EntrySec, 1, FATBuffer);
00956     for (idx = 0; idx < 8; idx++) {        /* Fill the first eight charecters of the entry with file name   */
00957         if (*ent_name_given == '.') {
00958             while (idx < 8) {
00959                 FATBuffer[entry->EntrySecOffset + idx] = 0x20;
00960                 idx++;
00961             }
00962             ent_name_given++;
00963         } else {
00964             FATBuffer[entry->EntrySecOffset + idx] = *ent_name_given;
00965             ent_name_given++;
00966         }
00967     }
00968 
00969     for (idx = 8; idx < 11; idx++) {                      /* Fill the next 3 charecters with file extension */
00970         if (*ent_name_given == '.') {
00971             while (idx < 11) {
00972                 FATBuffer[entry->EntrySecOffset + idx] = 0x20;
00973                 idx++;
00974             }
00975         } else {
00976             FATBuffer[entry->EntrySecOffset + idx] = *ent_name_given;
00977             ent_name_given++;
00978         }
00979     }
00980     FATBuffer[entry->EntrySecOffset + idx] = 0x20;
00981     for (idx = 12; idx < 32; idx++) {                           /* Fill all the remaining bytes with 0's    */
00982         FATBuffer[entry->EntrySecOffset + idx] = 0;
00983     }
00984     MS_BulkSend(entry->EntrySec, 1, FATBuffer);                 /* Write the sector into the root directory */
00985 }
00986 
00987 /*
00988 **************************************************************************************************************
00989 *                                                  FILE CLOSE
00990 *
00991 * Description: This function closes the opened file by making all the elements of FILE_ENTRY structure to 0
00992 *
00993 * Arguments  : fd    File descriptor which points to the file to be closed
00994 *
00995 * Returns    : None
00996 *
00997 **************************************************************************************************************
00998 */
00999 
01000 void  FILE_Close (USB_INT32S  fd)
01001 {
01002     FILE_ENTRY  *entry;
01003 
01004 
01005     entry = &FAT_FileEntry[fd-1];
01006     MS_BulkRecv(entry->EntrySec, 1, FATBuffer);
01007     WriteLE32U(&FATBuffer[entry->EntrySecOffset + 28], entry->FileSize);    /* Update the file size         */
01008     MS_BulkSend(entry->EntrySec, 1, FATBuffer);
01009     entry->CurrClus       = 0;
01010     entry->CurrClusOffset = 0;
01011     entry->FileSize       = 0;
01012     entry->EntrySec       = 0;
01013     entry->EntrySecOffset = 0;
01014     entry->FileStatus     = 0;
01015 }
01016 
01017 /*
01018 **************************************************************************************************************
01019 *                                               GET END CLUSTER
01020 *
01021 * Description: This function end cluster in the cluster chain of a cluster
01022 *
01023 * Arguments  : clus_no    Starting cluster of the cluster chain in which end cluster to be found
01024 *
01025 * Returns    : End cluster in the cluster chain
01026 *
01027 **************************************************************************************************************
01028 */
01029 
01030 USB_INT16U  FAT_GetEndClus (USB_INT16U  clus_no)
01031 {
01032     USB_INT16U  next_clus;
01033 
01034 
01035     next_clus = clus_no;
01036     while (next_clus) {
01037         next_clus = FAT_GetNextClus(clus_no);
01038         if (next_clus) {
01039             clus_no = next_clus;
01040         }
01041     }
01042     return (clus_no);
01043 }