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.
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 "mbed_critical.h" 00019 00020 00021 ChainingBlockDevice::ChainingBlockDevice(BlockDevice **bds, size_t bd_count) 00022 : _bds(bds), _bd_count(bd_count) 00023 , _read_size(0), _program_size(0), _erase_size(0), _size(0) 00024 , _erase_value(-1), _init_ref_count(0), _is_initialized(false) 00025 { 00026 } 00027 00028 static bool is_aligned(uint64_t x, uint64_t alignment) 00029 { 00030 return (x / alignment) * alignment == x; 00031 } 00032 00033 int ChainingBlockDevice::init() 00034 { 00035 int err; 00036 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1); 00037 00038 if (val != 1) { 00039 return BD_ERROR_OK; 00040 } 00041 00042 _read_size = 0; 00043 _program_size = 0; 00044 _erase_size = 0; 00045 _erase_value = -1; 00046 _size = 0; 00047 00048 // Initialize children block devices, find all sizes and 00049 // assert that block sizes are similar. We can't do this in 00050 // the constructor since some block devices may need to be 00051 // initialized before they know their block size/count 00052 for (size_t i = 0; i < _bd_count; i++) { 00053 err = _bds[i]->init(); 00054 if (err) { 00055 goto fail; 00056 } 00057 00058 bd_size_t read = _bds[i]->get_read_size(); 00059 if (i == 0 || (read >= _read_size && is_aligned(read, _read_size))) { 00060 _read_size = read; 00061 } else { 00062 MBED_ASSERT(_read_size > read && is_aligned(_read_size, read)); 00063 } 00064 00065 bd_size_t program = _bds[i]->get_program_size(); 00066 if (i == 0 || (program >= _program_size && is_aligned(program, _program_size))) { 00067 _program_size = program; 00068 } else { 00069 MBED_ASSERT(_program_size > program && is_aligned(_program_size, program)); 00070 } 00071 00072 bd_size_t erase = _bds[i]->get_erase_size(); 00073 if (i == 0 || (erase >= _erase_size && is_aligned(erase, _erase_size))) { 00074 _erase_size = erase; 00075 } else { 00076 MBED_ASSERT(_erase_size > erase && is_aligned(_erase_size, erase)); 00077 } 00078 00079 int value = _bds[i]->get_erase_value(); 00080 if (i == 0 || value == _erase_value) { 00081 _erase_value = value; 00082 } else { 00083 _erase_value = -1; 00084 } 00085 00086 _size += _bds[i]->size(); 00087 } 00088 00089 _is_initialized = true; 00090 return BD_ERROR_OK; 00091 00092 fail: 00093 _is_initialized = false; 00094 _init_ref_count = 0; 00095 return err; 00096 } 00097 00098 int ChainingBlockDevice::deinit() 00099 { 00100 if (!_is_initialized) { 00101 return BD_ERROR_OK; 00102 } 00103 00104 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1); 00105 00106 if (val) { 00107 return BD_ERROR_OK; 00108 } 00109 00110 for (size_t i = 0; i < _bd_count; i++) { 00111 int err = _bds[i]->deinit(); 00112 if (err) { 00113 return err; 00114 } 00115 } 00116 00117 _is_initialized = false; 00118 return BD_ERROR_OK; 00119 } 00120 00121 int ChainingBlockDevice::sync() 00122 { 00123 if (!_is_initialized) { 00124 return BD_ERROR_DEVICE_ERROR; 00125 } 00126 00127 for (size_t i = 0; i < _bd_count; i++) { 00128 int err = _bds[i]->sync(); 00129 if (err) { 00130 return err; 00131 } 00132 } 00133 00134 return 0; 00135 } 00136 00137 int ChainingBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00138 { 00139 MBED_ASSERT(is_valid_read(addr, size)); 00140 if (!_is_initialized) { 00141 return BD_ERROR_DEVICE_ERROR; 00142 } 00143 00144 uint8_t *buffer = static_cast<uint8_t*>(b); 00145 00146 // Find block devices containing blocks, may span multiple block devices 00147 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00148 bd_size_t bdsize = _bds[i]->size(); 00149 00150 if (addr < bdsize) { 00151 bd_size_t read = size; 00152 if (addr + read > bdsize) { 00153 read = bdsize - addr; 00154 } 00155 00156 int err = _bds[i]->read(buffer, addr, read); 00157 if (err) { 00158 return err; 00159 } 00160 00161 buffer += read; 00162 addr += read; 00163 size -= read; 00164 } 00165 00166 addr -= bdsize; 00167 } 00168 00169 return 0; 00170 } 00171 00172 int ChainingBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00173 { 00174 MBED_ASSERT(is_valid_program(addr, size)); 00175 if (!_is_initialized) { 00176 return BD_ERROR_DEVICE_ERROR; 00177 } 00178 00179 const uint8_t *buffer = static_cast<const uint8_t*>(b); 00180 00181 // Find block devices containing blocks, may span multiple block devices 00182 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00183 bd_size_t bdsize = _bds[i]->size(); 00184 00185 if (addr < bdsize) { 00186 bd_size_t program = size; 00187 if (addr + program > bdsize) { 00188 program = bdsize - addr; 00189 } 00190 00191 int err = _bds[i]->program(buffer, addr, program); 00192 if (err) { 00193 return err; 00194 } 00195 00196 buffer += program; 00197 addr += program; 00198 size -= program; 00199 } 00200 00201 addr -= bdsize; 00202 } 00203 00204 return 0; 00205 } 00206 00207 int ChainingBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00208 { 00209 MBED_ASSERT(is_valid_erase(addr, size)); 00210 if (!_is_initialized) { 00211 return BD_ERROR_DEVICE_ERROR; 00212 } 00213 00214 // Find block devices containing blocks, may span multiple block devices 00215 for (size_t i = 0; i < _bd_count && size > 0; i++) { 00216 bd_size_t bdsize = _bds[i]->size(); 00217 00218 if (addr < bdsize) { 00219 bd_size_t erase = size; 00220 if (addr + erase > bdsize) { 00221 erase = bdsize - addr; 00222 } 00223 00224 int err = _bds[i]->erase(addr, erase); 00225 if (err) { 00226 return err; 00227 } 00228 00229 addr += erase; 00230 size -= erase; 00231 } 00232 00233 addr -= bdsize; 00234 } 00235 00236 return 0; 00237 } 00238 00239 bd_size_t ChainingBlockDevice::get_read_size() const 00240 { 00241 return _read_size; 00242 } 00243 00244 bd_size_t ChainingBlockDevice::get_program_size() const 00245 { 00246 return _program_size; 00247 } 00248 00249 bd_size_t ChainingBlockDevice::get_erase_size() const 00250 { 00251 return _erase_size; 00252 } 00253 00254 bd_size_t ChainingBlockDevice::get_erase_size(bd_addr_t addr) const 00255 { 00256 if (!_is_initialized) { 00257 return BD_ERROR_DEVICE_ERROR; 00258 } 00259 00260 bd_addr_t bd_start_addr = 0; 00261 for (size_t i = 0; i < _bd_count; i++) { 00262 bd_size_t bdsize = _bds[i]->size(); 00263 if (addr < (bd_start_addr + bdsize)) { 00264 return _bds[i]->get_erase_size(addr - bd_start_addr); 00265 } 00266 bd_start_addr += bdsize; 00267 } 00268 00269 // Getting here implies an illegal address 00270 MBED_ASSERT(0); 00271 return 0; // satisfy compiler 00272 } 00273 00274 int ChainingBlockDevice::get_erase_value() const 00275 { 00276 return _erase_value; 00277 } 00278 00279 bd_size_t ChainingBlockDevice::size() const 00280 { 00281 return _size; 00282 }
Generated on Tue Aug 9 2022 00:37:04 by
