1*9da7a653SHaojian Zhuang /* 2*9da7a653SHaojian Zhuang * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3*9da7a653SHaojian Zhuang * 4*9da7a653SHaojian Zhuang * Redistribution and use in source and binary forms, with or without 5*9da7a653SHaojian Zhuang * modification, are permitted provided that the following conditions are met: 6*9da7a653SHaojian Zhuang * 7*9da7a653SHaojian Zhuang * Redistributions of source code must retain the above copyright notice, this 8*9da7a653SHaojian Zhuang * list of conditions and the following disclaimer. 9*9da7a653SHaojian Zhuang * 10*9da7a653SHaojian Zhuang * Redistributions in binary form must reproduce the above copyright notice, 11*9da7a653SHaojian Zhuang * this list of conditions and the following disclaimer in the documentation 12*9da7a653SHaojian Zhuang * and/or other materials provided with the distribution. 13*9da7a653SHaojian Zhuang * 14*9da7a653SHaojian Zhuang * Neither the name of ARM nor the names of its contributors may be used 15*9da7a653SHaojian Zhuang * to endorse or promote products derived from this software without specific 16*9da7a653SHaojian Zhuang * prior written permission. 17*9da7a653SHaojian Zhuang * 18*9da7a653SHaojian Zhuang * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*9da7a653SHaojian Zhuang * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*9da7a653SHaojian Zhuang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*9da7a653SHaojian Zhuang * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*9da7a653SHaojian Zhuang * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*9da7a653SHaojian Zhuang * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*9da7a653SHaojian Zhuang * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*9da7a653SHaojian Zhuang * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*9da7a653SHaojian Zhuang * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*9da7a653SHaojian Zhuang * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*9da7a653SHaojian Zhuang * POSSIBILITY OF SUCH DAMAGE. 29*9da7a653SHaojian Zhuang */ 30*9da7a653SHaojian Zhuang 31*9da7a653SHaojian Zhuang #include <assert.h> 32*9da7a653SHaojian Zhuang #include <debug.h> 33*9da7a653SHaojian Zhuang #include <errno.h> 34*9da7a653SHaojian Zhuang #include <io_block.h> 35*9da7a653SHaojian Zhuang #include <io_driver.h> 36*9da7a653SHaojian Zhuang #include <io_storage.h> 37*9da7a653SHaojian Zhuang #include <platform_def.h> 38*9da7a653SHaojian Zhuang #include <string.h> 39*9da7a653SHaojian Zhuang 40*9da7a653SHaojian Zhuang typedef struct { 41*9da7a653SHaojian Zhuang io_block_dev_spec_t *dev_spec; 42*9da7a653SHaojian Zhuang uintptr_t base; 43*9da7a653SHaojian Zhuang size_t file_pos; 44*9da7a653SHaojian Zhuang size_t size; 45*9da7a653SHaojian Zhuang } block_dev_state_t; 46*9da7a653SHaojian Zhuang 47*9da7a653SHaojian Zhuang #define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0)) 48*9da7a653SHaojian Zhuang 49*9da7a653SHaojian Zhuang io_type_t device_type_block(void); 50*9da7a653SHaojian Zhuang 51*9da7a653SHaojian Zhuang static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 52*9da7a653SHaojian Zhuang io_entity_t *entity); 53*9da7a653SHaojian Zhuang static int block_seek(io_entity_t *entity, int mode, ssize_t offset); 54*9da7a653SHaojian Zhuang static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 55*9da7a653SHaojian Zhuang size_t *length_read); 56*9da7a653SHaojian Zhuang static int block_write(io_entity_t *entity, const uintptr_t buffer, 57*9da7a653SHaojian Zhuang size_t length, size_t *length_written); 58*9da7a653SHaojian Zhuang static int block_close(io_entity_t *entity); 59*9da7a653SHaojian Zhuang static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 60*9da7a653SHaojian Zhuang static int block_dev_close(io_dev_info_t *dev_info); 61*9da7a653SHaojian Zhuang 62*9da7a653SHaojian Zhuang static const io_dev_connector_t block_dev_connector = { 63*9da7a653SHaojian Zhuang .dev_open = block_dev_open 64*9da7a653SHaojian Zhuang }; 65*9da7a653SHaojian Zhuang 66*9da7a653SHaojian Zhuang static const io_dev_funcs_t block_dev_funcs = { 67*9da7a653SHaojian Zhuang .type = device_type_block, 68*9da7a653SHaojian Zhuang .open = block_open, 69*9da7a653SHaojian Zhuang .seek = block_seek, 70*9da7a653SHaojian Zhuang .size = NULL, 71*9da7a653SHaojian Zhuang .read = block_read, 72*9da7a653SHaojian Zhuang .write = block_write, 73*9da7a653SHaojian Zhuang .close = block_close, 74*9da7a653SHaojian Zhuang .dev_init = NULL, 75*9da7a653SHaojian Zhuang .dev_close = block_dev_close, 76*9da7a653SHaojian Zhuang }; 77*9da7a653SHaojian Zhuang 78*9da7a653SHaojian Zhuang static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; 79*9da7a653SHaojian Zhuang static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; 80*9da7a653SHaojian Zhuang 81*9da7a653SHaojian Zhuang /* Track number of allocated block state */ 82*9da7a653SHaojian Zhuang static unsigned int block_dev_count; 83*9da7a653SHaojian Zhuang 84*9da7a653SHaojian Zhuang io_type_t device_type_block(void) 85*9da7a653SHaojian Zhuang { 86*9da7a653SHaojian Zhuang return IO_TYPE_BLOCK; 87*9da7a653SHaojian Zhuang } 88*9da7a653SHaojian Zhuang 89*9da7a653SHaojian Zhuang /* Locate a block state in the pool, specified by address */ 90*9da7a653SHaojian Zhuang static int find_first_block_state(const io_block_dev_spec_t *dev_spec, 91*9da7a653SHaojian Zhuang unsigned int *index_out) 92*9da7a653SHaojian Zhuang { 93*9da7a653SHaojian Zhuang int result = -ENOENT; 94*9da7a653SHaojian Zhuang for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) { 95*9da7a653SHaojian Zhuang /* dev_spec is used as identifier since it's unique */ 96*9da7a653SHaojian Zhuang if (state_pool[index].dev_spec == dev_spec) { 97*9da7a653SHaojian Zhuang result = 0; 98*9da7a653SHaojian Zhuang *index_out = index; 99*9da7a653SHaojian Zhuang break; 100*9da7a653SHaojian Zhuang } 101*9da7a653SHaojian Zhuang } 102*9da7a653SHaojian Zhuang return result; 103*9da7a653SHaojian Zhuang } 104*9da7a653SHaojian Zhuang 105*9da7a653SHaojian Zhuang /* Allocate a device info from the pool and return a pointer to it */ 106*9da7a653SHaojian Zhuang static int allocate_dev_info(io_dev_info_t **dev_info) 107*9da7a653SHaojian Zhuang { 108*9da7a653SHaojian Zhuang int result = -ENOMEM; 109*9da7a653SHaojian Zhuang assert(dev_info != NULL); 110*9da7a653SHaojian Zhuang 111*9da7a653SHaojian Zhuang if (block_dev_count < MAX_IO_BLOCK_DEVICES) { 112*9da7a653SHaojian Zhuang unsigned int index = 0; 113*9da7a653SHaojian Zhuang result = find_first_block_state(NULL, &index); 114*9da7a653SHaojian Zhuang assert(result == 0); 115*9da7a653SHaojian Zhuang /* initialize dev_info */ 116*9da7a653SHaojian Zhuang dev_info_pool[index].funcs = &block_dev_funcs; 117*9da7a653SHaojian Zhuang dev_info_pool[index].info = (uintptr_t)&state_pool[index]; 118*9da7a653SHaojian Zhuang *dev_info = &dev_info_pool[index]; 119*9da7a653SHaojian Zhuang ++block_dev_count; 120*9da7a653SHaojian Zhuang } 121*9da7a653SHaojian Zhuang 122*9da7a653SHaojian Zhuang return result; 123*9da7a653SHaojian Zhuang } 124*9da7a653SHaojian Zhuang 125*9da7a653SHaojian Zhuang 126*9da7a653SHaojian Zhuang /* Release a device info to the pool */ 127*9da7a653SHaojian Zhuang static int free_dev_info(io_dev_info_t *dev_info) 128*9da7a653SHaojian Zhuang { 129*9da7a653SHaojian Zhuang int result; 130*9da7a653SHaojian Zhuang unsigned int index = 0; 131*9da7a653SHaojian Zhuang block_dev_state_t *state; 132*9da7a653SHaojian Zhuang assert(dev_info != NULL); 133*9da7a653SHaojian Zhuang 134*9da7a653SHaojian Zhuang state = (block_dev_state_t *)dev_info->info; 135*9da7a653SHaojian Zhuang result = find_first_block_state(state->dev_spec, &index); 136*9da7a653SHaojian Zhuang if (result == 0) { 137*9da7a653SHaojian Zhuang /* free if device info is valid */ 138*9da7a653SHaojian Zhuang memset(state, 0, sizeof(block_dev_state_t)); 139*9da7a653SHaojian Zhuang memset(dev_info, 0, sizeof(io_dev_info_t)); 140*9da7a653SHaojian Zhuang --block_dev_count; 141*9da7a653SHaojian Zhuang } 142*9da7a653SHaojian Zhuang 143*9da7a653SHaojian Zhuang return result; 144*9da7a653SHaojian Zhuang } 145*9da7a653SHaojian Zhuang 146*9da7a653SHaojian Zhuang static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 147*9da7a653SHaojian Zhuang io_entity_t *entity) 148*9da7a653SHaojian Zhuang { 149*9da7a653SHaojian Zhuang block_dev_state_t *cur; 150*9da7a653SHaojian Zhuang io_block_spec_t *region; 151*9da7a653SHaojian Zhuang 152*9da7a653SHaojian Zhuang assert((dev_info->info != (uintptr_t)NULL) && 153*9da7a653SHaojian Zhuang (spec != (uintptr_t)NULL) && 154*9da7a653SHaojian Zhuang (entity->info == (uintptr_t)NULL)); 155*9da7a653SHaojian Zhuang 156*9da7a653SHaojian Zhuang region = (io_block_spec_t *)spec; 157*9da7a653SHaojian Zhuang cur = (block_dev_state_t *)dev_info->info; 158*9da7a653SHaojian Zhuang assert(((region->offset % cur->dev_spec->block_size) == 0) && 159*9da7a653SHaojian Zhuang ((region->length % cur->dev_spec->block_size) == 0)); 160*9da7a653SHaojian Zhuang 161*9da7a653SHaojian Zhuang cur->base = region->offset; 162*9da7a653SHaojian Zhuang cur->size = region->length; 163*9da7a653SHaojian Zhuang cur->file_pos = 0; 164*9da7a653SHaojian Zhuang 165*9da7a653SHaojian Zhuang entity->info = (uintptr_t)cur; 166*9da7a653SHaojian Zhuang return 0; 167*9da7a653SHaojian Zhuang } 168*9da7a653SHaojian Zhuang 169*9da7a653SHaojian Zhuang /* parameter offset is relative address at here */ 170*9da7a653SHaojian Zhuang static int block_seek(io_entity_t *entity, int mode, ssize_t offset) 171*9da7a653SHaojian Zhuang { 172*9da7a653SHaojian Zhuang block_dev_state_t *cur; 173*9da7a653SHaojian Zhuang 174*9da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 175*9da7a653SHaojian Zhuang 176*9da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 177*9da7a653SHaojian Zhuang assert((offset >= 0) && (offset < cur->size)); 178*9da7a653SHaojian Zhuang 179*9da7a653SHaojian Zhuang switch (mode) { 180*9da7a653SHaojian Zhuang case IO_SEEK_SET: 181*9da7a653SHaojian Zhuang cur->file_pos = offset; 182*9da7a653SHaojian Zhuang break; 183*9da7a653SHaojian Zhuang case IO_SEEK_CUR: 184*9da7a653SHaojian Zhuang cur->file_pos += offset; 185*9da7a653SHaojian Zhuang break; 186*9da7a653SHaojian Zhuang default: 187*9da7a653SHaojian Zhuang return -EINVAL; 188*9da7a653SHaojian Zhuang } 189*9da7a653SHaojian Zhuang assert(cur->file_pos < cur->size); 190*9da7a653SHaojian Zhuang return 0; 191*9da7a653SHaojian Zhuang } 192*9da7a653SHaojian Zhuang 193*9da7a653SHaojian Zhuang static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 194*9da7a653SHaojian Zhuang size_t *length_read) 195*9da7a653SHaojian Zhuang { 196*9da7a653SHaojian Zhuang block_dev_state_t *cur; 197*9da7a653SHaojian Zhuang io_block_spec_t *buf; 198*9da7a653SHaojian Zhuang io_block_ops_t *ops; 199*9da7a653SHaojian Zhuang size_t aligned_length, skip, count, left, padding, block_size; 200*9da7a653SHaojian Zhuang int lba; 201*9da7a653SHaojian Zhuang 202*9da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 203*9da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 204*9da7a653SHaojian Zhuang ops = &(cur->dev_spec->ops); 205*9da7a653SHaojian Zhuang buf = &(cur->dev_spec->buffer); 206*9da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 207*9da7a653SHaojian Zhuang assert((length <= cur->size) && 208*9da7a653SHaojian Zhuang (length > 0) && 209*9da7a653SHaojian Zhuang (ops->read != 0)); 210*9da7a653SHaojian Zhuang 211*9da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 212*9da7a653SHaojian Zhuang aligned_length = ((skip + length) + (block_size - 1)) & 213*9da7a653SHaojian Zhuang ~(block_size - 1); 214*9da7a653SHaojian Zhuang padding = aligned_length - (skip + length); 215*9da7a653SHaojian Zhuang left = aligned_length; 216*9da7a653SHaojian Zhuang do { 217*9da7a653SHaojian Zhuang lba = (cur->file_pos + cur->base) / block_size; 218*9da7a653SHaojian Zhuang if (left >= buf->length) { 219*9da7a653SHaojian Zhuang /* Since left is larger, it's impossible to padding. */ 220*9da7a653SHaojian Zhuang if (skip) { 221*9da7a653SHaojian Zhuang /* 222*9da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 223*9da7a653SHaojian Zhuang * aligned with block size, we need to use 224*9da7a653SHaojian Zhuang * block buffer to read block. Since block 225*9da7a653SHaojian Zhuang * device is always relied on DMA operation. 226*9da7a653SHaojian Zhuang */ 227*9da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, 228*9da7a653SHaojian Zhuang buf->length); 229*9da7a653SHaojian Zhuang } else { 230*9da7a653SHaojian Zhuang count = ops->read(lba, buffer, buf->length); 231*9da7a653SHaojian Zhuang } 232*9da7a653SHaojian Zhuang assert(count == buf->length); 233*9da7a653SHaojian Zhuang cur->file_pos += count - skip; 234*9da7a653SHaojian Zhuang if (skip) { 235*9da7a653SHaojian Zhuang /* 236*9da7a653SHaojian Zhuang * Since it's not aligned with block size, 237*9da7a653SHaojian Zhuang * block buffer is used to store data. 238*9da7a653SHaojian Zhuang */ 239*9da7a653SHaojian Zhuang memcpy((void *)buffer, 240*9da7a653SHaojian Zhuang (void *)(buf->offset + skip), 241*9da7a653SHaojian Zhuang count - skip); 242*9da7a653SHaojian Zhuang } 243*9da7a653SHaojian Zhuang left = left - (count - skip); 244*9da7a653SHaojian Zhuang } else { 245*9da7a653SHaojian Zhuang if (skip || padding) { 246*9da7a653SHaojian Zhuang /* 247*9da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 248*9da7a653SHaojian Zhuang * aligned with block size, we have to read 249*9da7a653SHaojian Zhuang * full block by block buffer instead. 250*9da7a653SHaojian Zhuang * The size isn't aligned with block size. 251*9da7a653SHaojian Zhuang * Use block buffer to avoid overflow. 252*9da7a653SHaojian Zhuang */ 253*9da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, left); 254*9da7a653SHaojian Zhuang } else 255*9da7a653SHaojian Zhuang count = ops->read(lba, buffer, left); 256*9da7a653SHaojian Zhuang assert(count == left); 257*9da7a653SHaojian Zhuang left = left - (skip + padding); 258*9da7a653SHaojian Zhuang cur->file_pos += left; 259*9da7a653SHaojian Zhuang if (skip || padding) { 260*9da7a653SHaojian Zhuang /* 261*9da7a653SHaojian Zhuang * Since it's not aligned with block size, 262*9da7a653SHaojian Zhuang * block buffer is used to store data. 263*9da7a653SHaojian Zhuang */ 264*9da7a653SHaojian Zhuang memcpy((void *)buffer, 265*9da7a653SHaojian Zhuang (void *)(buf->offset + skip), 266*9da7a653SHaojian Zhuang left); 267*9da7a653SHaojian Zhuang } 268*9da7a653SHaojian Zhuang /* It's already the last block operation */ 269*9da7a653SHaojian Zhuang left = 0; 270*9da7a653SHaojian Zhuang } 271*9da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 272*9da7a653SHaojian Zhuang } while (left > 0); 273*9da7a653SHaojian Zhuang *length_read = length; 274*9da7a653SHaojian Zhuang 275*9da7a653SHaojian Zhuang return 0; 276*9da7a653SHaojian Zhuang } 277*9da7a653SHaojian Zhuang 278*9da7a653SHaojian Zhuang static int block_write(io_entity_t *entity, const uintptr_t buffer, 279*9da7a653SHaojian Zhuang size_t length, size_t *length_written) 280*9da7a653SHaojian Zhuang { 281*9da7a653SHaojian Zhuang block_dev_state_t *cur; 282*9da7a653SHaojian Zhuang io_block_spec_t *buf; 283*9da7a653SHaojian Zhuang io_block_ops_t *ops; 284*9da7a653SHaojian Zhuang size_t aligned_length, skip, count, left, padding, block_size; 285*9da7a653SHaojian Zhuang int lba; 286*9da7a653SHaojian Zhuang 287*9da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 288*9da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 289*9da7a653SHaojian Zhuang ops = &(cur->dev_spec->ops); 290*9da7a653SHaojian Zhuang buf = &(cur->dev_spec->buffer); 291*9da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 292*9da7a653SHaojian Zhuang assert((length <= cur->size) && 293*9da7a653SHaojian Zhuang (length > 0) && 294*9da7a653SHaojian Zhuang (ops->read != 0) && 295*9da7a653SHaojian Zhuang (ops->write != 0)); 296*9da7a653SHaojian Zhuang 297*9da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 298*9da7a653SHaojian Zhuang aligned_length = ((skip + length) + (block_size - 1)) & 299*9da7a653SHaojian Zhuang ~(block_size - 1); 300*9da7a653SHaojian Zhuang padding = aligned_length - (skip + length); 301*9da7a653SHaojian Zhuang left = aligned_length; 302*9da7a653SHaojian Zhuang do { 303*9da7a653SHaojian Zhuang lba = (cur->file_pos + cur->base) / block_size; 304*9da7a653SHaojian Zhuang if (left >= buf->length) { 305*9da7a653SHaojian Zhuang /* Since left is larger, it's impossible to padding. */ 306*9da7a653SHaojian Zhuang if (skip) { 307*9da7a653SHaojian Zhuang /* 308*9da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 309*9da7a653SHaojian Zhuang * aligned with block size, we need to use 310*9da7a653SHaojian Zhuang * block buffer to write block. Since block 311*9da7a653SHaojian Zhuang * device is always relied on DMA operation. 312*9da7a653SHaojian Zhuang */ 313*9da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, 314*9da7a653SHaojian Zhuang buf->length); 315*9da7a653SHaojian Zhuang assert(count == buf->length); 316*9da7a653SHaojian Zhuang memcpy((void *)(buf->offset + skip), 317*9da7a653SHaojian Zhuang (void *)buffer, 318*9da7a653SHaojian Zhuang count - skip); 319*9da7a653SHaojian Zhuang count = ops->write(lba, buf->offset, 320*9da7a653SHaojian Zhuang buf->length); 321*9da7a653SHaojian Zhuang } else 322*9da7a653SHaojian Zhuang count = ops->write(lba, buffer, buf->length); 323*9da7a653SHaojian Zhuang assert(count == buf->length); 324*9da7a653SHaojian Zhuang cur->file_pos += count - skip; 325*9da7a653SHaojian Zhuang left = left - (count - skip); 326*9da7a653SHaojian Zhuang } else { 327*9da7a653SHaojian Zhuang if (skip || padding) { 328*9da7a653SHaojian Zhuang /* 329*9da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 330*9da7a653SHaojian Zhuang * aligned with block size, we need to avoid 331*9da7a653SHaojian Zhuang * poluate data in the beginning. Reading and 332*9da7a653SHaojian Zhuang * skipping the beginning is the only way. 333*9da7a653SHaojian Zhuang * The size isn't aligned with block size. 334*9da7a653SHaojian Zhuang * Use block buffer to avoid overflow. 335*9da7a653SHaojian Zhuang */ 336*9da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, left); 337*9da7a653SHaojian Zhuang assert(count == left); 338*9da7a653SHaojian Zhuang memcpy((void *)(buf->offset + skip), 339*9da7a653SHaojian Zhuang (void *)buffer, 340*9da7a653SHaojian Zhuang left - skip - padding); 341*9da7a653SHaojian Zhuang count = ops->write(lba, buf->offset, left); 342*9da7a653SHaojian Zhuang } else 343*9da7a653SHaojian Zhuang count = ops->write(lba, buffer, left); 344*9da7a653SHaojian Zhuang assert(count == left); 345*9da7a653SHaojian Zhuang cur->file_pos += left - (skip + padding); 346*9da7a653SHaojian Zhuang /* It's already the last block operation */ 347*9da7a653SHaojian Zhuang left = 0; 348*9da7a653SHaojian Zhuang } 349*9da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 350*9da7a653SHaojian Zhuang } while (left > 0); 351*9da7a653SHaojian Zhuang *length_written = length; 352*9da7a653SHaojian Zhuang return 0; 353*9da7a653SHaojian Zhuang } 354*9da7a653SHaojian Zhuang 355*9da7a653SHaojian Zhuang static int block_close(io_entity_t *entity) 356*9da7a653SHaojian Zhuang { 357*9da7a653SHaojian Zhuang entity->info = (uintptr_t)NULL; 358*9da7a653SHaojian Zhuang return 0; 359*9da7a653SHaojian Zhuang } 360*9da7a653SHaojian Zhuang 361*9da7a653SHaojian Zhuang static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) 362*9da7a653SHaojian Zhuang { 363*9da7a653SHaojian Zhuang block_dev_state_t *cur; 364*9da7a653SHaojian Zhuang io_block_spec_t *buffer; 365*9da7a653SHaojian Zhuang io_dev_info_t *info; 366*9da7a653SHaojian Zhuang size_t block_size; 367*9da7a653SHaojian Zhuang int result; 368*9da7a653SHaojian Zhuang 369*9da7a653SHaojian Zhuang assert(dev_info != NULL); 370*9da7a653SHaojian Zhuang result = allocate_dev_info(&info); 371*9da7a653SHaojian Zhuang if (result) 372*9da7a653SHaojian Zhuang return -ENOENT; 373*9da7a653SHaojian Zhuang 374*9da7a653SHaojian Zhuang cur = (block_dev_state_t *)info->info; 375*9da7a653SHaojian Zhuang /* dev_spec is type of io_block_dev_spec_t. */ 376*9da7a653SHaojian Zhuang cur->dev_spec = (io_block_dev_spec_t *)dev_spec; 377*9da7a653SHaojian Zhuang buffer = &(cur->dev_spec->buffer); 378*9da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 379*9da7a653SHaojian Zhuang assert((block_size > 0) && 380*9da7a653SHaojian Zhuang (is_power_of_2(block_size) != 0) && 381*9da7a653SHaojian Zhuang ((buffer->offset % block_size) == 0) && 382*9da7a653SHaojian Zhuang ((buffer->length % block_size) == 0)); 383*9da7a653SHaojian Zhuang 384*9da7a653SHaojian Zhuang *dev_info = info; /* cast away const */ 385*9da7a653SHaojian Zhuang (void)block_size; 386*9da7a653SHaojian Zhuang (void)buffer; 387*9da7a653SHaojian Zhuang return 0; 388*9da7a653SHaojian Zhuang } 389*9da7a653SHaojian Zhuang 390*9da7a653SHaojian Zhuang static int block_dev_close(io_dev_info_t *dev_info) 391*9da7a653SHaojian Zhuang { 392*9da7a653SHaojian Zhuang return free_dev_info(dev_info); 393*9da7a653SHaojian Zhuang } 394*9da7a653SHaojian Zhuang 395*9da7a653SHaojian Zhuang /* Exported functions */ 396*9da7a653SHaojian Zhuang 397*9da7a653SHaojian Zhuang /* Register the Block driver with the IO abstraction */ 398*9da7a653SHaojian Zhuang int register_io_dev_block(const io_dev_connector_t **dev_con) 399*9da7a653SHaojian Zhuang { 400*9da7a653SHaojian Zhuang int result; 401*9da7a653SHaojian Zhuang 402*9da7a653SHaojian Zhuang assert(dev_con != NULL); 403*9da7a653SHaojian Zhuang 404*9da7a653SHaojian Zhuang /* 405*9da7a653SHaojian Zhuang * Since dev_info isn't really used in io_register_device, always 406*9da7a653SHaojian Zhuang * use the same device info at here instead. 407*9da7a653SHaojian Zhuang */ 408*9da7a653SHaojian Zhuang result = io_register_device(&dev_info_pool[0]); 409*9da7a653SHaojian Zhuang if (result == 0) 410*9da7a653SHaojian Zhuang *dev_con = &block_dev_connector; 411*9da7a653SHaojian Zhuang return result; 412*9da7a653SHaojian Zhuang } 413