static int cpuload_open(FAR struct file *filep, FAR const char *relpath,
                      int oflags, mode_t mode)
{
  FAR struct cpuload_file_s *attr;

  fvdbg("Open '%s'\n", relpath);

  /* PROCFS is read-only.  Any attempt to open with any kind of write
   * access is not permitted.
   *
   * REVISIT:  Write-able proc files could be quite useful.
   */

  if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
    {
      fdbg("ERROR: Only O_RDONLY supported\n");
      return -EACCES;
    }

  /* "cpuload" is the only acceptable value for the relpath */

  if (strcmp(relpath, "cpuload") != 0)
    {
      fdbg("ERROR: relpath is '%s'\n", relpath);
      return -ENOENT;
    }

  /* Allocate a container to hold the file attributes */

  attr = (FAR struct cpuload_file_s *)kmm_zalloc(sizeof(struct cpuload_file_s));
  if (!attr)
    {
      fdbg("ERROR: Failed to allocate file attributes\n");
      return -ENOMEM;
    }

  /* Save the attributes as the open-specific state in filep->f_priv */

  filep->f_priv = (FAR void *)attr;
  return OK;
}
Exemple #2
0
static int romfs_close(FAR struct file *filep)
{
  FAR struct romfs_mountpt_s *rm;
  FAR struct romfs_file_s    *rf;
  int                         ret = OK;

  fvdbg("Closing\n");

  /* Sanity checks */

  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);

  /* Recover our private data from the struct file instance */

  rf = filep->f_priv;
  rm = filep->f_inode->i_private;

  DEBUGASSERT(rm != NULL);

  /* Do not check if the mount is healthy.  We must support closing of
   * the file even when there is healthy mount.
   */

  /* Deallocate the memory structures created when the open method
   * was called.
   *
   * Free the sector buffer that was used to manage partial sector
   * accesses.
   */

  if (!rm->rm_xipbase && rf->rf_buffer)
    {
      kfree(rf->rf_buffer);
    }

  /* Then free the file structure itself. */

  kfree(rf);
  filep->f_priv = NULL;
  return ret;
}
static int lpc43_pagewrite(FAR struct lpc43_dev_s *priv, FAR uint8_t *dest,
                           FAR const uint8_t *src, size_t nbytes)
{
  int result;

  /* Write FLASH pages:
   *
   * dest   - Specifies the first address to be programmed or erased, either in
   *          the SPIFI memory area or as a zero-based device address.  It must
   *          be at an offset that is an exact multiple of the erase block size.
   * length - The number of bytes to be programmed or erased
   */

  priv->operands.dest   = dest;
  priv->operands.length = nbytes;

  fvdbg("SPIFI_PROGRAM: src=%p dest=%p length=%d\n",
        src, priv->operands.dest, priv->operands.length);

  result = SPIFI_PROGRAM(priv, &priv->rom, src, &priv->operands);
  if (result != 0)
    {
      fdbg("ERROR: SPIFI_PROGRAM failed: %05x\n", result);
      return -EIO;
    }

  /* Verify the data that was written by comparing to the data visible in the
   * SPIFI address space.
   */

#ifdef CONFIG_SPIFI_VERIFY
  result = lpc43_verify(priv, dest, src, nbytes);
  if (result != 0)
    {
      fdbg("ERROR: lpc43_verify failed: %05x\n", result);
      return -EIO;
    }
#endif

  return OK;
}
Exemple #4
0
static ssize_t procfs_write(FAR struct file *filep, FAR const char *buffer,
                           size_t buflen)
{
  FAR struct procfs_file_s *handler;
  ssize_t ret = 0;

  fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);

  /* Recover our private data from the struct file instance */

  handler = (FAR struct procfs_file_s *)filep->f_priv;
  DEBUGASSERT(handler);

  /* Call the handler's read routine */

  if (handler->procfsentry->ops->write)
    {
      ret = handler->procfsentry->ops->write(filep, buffer, buflen);
    }

  return ret;
}
Exemple #5
0
int nxffs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
                  FAR struct fs_dirent_s *dir)
{
  struct nxffs_volume_s *volume;
  int ret;

  fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL");

  /* Sanity checks */

  DEBUGASSERT(mountpt != NULL && mountpt->i_private != NULL);

  /* Recover the file system state from the NuttX inode instance */

  volume = mountpt->i_private;
  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      goto errout;
    }

  /* The requested directory must be the volume-relative "root" directory */

  if (relpath && relpath[0] != '\0')
    {
      ret = -ENOENT;
      goto errout_with_semaphore;
    }

  /* Set the offset to the offset to the first valid inode */

  dir->u.nxffs.nx_offset = volume->inoffset;
  ret = OK;

errout_with_semaphore:
  sem_post(&volume->exclsem);
