takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

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 "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 }