µ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 Liviu Ionescu.
5 *
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
13 * conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
30
32
33#include <cstring>
34#include <cassert>
35#include <cerrno>
36#include <cstdarg>
37
38// ----------------------------------------------------------------------------
39
40#if defined(__clang__)
41#pragma clang diagnostic ignored "-Wc++98-compat"
42#endif
43
44// ----------------------------------------------------------------------------
45
46namespace os
47{
48 namespace posix
49 {
50 // ========================================================================
51
53 device
55 {
56#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
57 trace::printf ("block_device::%s(\"%s\")=@%p\n", __func__, name_, this);
58#endif
59
61 }
62
64 {
65#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
66 trace::printf ("block_device::%s() @%p %s\n", __func__, this, name_);
67#endif
68 }
69
70 // ------------------------------------------------------------------------
71
72 ssize_t
73 block_device::read_block (void* buf, blknum_t blknum, std::size_t nblocks)
74 {
75#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
76 trace::printf ("block_device::%s(%p, %u, %u) @%p\n", __func__, buf,
77 blknum, nblocks, this);
78#endif
79
80 if (blknum + nblocks > impl ().num_blocks_)
81 {
82 errno = EINVAL;
83 return -1;
84 }
85
86 if (!impl ().do_is_opened ())
87 {
88 errno = EBADF; // Not opened.
89 return -1;
90 }
91
92 return impl ().do_read_block (buf, blknum, nblocks);
93 }
94
95 ssize_t
96 block_device::write_block (const void* buf, blknum_t blknum,
97 std::size_t nblocks)
98 {
99#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
100 trace::printf ("block_device::%s(%p, %u, %u) @%p\n", __func__, buf,
101 blknum, nblocks, this);
102#endif
103
104 if (blknum + nblocks > impl ().num_blocks_)
105 {
106 errno = EINVAL;
107 return -1;
108 }
109
110 if (!impl ().do_is_opened ())
111 {
112 errno = EBADF; // Not opened.
113 return -1;
114 }
115
116 return impl ().do_write_block (buf, blknum, nblocks);
117 }
118
119 int
120 block_device::vioctl (int request, std::va_list args)
121 {
122#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
123 trace::printf ("block_device::%s(%d) @%p\n", __func__, request, this);
124#endif
125
126 if (!impl ().do_is_opened ())
127 {
128 errno = EBADF; // Not opened.
129 return -1;
130 }
131
132 errno = 0;
133
134 switch (static_cast<unsigned int> (request))
135 {
136 case BLKSSZGET:
137 // Get logical device sector size (to be used for read/writes).
138 {
139 std::size_t* sz = va_arg(args, std::size_t*);
140 if (sz == nullptr || impl ().block_logical_size_bytes_ != 0)
141 {
142 errno = EINVAL;
143 return -1;
144 }
145
146 *sz = impl ().block_logical_size_bytes_;
147 return 0;
148 }
149
150 case BLKPBSZGET:
151 // Get physical device sector size (internally used for erase).
152 {
153 std::size_t* sz = va_arg(args, std::size_t*);
154 if (sz == nullptr || impl ().block_physical_size_bytes_ != 0)
155 {
156 errno = EINVAL;
157 return -1;
158 }
159
160 *sz = impl ().block_physical_size_bytes_;
161 return 0;
162 }
163
164 case BLKGETSIZE64:
165 // Get device size in bytes.
166 {
167 uint64_t* sz = va_arg(args, uint64_t*);
168 if (sz == nullptr || impl ().num_blocks_ != 0)
169 {
170 errno = EINVAL;
171 return -1;
172 }
173
174 *sz = (static_cast<uint64_t> (impl ().num_blocks_
175 * impl ().block_logical_size_bytes_));
176 return 0;
177 }
178
179 default:
180
181 // Execute the implementation specific code.
182 return impl ().do_vioctl (request, args);
183 }
184 }
185
186 // ========================================================================
187
189 {
190#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
191 trace::printf ("block_device_impl::%s()=@%p\n", __func__, this);
192#endif
193 }
194
196 {
197#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
198 trace::printf ("block_device_impl::%s() @%p\n", __func__, this);
199#endif
200
201 block_logical_size_bytes_ = 0;
202 num_blocks_ = 0;
203 }
204
205 // ------------------------------------------------------------------------
206
207 off_t
208 block_device_impl::do_lseek (off_t offset, int whence)
209 {
210#if defined(OS_TRACE_POSIX_IO_BLOCK_DEVICE)
211 trace::printf ("block_device_impl::%s(%d, %d) @%p\n", __func__, offset,
212 whence, this);
213#endif
214
215 errno = 0;
216 off_t tmp = offset_;
217
218 switch (whence)
219 {
220 case SEEK_SET:
221 tmp = offset;
222 break;
223
224 case SEEK_CUR:
225 tmp += offset;
226 break;
227
228 case SEEK_END:
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 *= 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 *= 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:78
const char * name(void) const
Definition device.h:310
off_t offset(void)
Definition io.h:461
@ block_device
Definition io.h:138
int printf(const char *format,...)
Write a formatted string to the trace device.
Definition trace.cpp:74
#define BLKPBSZGET
Definition ioctl.h:116
#define BLKGETSIZE64
Definition ioctl.h:115
#define BLKSSZGET
Definition ioctl.h:114
System namespace.