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; }
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; }