/****************************************************************************
 * fs/romfs/fs_romfs.h
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __FS_ROMFS_FS_ROMFS_H
#define __FS_ROMFS_FS_ROMFS_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <stdint.h>
#include <stdbool.h>

#include <nuttx/fs/dirent.h>

#include "inode/inode.h"

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Volume header (multi-byte values are big-endian) */

#define ROMFS_VHDR_ROM1FS   0  /*  0-7:  "-rom1fs-" */
#define ROMFS_VHDR_SIZE     8  /*  8-11: Number of accessible bytes in this fs. */
#define ROMFS_VHDR_CHKSUM  12  /* 12-15: Checksum of the first 512 bytes. */
#define ROMFS_VHDR_VOLNAME 16  /* 16-..: Zero terminated volume name, padded to
                                *        16 byte boundary. */

#define ROMFS_VHDR_MAGIC   "-rom1fs-"

/* File header offset (multi-byte values are big-endian) */

#define ROMFS_FHDR_NEXT     0  /*  0-3:  Offset of the next file header
                                *        (zero if no more files) */
#define ROMFS_FHDR_INFO     4  /*  4-7:  Info for directories/hard links/
                                *        devices */
#define ROMFS_FHDR_SIZE     8  /*  8-11: Size of this file in bytes */
#define ROMFS_FHDR_CHKSUM  12  /* 12-15: Checksum covering the meta data,
                                *        including the file name, and
                                *        padding. */
#define ROMFS_FHDR_NAME    16  /* 16-..: Zero terminated volume name, padded
                                *        to 16 byte boundary. */

/* Bits 0-3 of the rf_next offset provide mode information.  These are the
 * values specified in
 */

#define RFNEXT_MODEMASK    7    /* Bits 0-2: Mode; bit 3: Executable */
#define RFNEXT_ALLMODEMASK 15   /* Bits 0-3: All mode bits */
#define RFNEXT_OFFSETMASK (~15) /* Bits n-3: Offset to next entry */

#define RFNEXT_HARDLINK    0    /* rf_info = Link destination file header */
#define RFNEXT_DIRECTORY   1    /* rf_info = First file's header */
#define RFNEXT_FILE        2    /* rf_info = Unused, must be zero */
#define RFNEXT_SOFTLINK    3    /* rf_info = Unused, must be zero */
#define RFNEXT_BLOCKDEV    4    /* rf_info = 16/16 bits major/minor number */
#define RFNEXT_CHARDEV     5    /* rf_info = 16/16 bits major/minor number */
#define RFNEXT_SOCKET      6    /* rf_info = Unused, must be zero */
#define RFNEXT_FIFO        7    /* rf_info = Unused, must be zero */
#define RFNEXT_EXEC        8    /* Modifier of RFNEXT_DIRECTORY and RFNEXT_FILE */

#define IS_MODE(rfn,mode)  ((((uint32_t)(rfn))&RFNEXT_MODEMASK)==(mode))
#define IS_HARDLINK(rfn)   IS_MODE(rfn,RFNEXT_HARDLINK)
#define IS_DIRECTORY(rfn)  IS_MODE(rfn,RFNEXT_DIRECTORY)
#define IS_FILE(rfn)       IS_MODE(rfn,RFNEXT_FILE)
#define IS_SOFTLINK(rfn)   IS_MODE(rfn,RFNEXT_SOFTLINK)
#define IS_BLOCKDEV(rfn)   IS_MODE(rfn,RFNEXT_BLOCKDEV)
#define IS_CHARDEV(rfn)    IS_MODE(rfn,RFNEXT_CHARDEV)
#define IS_SOCKET(rfn)     IS_MODE(rfn,RFNEXT_SOCKET)
#define IS_FIFO(rfn)       IS_MODE(rfn,RFNEXT_FIFO)
#define IS_EXECUTABLE(rfn) (((rfn) & RFNEXT_EXEC) != 0)

/* RFNEXT_SOFTLINK, RFNEXT_BLOCKDEV, RFNEXT_CHARDEV, RFNEXT_SOCKET, and
 * RFNEXT_FIFO are not presently supported in NuttX.
 */

/* Alignment macros */

#define ROMFS_ALIGNMENT       16
#define ROMFS_MAXPADDING      (ROMFS_ALIGNMENT-1)
#define ROMFS_ALIGNMASK       (~ROMFS_MAXPADDING)
#define ROMFS_ALIGNUP(addr)   ((((uint32_t)(addr))+ROMFS_MAXPADDING)&ROMFS_ALIGNMASK)
#define ROMFS_ALIGNDOWN(addr) (((uint32_t)(addr))&ROMFS_ALIGNMASK)

