Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ChainingBlockDevice.cpp Source File

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