errout:
  return ret;
}
Exemple #6
0
static void uart_pollnotify(FAR uart_dev_t *dev, pollevent_t eventset)
{
    int i;

    for (i = 0; i < CONFIG_SERIAL_NPOLLWAITERS; i++)
    {
        struct pollfd *fds = dev->fds[i];
        if (fds)
        {
#ifdef CONFIG_SERIAL_REMOVABLE
            fds->revents |= ((fds->events | (POLLERR|POLLHUP)) & eventset);
#else
            fds->revents |= (fds->events & eventset);
#endif
            if (fds->revents != 0)
            {
                fvdbg("Report events: %02x\n", fds->revents);
                sem_post(fds->sem);
            }
        }
    }
}
Exemple #7
0
static int tiva_erase(FAR struct mtd_dev_s *dev, off_t startblock, size_t nblocks)
{

#if !defined(CONFIG_QEMU_SRAM) &&  !defined(CONFIG_QEMU_SDRAM)
	int curpage;
	uint32_t pageaddr;
#endif

	DEBUGASSERT(nblocks <= TIVA_VIRTUAL_NPAGES);

#if defined(CONFIG_QEMU_SRAM) || defined(CONFIG_QEMU_SDRAM)
	/* Qemu doesnt implement tiva flash memory controller.
	 * Hence set the erase state to 0xFF using memset
	 */
	memset((void *)(TIVA_VIRTUAL_BASE + startblock * TIVA_FLASH_PAGESIZE), 0xFF, nblocks * TIVA_FLASH_PAGESIZE);
#else

	for (curpage = startblock; curpage < nblocks; curpage++) {
		pageaddr = TIVA_VIRTUAL_BASE + curpage * TIVA_FLASH_PAGESIZE;

		fvdbg("Erase page at %08x\n", pageaddr);

		/* set page address */

		putreg32((pageaddr << FLASH_FMA_OFFSET_SHIFT) & FLASH_FMA_OFFSET_MASK, TIVA_FLASH_FMA);

		/* set flash write key and erase bit */

		putreg32(FLASH_FMC_WRKEY | FLASH_FMC_ERASE, TIVA_FLASH_FMC);

		/* wait until erase has finished */

		while (getreg32(TIVA_FLASH_FMC) & FLASH_FMC_ERASE) ;
	}
#endif

	return OK;
}
static void lpc43_cacheerase(struct lpc43_dev_s *priv, off_t sector)
{
  FAR uint8_t *dest;

  /* First, make sure that the erase block containing the 512 byte sector is in
   * the cache.
   */

  dest = lpc43_cacheread(priv, sector);

  /* Erase the block containing this sector if it is not already erased.
   * The erased indicated will be cleared when the data from the erase sector
   * is read into the cache and set here when we erase the block.
   */

  if (!IS_ERASED(priv))
    {
      off_t blkno  = sector >> (SPIFI_BLKSHIFT - SPIFI_512SHIFT);
      fvdbg("sector: %ld blkno: %d\n", sector, blkno);

      lpc43_blockerase(priv, blkno);
      SET_ERASED(priv);
    }
Exemple #9
0
static int skel_open(FAR struct file *filep, FAR const char *relpath,
                      int oflags, mode_t mode)
{
  FAR struct skel_file_s *priv;

  fvdbg("Open '%s'\n", relpath);

  /* PROCFS is read-only.  Any attempt to open with any kind of write
   * access is not permitted.
   *
   * REVISIT:  Write-able proc files could be quite useful.
   */

  if (((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0) &&
      (skel_procfsoperations.write == NULL))
    {
      fdbg("ERROR: Only O_RDONLY supported\n");
      return -EACCES;
    }

  /* Allocate a container to hold the task and attribute selection */

  priv = (FAR struct skel_file_s *)kmm_zalloc(sizeof(struct skel_file_s));
  if (!priv)
    {
      fdbg("ERROR: Failed to allocate file attributes\n");
      return -ENOMEM;
    }

  /* TODO: Initialize the context specific data here */


  /* Save the index as the open-specific state in filep->f_priv */

  filep->f_priv = (FAR void *)priv;
  return OK;
}
Exemple #10
0
int nxffs_statfs(FAR struct inode *mountpt, FAR struct statfs *buf)
{
  FAR struct nxffs_volume_s *volume;
  int ret;

  fvdbg("Entry\n");

  /* Sanity checks */

  DEBUGASSERT(mountpt && mountpt->i_private);

  /* Get the mountpoint private data from the NuttX inode structure */

  volume = mountpt->i_private;
  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      goto errout;
    }

  /* Fill in the statfs info
   *
   * REVISIT: Need f_bfree, f_bavail, f_files, f_ffree calculation
   */

  memset(buf, 0, sizeof(struct statfs));
  buf->f_type    = NXFFS_MAGIC;
  buf->f_bsize   = volume->geo.blocksize;
  buf->f_blocks  = volume->nblocks;
  buf->f_namelen = volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR - SIZEOF_NXFFS_INODE_HDR;
  ret            = OK;

  sem_post(&volume->exclsem);
errout:
  return ret;
}
Exemple #11
0
static void lpc43_blockerase(struct lpc43_dev_s *priv, off_t sector)
{
  int result;

  /* Erase one block on the chip:
   *
   * dest   - Specifies the first address to be programmed or erased, either in
   *          the SPIFI memory area or as a zero-based device address.  It must
   *          be at an offset that is an exact multiple of the erase block size.
   * length - The number of bytes to be programmed or erased
   */

  priv->operands.dest   = SPIFI_BASE + (sector << SPIFI_BLKSHIFT);
  priv->operands.length = SPIFI_BLKSIZE;

  fvdbg("SPIFI_ERASE: dest=%p length=%d\n",
        priv->operands.dest, priv->operands.length);

  result = SPIFI_ERASE(priv, &priv->rom, &priv->operands);
  if (result != 0)
    {
      fdbg("ERROR: SPIFI_ERASE failed: %05x\n", result);
    }
}
Exemple #12
0
static ssize_t skel_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
	FAR struct skel_file_s *priv;
	ssize_t ret;

	fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);

	/* Recover our private data from the struct file instance */

	priv = (FAR struct skel_file_s *)filep->f_priv;
	DEBUGASSERT(priv);

	/* TODO: Provide the requested data */

	ret = 0;

	/* Update the file offset */

	if (ret > 0) {
		filep->f_pos += ret;
	}

	return ret;
}
Exemple #13
0
int nxffs_nextblock(FAR struct nxffs_volume_s *volume, off_t offset,
                    FAR struct nxffs_blkentry_s *blkentry)
{
  int nmagic;
  int ch;
  int nerased;
  int ret;

  /* Seek to the first FLASH offset provided by the caller. */

  nxffs_ioseek(volume, offset);

  /* Skip the block header */

  if (volume->iooffset < SIZEOF_NXFFS_BLOCK_HDR)
    {
      volume->iooffset = SIZEOF_NXFFS_BLOCK_HDR;
    }

  /* Then begin searching */

  nerased = 0;
  nmagic  = 0;

  for (;;)
    {
      /* Read the next character */

      ch = nxffs_getc(volume, SIZEOF_NXFFS_DATA_HDR - nmagic);
      if (ch < 0)
        {
          fdbg("ERROR: nxffs_getc failed: %d\n", -ch);
          return ch;
        }

      /* Check for another erased byte */

      else if (ch == CONFIG_NXFFS_ERASEDSTATE)
        {
          /* If we have encountered NXFFS_NERASED number of consecutive
           * erased bytes, then presume we have reached the end of valid
           * data.
           */

          if (++nerased >= NXFFS_NERASED)
            {
              fvdbg("No entry found\n");
              return -ENOENT;
            }
        }
      else
        {
          nerased = 0;

          /* Check for the magic sequence indicating the start of an NXFFS
           * data block or start of the next inode. There is the possibility
           * of this magic sequnce occurring in FLASH data.  However, the
           * data block CRC should distinguish between real NXFFS data blocks
           * headers and such false alarms.
           */

          if (ch != g_datamagic[nmagic])
            {
              /* Ooops... this is the not the right character for the magic
               * Sequence.  Check if we need to restart or to cancel the sequence:
               */

              if (ch == g_datamagic[0])
                {
                  nmagic = 1;
                }
              else
                {
                  nmagic = 0;
                }
            }
          else if (nmagic < NXFFS_MAGICSIZE - 1)
            {
              /* We have one more character in the magic sequence */

              nmagic++;
            }

          /* We have found the magic sequence in the FLASH data that may
           * indicate the beginning of an NXFFS data block.
           */

          else
            {
              /* The offset to the header must be 4 bytes before the current
               * FLASH seek location.
               */

              blkentry->hoffset = nxffs_iotell(volume) - NXFFS_MAGICSIZE;

              /* Read the block header and verify the block at that address */

              ret = nxffs_rdblkhdr(volume, blkentry->hoffset, &blkentry->datlen);
              if (ret == OK)
                {
                  fvdbg("Found a valid data block, offset: %d datlen: %d\n",
                        blkentry->hoffset, blkentry->datlen);
                  return OK;
                }

              /* False alarm.. Restore the volume cache position (that was
               * destroyed by nxfs_rdblkhdr()) and keep looking.
               */

              nxffs_ioseek(volume, blkentry->hoffset + NXFFS_MAGICSIZE);
              nmagic = 0;
            }
        }
    }

  /* We won't get here, but to keep some compilers happy: */

  return -ENOENT;
}
Exemple #14
0
ssize_t nxffs_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
  FAR struct nxffs_volume_s *volume;
  FAR struct nxffs_ofile_s *ofile;
  struct nxffs_blkentry_s blkentry;
  ssize_t total;
  size_t available;
  size_t readsize;
  int ret;

  fvdbg("Read %d bytes from offset %d\n", buflen, filep->f_pos);

  /* Sanity checks */

  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);

  /* Recover the open file state from the struct file instance */

  ofile = (FAR struct nxffs_ofile_s *)filep->f_priv;

  /* Recover the volume state from the open file */

  volume = (FAR struct nxffs_volume_s *)filep->f_inode->i_private;
  DEBUGASSERT(volume != NULL);

  /* Get exclusive access to the volume.  Note that the volume exclsem
   * protects the open file list.
   */

  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      ret = -get_errno();
      fdbg("ERROR: sem_wait failed: %d\n", ret);
      goto errout;
    }

  /* Check if the file was opened with read access */

  if ((ofile->oflags & O_RDOK) == 0)
    {
      fdbg("ERROR: File not open for read access\n");
      ret = -EACCES;
      goto errout_with_semaphore;
    }

  /* Loop until all bytes have been read */

  for (total = 0; total < buflen; )
    {
      /* Don't seek past the end of the file */

      if (filep->f_pos >= ofile->entry.datlen)
        {
          /* Return the partial read */

          filep->f_pos = ofile->entry.datlen;
          break;
        }

      /* Seek to the current file offset */

      ret = nxffs_rdseek(volume, &ofile->entry, filep->f_pos, &blkentry);
      if (ret < 0)
        {
          fdbg("ERROR: nxffs_rdseek failed: %d\n", -ret);
          ret = -EACCES;
          goto errout_with_semaphore;
        }

      /* How many bytes are available at this offset */

      available = blkentry.datlen - blkentry.foffset;

      /* Don't read more than we need to */

      readsize = buflen - total;
      if (readsize > available)
        {
          readsize = available;
        }

      /* Read data from that file offset */

      memcpy(&buffer[total], &volume->cache[volume->iooffset], readsize);

      /* Update the file offset */

      filep->f_pos += readsize;
      total        += readsize;
    }

  sem_post(&volume->exclsem);
  return total;

