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; }
static void rwb_wrtimeout(FAR void *arg) { /* The following assumes that the size of a pointer is 4-bytes or less */ FAR struct rwbuffer_s *rwb = (struct rwbuffer_s *)arg; DEBUGASSERT(rwb != NULL); /* If a timeout elapses with with write buffer activity, this watchdog * handler function will be evoked on the thread of execution of the * worker thread. */ rwb_wrflush(rwb); }
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; }