µOS++ IIIe Reference 7.0.0
The third edition of µOS++, a POSIX inspired open source framework, written in C++
Loading...
Searching...
No Matches
block-device.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ distribution.
3 * (https://github.com/micro-os-plus)
4 * Copyright (c) 2018-2023 Liviu Ionescu. All rights reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software
7 * for any purpose is hereby granted, under the terms of the MIT license.
8 *
9 * If a copy of the license was not distributed with this file, it can
10 * be obtained from https://opensource.org/licenses/mit/.
11 */
12
13#if defined(OS_USE_OS_APP_CONFIG_H)
14#include <cmsis-plus/os-app-config.h>
15#endif
16
19
21
22#include <cstring>
23#include <cassert>
24#include <cerrno>
25#include <cstdarg>
26
27// ----------------------------------------------------------------------------
28
29#if defined(__clang__)
30#pragma clang diagnostic ignored "-Wc++98-compat"
31#endif
32
33// ----------------------------------------------------------------------------
34
35namespace os
36{
37 namespace posix
38 {
39 // ========================================================================
40
42 device
44 {
45#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
46 trace::printf ("block_device::%s(\"%s\")=@%p\n", __func__, name_, this);
47#endif
48
50 }
51
53 {
54#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
55 trace::printf ("block_device::%s() @%p %s\n", __func__, this, name_);
56#endif
57 }
58
59 // ------------------------------------------------------------------------
60
61 ssize_t
62 block_device::read_block (void* buf, blknum_t blknum, std::size_t nblocks)
63 {
64#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
65 trace::printf ("block_device::%s(%p, %u, %u) @%p\n", __func__, buf,
66 blknum, nblocks, this);
67#endif
68
69 if (blknum + nblocks > impl ().num_blocks_)
70 {
71 errno = EINVAL;
72 return -1;
73 }
74
75 if (!impl ().do_is_opened ())
76 {
77 errno = EBADF; // Not opened.
78 return -1;
79 }
80
81 return impl ().do_read_block (buf, blknum, nblocks);
82 }
83
84 ssize_t
85 block_device::write_block (const void* buf, blknum_t blknum,
86 std::size_t nblocks)
87 {
88#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
89 trace::printf ("block_device::%s(%p, %u, %u) @%p\n", __func__, buf,
90 blknum, nblocks, this);
91#endif
92
93 if (blknum + nblocks > impl ().num_blocks_)
94 {
95 errno = EINVAL;
96 return -1;
97 }
98
99 if (!impl ().do_is_opened ())
100 {
101 errno = EBADF; // Not opened.
102 return -1;
103 }
104
105 return impl ().do_write_block (buf, blknum, nblocks);
106 }
107
108 int
109 block_device::vioctl (int request, std::va_list args)
110 {
111#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
112 trace::printf ("block_device::%s(%d) @%p\n", __func__, request, this);
113#endif
114
115 if (!impl ().do_is_opened ())
116 {
117 errno = EBADF; // Not opened.
118 return -1;
119 }
120
121 errno = 0;
122
123 switch (static_cast<unsigned int> (request))
124 {
125 case BLKSSZGET:
126 // Get logical device sector size (to be used for read/writes).
127 {
128 std::size_t* sz = va_arg(args, std::size_t*);
129 if (sz == nullptr || impl ().block_logical_size_bytes_ != 0)
130 {
131 errno = EINVAL;
132 return -1;
133 }
134
135 *sz = impl ().block_logical_size_bytes_;
136 return 0;
137 }
138
139 case BLKPBSZGET:
140 // Get physical device sector size (internally used for erase).
141 {
142 std::size_t* sz = va_arg(args, std::size_t*);
143 if (sz == nullptr || impl ().block_physical_size_bytes_ != 0)
144 {
145 errno = EINVAL;
146 return -1;
147 }
148
149 *sz = impl ().block_physical_size_bytes_;
150 return 0;
151 }
152
153 case BLKGETSIZE64:
154 // Get device size in bytes.
155 {
156 uint64_t* sz = va_arg(args, uint64_t*);
157 if (sz == nullptr || impl ().num_blocks_ != 0)
158 {
159 errno = EINVAL;
160 return -1;
161 }
162
163#pragma GCC diagnostic push
164#if defined(__clang__)
165#elif defined(__GNUC__)
166#pragma GCC diagnostic ignored "-Wuseless-cast"
167#endif
168 *sz = (static_cast<uint64_t> (impl ().num_blocks_
169 * impl ().block_logical_size_bytes_));
170#pragma GCC diagnostic pop
171
172 return 0;
173 }
174
175 default:
176
177 // Execute the implementation specific code.
178 return impl ().do_vioctl (request, args);
179 }
180 }
181
182 // ========================================================================
183
185 {
186#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
187 trace::printf ("block_device_impl::%s()=@%p\n", __func__, this);
188#endif
189 }
190
192 {
193#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
194 trace::printf ("block_device_impl::%s() @%p\n", __func__, this);
195#endif
196
197 block_logical_size_bytes_ = 0;
198 num_blocks_ = 0;
199 }
200
201 // ------------------------------------------------------------------------
202
203 off_t
204 block_device_impl::do_lseek (off_t offset, int whence)
205 {
206#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
207 trace::printf ("block_device_impl::%s(%d, %d) @%p\n", __func__, offset,
208 whence, this);
209#endif
210
211 errno = 0;
212 off_t tmp = offset_;
213
214 switch (whence)
215 {
216 case SEEK_SET:
217 tmp = offset;
218 break;
219
220 case SEEK_CUR:
221 tmp += offset;
222 break;
223
224 case SEEK_END:
225 errno = EINVAL;
226 return -1;
227
228 default:
229 errno = EINVAL;
230 return -1;
231 }
232
233 if (tmp < 0)
234 {
235 errno = EINVAL;
236 return -1;
237 }
238 offset_ = tmp;
239 return tmp;
240 }
241
242 // ------------------------------------------------------------------------
243
244 ssize_t
245 block_device_impl::do_read (void* buf, std::size_t nbyte)
246 {
247#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
248 trace::printf ("block_device_impl::%s(%p, %u) @%p\n", __func__, buf,
249 nbyte, this);
250#endif
251
252 if ((block_logical_size_bytes_ == 0)
253 || ((nbyte % block_logical_size_bytes_) != 0)
254 || ((static_cast<std::size_t> (offset_) % block_logical_size_bytes_)
255 != 0))
256 {
257 errno = EINVAL;
258 return -1;
259 }
260
261 std::size_t nblocks = nbyte / block_logical_size_bytes_;
262 blknum_t blknum = static_cast<std::size_t> (offset_)
263 / block_logical_size_bytes_;
264
265 if (blknum + nblocks > num_blocks_)
266 {
267 errno = EINVAL;
268 return -1;
269 }
270
271 ssize_t ret = do_read_block (buf, blknum, nblocks);
272 if (ret >= 0)
273 {
274 ret *= static_cast<ssize_t>(block_logical_size_bytes_);
275 }
276 return ret;
277 }
278
279 ssize_t
280 block_device_impl::do_write (const void* buf, std::size_t nbyte)
281 {
282#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
283 trace::printf ("block_device_impl::%s(%p, %u) @%p\n", __func__, buf,
284 nbyte, this);
285#endif
286
287 if ((block_logical_size_bytes_ == 0)
288 || ((nbyte % block_logical_size_bytes_) != 0)
289 || ((static_cast<std::size_t> (offset_) % block_logical_size_bytes_)
290 != 0))
291 {
292 errno = EINVAL;
293 return -1;
294 }
295
296 std::size_t nblocks = nbyte / block_logical_size_bytes_;
297 blknum_t blknum = static_cast<std::size_t> (offset_)
298 / block_logical_size_bytes_;
299
300 if (blknum + nblocks > num_blocks_)
301 {
302 errno = EINVAL;
303 return -1;
304 }
305
306 ssize_t ret = do_write_block (buf, blknum, nblocks);
307 if (ret >= 0)
308 {
309 ret *= static_cast<ssize_t>(block_logical_size_bytes_);
310 }
311 return ret;
312 }
313
314 // ==========================================================================
315 } /* namespace posix */
316} /* namespace os */
317
318// ----------------------------------------------------------------------------
virtual ssize_t do_read(void *buf, std::size_t nbyte) override
virtual off_t do_lseek(off_t offset, int whence) override
virtual ssize_t do_read_block(void *buf, blknum_t blknum, std::size_t nblocks)=0
virtual ~block_device_impl() override
virtual ssize_t do_write(const void *buf, std::size_t nbyte) override
virtual ssize_t do_write_block(const void *buf, blknum_t blknum, std::size_t nblocks)=0
block_device::blknum_t blknum_t
virtual ~block_device() override
block_device_impl & impl(void) const
virtual int vioctl(int request, std::va_list args) override
virtual ssize_t read_block(void *buf, blknum_t blknum, std::size_t nblocks=1)
virtual ssize_t write_block(const void *buf, blknum_t blknum, std::size_t nblocks=1)
virtual int do_vioctl(int request, std::va_list args)=0
static void link(value_type *device)
Base device class.
Definition device.h:68
const char * name(void) const
Definition device.h:307
off_t offset(void)
Definition io.h:476
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:60
#define BLKPBSZGET
Definition ioctl.h:101
#define BLKGETSIZE64
Definition ioctl.h:100
#define BLKSSZGET
Definition ioctl.h:99
System namespace.