Blame view

RIOT/drivers/nvram/nvram-vfs.c 3.05 KB
a752c7ab   elopes   add first test an...
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
  /*
   * 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 "nvram.h"
  #include "vfs.h"
  
  /**
   * @ingroup     nvram
   * @{
   *
   * @file
   *
   * @brief       NVRAM generic VFS operations
   *
   * This allows the nvram driver to register as a node on DevFS
   *
   * See boards/mulle or tests/unittests/tests-devfs for examples on how to use.
   *
   * Tested with nvram_spi on Mulle
   *
   * @author      Joakim Nohlgård <joakim.nohlgard@eistec.se>
   */
  
  static int nvram_vfs_fstat(vfs_file_t *filp, struct stat *buf);
  static off_t nvram_vfs_lseek(vfs_file_t *filp, off_t off, int whence);
  static ssize_t nvram_vfs_read(vfs_file_t *filp, void *dest, size_t nbytes);
  static ssize_t nvram_vfs_write(vfs_file_t *filp, const void *src, size_t nbytes);
  
  const vfs_file_ops_t nvram_vfs_ops = {
      .fstat = nvram_vfs_fstat,
      .lseek = nvram_vfs_lseek,
      .read  = nvram_vfs_read,
      .write = nvram_vfs_write,
  };
  
  static int nvram_vfs_fstat(vfs_file_t *filp, struct stat *buf)
  {
      if (buf == NULL) {
          return -EFAULT;
      }
      nvram_t *dev = filp->private_data.ptr;
      if (dev == NULL) {
          return -EFAULT;
      }
      buf->st_nlink = 1;
      buf->st_size = dev->size;
      return 0;
  }
  
  static off_t nvram_vfs_lseek(vfs_file_t *filp, off_t off, int whence)
  {
      nvram_t *dev = filp->private_data.ptr;
      if (dev == NULL) {
          return -EFAULT;
      }
      switch (whence) {
          case SEEK_SET:
              break;
          case SEEK_CUR:
              off += filp->pos;
              break;
          case SEEK_END:
              off += dev->size;
              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 nvram_vfs_read(vfs_file_t *filp, void *dest, size_t nbytes)
  {
      nvram_t *dev = filp->private_data.ptr;
      if (dev == NULL) {
          return -EFAULT;
      }
      uint32_t src = filp->pos;
      if (src >= dev->size) {
          return 0;
      }
      if (src + nbytes > dev->size) {
          nbytes = dev->size - src;
      }
      int res = dev->read(dev, dest, src, nbytes);
      if (res < 0) {
          return res;
      }
      /* Advance file position */
      filp->pos += res;
      return res;
  }
  
  static ssize_t nvram_vfs_write(vfs_file_t *filp, const void *src, size_t nbytes)
  {
      nvram_t *dev = filp->private_data.ptr;
      if (dev == NULL) {
          return -EFAULT;
      }
      uint32_t dest = filp->pos;
      if (dest >= dev->size) {
          return 0;
      }
      if (dest + nbytes > dev->size) {
          nbytes = dev->size - dest;
      }
      int res = dev->write(dev, 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 */