errout_with_semaphore:
  sem_post(&volume->exclsem);
errout:
  return (ssize_t)ret;
}
static int proc_open(FAR struct file *filep, FAR const char *relpath,
                     int oflags, mode_t mode)
{
  FAR struct proc_file_s *procfile;
  FAR const struct proc_node_s *node;
  FAR struct tcb_s *tcb;
  FAR char *ptr;
  irqstate_t flags;
  unsigned long tmp;
  pid_t pid;

  fvdbg("Open '%s'\n", relpath);

  /* PROCFS is read-only.  Any attempt to open with any kind of write
   * access is not permitted.
   *
   * REVISIT:  Write-able proc files could be quite useful.
   */

  if ((oflags & O_WRONLY) != 0 || (oflags & O_RDONLY) == 0)
    {
      fdbg("ERROR: Only O_RDONLY supported\n");
      return -EACCES;
    }

  /* The first segment of the relative path should be a task/thread ID */

  ptr = NULL;
  tmp = strtoul(relpath, &ptr, 10);

  if (!ptr || *ptr != '/')
    {
      fdbg("ERROR: Invalid path \"%s\"\n", relpath);
      return -ENOENT;
    }

  /* Skip over the slash */

  ptr++;

  /* A valid PID would be in the range of 0-32767 (0 is reserved for the
   * IDLE thread).
   */

  if (tmp >= 32768)
    {
      fdbg("ERROR: Invalid PID %ld\n", tmp);
      return -ENOENT;
    }

  /* Now verify that a task with this task/thread ID exists */

  pid = (pid_t)tmp;

  flags = irqsave();
  tcb = sched_gettcb(pid);
  irqrestore(flags);

  if (!tcb)
    {
      fdbg("ERROR: PID %d is no longer valid\n", (int)pid);
      return -ENOENT;
    }

  /* The remaining segments of the relpath should be a well known node in
   * the task/thread tree.
   */

  node = proc_findnode(ptr);
  if (!node)
    {
      fdbg("ERROR: Invalid path \"%s\"\n", relpath);
      return -ENOENT;
    }

  /* The node must be a file, not a directory */

  if (node->dtype != DTYPE_FILE)
    {
      fdbg("ERROR: Path \"%s\" is a directory\n", relpath);
      return -EISDIR;
    }

  /* Allocate a container to hold the task and node selection */

  procfile = (FAR struct proc_file_s *)kzalloc(sizeof(struct proc_file_s));
  if (!procfile)
    {
      fdbg("ERROR: Failed to allocate file container\n");
      return -ENOMEM;
    }

  /* Initialize the file container */

  procfile->pid  = pid;
  procfile->node = node;

  /* Save the index as the open-specific state in filep->f_priv */

  filep->f_priv = (FAR void *)procfile;
  return OK;
}
Exemple #16
0
static int procfs_readdir(struct inode *mountpt, struct fs_dirent_s *dir)
{
  FAR struct procfs_dir_priv_s *priv;
  FAR struct procfs_level0_s *level0;
  FAR struct tcb_s *tcb;
  FAR const char *name = NULL;
  unsigned int index;
  irqstate_t flags;
  pid_t pid;
  int ret = -ENOENT;

  DEBUGASSERT(mountpt && dir && dir->u.procfs);
  priv = dir->u.procfs;

  /* Are we reading the 1st directory level with dynamic PID and static
   * entries?
   */

  if (priv->level == 0)
    {
      level0 = (FAR struct procfs_level0_s *)priv;

      /* Have we reached the end of the PID information */

      index = priv->index;
      if (index >= priv->nentries)
        {
          /* We must report the next static entry ... no more PID entries.
           * skip any entries with wildcards in the first segment of the
           * directory name.
           */

          while (index < priv->nentries + g_procfsentrycount)
            {
              name = g_procfsentries[index - priv->nentries].pathpattern;
              while (*name != '/' && *name != '\0')
                {
                  if (*name == '*' || *name == '[' || *name == '?')
                    {
                      /* Wildcard found.  Skip this entry */

                      index++;
                      name = NULL;
                      break;
                    }

                  name++;
                }

              /* Test if we skipped this entry */

              if (name != NULL)
              {
                /* This entry is okay to report. Test if it has a duplicate
                 * first level name as the one we just reported.  This could
                 * happen in the event of procfs_entry_s such as:
                 *
                 *    fs/smartfs
                 *    fs/nfs
                 *    fs/nxffs
                 */

                name = g_procfsentries[index - priv->nentries].pathpattern;
                if (!level0->lastlen || (strncmp(name, level0->lastread,
                      level0->lastlen) != 0))
                  {
                    /* Not a duplicate, return the first segment of this
                     * entry
                     */

                    break;
                  }
                else
                  {
                    /* Skip this entry ... duplicate 1st level name found */

                    index++;
                  }
              }
            }

          /* Test if we are at the end of the directory */

          if (index >= priv->nentries + g_procfsentrycount)
            {
              /* We signal the end of the directory by returning the special
               * error -ENOENT
               */

              fvdbg("Entry %d: End of directory\n", index);
              ret = -ENOENT;
            }
          else
            {
              /* Report the next static entry */

              level0->lastlen = strcspn(name, "/");
              level0->lastread = name;
              strncpy(dir->fd_dir.d_name, name, level0->lastlen);
              dir->fd_dir.d_name[level0->lastlen] = '\0';

              if (name[level0->lastlen] == '/')
                {
                  dir->fd_dir.d_type = DTYPE_DIRECTORY;
                }
              else
                {
                  dir->fd_dir.d_type = DTYPE_FILE;
                }

              /* Advance to next entry for the next read */

              priv->index = index;
              ret = OK;
            }
        }
#ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
      else
        {
          /* Verify that the pid still refers to an active task/thread */

          pid = level0->pid[index];

          flags = irqsave();
          tcb = sched_gettcb(pid);
          irqrestore(flags);

          if (!tcb)
            {
              fdbg("ERROR: PID %d is no longer valid\n", (int)pid);
              return -ENOENT;
            }

          /* Save the filename=pid and file type=directory */

          dir->fd_dir.d_type = DTYPE_DIRECTORY;
          snprintf(dir->fd_dir.d_name, NAME_MAX+1, "%d", (int)pid);

          /* Set up the next directory entry offset.  NOTE that we could use the
           * standard f_pos instead of our own private index.
           */

          level0->base.index = index + 1;
          ret = OK;
        }
#endif /* CONFIG_FS_PROCFS_EXCLUDE_PROCESS */
    }

    /* Are we reading an intermediate subdirectory? */

  else if (priv->level > 0 && priv->procfsentry == NULL)
    {
      FAR struct procfs_level1_s *level1;

      level1 = (FAR struct procfs_level1_s *) priv;

      /* Test if this entry matches.  We assume all entries of the same
       * subdirectory are listed in order in the procfs_entry array.
       */

      if (strncmp(g_procfsentries[level1->base.index].pathpattern,
              g_procfsentries[level1->firstindex].pathpattern,
              level1->subdirlen) == 0)
        {
          /* This entry matches.  Report the subdir entry */

          name = &g_procfsentries[level1->base.index].pathpattern[
                    level1->subdirlen + 1];
          level1->lastlen = strcspn(name, "/");
          level1->lastread = name;
          strncpy(dir->fd_dir.d_name, name, level1->lastlen);

          /* Some of the search entries contain '**' wildcards.  When we
           * report the entry name, we must remove this wildcard search
           * specifier.
           */

          while (dir->fd_dir.d_name[level1->lastlen - 1] == '*')
            {
              level1->lastlen--;
            }

          dir->fd_dir.d_name[level1->lastlen] = '\0';

          if (name[level1->lastlen] == '/')
            {
              dir->fd_dir.d_type = DTYPE_DIRECTORY;
            }
          else
            {
              dir->fd_dir.d_type = DTYPE_FILE;
            }

          level1->base.index++;
          ret = OK;
        }
      else
        {
          /* No more entries in the subdirectory */

          ret = -ENOENT;
        }
    }
  else
    {
      /* We are performing a directory search of one of the subdirectories
       * and we must let the handler perform the read.
       */

      DEBUGASSERT(priv->procfsentry && priv->procfsentry->ops->readdir);
      ret = priv->procfsentry->ops->readdir(dir);
    }

  return ret;
}
Exemple #17
0
static int procfs_opendir(FAR struct inode *mountpt, FAR const char *relpath,
                          FAR struct fs_dirent_s *dir)
{
  FAR struct procfs_level0_s *level0;
  FAR struct procfs_dir_priv_s *dirpriv;
  FAR void *priv = NULL;
  irqstate_t flags;

  fvdbg("relpath: \"%s\"\n", relpath ? relpath : "NULL");
  DEBUGASSERT(mountpt && relpath && dir && !dir->u.procfs);

  /* The relative must be either:
   *
   * ""      - The top level directory of task/thread IDs
   * "<pid>" - The sub-directory of task/thread attributes
   */

  if (!relpath || relpath[0] == '\0')
    {
      /* The path refers to the top level directory.  Allocate the level0
       * dirent structure.
       */

      level0 = (FAR struct procfs_level0_s *)
         kmm_zalloc(sizeof(struct procfs_level0_s));

      if (!level0)
        {
          fdbg("ERROR: Failed to allocate the level0 directory structure\n");
          return -ENOMEM;
        }

      /* Take a snapshot of all currently active tasks.  Any new tasks
       * added between the opendir() and closedir() call will not be
       * visible.
       *
       * NOTE that interrupts must be disabled throughout the traversal.
       */

#ifndef CONFIG_FS_PROCFS_EXCLUDE_PROCESS
      flags = irqsave();
      sched_foreach(procfs_enum, level0);
      irqrestore(flags);
#else
      level0->base.index = 0;
      level0->base.nentries = 0;
#endif

      /* Initialze lastread entries */

      level0->lastread = "";
      level0->lastlen = 0;
      level0->base.procfsentry = NULL;

      priv = (FAR void *)level0;
    }
  else
    {
      int x, ret;
      int len = strlen(relpath);

      /* Search the static array of procfs_entries */

      for (x = 0; x < g_procfsentrycount; x++)
        {
          /* Test if the path matches this entry's specification */

          if (match(g_procfsentries[x].pathpattern, relpath))
            {
              /* Match found!  Call the handler's opendir routine.  If successful,
               * this opendir routine will create an entry derived from struct
               * procfs_dir_priv_s as dir->u.procfs.
               */

              DEBUGASSERT(g_procfsentries[x].ops && g_procfsentries[x].ops->opendir);
              ret = g_procfsentries[x].ops->opendir(relpath, dir);

              if (ret == OK)
                {
                  DEBUGASSERT(dir->u.procfs);

                  /* Set the procfs_entry handler */

                  dirpriv = (FAR struct procfs_dir_priv_s *)dir->u.procfs;
                  dirpriv->procfsentry = &g_procfsentries[x];
                }

              return ret;
            }

            /* Test for a sub-string match (e.g. "ls /proc/fs") */

          else if (strncmp(g_procfsentries[x].pathpattern, relpath, len) == 0)
            {
              FAR struct procfs_level1_s *level1;

              /* Doing an intermediate directory search */

              /* The path refers to the top level directory.  Allocate the level0
               * dirent structure.
               */

              level1 = (FAR struct procfs_level1_s *)
                 kmm_zalloc(sizeof(struct procfs_level1_s));

              if (!level1)
                {
                  fdbg("ERROR: Failed to allocate the level0 directory structure\n");
                  return -ENOMEM;
                }

              level1->base.level = 1;
              level1->base.index = x;
              level1->firstindex = x;
              level1->subdirlen = len;
              level1->lastread = "";
              level1->lastlen = 0;
              level1->base.procfsentry = NULL;

              priv = (FAR void *)level1;
              break;
            }
        }
    }

  dir->u.procfs = priv;
  return OK;
}
Exemple #18
0
int rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock,
              size_t nblocks, FAR const uint8_t *wrbuffer)
{
  int ret;

#ifdef CONFIG_DRVR_READAHEAD
  if (rhmaxblocks > 0)
    {
      /* If the new write data overlaps any part of the read buffer, then
       * flush the data from the read buffer.  We could attempt some more
       * exotic handling -- but this simple logic is well-suited for simple
       * streaming applications.
       */

      rwb_semtake(&rwb->rhsem);
      if (rwb_overlap(rwb->rhblockstart, rwb->rhnblocks, startblock, nblocks))
        {
          rwb_resetrhbuffer(rwb);
        }

      rwb_semgive(&rwb->rhsem);
    }
#endif

#ifdef CONFIG_DRVR_WRITEBUFFER
  if (rwb->wrmaxblocks > 0)
    {
      fvdbg("startblock=%d wrbuffer=%p\n", startblock, wrbuffer);

      /* Use the block cache unless the buffer size is bigger than block cache */

      if (nblocks > rwb->wrmaxblocks)
        {
          /* First flush the cache */

          rwb_semtake(&rwb->wrsem);
          rwb_wrflush(rwb);
          rwb_semgive(&rwb->wrsem);

          /* Then transfer the data directly to the media */

          ret = rwb->wrflush(rwb->dev, startblock, nblocks, wrbuffer);
        }
      else
        {
          /* Buffer the data in the write buffer */

          ret = rwb_writebuffer(rwb, startblock, nblocks, wrbuffer);
        }

      /* On success, return the number of blocks that we were requested to
       * write.  This is for compatibility with the normal return of a block
       * driver write method
       */
    }
  else
#else
    {
      /* No write buffer.. just pass the write operation through via the
       * flush callback.
       */

      ret = rwb->wrflush(rwb->dev, startblock, nblocks, wrbuffer);
    }

#endif

  return ret;
}
Exemple #19
0
int nxffs_stat(FAR struct inode *mountpt, FAR const char *relpath,
               FAR struct stat *buf)
{
  FAR struct nxffs_volume_s *volume;
  struct nxffs_entry_s entry;
  int ret;

  fvdbg("Entry\n");

  /* Sanity checks */

  DEBUGASSERT(mountpt && mountpt->i_private && buf);

  /* Get the mountpoint private data from the NuttX inode structure */

  volume = mountpt->i_private;
  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      goto errout;
    }

  /* Initialize the return stat instance */

  memset(buf, 0, sizeof(struct stat));
  buf->st_blksize = volume->geo.blocksize;
  buf->st_blocks  = entry.datlen / (volume->geo.blocksize - SIZEOF_NXFFS_BLOCK_HDR);

  /* The requested directory must be the volume-relative "root" directory */

  if (relpath && relpath[0] != '\0')
    {
      /* Not the top directory.. find the NXFFS inode with this name */

      ret = nxffs_findinode(volume, relpath, &entry);
      if (ret < 0)
        {
          fdbg("ERROR: Inode '%s' not found: %d\n", -ret);
          goto errout_with_semaphore;
        }

      buf->st_mode    = S_IFREG|S_IXOTH|S_IXGRP|S_IXUSR;
      buf->st_size    = entry.datlen;
      buf->st_atime   = entry.utc;
      buf->st_mtime   = entry.utc;
      buf->st_ctime   = entry.utc;

      /* Free inode resources */

      nxffs_freeentry(&entry);
    }
  else
    {
      /* It's a read/execute-only directory name */

      buf->st_mode   = S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR|S_IXOTH|S_IXGRP|S_IXUSR;
    }

  ret = OK;

