mtd-vfs.c
3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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 drivers_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;
}
const 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)
{
const 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 */