mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 10:12:45 +01:00
mtd: Add MTD VFS wrapper for use with DevFS
This commit is contained in:
parent
81149f1843
commit
6d3304f52c
@ -23,6 +23,9 @@
|
||||
#define MTD_H
|
||||
|
||||
#include <stdint.h>
|
||||
#if MODULE_VFS
|
||||
#include "vfs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -225,6 +228,13 @@ int mtd_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t count);
|
||||
*/
|
||||
int mtd_power(mtd_dev_t *mtd, enum mtd_power_state power);
|
||||
|
||||
#if defined(MODULE_VFS) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief MTD driver for VFS
|
||||
*/
|
||||
extern const vfs_file_ops_t mtd_vfs_ops;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
139
drivers/mtd/mtd-vfs.c
Normal file
139
drivers/mtd/mtd-vfs.c
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Eistec AB
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser General
|
||||
* Public License v2.1. See the file LICENSE in the top level directory for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#if MODULE_VFS
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mtd.h"
|
||||
#include "vfs.h"
|
||||
|
||||
/**
|
||||
* @ingroup mtd
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @brief MTD generic VFS operations
|
||||
*
|
||||
* This allows the MTD driver to register as a node on DevFS
|
||||
*
|
||||
* See boards/mulle or tests/unittests/tests-devfs for examples on how to use.
|
||||
*
|
||||
* Tested with mtd_spi_nor on Mulle
|
||||
*
|
||||
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
||||
*/
|
||||
|
||||
static int mtd_vfs_fstat(vfs_file_t *filp, struct stat *buf);
|
||||
static off_t mtd_vfs_lseek(vfs_file_t *filp, off_t off, int whence);
|
||||
static ssize_t mtd_vfs_read(vfs_file_t *filp, void *dest, size_t nbytes);
|
||||
static ssize_t mtd_vfs_write(vfs_file_t *filp, const void *src, size_t nbytes);
|
||||
|
||||
const vfs_file_ops_t mtd_vfs_ops = {
|
||||
.fstat = mtd_vfs_fstat,
|
||||
.lseek = mtd_vfs_lseek,
|
||||
.read = mtd_vfs_read,
|
||||
.write = mtd_vfs_write,
|
||||
};
|
||||
|
||||
static int mtd_vfs_fstat(vfs_file_t *filp, struct stat *buf)
|
||||
{
|
||||
if (buf == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
mtd_dev_t *mtd = filp->private_data.ptr;
|
||||
if (mtd == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
buf->st_nlink = 1;
|
||||
buf->st_size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static off_t mtd_vfs_lseek(vfs_file_t *filp, off_t off, int whence)
|
||||
{
|
||||
mtd_dev_t *mtd = filp->private_data.ptr;
|
||||
if (mtd == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
off += filp->pos;
|
||||
break;
|
||||
case SEEK_END:
|
||||
off += mtd->page_size * mtd->sector_count * mtd->pages_per_sector;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (off < 0) {
|
||||
/* the resulting file offset would be negative */
|
||||
return -EINVAL;
|
||||
}
|
||||
/* POSIX allows seeking past the end of the file */
|
||||
filp->pos = off;
|
||||
return off;
|
||||
}
|
||||
|
||||
static ssize_t mtd_vfs_read(vfs_file_t *filp, void *dest, size_t nbytes)
|
||||
{
|
||||
mtd_dev_t *mtd = filp->private_data.ptr;
|
||||
if (mtd == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
uint32_t size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector;
|
||||
uint32_t src = filp->pos;
|
||||
if (src >= size) {
|
||||
return 0;
|
||||
}
|
||||
if ((src + nbytes) > size) {
|
||||
nbytes = size - src;
|
||||
}
|
||||
int res = mtd_read(mtd, dest, src, nbytes);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
/* Advance file position */
|
||||
filp->pos += res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t mtd_vfs_write(vfs_file_t *filp, const void *src, size_t nbytes)
|
||||
{
|
||||
mtd_dev_t *mtd = filp->private_data.ptr;
|
||||
if (mtd == NULL) {
|
||||
return -EFAULT;
|
||||
}
|
||||
uint32_t size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector;
|
||||
uint32_t dest = filp->pos;
|
||||
if (dest >= size) {
|
||||
/* attempt to write outside the device memory */
|
||||
return -ENOSPC;
|
||||
}
|
||||
if ((dest + nbytes) > size) {
|
||||
nbytes = size - dest;
|
||||
}
|
||||
int res = mtd_write(mtd, src, dest, nbytes);
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
/* Advance file position */
|
||||
filp->pos += res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
#else
|
||||
typedef int dont_be_pedantic;
|
||||
#endif /* MODULE_VFS */
|
Loading…
Reference in New Issue
Block a user