errout_with_semaphore:
  sem_post(&volume->exclsem);
errout:
  return ret;
}
Exemple #20
0
int rwb_initialize(FAR struct rwbuffer_s *rwb)
{
  uint32_t allocsize;

  /* Sanity checking */

  DEBUGASSERT(rwb != NULL);
  DEBUGASSERT(rwb->blocksize > 0);
  DEBUGASSERT(rwb->nblocks > 0);
  DEBUGASSERT(rwb->dev != NULL);

  /* Setup so that rwb_uninitialize can handle a failure */

#ifdef CONFIG_DRVR_WRITEBUFFER
  DEBUGASSERT(rwb->wrflush!= NULL);
  rwb->wrbuffer = NULL;
#endif
#ifdef CONFIG_DRVR_READAHEAD
  DEBUGASSERT(rwb->rhreload != NULL);
  rwb->rhbuffer = NULL;
#endif

#ifdef CONFIG_DRVR_WRITEBUFFER
  if (rwb->wrmaxblocks > 0)
    {
      fvdbg("Initialize the write buffer\n");

      /* Initialize the write buffer access semaphore */

      sem_init(&rwb->wrsem, 0, 1);

      /* Initialize write buffer parameters */

      rwb_resetwrbuffer(rwb);

      /* Allocate the write buffer */

      rwb->wrbuffer = NULL;
      if (rwb->wrmaxblocks > 0)
        {
          allocsize     = rwb->wrmaxblocks * rwb->blocksize;
          rwb->wrbuffer = kmm_malloc(allocsize);
          if (!rwb->wrbuffer)
            {
              fdbg("Write buffer kmm_malloc(%d) failed\n", allocsize);
              return -ENOMEM;
            }
        }

      fvdbg("Write buffer size: %d bytes\n", allocsize);
    }
#endif /* CONFIG_DRVR_WRITEBUFFER */

#ifdef CONFIG_DRVR_READAHEAD
  if (rhmaxblocks > 0)
    {
      fvdbg("Initialize the read-ahead buffer\n");

      /* Initialize the read-ahead buffer access semaphore */

      sem_init(&rwb->rhsem, 0, 1);

      /* Initialize read-ahead buffer parameters */

      rwb_resetrhbuffer(rwb);

      /* Allocate the read-ahead buffer */

      rwb->rhbuffer = NULL;
      if (rwb->rhmaxblocks > 0)
        {
          allocsize     = rwb->rhmaxblocks * rwb->blocksize;
          rwb->rhbuffer = kmm_malloc(allocsize);
          if (!rwb->rhbuffer)
            {
              fdbg("Read-ahead buffer kmm_malloc(%d) failed\n", allocsize);
              return -ENOMEM;
            }
        }

      fvdbg("Read-ahead buffer size: %d bytes\n", allocsize);
    }
#endif /* CONFIG_DRVR_READAHEAD */

  return OK;
}
Exemple #21
0
int rwb_read(FAR struct rwbuffer_s *rwb, off_t startblock, uint32_t nblocks,
             FAR uint8_t *rdbuffer)
{
  uint32_t remaining;

  fvdbg("startblock=%ld nblocks=%ld rdbuffer=%p\n",
        (long)startblock, (long)nblocks, rdbuffer);

#ifdef CONFIG_DRVR_WRITEBUFFER
  /* If the new read data overlaps any part of the write buffer, then
   * flush the write data onto the physical media before reading.  We
   * could attempt some more exotic handling -- but this simple logic
   * is well-suited for simple streaming applications.
   */

  if (rwb->wrmaxblocks > 0)
    {
      /* If the write buffer overlaps the block(s) requested, then flush the
       * write buffer.
       */

      rwb_semtake(&rwb->wrsem);
      if (rwb_overlap(rwb->wrblockstart, rwb->wrnblocks, startblock, nblocks))
        {
          rwb_wrflush(rwb);
        }

      rwb_semgive(&rwb->wrsem);
    }
#endif

#ifdef CONFIG_DRVR_READAHEAD
  if (rhmaxblocks > 0)
    {
      /* Loop until we have read all of the requested blocks */

      rwb_semtake(&rwb->rhsem);
      for (remaining = nblocks; remaining > 0;)
        {
          /* Is there anything in the read-ahead buffer? */

          if (rwb->rhnblocks > 0)
            {
              off_t  startblock = startblock;
              size_t nbufblocks = 0;
              off_t  bufferend;

              /* Loop for each block we find in the read-head buffer.  Count
               * the number of buffers that we can read from read-ahead
               * buffer.
               */

              bufferend = rwb->rhblockstart + rwb->rhnblocks;

              while ((startblock >= rwb->rhblockstart) &&
                     (startblock < bufferend) &&
                     (remaining > 0))
                {
                  /* This is one more that we will read from the read ahead
                   * buffer.
                   */

                  nbufblocks++;

                  /* And one less that we will read from the media */

                  startblock++;
                  remaining--;
                }

              /* Then read the data from the read-ahead buffer */

             rwb_bufferread(rwb, startblock, nbufblocks, &rdbuffer);
            }

          /* If we did not get all of the data from the buffer, then we have
           * to refill the buffer and try again.
           */

          if (remaining > 0)
            {
              int ret = rwb_rhreload(rwb, startblock);
              if (ret < 0)
                {
                  fdbg("ERROR: Failed to fill the read-ahead buffer: %d\n", ret);
                  return ret;
                }
            }
        }

      /* On success, return the number of blocks that we were requested to
       * read. This is for compatibility with the normal return of a block
       * driver read method
       */

      rwb_semgive(&rwb->rhsem);
      ret = nblocks;
    }
  else
#else
    {
      /* No read-ahead buffering, (re)load the data directly into
       * the user buffer.
       */

      ret = rwb->rhreload(rwb->dev, startblock, nblocks, rdbuffer);
    }
#endif

  return ret;
}
Exemple #22
0
int nxffs_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct nxffs_volume_s *volume;
  int ret;

  fvdbg("cmd: %d arg: %08lx\n", cmd, arg);

  /* Sanity checks */

  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);

  /* Recover the file system state from the open file */

  volume = filep->f_inode->i_private;
  DEBUGASSERT(volume != NULL);

  /* Get exclusive access to the volume.  Note that the volume exclsem
   * protects the open file list.
   */

  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      ret = -errno;
      fdbg("sem_wait failed: %d\n", ret);
      goto errout;
    }

  /* Only a reformat and optimize commands are supported */

  if (cmd == FIOC_REFORMAT)
    {
      fvdbg("Reformat command\n");

      /* We cannot reformat the volume if there are any open inodes */

      if (volume->ofiles)
        {
          fdbg("Open files\n");
          ret = -EBUSY;
          goto errout_with_semaphore;
        }

      /* Re-format the volume -- all is lost */

      ret = nxffs_reformat(volume);
    }

  else if (cmd == FIOC_OPTIMIZE)
    {
      fvdbg("Optimize command\n");

      /* Pack the volume */

      ret = nxffs_pack(volume);
    }
  else
    {
      /* No other commands supported */

      ret = -ENOTTY;
    }

