Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
ChainingBlockDevice.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "ChainingBlockDevice.h" 00018 #include "platform/mbed_atomic.h" 00019 #include "platform/mbed_assert.h" 00020 00021 namespace mbed { 00022 00023 ChainingBlockDevice::ChainingBlockDevice(BlockDevice **bds, size_t bd_count) 00024 : _bds(bds), _bd_count(bd_count) 00025 , _read_size(0), _program_size(0), _erase_size(0), _size(0) 00026 , _erase_value(-1), _init_ref_count(0), _is_initialized(false) 00027 { 00028 } 00029 00030 static bool is_aligned(uint64_t x, uint64_t alignment) 00031 { 00032 return (x / alignment) * alignment == x; 00033 } 00034 00035 int ChainingBlockDevice::init() 00036 { 00037 int err; 00038 uint32_t val = core_util_atomic_incr_u32 (&_init_ref_count, 1); 00039 00040 if (val != 1) { 00041 return BD_ERROR_OK; 00042 } 00043 00044 _read_size = 0; 00045 _program_size = 0; 00046 _erase_size = 0; 00047 _erase_value = -1; 00048 _size = 0; 00049 00050 // Initialize children block devices, find all sizes and 00051 // assert that block sizes are similar. We can't do this in 00052 // the constructor since some block devices may need to be 00053 // initialized before they know their block size/count 00054 for (size_t i = 0; i < _bd_count; i++) { 00055 err = _bds[i]->init(); 00056 if (err) { 00057 goto fail; 00058 } 00059 00060 bd_size_t read = _bds[i]->get_read_size(); 00061 if (i == 0 || (read >= _read_size && is_aligned(read, _read_size))) { 00062 _read_size = read; 00063 } else { 00064 MBED_ASSERT(_read_size > read && is_aligned(_read_size, read)); 00065 } 00066 00067 bd_size_t program = _bds[i]->get_program_size(); 00068 if (i == 0 || (program >= _program_size && is_aligned(program, _program_size))) { 00069 _program_size = program; 00070 } else { 00071 MBED_ASSERT(_program_size > program && is_aligned(_program_size, program)); 00072 } 00073 00074 bd_size_t erase = _bds[i]->get_erase_size(); 00075 if (i == 0 || (erase >= _erase_size && is_aligned(erase, _erase_size))) { 00076 _erase_size = erase; 00077 } else { 00078 MBED_ASSERT(_erase_size > erase && is_aligned(_erase_size, erase)); 00079 } 00080 00081 int value = _bds[i]->get_erase_value(); 00082 if (i == 0 || value == _erase_value) { 00083 _erase_value = value; 00084 } else { 00085 _erase_value = -1; 00086 } 00087 00088 _size += _bds[i]->size(); 00089 } 00090 00091 _is_initialized = true; 00092 return BD_ERROR_OK; 00093 00094 fail: 00095 _is_initialized = false; 00096 _init_ref_count = 0; 00097 return err; 00098 } 00099 00100 int ChainingBlockDevice::deinit() 00101 { 00102 if (!_is_initialized) { 00103 return BD_ERROR_OK; 00104 } 00105 00106 uint32_t val = core_util_atomic_decr_u32 (&_init_ref_count, 1); 00107 00108 if (val) { 00109 return BD_ERROR_OK; 00110 } 00111 00112 for (size_t i = 0; i < _bd_count; i++) { 00113 int err = _bds[i]->deinit(); 00114 if (err) { 00115 return err; 00116 } 00117 } 00118 00119 _is_initialized = false; 00120 return BD_ERROR_OK; 00121 } 00122 00123 int ChainingBlockDevice::sync() 00124 { 00125 if (!_is_initialized) { 00126 return BD_ERROR_DEVICE_ERROR; 00127 } 00128 00129 for (size_t i = 0; i < _bd_count; i++) { 00130 int err = _bds[i]->sync(); 00131 if (err) { 00132 return err; 00133 } 00134 } 00135 00136 return 0; 00137 } 00138 00139 int ChainingBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00140 { 00141 MBED_ASSERT(is_valid_read(addr, size)); 00142 if (!_is_initialized) { 00143 return BD_ERROR_DEVICE_ERROR; 00144 } 00145 00146 uint8_t *buffer = static_cast<uint8_t *>(b); 00147 00148 // Find block devices containing blocks, may span multiple block devices 00149 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00150 bd_size_t bdsize = _bds[i]->size(); 00151 00152 if (addr < bdsize) { 00153 bd_size_t read = size; 00154 if (addr + read > bdsize) { 00155 read = bdsize - addr; 00156 } 00157 00158 int err = _bds[i]->read(buffer, addr, read); 00159 if (err) { 00160 return err; 00161 } 00162 00163 buffer += read; 00164 addr += read; 00165 size -= read; 00166 } 00167 00168 addr -= bdsize; 00169 } 00170 00171 return 0; 00172 } 00173 00174 int ChainingBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00175 { 00176 MBED_ASSERT(is_valid_program(addr, size)); 00177 if (!_is_initialized) { 00178 return BD_ERROR_DEVICE_ERROR; 00179 } 00180 00181 const uint8_t *buffer = static_cast<const uint8_t *>(b); 00182 00183 // Find block devices containing blocks, may span multiple block devices 00184 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00185 bd_size_t bdsize = _bds[i]->size(); 00186 00187 if (addr < bdsize) { 00188 bd_size_t program = size; 00189 if (addr + program > bdsize) { 00190 program = bdsize - addr; 00191 } 00192 00193 int err = _bds[i]->program(buffer, addr, program); 00194 if (err) { 00195 return err; 00196 } 00197 00198 buffer += program; 00199 addr += program; 00200 size -= program; 00201 } 00202 00203 addr -= bdsize; 00204 } 00205 00206 return 0; 00207 } 00208 00209 int ChainingBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00210 { 00211 MBED_ASSERT(is_valid_erase(addr, size)); 00212 if (!_is_initialized) { 00213 return BD_ERROR_DEVICE_ERROR; 00214 } 00215 00216 // Find block devices containing blocks, may span multiple block devices 00217 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00218 bd_size_t bdsize = _bds[i]->size(); 00219 00220 if (addr < bdsize) { 00221 bd_size_t erase = size; 00222 if (addr + erase > bdsize) { 00223 erase = bdsize - addr; 00224 } 00225 00226 int err = _bds[i]->erase(addr, erase); 00227 if (err) { 00228 return err; 00229 } 00230 00231 addr += erase; 00232 size -= erase; 00233 } 00234 00235 addr -= bdsize; 00236 } 00237 00238 return 0; 00239 } 00240 00241 bd_size_t ChainingBlockDevice::get_read_size() const 00242 { 00243 return _read_size; 00244 } 00245 00246 bd_size_t ChainingBlockDevice::get_program_size() const 00247 { 00248 return _program_size; 00249 } 00250 00251 bd_size_t ChainingBlockDevice::get_erase_size() const 00252 { 00253 return _erase_size; 00254 } 00255 00256 bd_size_t ChainingBlockDevice::get_erase_size(bd_addr_t addr) const 00257 { 00258 if (!_is_initialized) { 00259 return 0; 00260 } 00261 00262 bd_addr_t bd_start_addr = 0; 00263 for (size_t i = 0; i < _bd_count; i++) { 00264 bd_size_t bdsize = _bds[i]->size(); 00265 if (addr < (bd_start_addr + bdsize)) { 00266 return _bds[i]->get_erase_size(addr - bd_start_addr); 00267 } 00268 bd_start_addr += bdsize; 00269 } 00270 00271 // Getting here implies an illegal address 00272 MBED_ASSERT(0); 00273 return 0; // satisfy compiler 00274 } 00275 00276 int ChainingBlockDevice::get_erase_value() const 00277 { 00278 return _erase_value; 00279 } 00280 00281 bd_size_t ChainingBlockDevice::size() const 00282 { 00283 return _size; 00284 } 00285 00286 const char *ChainingBlockDevice::get_type() const 00287 { 00288 return "CHAINING"; 00289 } 00290 00291 } // namespace mbed
Generated on Tue Jul 12 2022 13:54:06 by
