Ejemplo n.º 1
0
int rwb_write(FAR struct rwbuffer_s *rwb, off_t startblock, size_t nblocks, FAR const uint8_t *wrbuffer)
{
	int ret = OK;

#ifdef CONFIG_DRVR_READAHEAD
	if (rwb->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, wrbuffer, startblock, nblocks);
		} 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
#endif
	{
		/* No write buffer.. just pass the write operation through via the
		 * flush callback.
		 */

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

	return ret;
}
Ejemplo n.º 2
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;
}