Exemplo n.º 1
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;
}
Exemplo n.º 2
0
Arquivo: ftl.c Projeto: a1ien/nuttx
int ftl_initialize(int minor, FAR struct mtd_dev_s *mtd)
{
  struct ftl_struct_s *dev;
  char devname[16];
  int ret = -ENOMEM;

  /* Sanity check */

#ifdef CONFIG_DEBUG_FEATURES
  if (minor < 0 || minor > 255 || !mtd)
    {
      return -EINVAL;
    }
#endif

  /* Allocate a FTL device structure */

  dev = (struct ftl_struct_s *)kmm_malloc(sizeof(struct ftl_struct_s));
  if (dev)
    {
      /* Initialize the FTL device structure */

      dev->mtd = mtd;

      /* Get the device geometry. (casting to uintptr_t first eliminates
       * complaints on some architectures where the sizeof long is different
       * from the size of a pointer).
       */

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

      /* Allocate one, in-memory erase block buffer */

#ifdef CONFIG_FS_WRITABLE
      dev->eblock  = (FAR uint8_t *)kmm_malloc(dev->geo.erasesize);
      if (!dev->eblock)
        {
          ferr("ERROR: Failed to allocate an erase block buffer\n");
          kmm_free(dev);
          return -ENOMEM;
        }
#endif

      /* Get the number of R/W blocks per erase block */

      dev->blkper = dev->geo.erasesize / dev->geo.blocksize;
      DEBUGASSERT(dev->blkper * dev->geo.blocksize == dev->geo.erasesize);

      /* Configure read-ahead/write buffering */

#ifdef FTL_HAVE_RWBUFFER
      dev->rwb.blocksize   = dev->geo.blocksize;
      dev->rwb.nblocks     = dev->geo.neraseblocks * dev->blkper;
      dev->rwb.dev         = (FAR void *)dev;

#if defined(CONFIG_FS_WRITABLE) && defined(CONFIG_FTL_WRITEBUFFER)
      dev->rwb.wrmaxblocks = dev->blkper;
      dev->rwb.wrflush     = ftl_flush;
#endif

#ifdef CONFIG_FTL_READAHEAD
      dev->rwb.rhmaxblocks = dev->blkper;
      dev->rwb.rhreload    = ftl_reload;
#endif

      ret = rwb_initialize(&dev->rwb);
      if (ret < 0)
        {
          ferr("ERROR: rwb_initialize failed: %d\n", ret);
          kmm_free(dev);
          return ret;
        }
#endif

      /* Create a MTD block device name */

      snprintf(devname, 16, "/dev/mtdblock%d", minor);

      /* Inode private data is a reference to the FTL device structure */

      ret = register_blockdriver(devname, &g_bops, 0, dev);
      if (ret < 0)
        {
          ferr("ERROR: register_blockdriver failed: %d\n", -ret);
          kmm_free(dev);
        }
    }

  return ret;
}