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