mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-08-03 22:47:47 +00:00
add BlockDevice
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
package sd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
var (
|
||||
errNegativeOffset = errors.New("sd: negative offset")
|
||||
)
|
||||
|
||||
type Card interface {
|
||||
WriteBlocks(data []byte, startBlockIdx int64) error
|
||||
ReadBlocks(dst []byte, startBlockIdx int64) error
|
||||
EraseBlockSize() int64
|
||||
EraseBlocks(start, len int64) error
|
||||
}
|
||||
|
||||
func NewBlockDevice(card Card, blockSize int, numBlocks int64) *BlockDevice {
|
||||
if card == nil || blockSize <= 0 {
|
||||
panic("invalid arguments")
|
||||
}
|
||||
tz := bits.TrailingZeros(uint(blockSize))
|
||||
if blockSize>>tz != 1 {
|
||||
panic("blockSize must be a power of 2")
|
||||
}
|
||||
bd := &BlockDevice{
|
||||
card: card,
|
||||
blockbuf: make([]byte, blockSize),
|
||||
blockshift: tz,
|
||||
blockmask: (1 << tz) - 1,
|
||||
numblocks: numBlocks,
|
||||
}
|
||||
return bd
|
||||
}
|
||||
|
||||
// BlockDevice implements tinyfs.BlockDevice interface.
|
||||
type BlockDevice struct {
|
||||
card Card
|
||||
blockbuf []byte
|
||||
blockshift int
|
||||
blockmask int64
|
||||
numblocks int64
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) moduloBlockSize(n int64) int64 {
|
||||
return n &^ bd.blockmask
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) divideBlockSize(n int64) int64 {
|
||||
return n >> bd.blockshift
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, errNegativeOffset
|
||||
}
|
||||
blockSize := len(bd.blockbuf)
|
||||
blockIdx := bd.divideBlockSize(off)
|
||||
blockOff := bd.moduloBlockSize(off)
|
||||
if blockOff != 0 {
|
||||
// Non-aligned first block case.
|
||||
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += copy(p, bd.blockbuf[blockOff:])
|
||||
p = p[n:]
|
||||
blockIdx++
|
||||
}
|
||||
|
||||
remaining := len(p) - n
|
||||
if remaining >= blockSize {
|
||||
// 1 or more full blocks case.
|
||||
endOffset := remaining - int(bd.moduloBlockSize(int64(remaining)))
|
||||
err = bd.card.ReadBlocks(p[:endOffset], blockIdx)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[endOffset:]
|
||||
n += endOffset
|
||||
blockIdx += int64(endOffset / blockSize)
|
||||
}
|
||||
|
||||
if len(p) > 0 {
|
||||
// Non-aligned last block case.
|
||||
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += copy(p, bd.blockbuf)
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
if off < 0 {
|
||||
return 0, errNegativeOffset
|
||||
}
|
||||
blockSize := len(bd.blockbuf)
|
||||
blockIdx := bd.divideBlockSize(off)
|
||||
blockOff := bd.moduloBlockSize(off)
|
||||
if blockOff != 0 {
|
||||
// Non-aligned first block case.
|
||||
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += copy(bd.blockbuf[blockOff:], p)
|
||||
if err := bd.card.WriteBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[n:]
|
||||
blockIdx++
|
||||
}
|
||||
|
||||
remaining := len(p) - n
|
||||
if remaining >= blockSize {
|
||||
// 1 or more full blocks case.
|
||||
endOffset := remaining - int(bd.moduloBlockSize(int64(remaining)))
|
||||
err = bd.card.WriteBlocks(p[:endOffset], blockIdx)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
p = p[endOffset:]
|
||||
n += endOffset
|
||||
blockIdx += int64(endOffset / blockSize)
|
||||
}
|
||||
|
||||
if len(p) > 0 {
|
||||
// Non-aligned last block case.
|
||||
if err := bd.card.ReadBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += copy(bd.blockbuf, p)
|
||||
if err := bd.card.WriteBlocks(bd.blockbuf, blockIdx); err != nil {
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) Size() int64 {
|
||||
return int64(len(bd.blockbuf)) * bd.numblocks
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) EraseBlocks(start, len int64) error {
|
||||
return bd.card.EraseBlocks(start, len)
|
||||
}
|
||||
|
||||
func (bd *BlockDevice) EraseBlockSize() int64 {
|
||||
return bd.card.EraseBlockSize()
|
||||
}
|
||||
Reference in New Issue
Block a user