errout_with_semaphore:
  sem_post(&volume->exclsem);
errout:
  return ret;
}
Exemple #23
0
int rwb_invalidate_writebuffer(FAR struct rwbuffer_s *rwb,
                               off_t startblock, size_t blockcount)
{
  int ret;

  if (rwb->wrmaxblocks > 0 && wrnblocks > 0)
    {
      off_t wrbend;
      off_t invend;

      fvdbg("startblock=%d blockcount=%p\n", startblock, blockcount);

      rwb_semtake(&rwb->wrsem);

      /* Now there are five cases:
       *
       * 1. We invalidate nothing
       */

      wrbend = rwb->wrblockstart + rwb->wrnblocks;
      invend = startblock + blockcount;

      if (rwb->wrblockstart > invend || wrbend < startblock)
        {
          ret = OK;
        }

      /* 2. We invalidate the entire write buffer. */

      else if (rwb->wrblockstart >= startblock && wrbend <= invend)
        {
          rwb->wrnblocks = 0;
          ret = OK;
        }

      /* We are going to invalidate a subset of the write buffer.  Three
       * more cases to consider:
       *
       * 2. We invalidate a portion in the middle of the write buffer
       */

      else if (rwb->wrblockstart < startblock && wrbend > invend)
        {
          uint8_t *src;
          off_t    block;
          off_t    offset;
          size_t   nblocks;

          /* Write the blocks at the end of the media to hardware */

          nblocks = wrbend - invend;
          block   = invend;
          offset  = block - rwb->wrblockstart;
          src     = rwb->wrbuffer + offset * rwb->blocksize;

          ret = rwb->wrflush(rwb->dev, block, nblocks, src);
          if (ret < 0)
            {
              fdbg("ERROR: wrflush failed: %d\n", ret);
            }

          /* Keep the blocks at the beginning of the buffer up the
           * start of the invalidated region.
           */
          else
            {
              rwb->wrnblocks = startblock - rwb->wrblockstart;
              ret = OK;
            }
        }

      /* 3. We invalidate a portion at the end of the write buffer */

      else if (wrbend > startblock && wrbend <= invend)
        {
          rwb->wrnblocks = wrbend - startblock;
          ret = OK;
        }

      /* 4. We invalidate a portion at the beginning of the write buffer */

      else /* if (rwb->wrblockstart >= startblock && wrbend < invend) */
        {
          uint8_t *src;
          size_t   ninval;
          size_t   nkeep;

          DEBUGASSERT(rwb->wrblockstart >= startblock && wrbend < invend);

          /* Copy the data from the uninvalidated region to the beginning
           * of the write buffer.
           *
           * First calculate the source and destination of the transfer.
           */

          ninval = invend - rwb->wrblockstart;
          src    = rwb->wrbuffer + ninval * rwb->blocksize;

          /* Calculate the number of blocks we are keeping.  We keep
           * the ones that we don't invalidate.
           */

          nkeep  = rwb->wrnblocks - ninval;

          /* Then move the data that we are keeping to the beginning
           * the write buffer.
           */

          memcpy(rwb->wrbuffer, src, nkeep * rwb->blocksize);

          /* Update the block info.  The first block is now the one just
           * after the invalidation region and the number buffered blocks
           * is the number that we kept.
           */

          rwb->wrblockstart = invend;
          rwb->wrnblocks    = nkeep;
          ret = OK;
        }

      rwb_semgive(&rwb->wrsem);
    }

  return ret;
}
Exemple #24
0
static int rd_close(FAR struct inode *inode)
{
  fvdbg("Entry\n");
  return OK;
}
Exemple #25
0
int nxffs_close(FAR struct file *filep)
{
  FAR struct nxffs_volume_s *volume;
  FAR struct nxffs_ofile_s *ofile;
  int ret;

  fvdbg("Closing\n");

  /* Sanity checks */

  DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);

  /* Recover the open file state from the struct file instance */

  ofile = (FAR struct nxffs_ofile_s *)filep->f_priv;

  /* Recover the volume state from the open file */

  volume = (FAR struct nxffs_volume_s *)filep->f_inode->i_private;
  DEBUGASSERT(volume != NULL);

  /* Get exclusive access to the volume.  Note that the volume exclsem
   * protects the open file list.
   */

  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      ret = -get_errno();
      fdbg("ERROR: sem_wait failed: %d\n", ret);
      goto errout;
    }

  /* Decrement the reference count on the open file */

  ret = OK;
  if (ofile->crefs == 1)
    {
      /* Decrementing the reference count would take it zero.
       *
       * Remove the entry from the open file list.  We do this early
       * to avoid some chick-and-egg problems with file truncation.
       */

      nxffs_remofile(volume, ofile);

      /* Handle special finalization of the write operation. */

      if ((ofile->oflags & O_WROK) != 0)
        {
          ret = nxffs_wrclose(volume, (FAR struct nxffs_wrfile_s *)ofile);
        }

      /* Release all resouces held by the open file */

      nxffs_freeofile(volume, ofile);
    }
  else
    {
      /* Just decrement the reference count */

      ofile->crefs--;
    }


  filep->f_priv = NULL;
  sem_post(&volume->exclsem);