/* Offset and sector conversions */

#define SEC_NDXMASK(r)       ((r)->rm_hwsectorsize - 1)
#define SEC_NSECTORS(r,o)    ((o) / (r)->rm_hwsectorsize)
#define SEC_ALIGN(r,o)       ((o) & ~SEC_NDXMASK(r))

/* Maximum numbr of links that will be followed before we decide that there
 * is a problem.
 */

#define ROMF_MAX_LINKS 64

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* This structure represents the overall mountpoint state.  An instance of
 * this structure is retained as inode private data on each mountpoint that
 * is mounted with a fat32 filesystem.
 */

struct romfs_file_s;
struct romfs_mountpt_s
{
  struct inode        *rm_blkdriver; /* The block driver inode that hosts the FAT32 fs */
  struct romfs_file_s *rm_head;      /* A list to all files opened on this mountpoint */

  bool     rm_mounted;              /* true: The file system is ready */
  uint16_t rm_hwsectorsize;         /* HW: Sector size reported by block driver */
  sem_t    rm_sem;                  /* Used to assume thread-safe access */
  uint32_t rm_rootoffset;           /* Saved offset to the first root directory entry */
  uint32_t rm_hwnsectors;           /* HW: The number of sectors reported by the hardware */
  uint32_t rm_volsize;              /* Size of the ROMFS volume */
  uint32_t rm_cachesector;          /* Current sector in the rm_buffer */
  uint8_t *rm_xipbase;              /* Base address of directly accessible media */
  uint8_t *rm_buffer;               /* Device sector buffer, allocated if rm_xipbase==0 */
};

/* This structure represents on open file under the mountpoint.  An instance
 * of this structure is retained as struct file specific information on each
 * opened file.
 */

struct romfs_file_s
{
  FAR struct romfs_file_s *rf_next; /* Retained in a singly linked list */
  uint32_t rf_startoffset;          /* Offset to the start of the file data */
  uint32_t rf_size;                 /* Size of the file in bytes */
  uint32_t rf_cachesector;          /* Current sector in the rf_buffer */
  uint8_t *rf_buffer;               /* File sector buffer, allocated if rm_xipbase==0 */
  uint8_t rf_type;                  /* File type (for fstat()) */
};

/* This structure is used internally for describing the result of
 * walking a path
 */

struct romfs_dirinfo_s
{
  /* These values describe the directory containing the terminal
   * path component (of the terminal component itself if it is
   * a directory.
   */

  struct fs_romfsdir_s rd_dir;    /* Describes directory. */

  /* Values from the ROMFS file entry */

  uint32_t rd_next;               /* Offset of the next file header+flags */
  uint32_t rd_size;               /* Size (if file) */
};

/****************************************************************************
 * Public Data
 ****************************************************************************/

#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

int  romfs_semtake(FAR struct romfs_mountpt_s *rm);
void romfs_semgive(FAR struct romfs_mountpt_s *rm);
int  romfs_hwread(FAR struct romfs_mountpt_s *rm, FAR uint8_t *buffer,
       uint32_t sector, unsigned int nsectors);
int  romfs_filecacheread(FAR struct romfs_mountpt_s *rm,
       FAR struct romfs_file_s *rf, uint32_t sector);
int  romfs_hwconfigure(FAR struct romfs_mountpt_s *rm);
int  romfs_fsconfigure(FAR struct romfs_mountpt_s *rm);
int  romfs_fileconfigure(FAR struct romfs_mountpt_s *rm,
       FAR struct romfs_file_s *rf);
int  romfs_checkmount(FAR struct romfs_mountpt_s *rm);
int  romfs_finddirentry(FAR struct romfs_mountpt_s *rm,
       FAR struct romfs_dirinfo_s *dirinfo,
       FAR const char *path);
int  romfs_parsedirentry(FAR struct romfs_mountpt_s *rm,
       uint32_t offset, FAR uint32_t *poffset, FAR uint32_t *pnext,
       FAR uint32_t *pinfo, FAR uint32_t *psize);
int  romfs_parsefilename(FAR struct romfs_mountpt_s *rm, uint32_t offset,
       FAR char *pname);
int  romfs_datastart(FAR struct romfs_mountpt_s *rm, uint32_t offset,
       FAR uint32_t *start);

#undef EXTERN
#if defined(__cplusplus)
}
#endif

#endif /* __FS_ROMFS_FS_ROMFS_H */