Nut/OS  4.10.3
API Reference
phatvol.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005-2006 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  */
00032 
00089 #include <dev/blockdev.h>
00090 
00091 #include <sys/event.h>
00092 
00093 #include <fs/dospart.h>
00094 #include <fs/phatio.h>
00095 #include <fs/phatutil.h>
00096 #include <fs/phatvol.h>
00097 
00098 #include <errno.h>
00099 #include <stdlib.h>
00100 #include <string.h>
00101 #include <memdebug.h>
00102 
00103 
00104 #if 0
00105 /* Use for local debugging. */
00106 #define NUTDEBUG
00107 #include <stdio.h>
00108 #include <fs/phatdbg.h>
00109 #endif
00110 
00115 
00123 static uint32_t PhatCountFreeClusters(NUTDEVICE * dev)
00124 {
00125     uint32_t rc = 0;
00126     uint32_t i = 2;
00127     uint32_t link;
00128     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00129 
00130     if (vol->vol_type == 32) {
00131         while (i < vol->vol_last_clust) {
00132             if (Phat32GetClusterLink(dev, i, &link)) {
00133                 break;
00134             }
00135             if (link == 0) {
00136                 rc++;
00137             }
00138             i++;
00139         }
00140     } else if (vol->vol_type == 16) {
00141         while (i < vol->vol_last_clust) {
00142             if (Phat16GetClusterLink(dev, i, &link)) {
00143                 break;
00144             }
00145             if (link == 0) {
00146                 rc++;
00147             }
00148             i++;
00149         }
00150     } else {
00151         while (i < vol->vol_last_clust) {
00152             if (Phat12GetClusterLink(dev, i, &link)) {
00153                 break;
00154             }
00155             if (link == 0) {
00156                 rc++;
00157             }
00158             i++;
00159         }
00160     }
00161     return rc;
00162 }
00163 
00186 int PhatVolMount(NUTDEVICE * dev, NUTFILE * blkmnt, uint8_t part_type)
00187 {
00188     PHATVOL *vol;
00189     PHATVBR *vbr;
00190     BLKPAR_INFO pari;
00191     int sbn;
00192     NUTDEVICE *blkdev = blkmnt->nf_dev;
00193 
00194     /*
00195      * Allocate the volume information structure 
00196      */
00197     if ((dev->dev_dcb = malloc(sizeof(PHATVOL))) == 0) {
00198         return -1;
00199     }
00200     vol = (PHATVOL *) memset(dev->dev_dcb, 0, sizeof(PHATVOL));
00201 
00202     /*
00203      * Determine the PHAT type.
00204      */
00205     switch (part_type) {
00206     case PTYPE_FAT32:
00207     case PTYPE_FAT32_LBA:
00208         vol->vol_type = 32;
00209         break;
00210     case PTYPE_FAT16:
00211     case PTYPE_FAT16_BIG:
00212     case PTYPE_FAT16_LBA:
00213         vol->vol_type = 16;
00214         break;
00215     case PTYPE_FAT12:
00216         vol->vol_type = 12;
00217         break;
00218     }
00219 
00220     /*
00221      * Query information from the block device driver.
00222      */
00223     pari.par_nfp = blkmnt;
00224     if ((*blkdev->dev_ioctl) (blkdev, NUTBLKDEV_INFO, &pari)) {
00225         free(vol);
00226         errno = ENODEV;
00227         return -1;
00228     }
00229 #if PHAT_SECTOR_BUFFERS
00230     for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00231         if ((vol->vol_buf[sbn].sect_data = malloc(pari.par_blksz)) == NULL) {
00232             PhatVolUnmount(dev);
00233             return -1;
00234         }
00235         vol->vol_buf[sbn].sect_num = (uint32_t)-1;
00236     }
00237 #else
00238     vol->vol_buf[0].sect_data = pari.par_blkbp;
00239 #endif
00240     sbn = 0;
00241 
00242     /*
00243      * We use PhatSectorRead() instead of PhatSectorLoad() for our 
00244      * very first read to properly initialize the caching status.
00245      */
00246     if (PhatSectorRead(blkmnt, 0, vol->vol_buf[sbn].sect_data)) {
00247         PhatVolUnmount(dev);
00248         return -1;
00249     }
00250     vol->vol_buf[sbn].sect_num = 0;
00251     vbr = (PHATVBR *) vol->vol_buf[sbn].sect_data;
00252 
00253     /*
00254      * PHAT32 doesn't have a fixed root directory. At this point
00255      * we reliably know wether we got PHAT32 or not. After having
00256      * determined the total number of clusters later, we can check
00257      * for PHAT12 or PHAT16.
00258      */
00259     if (vol->vol_type == 0 && vbr->bios_rootsz == 0) {
00260         vol->vol_type = 32;
00261     }
00262 
00263     /* Convert to PHAT12/PHAT16 layout. */
00264     if (vol->vol_type != 32) {
00265         memcpy(&vbr->boot_drive, &vbr->bios_tabsz_big, 26);
00266         memset(&vbr->bios_tabsz_big, 0, 28);
00267     }
00268 #ifdef NUTDEBUG
00269     PhatDbgVbr(stdout, "Volume Boot Record", vbr);
00270 #endif
00271 
00272     /*
00273      * Verify the VBR signature.
00274      */
00275     if (vol->vol_buf[sbn].sect_data[510] != 0x55 || vol->vol_buf[sbn].sect_data[511] != 0xAA) {
00276         PhatVolUnmount(dev);
00277         errno = ENODEV;
00278         return -1;
00279     }
00280 
00281     /*
00282      * Make sure we got a valid media type.
00283      */
00284     if (vbr->bios_media != 0xF0 && vbr->bios_media < 0xF8) {
00285         PhatVolUnmount(dev);
00286         errno = ENODEV;
00287         return -1;
00288     }
00289 
00290     /*
00291      * Examine the informations found in the boot record.
00292      */
00293     /* Bytes per sector. */
00294     vol->vol_sectsz = vbr->bios_sectsz;
00295     if (vol->vol_sectsz < 512 || vol->vol_sectsz & 0xFF) {
00296         PhatVolUnmount(dev);
00297         errno = ENODEV;
00298         return -1;
00299     }
00300     /* Sectors per cluster. */
00301     if ((vol->vol_clustsz = vbr->bios_clustsz) == 0) {
00302         PhatVolUnmount(dev);
00303         errno = ENODEV;
00304         return -1;
00305     }
00306     /* Allocation table size and position. */
00307     if (vbr->bios_tabsz) {
00308         vol->vol_tabsz = vbr->bios_tabsz;
00309     } else {
00310         vol->vol_tabsz = vbr->bios_tabsz_big;
00311     }
00312     vol->vol_tab_sect[0] = vbr->bios_rsvd_sects;
00313     if (vbr->bios_ntabs > 1) {
00314         vol->vol_tab_sect[1] = vol->vol_tab_sect[0] + vol->vol_tabsz;
00315     }
00316     /* Root directory size and position. */
00317     vol->vol_rootsz = (vbr->bios_rootsz * sizeof(PHATDIRENT) +  /* */
00318                        vol->vol_sectsz - 1) / vol->vol_sectsz;
00319     vol->vol_root_sect = vbr->bios_rsvd_sects + /* */
00320         vbr->bios_ntabs * vol->vol_tabsz;
00321     if (vol->vol_type == 32) {
00322         vol->vol_root_clust = vbr->bios_root_clust;
00323     }
00324     /* First data sector and number of data clusters. */
00325     vol->vol_data_sect = vol->vol_root_sect + vol->vol_rootsz;
00326     if (vbr->bios_volsz) {
00327         vol->vol_last_clust = vbr->bios_volsz - vol->vol_data_sect;
00328     } else {
00329         vol->vol_last_clust = vbr->bios_volsz_big - vol->vol_data_sect;
00330     }
00331     vol->vol_last_clust /= vol->vol_clustsz;
00332     /* First cluster number is 2. */
00333     vol->vol_last_clust += 2;
00334 
00335     /* 
00336      * Having calculated the total number of clusters allows us to 
00337      * distinguish between PHAT12 and PHAT16. 
00338      */
00339     if (vol->vol_type == 0) {
00340         if (vol->vol_last_clust > 4086) {
00341             vol->vol_type = 16;
00342         }
00343         else {
00344             vol->vol_type = 12;
00345         }
00346     }
00347 #ifdef NUTDEBUG
00348     printf("\n%lu cluster -> PHAT%d\n", vol->vol_last_clust, vol->vol_type);
00349 #endif
00350 
00351     dev->dev_icb = blkmnt;
00352 
00353     /* Initialize mutual exclusion semaphores. */
00354     NutEventPost(&vol->vol_fsmutex);
00355     NutEventPost(&vol->vol_iomutex);
00356 
00357     vol->vol_numfree = PhatCountFreeClusters(dev);
00358 
00359     return 0;
00360 }
00361 
00372 int PhatVolUnmount(NUTDEVICE * dev)
00373 {
00374     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00375 
00376     if (vol) {
00377 #if PHAT_SECTOR_BUFFERS
00378         int sbn;
00379 
00380         for (sbn = 0; sbn < PHAT_SECTOR_BUFFERS; sbn++) {
00381             if (vol->vol_buf[sbn].sect_data) {
00382                 free(vol->vol_buf[sbn].sect_data);
00383             }
00384         }
00385 #endif
00386         free(vol);
00387     }
00388     return 0;
00389 }
00390 
00391 /*
00392  * \brief Get first sector of a specified cluster.
00393  *
00394  * \param nfp   File descriptor.
00395  * \param clust Specified cluster.
00396  */
00397 uint32_t PhatClusterSector(NUTFILE * nfp, uint32_t clust)
00398 {
00399     NUTDEVICE *dev = nfp->nf_dev;
00400     PHATVOL *vol = (PHATVOL *) dev->dev_dcb;
00401 
00402     /*
00403      * If the file descriptor specifies the root directory, then the first
00404      * sector is located after the reserved sectors and the allocation table.
00405      */
00406     if (IsFixedRootDir(nfp)) {
00407         return vol->vol_root_sect;
00408     }
00409 
00410     /*
00411      * For all other files/directories the sector is located in the data
00412      * area of the volume.
00413      */
00414     if (clust >= 2) {
00415         clust -= 2;
00416     }
00417     return vol->vol_data_sect + clust * vol->vol_clustsz;
00418 }
00419