errout:
  return ret;
}
Exemple #26
0
FAR struct mtd_dev_s *mtd_rwb_initialize(FAR struct mtd_dev_s *mtd)
{
  FAR struct mtd_rwbuffer_s *priv;
  struct mtd_geometry_s geo;
  int ret;

  fvdbg("mtd: %p\n", mtd);
  DEBUGASSERT(mtd && mtd->ioctl);

  /* Get the device geometry */

  ret = mtd->ioctl(mtd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geo));
  if (ret < 0)
    {
      fdbg("ERROR: MTDIOC_GEOMETRY ioctl failed: %d\n", ret);
      return NULL;
    }

  /* Allocate a state structure (we allocate the structure instead of using
   * a fixed, static allocation so that we can handle multiple FLASH devices.
   * The current implementation would handle only one FLASH part per SPI
   * device (only because of the SPIDEV_FLASH definition) and so would have
   * to be extended to handle multiple FLASH parts on the same SPI bus.
   */

  priv = (FAR struct mtd_rwbuffer_s *)kmm_zalloc(sizeof(struct mtd_rwbuffer_s));
  if (priv)
    {
      /* Initialize the allocated structure. (unsupported methods/fields
       * were already nullified by kmm_zalloc).
       */

      priv->mtd.erase    = mtd_erase;  /* Our MTD erase method */
      priv->mtd.bread    = mtd_bread;  /* Our MTD bread method */
      priv->mtd.bwrite   = mtd_bwrite; /* Our MTD bwrite method */
      priv->mtd.read     = mtd_read;   /* Our MTD read method */
      priv->mtd.ioctl    = mtd_ioctl;  /* Our MTD ioctl method */

      priv->dev          = mtd;        /* The contained MTD instance */

      /* Sectors per block.  The erase block size must be an even multiple
       * of the sector size.
       */

      priv->spb          = geo.erasesize / geo.blocksize;
      DEBUGASSERT((size_t)priv->spb * geo_blocksize = geo.erasesize);

      /* Values must be provided to rwb_initialize() */
      /* Supported geometry */

      priv->rwb.blocksize = geo.blocksize;
      priv->rwb.nblocks   = geo.neraseblocks * priv->spb;

      /* Buffer setup */

#ifdef CONFIG_DRVR_WRITEBUFFER
      priv->rwb.wrmaxblocks = CONFIG_MTD_NWRBLOCKS;
#endif
#ifdef CONFIG_DRVR_READAHEAD
      priv->rwb.rhmaxblocks = CONFIG_MTD_NRDBLOCKS;
#endif

      /* Callouts */

      priv->rwb.dev       = priv;             /* Device state passed to callouts */
      priv->rwb.wrflush   = mtd_flush;        /* Callout to flush buffer */
      priv->rwb.rhreload  = mtd_reload;       /* Callout to reload buffer */

      /* Initialize read-ahead/write buffering */

      ret = rwb_initialize(&priv->rwb);
      if (ret < 0)
        {
          fdbg("ERROR: rwb_initialize failed: %d\n", ret);
          kmm_free(priv);
          return NULL;
        }
    }

  /* Register the MTD with the procfs system if enabled */

