int bchlib_teardown(FAR void *handle) { FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle; DEBUGASSERT(handle); /* Check that there are not outstanding reference counts on the object */ if (bch->refs > 0) { return -EBUSY; } /* Flush any pending data to the block driver */ bchlib_flushsector(bch); /* Close the block driver */ (void)close_blockdriver(bch->inode); /* Free the BCH state structure */ if (bch->buffer) { kfree(bch->buffer); } sem_destroy(&bch->sem); kfree(bch); return OK; }
static int bch_close(FAR struct file *filep) { FAR struct inode *inode = filep->f_inode; FAR struct bchlib_s *bch; int ret = OK; DEBUGASSERT(inode && inode->i_private); bch = (FAR struct bchlib_s *)inode->i_private; /* Flush any dirty pages remaining in the cache */ bchlib_semtake(bch); (void)bchlib_flushsector(bch); /* Decrement the reference count (I don't use bchlib_decref() because I * want the entire close operation to be atomic wrt other driver operations. */ if (bch->refs == 0) { ret = -EIO; } else { bch->refs--; } bchlib_semgive(bch); return ret; }
int bchlib_readsector(FAR struct bchlib_s *bch, size_t sector) { FAR struct inode *inode; ssize_t ret = OK; if (bch->sector != sector) { inode = bch->inode; (void)bchlib_flushsector(bch); bch->sector = (size_t)-1; ret = inode->u.i_bops->read(inode, bch->buffer, sector, 1); if (ret < 0) { fdbg("Read failed: %d\n"); } bch->sector = sector; #if defined(CONFIG_BCH_ENCRYPTION) bch_cypher(bch, CYPHER_DECRYPT); #endif } return (int)ret; }
ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset, size_t len) { FAR struct bchlib_s *bch = (FAR struct bchlib_s *)handle; size_t nsectors; size_t sector; uint16_t sectoffset; size_t nbytes; size_t byteswritten; int ret; /* Get rid of this special case right away */ if (len < 1) { return 0; } /* Convert the file position into a sector number and offset. */ sector = offset / bch->sectsize; sectoffset = offset - sector * bch->sectsize; if (sector >= bch->nsectors) { return -EFBIG; } /* Write the initial partial sector */ byteswritten = 0; if (sectoffset > 0) { /* Read the full sector into the sector buffer */ bchlib_readsector(bch, sector); /* Copy the tail end of the sector from the user buffer */ if (sectoffset + len > bch->sectsize) { nbytes = bch->sectsize - sectoffset; } else { nbytes = len; } memcpy(&bch->buffer[sectoffset], buffer, nbytes); bch->dirty = true; /* Adjust pointers and counts */ sector++; if (sector >= bch->nsectors) { return nbytes; } byteswritten = nbytes; buffer += nbytes; len -= nbytes; } /* Then write all of the full sectors following the partial sector * directly from the user buffer. */ if (len >= bch->sectsize ) { nsectors = len / bch->sectsize; if (sector + nsectors > bch->nsectors) { nsectors = bch->nsectors - sector; } /* Write the contiguous sectors */ ret = bch->inode->u.i_bops->write(bch->inode, (FAR uint8_t *)buffer, sector, nsectors); if (ret < 0) { fdbg("Write failed: %d\n", ret); return ret; } /* Adjust pointers and counts */ sector += nsectors; nbytes = nsectors * bch->sectsize; byteswritten += nbytes; if (sector >= bch->nsectors) { return byteswritten; } buffer += nbytes; len -= nbytes; } /* Then write any partial final sector */ if (len > 0) { /* Read the sector into the sector buffer */ bchlib_readsector(bch, sector); /* Copy the head end of the sector from the user buffer */ memcpy(bch->buffer, buffer, len); bch->dirty = true; /* Adjust counts */ byteswritten += len; } /* Finally, flush any cached writes to the device as well */ ret = bchlib_flushsector(bch); if (ret < 0) { fdbg("Flush failed: %d\n", ret); return ret; } return byteswritten; }