#ifdef CONFIG_MTD_REGISTRATION
  mtd_register(&priv->mtd, "rwbuffer");
#endif

  /* Return the implementation-specific state structure as the MTD device */

  fvdbg("Return %p\n", priv);
  return &priv->mtd;
}
Exemple #27
0
static inline int nxffs_rdopen(FAR struct nxffs_volume_s *volume,
                               FAR const char *name,
                               FAR struct nxffs_ofile_s **ppofile)
{
  FAR struct nxffs_ofile_s *ofile;
  int ret;

  /* Get exclusive access to the volume.  Note that the volume exclsem
   * protects the open file list.
   */

  ret = sem_wait(&volume->exclsem);
  if (ret != OK)
    {
      fdbg("ERROR: sem_wait failed: %d\n", ret);
      ret = -get_errno();
      goto errout;
    }

  /* Check if the file has already been opened (for reading) */

  ofile = nxffs_findofile(volume, name);
  if (ofile)
    {
      /* The file is already open.
       * Limitation:  Files cannot be open both for reading and writing.
       */

      if ((ofile->oflags & O_WROK) != 0)
        {
          fdbg("ERROR: File is open for writing\n");
          ret = -ENOSYS;
          goto errout_with_exclsem;
        }

      /* Just increment the reference count on the ofile */

      ofile->crefs++;
      fvdbg("crefs: %d\n", ofile->crefs);
    }

  /* The file has not yet been opened.
   * Limitation: The file must exist.  We do not support creation of files
   * read-only.
   */

  else
    {
      /* Not already open.. create a new open structure */

      ofile = (FAR struct nxffs_ofile_s *)kmm_zalloc(sizeof(struct nxffs_ofile_s));
      if (!ofile)
        {
          fdbg("ERROR: ofile allocation failed\n");
          ret = -ENOMEM;
          goto errout_with_exclsem;
        }

      /* Initialize the open file state structure */

      ofile->crefs  = 1;
      ofile->oflags = O_RDOK;

      /* Find the file on this volume associated with this file name */

      ret = nxffs_findinode(volume, name, &ofile->entry);
      if (ret != OK)
        {
          fvdbg("Inode '%s' not found: %d\n", name, -ret);
          goto errout_with_ofile;
        }

      /* Add the open file structure to the head of the list of open files */

      ofile->flink   = volume->ofiles;
      volume->ofiles = ofile;
    }

  /* Return the open file state structure */

  *ppofile = ofile;
  sem_post(&volume->exclsem);
  return OK;

errout_with_ofile:
  kmm_free(ofile);
errout_with_exclsem:
  sem_post(&volume->exclsem);
errout:
  return ret;
}
Exemple #28
0
static int mtd_ioctl(FAR struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
  FAR struct mtd_rwbuffer_s *priv = (FAR struct mtd_rwbuffer_s *)dev;
  int ret = -EINVAL; /* Assume good command with bad parameters */

  fvdbg("cmd: %d \n", cmd);

  switch (cmd)
    {
      case MTDIOC_GEOMETRY:
        {
          FAR struct mtd_geometry_s *geo = (FAR struct mtd_geometry_s *)((uintptr_t)arg);
          if (geo)
            {
              /* Populate the geometry structure with information need to know
               * the capacity and how to access the device.
               *
               * NOTE: that the device is treated as though it where just an array
               * of fixed size blocks.  That is most likely not true, but the client
               * will expect the device logic to do whatever is necessary to make it
               * appear so.
               */

              geo->blocksize    = priv->rwb.blocksize;
              geo->erasesize    = priv->rwb.blocksize* priv->spb;
              geo->neraseblocks = priv->rwb.nblocks * priv->spb;
              ret               = OK;

              fvdbg("blocksize: %d erasesize: %d neraseblocks: %d\n",
                    geo->blocksize, geo->erasesize, geo->neraseblocks);
            }
        }
        break;

      case MTDIOC_BULKERASE:
        {
          /* Erase the entire device */

          ret = priv->dev->ioctl(priv->dev, MTDIOC_BULKERASE, 0);
          if (ret >= 0)
            {
              fdbg("ERROR: Device ioctl failed: %d\n", ret);
              break;
            }

          /* Then invalidate in cached data */

         ret = rwb_invalidate(&priv->rwb,0, priv->rwb.nblocks);
         if (ret < 0)
           {
              fdbg("ERROR: rwb_invalidate failed: %d\n", ret);
           }
        }
        break;

      case MTDIOC_XIPBASE:
      default:
        ret = -ENOTTY; /* Bad command */
        break;
    }

  fvdbg("return %d\n", ret);
  return ret;
}
Exemple #29
0
int rwb_invalidate_readahead(FAR struct rwbuffer_s *rwb,
                               off_t startblock, size_t blockcount)
{
  int ret;

  if (rwb->rhmaxblocks > 0 && rhnblocks > 0)
    {
      off_t rhbend;
      off_t invend;

      fvdbg("startblock=%d blockcount=%p\n", startblock, blockcount);

      rwb_semtake(&rwb->rhsem);

      /* Now there are five cases:
       *
       * 1. We invalidate nothing
       */

      rhbend = rwb->rhblockstart + rwb->rhnblocks;
      invend = startblock + blockcount;

      if (rwb->rhblockstart > invend || rhbend < startblock)
        {
          ret = OK;
        }

      /* 2. We invalidate the entire read-ahead buffer. */

      else if (rwb->rhblockstart >= startblock && rhbend <= invend)
        {
          rwb->rhnblocks = 0;
          ret = OK;
        }

      /* We are going to invalidate a subset of the read-ahead buffer.
       * Three more cases to consider:
       *
       * 2. We invalidate a portion in the middle of the write buffer
       */

      else if (rwb->rhblockstart < startblock && rhbend > invend)
        {
          /* Keep the blocks at the beginning of the buffer up the
           * start of the invalidated region.
           */

          rwb->rhnblocks = startblock - rwb->rhblockstart;
          ret = OK;
        }

      /* 3. We invalidate a portion at the end of the read-ahead buffer */

      else if (rhbend > startblock && rhbend <= invend)
        {
          rwb->rhnblocks = rhbend - startblock;
          ret = OK;
        }

      /* 4. We invalidate a portion at the beginning of the write buffer */

      else /* if (rwb->rhblockstart >= startblock && rhbend < invend) */
        {
          /* Let's just force the whole read-ahead buffer to be reloaded.
           * That might cost s small amount of performance, but well worth
           * the lower complexity.
           */

          DEBUGASSERT(rwb->rhblockstart >= startblock && rhbend < invend);
          rwb->rhnblocks = 0;
          ret = OK;
        }

      rwb_semgive(&rwb->rhsem);
    }

  return ret;
}
static ssize_t uptime_read(FAR struct file *filep, FAR char *buffer,
                           size_t buflen)
{
  FAR struct uptime_file_s *attr;
  size_t linesize;
  off_t offset;
  ssize_t ret;

#ifdef CONFIG_SYSTEM_TIME64
  uint64_t ticktime;
#if !defined(CONFIG_HAVE_DOUBLE) || !defined(CONFIG_LIBC_FLOATINGPOINT)
  uint64_t sec;
#endif

#else
  uint32_t ticktime;
#if !defined(CONFIG_HAVE_DOUBLE) || !defined(CONFIG_LIBC_FLOATINGPOINT)
  uint32_t sec;
#endif
#endif

#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
  double now;
#else
  unsigned int remainder;
  unsigned int csec;
#endif

  fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen);

  /* Recover our private data from the struct file instance */

  attr = (FAR struct uptime_file_s *)filep->f_priv;
  DEBUGASSERT(attr);

  /* If f_pos is zero, then sample the system time.  Otherwise, use
   * the cached system time from the previous read().  It is necessary
   * save the cached value in case, for example, the user is reading
   * the time one byte at a time.  In that case, the time must remain
   * stable throughout the reads.
   */

  if (filep->f_pos == 0)
    {
#ifdef CONFIG_SYSTEM_TIME64
      /* 64-bit timer */

      ticktime = clock_systimer64();
#else
      /* 32-bit timer */

      ticktime = clock_systimer();
#endif

#if defined(CONFIG_HAVE_DOUBLE) && defined(CONFIG_LIBC_FLOATINGPOINT)
      /* Convert the system up time to a seconds + hundredths of seconds string */

      now       = (double)ticktime / (double)CLOCKS_PER_SEC;
      linesize  = snprintf(attr->line, UPTIME_LINELEN, "%10.2f\n", now);

#else
      /* Convert the system up time to seconds + hundredths of seconds */

      sec       = ticktime / CLOCKS_PER_SEC;
      remainder = (unsigned int)(ticktime % CLOCKS_PER_SEC);
      csec      = (100 * remainder + (CLOCKS_PER_SEC / 2)) / CLOCKS_PER_SEC;

      /* Make sure that rounding did not force the hundredths of a second above 99 */

      if (csec > 99)
        {
          sec++;
          csec -= 100;
        }

      /* Convert the seconds + hundredths of seconds to a string */

      linesize = snprintf(attr->line, UPTIME_LINELEN, "%7lu.%02u\n", sec, csec);

#endif
      /* Save the linesize in case we are re-entered with f_pos > 0 */

      attr->linesize = linesize;
    }

  /* Transfer the system up time to user receive buffer */

  offset = filep->f_pos;
  ret    = procfs_memcpy(attr->line, attr->linesize, buffer, buflen, &offset);

  /* Update the file offset */

  if (ret > 0)
    {
      filep->f_pos += ret;
    }

  return ret;
}