19da7a653SHaojian Zhuang /* 232f0d3c6SDouglas Raillard * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. 39da7a653SHaojian Zhuang * 4*82cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 59da7a653SHaojian Zhuang */ 69da7a653SHaojian Zhuang 79da7a653SHaojian Zhuang #include <assert.h> 89da7a653SHaojian Zhuang #include <debug.h> 99da7a653SHaojian Zhuang #include <errno.h> 109da7a653SHaojian Zhuang #include <io_block.h> 119da7a653SHaojian Zhuang #include <io_driver.h> 129da7a653SHaojian Zhuang #include <io_storage.h> 139da7a653SHaojian Zhuang #include <platform_def.h> 149da7a653SHaojian Zhuang #include <string.h> 1532f0d3c6SDouglas Raillard #include <utils.h> 169da7a653SHaojian Zhuang 179da7a653SHaojian Zhuang typedef struct { 189da7a653SHaojian Zhuang io_block_dev_spec_t *dev_spec; 199da7a653SHaojian Zhuang uintptr_t base; 209da7a653SHaojian Zhuang size_t file_pos; 219da7a653SHaojian Zhuang size_t size; 229da7a653SHaojian Zhuang } block_dev_state_t; 239da7a653SHaojian Zhuang 249da7a653SHaojian Zhuang #define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0)) 259da7a653SHaojian Zhuang 269da7a653SHaojian Zhuang io_type_t device_type_block(void); 279da7a653SHaojian Zhuang 289da7a653SHaojian Zhuang static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 299da7a653SHaojian Zhuang io_entity_t *entity); 309da7a653SHaojian Zhuang static int block_seek(io_entity_t *entity, int mode, ssize_t offset); 319da7a653SHaojian Zhuang static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 329da7a653SHaojian Zhuang size_t *length_read); 339da7a653SHaojian Zhuang static int block_write(io_entity_t *entity, const uintptr_t buffer, 349da7a653SHaojian Zhuang size_t length, size_t *length_written); 359da7a653SHaojian Zhuang static int block_close(io_entity_t *entity); 369da7a653SHaojian Zhuang static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); 379da7a653SHaojian Zhuang static int block_dev_close(io_dev_info_t *dev_info); 389da7a653SHaojian Zhuang 399da7a653SHaojian Zhuang static const io_dev_connector_t block_dev_connector = { 409da7a653SHaojian Zhuang .dev_open = block_dev_open 419da7a653SHaojian Zhuang }; 429da7a653SHaojian Zhuang 439da7a653SHaojian Zhuang static const io_dev_funcs_t block_dev_funcs = { 449da7a653SHaojian Zhuang .type = device_type_block, 459da7a653SHaojian Zhuang .open = block_open, 469da7a653SHaojian Zhuang .seek = block_seek, 479da7a653SHaojian Zhuang .size = NULL, 489da7a653SHaojian Zhuang .read = block_read, 499da7a653SHaojian Zhuang .write = block_write, 509da7a653SHaojian Zhuang .close = block_close, 519da7a653SHaojian Zhuang .dev_init = NULL, 529da7a653SHaojian Zhuang .dev_close = block_dev_close, 539da7a653SHaojian Zhuang }; 549da7a653SHaojian Zhuang 559da7a653SHaojian Zhuang static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; 569da7a653SHaojian Zhuang static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; 579da7a653SHaojian Zhuang 589da7a653SHaojian Zhuang /* Track number of allocated block state */ 599da7a653SHaojian Zhuang static unsigned int block_dev_count; 609da7a653SHaojian Zhuang 619da7a653SHaojian Zhuang io_type_t device_type_block(void) 629da7a653SHaojian Zhuang { 639da7a653SHaojian Zhuang return IO_TYPE_BLOCK; 649da7a653SHaojian Zhuang } 659da7a653SHaojian Zhuang 669da7a653SHaojian Zhuang /* Locate a block state in the pool, specified by address */ 679da7a653SHaojian Zhuang static int find_first_block_state(const io_block_dev_spec_t *dev_spec, 689da7a653SHaojian Zhuang unsigned int *index_out) 699da7a653SHaojian Zhuang { 709da7a653SHaojian Zhuang int result = -ENOENT; 719da7a653SHaojian Zhuang for (int index = 0; index < MAX_IO_BLOCK_DEVICES; ++index) { 729da7a653SHaojian Zhuang /* dev_spec is used as identifier since it's unique */ 739da7a653SHaojian Zhuang if (state_pool[index].dev_spec == dev_spec) { 749da7a653SHaojian Zhuang result = 0; 759da7a653SHaojian Zhuang *index_out = index; 769da7a653SHaojian Zhuang break; 779da7a653SHaojian Zhuang } 789da7a653SHaojian Zhuang } 799da7a653SHaojian Zhuang return result; 809da7a653SHaojian Zhuang } 819da7a653SHaojian Zhuang 829da7a653SHaojian Zhuang /* Allocate a device info from the pool and return a pointer to it */ 839da7a653SHaojian Zhuang static int allocate_dev_info(io_dev_info_t **dev_info) 849da7a653SHaojian Zhuang { 859da7a653SHaojian Zhuang int result = -ENOMEM; 869da7a653SHaojian Zhuang assert(dev_info != NULL); 879da7a653SHaojian Zhuang 889da7a653SHaojian Zhuang if (block_dev_count < MAX_IO_BLOCK_DEVICES) { 899da7a653SHaojian Zhuang unsigned int index = 0; 909da7a653SHaojian Zhuang result = find_first_block_state(NULL, &index); 919da7a653SHaojian Zhuang assert(result == 0); 929da7a653SHaojian Zhuang /* initialize dev_info */ 939da7a653SHaojian Zhuang dev_info_pool[index].funcs = &block_dev_funcs; 949da7a653SHaojian Zhuang dev_info_pool[index].info = (uintptr_t)&state_pool[index]; 959da7a653SHaojian Zhuang *dev_info = &dev_info_pool[index]; 969da7a653SHaojian Zhuang ++block_dev_count; 979da7a653SHaojian Zhuang } 989da7a653SHaojian Zhuang 999da7a653SHaojian Zhuang return result; 1009da7a653SHaojian Zhuang } 1019da7a653SHaojian Zhuang 1029da7a653SHaojian Zhuang 1039da7a653SHaojian Zhuang /* Release a device info to the pool */ 1049da7a653SHaojian Zhuang static int free_dev_info(io_dev_info_t *dev_info) 1059da7a653SHaojian Zhuang { 1069da7a653SHaojian Zhuang int result; 1079da7a653SHaojian Zhuang unsigned int index = 0; 1089da7a653SHaojian Zhuang block_dev_state_t *state; 1099da7a653SHaojian Zhuang assert(dev_info != NULL); 1109da7a653SHaojian Zhuang 1119da7a653SHaojian Zhuang state = (block_dev_state_t *)dev_info->info; 1129da7a653SHaojian Zhuang result = find_first_block_state(state->dev_spec, &index); 1139da7a653SHaojian Zhuang if (result == 0) { 1149da7a653SHaojian Zhuang /* free if device info is valid */ 11532f0d3c6SDouglas Raillard zeromem(state, sizeof(block_dev_state_t)); 11632f0d3c6SDouglas Raillard zeromem(dev_info, sizeof(io_dev_info_t)); 1179da7a653SHaojian Zhuang --block_dev_count; 1189da7a653SHaojian Zhuang } 1199da7a653SHaojian Zhuang 1209da7a653SHaojian Zhuang return result; 1219da7a653SHaojian Zhuang } 1229da7a653SHaojian Zhuang 1239da7a653SHaojian Zhuang static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, 1249da7a653SHaojian Zhuang io_entity_t *entity) 1259da7a653SHaojian Zhuang { 1269da7a653SHaojian Zhuang block_dev_state_t *cur; 1279da7a653SHaojian Zhuang io_block_spec_t *region; 1289da7a653SHaojian Zhuang 1299da7a653SHaojian Zhuang assert((dev_info->info != (uintptr_t)NULL) && 1309da7a653SHaojian Zhuang (spec != (uintptr_t)NULL) && 1319da7a653SHaojian Zhuang (entity->info == (uintptr_t)NULL)); 1329da7a653SHaojian Zhuang 1339da7a653SHaojian Zhuang region = (io_block_spec_t *)spec; 1349da7a653SHaojian Zhuang cur = (block_dev_state_t *)dev_info->info; 1359da7a653SHaojian Zhuang assert(((region->offset % cur->dev_spec->block_size) == 0) && 1369da7a653SHaojian Zhuang ((region->length % cur->dev_spec->block_size) == 0)); 1379da7a653SHaojian Zhuang 1389da7a653SHaojian Zhuang cur->base = region->offset; 1399da7a653SHaojian Zhuang cur->size = region->length; 1409da7a653SHaojian Zhuang cur->file_pos = 0; 1419da7a653SHaojian Zhuang 1429da7a653SHaojian Zhuang entity->info = (uintptr_t)cur; 1439da7a653SHaojian Zhuang return 0; 1449da7a653SHaojian Zhuang } 1459da7a653SHaojian Zhuang 1469da7a653SHaojian Zhuang /* parameter offset is relative address at here */ 1479da7a653SHaojian Zhuang static int block_seek(io_entity_t *entity, int mode, ssize_t offset) 1489da7a653SHaojian Zhuang { 1499da7a653SHaojian Zhuang block_dev_state_t *cur; 1509da7a653SHaojian Zhuang 1519da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 1529da7a653SHaojian Zhuang 1539da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 1549da7a653SHaojian Zhuang assert((offset >= 0) && (offset < cur->size)); 1559da7a653SHaojian Zhuang 1569da7a653SHaojian Zhuang switch (mode) { 1579da7a653SHaojian Zhuang case IO_SEEK_SET: 1589da7a653SHaojian Zhuang cur->file_pos = offset; 1599da7a653SHaojian Zhuang break; 1609da7a653SHaojian Zhuang case IO_SEEK_CUR: 1619da7a653SHaojian Zhuang cur->file_pos += offset; 1629da7a653SHaojian Zhuang break; 1639da7a653SHaojian Zhuang default: 1649da7a653SHaojian Zhuang return -EINVAL; 1659da7a653SHaojian Zhuang } 1669da7a653SHaojian Zhuang assert(cur->file_pos < cur->size); 1679da7a653SHaojian Zhuang return 0; 1689da7a653SHaojian Zhuang } 1699da7a653SHaojian Zhuang 1709da7a653SHaojian Zhuang static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, 1719da7a653SHaojian Zhuang size_t *length_read) 1729da7a653SHaojian Zhuang { 1739da7a653SHaojian Zhuang block_dev_state_t *cur; 1749da7a653SHaojian Zhuang io_block_spec_t *buf; 1759da7a653SHaojian Zhuang io_block_ops_t *ops; 1769da7a653SHaojian Zhuang size_t aligned_length, skip, count, left, padding, block_size; 1779da7a653SHaojian Zhuang int lba; 1789d063aa2SHaojian Zhuang int buffer_not_aligned; 1799da7a653SHaojian Zhuang 1809da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 1819da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 1829da7a653SHaojian Zhuang ops = &(cur->dev_spec->ops); 1839da7a653SHaojian Zhuang buf = &(cur->dev_spec->buffer); 1849da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 1859da7a653SHaojian Zhuang assert((length <= cur->size) && 1869da7a653SHaojian Zhuang (length > 0) && 1879da7a653SHaojian Zhuang (ops->read != 0)); 1889da7a653SHaojian Zhuang 1899d063aa2SHaojian Zhuang if ((buffer & (block_size - 1)) != 0) { 1909d063aa2SHaojian Zhuang /* 1919d063aa2SHaojian Zhuang * buffer isn't aligned with block size. 1929d063aa2SHaojian Zhuang * Block device always relies on DMA operation. 1939d063aa2SHaojian Zhuang * It's better to make the buffer as block size aligned. 1949d063aa2SHaojian Zhuang */ 1959d063aa2SHaojian Zhuang buffer_not_aligned = 1; 1969d063aa2SHaojian Zhuang } else { 1979d063aa2SHaojian Zhuang buffer_not_aligned = 0; 1989d063aa2SHaojian Zhuang } 1999d063aa2SHaojian Zhuang 2009da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 2019da7a653SHaojian Zhuang aligned_length = ((skip + length) + (block_size - 1)) & 2029da7a653SHaojian Zhuang ~(block_size - 1); 2039da7a653SHaojian Zhuang padding = aligned_length - (skip + length); 2049da7a653SHaojian Zhuang left = aligned_length; 2059da7a653SHaojian Zhuang do { 2069da7a653SHaojian Zhuang lba = (cur->file_pos + cur->base) / block_size; 2079da7a653SHaojian Zhuang if (left >= buf->length) { 2089d063aa2SHaojian Zhuang /* 2099d063aa2SHaojian Zhuang * Since left is larger, it's impossible to padding. 2109d063aa2SHaojian Zhuang * 2119d063aa2SHaojian Zhuang * If buffer isn't aligned, we need to use aligned 2129d063aa2SHaojian Zhuang * buffer instead. 2139d063aa2SHaojian Zhuang */ 2149d063aa2SHaojian Zhuang if (skip || buffer_not_aligned) { 2159da7a653SHaojian Zhuang /* 2169da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 2179da7a653SHaojian Zhuang * aligned with block size, we need to use 2189da7a653SHaojian Zhuang * block buffer to read block. Since block 2199da7a653SHaojian Zhuang * device is always relied on DMA operation. 2209da7a653SHaojian Zhuang */ 2219da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, 2229da7a653SHaojian Zhuang buf->length); 2239da7a653SHaojian Zhuang } else { 2249da7a653SHaojian Zhuang count = ops->read(lba, buffer, buf->length); 2259da7a653SHaojian Zhuang } 2269da7a653SHaojian Zhuang assert(count == buf->length); 2279da7a653SHaojian Zhuang cur->file_pos += count - skip; 2289d063aa2SHaojian Zhuang if (skip || buffer_not_aligned) { 2299da7a653SHaojian Zhuang /* 2309d063aa2SHaojian Zhuang * Since there's not aligned block size caused 2319d063aa2SHaojian Zhuang * by skip or not aligned buffer, block buffer 2329d063aa2SHaojian Zhuang * is used to store data. 2339da7a653SHaojian Zhuang */ 2349da7a653SHaojian Zhuang memcpy((void *)buffer, 2359da7a653SHaojian Zhuang (void *)(buf->offset + skip), 2369da7a653SHaojian Zhuang count - skip); 2379da7a653SHaojian Zhuang } 2389da7a653SHaojian Zhuang left = left - (count - skip); 2399da7a653SHaojian Zhuang } else { 2409d063aa2SHaojian Zhuang if (skip || padding || buffer_not_aligned) { 2419da7a653SHaojian Zhuang /* 2429da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 2439da7a653SHaojian Zhuang * aligned with block size, we have to read 2449da7a653SHaojian Zhuang * full block by block buffer instead. 2459da7a653SHaojian Zhuang * The size isn't aligned with block size. 2469da7a653SHaojian Zhuang * Use block buffer to avoid overflow. 2479d063aa2SHaojian Zhuang * 2489d063aa2SHaojian Zhuang * If buffer isn't aligned, use block buffer 2499d063aa2SHaojian Zhuang * to avoid DMA error. 2509da7a653SHaojian Zhuang */ 2519da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, left); 2529da7a653SHaojian Zhuang } else 2539da7a653SHaojian Zhuang count = ops->read(lba, buffer, left); 2549da7a653SHaojian Zhuang assert(count == left); 2559da7a653SHaojian Zhuang left = left - (skip + padding); 2569da7a653SHaojian Zhuang cur->file_pos += left; 2579d063aa2SHaojian Zhuang if (skip || padding || buffer_not_aligned) { 2589da7a653SHaojian Zhuang /* 2599d063aa2SHaojian Zhuang * Since there's not aligned block size or 2609d063aa2SHaojian Zhuang * buffer, block buffer is used to store data. 2619da7a653SHaojian Zhuang */ 2629da7a653SHaojian Zhuang memcpy((void *)buffer, 2639da7a653SHaojian Zhuang (void *)(buf->offset + skip), 2649da7a653SHaojian Zhuang left); 2659da7a653SHaojian Zhuang } 2669da7a653SHaojian Zhuang /* It's already the last block operation */ 2679da7a653SHaojian Zhuang left = 0; 2689da7a653SHaojian Zhuang } 2699da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 2709da7a653SHaojian Zhuang } while (left > 0); 2719da7a653SHaojian Zhuang *length_read = length; 2729da7a653SHaojian Zhuang 2739da7a653SHaojian Zhuang return 0; 2749da7a653SHaojian Zhuang } 2759da7a653SHaojian Zhuang 2769da7a653SHaojian Zhuang static int block_write(io_entity_t *entity, const uintptr_t buffer, 2779da7a653SHaojian Zhuang size_t length, size_t *length_written) 2789da7a653SHaojian Zhuang { 2799da7a653SHaojian Zhuang block_dev_state_t *cur; 2809da7a653SHaojian Zhuang io_block_spec_t *buf; 2819da7a653SHaojian Zhuang io_block_ops_t *ops; 2829da7a653SHaojian Zhuang size_t aligned_length, skip, count, left, padding, block_size; 2839da7a653SHaojian Zhuang int lba; 2849d063aa2SHaojian Zhuang int buffer_not_aligned; 2859da7a653SHaojian Zhuang 2869da7a653SHaojian Zhuang assert(entity->info != (uintptr_t)NULL); 2879da7a653SHaojian Zhuang cur = (block_dev_state_t *)entity->info; 2889da7a653SHaojian Zhuang ops = &(cur->dev_spec->ops); 2899da7a653SHaojian Zhuang buf = &(cur->dev_spec->buffer); 2909da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 2919da7a653SHaojian Zhuang assert((length <= cur->size) && 2929da7a653SHaojian Zhuang (length > 0) && 2939da7a653SHaojian Zhuang (ops->read != 0) && 2949da7a653SHaojian Zhuang (ops->write != 0)); 2959da7a653SHaojian Zhuang 2969d063aa2SHaojian Zhuang if ((buffer & (block_size - 1)) != 0) { 2979d063aa2SHaojian Zhuang /* 2989d063aa2SHaojian Zhuang * buffer isn't aligned with block size. 2999d063aa2SHaojian Zhuang * Block device always relies on DMA operation. 3009d063aa2SHaojian Zhuang * It's better to make the buffer as block size aligned. 3019d063aa2SHaojian Zhuang */ 3029d063aa2SHaojian Zhuang buffer_not_aligned = 1; 3039d063aa2SHaojian Zhuang } else { 3049d063aa2SHaojian Zhuang buffer_not_aligned = 0; 3059d063aa2SHaojian Zhuang } 3069d063aa2SHaojian Zhuang 3079da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 3089da7a653SHaojian Zhuang aligned_length = ((skip + length) + (block_size - 1)) & 3099da7a653SHaojian Zhuang ~(block_size - 1); 3109da7a653SHaojian Zhuang padding = aligned_length - (skip + length); 3119da7a653SHaojian Zhuang left = aligned_length; 3129da7a653SHaojian Zhuang do { 3139da7a653SHaojian Zhuang lba = (cur->file_pos + cur->base) / block_size; 3149da7a653SHaojian Zhuang if (left >= buf->length) { 3159da7a653SHaojian Zhuang /* Since left is larger, it's impossible to padding. */ 3169d063aa2SHaojian Zhuang if (skip || buffer_not_aligned) { 3179da7a653SHaojian Zhuang /* 3189da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 3199d063aa2SHaojian Zhuang * aligned with block size or buffer isn't 3209d063aa2SHaojian Zhuang * aligned, we need to use block buffer to 3219d063aa2SHaojian Zhuang * write block. 3229da7a653SHaojian Zhuang */ 3239da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, 3249da7a653SHaojian Zhuang buf->length); 3259da7a653SHaojian Zhuang assert(count == buf->length); 3269da7a653SHaojian Zhuang memcpy((void *)(buf->offset + skip), 3279da7a653SHaojian Zhuang (void *)buffer, 3289da7a653SHaojian Zhuang count - skip); 3299da7a653SHaojian Zhuang count = ops->write(lba, buf->offset, 3309da7a653SHaojian Zhuang buf->length); 3319da7a653SHaojian Zhuang } else 3329da7a653SHaojian Zhuang count = ops->write(lba, buffer, buf->length); 3339da7a653SHaojian Zhuang assert(count == buf->length); 3349da7a653SHaojian Zhuang cur->file_pos += count - skip; 3359da7a653SHaojian Zhuang left = left - (count - skip); 3369da7a653SHaojian Zhuang } else { 3379d063aa2SHaojian Zhuang if (skip || padding || buffer_not_aligned) { 3389da7a653SHaojian Zhuang /* 3399da7a653SHaojian Zhuang * The beginning address (file_pos) isn't 3409da7a653SHaojian Zhuang * aligned with block size, we need to avoid 3419da7a653SHaojian Zhuang * poluate data in the beginning. Reading and 3429da7a653SHaojian Zhuang * skipping the beginning is the only way. 3439da7a653SHaojian Zhuang * The size isn't aligned with block size. 3449da7a653SHaojian Zhuang * Use block buffer to avoid overflow. 3459d063aa2SHaojian Zhuang * 3469d063aa2SHaojian Zhuang * If buffer isn't aligned, use block buffer 3479d063aa2SHaojian Zhuang * to avoid DMA error. 3489da7a653SHaojian Zhuang */ 3499da7a653SHaojian Zhuang count = ops->read(lba, buf->offset, left); 3509da7a653SHaojian Zhuang assert(count == left); 3519da7a653SHaojian Zhuang memcpy((void *)(buf->offset + skip), 3529da7a653SHaojian Zhuang (void *)buffer, 3539da7a653SHaojian Zhuang left - skip - padding); 3549da7a653SHaojian Zhuang count = ops->write(lba, buf->offset, left); 3559da7a653SHaojian Zhuang } else 3569da7a653SHaojian Zhuang count = ops->write(lba, buffer, left); 3579da7a653SHaojian Zhuang assert(count == left); 3589da7a653SHaojian Zhuang cur->file_pos += left - (skip + padding); 3599da7a653SHaojian Zhuang /* It's already the last block operation */ 3609da7a653SHaojian Zhuang left = 0; 3619da7a653SHaojian Zhuang } 3629da7a653SHaojian Zhuang skip = cur->file_pos % block_size; 3639da7a653SHaojian Zhuang } while (left > 0); 3649da7a653SHaojian Zhuang *length_written = length; 3659da7a653SHaojian Zhuang return 0; 3669da7a653SHaojian Zhuang } 3679da7a653SHaojian Zhuang 3689da7a653SHaojian Zhuang static int block_close(io_entity_t *entity) 3699da7a653SHaojian Zhuang { 3709da7a653SHaojian Zhuang entity->info = (uintptr_t)NULL; 3719da7a653SHaojian Zhuang return 0; 3729da7a653SHaojian Zhuang } 3739da7a653SHaojian Zhuang 3749da7a653SHaojian Zhuang static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) 3759da7a653SHaojian Zhuang { 3769da7a653SHaojian Zhuang block_dev_state_t *cur; 3779da7a653SHaojian Zhuang io_block_spec_t *buffer; 3789da7a653SHaojian Zhuang io_dev_info_t *info; 3799da7a653SHaojian Zhuang size_t block_size; 3809da7a653SHaojian Zhuang int result; 3819da7a653SHaojian Zhuang 3829da7a653SHaojian Zhuang assert(dev_info != NULL); 3839da7a653SHaojian Zhuang result = allocate_dev_info(&info); 3849da7a653SHaojian Zhuang if (result) 3859da7a653SHaojian Zhuang return -ENOENT; 3869da7a653SHaojian Zhuang 3879da7a653SHaojian Zhuang cur = (block_dev_state_t *)info->info; 3889da7a653SHaojian Zhuang /* dev_spec is type of io_block_dev_spec_t. */ 3899da7a653SHaojian Zhuang cur->dev_spec = (io_block_dev_spec_t *)dev_spec; 3909da7a653SHaojian Zhuang buffer = &(cur->dev_spec->buffer); 3919da7a653SHaojian Zhuang block_size = cur->dev_spec->block_size; 3929da7a653SHaojian Zhuang assert((block_size > 0) && 3939da7a653SHaojian Zhuang (is_power_of_2(block_size) != 0) && 3949da7a653SHaojian Zhuang ((buffer->offset % block_size) == 0) && 3959da7a653SHaojian Zhuang ((buffer->length % block_size) == 0)); 3969da7a653SHaojian Zhuang 3979da7a653SHaojian Zhuang *dev_info = info; /* cast away const */ 3989da7a653SHaojian Zhuang (void)block_size; 3999da7a653SHaojian Zhuang (void)buffer; 4009da7a653SHaojian Zhuang return 0; 4019da7a653SHaojian Zhuang } 4029da7a653SHaojian Zhuang 4039da7a653SHaojian Zhuang static int block_dev_close(io_dev_info_t *dev_info) 4049da7a653SHaojian Zhuang { 4059da7a653SHaojian Zhuang return free_dev_info(dev_info); 4069da7a653SHaojian Zhuang } 4079da7a653SHaojian Zhuang 4089da7a653SHaojian Zhuang /* Exported functions */ 4099da7a653SHaojian Zhuang 4109da7a653SHaojian Zhuang /* Register the Block driver with the IO abstraction */ 4119da7a653SHaojian Zhuang int register_io_dev_block(const io_dev_connector_t **dev_con) 4129da7a653SHaojian Zhuang { 4139da7a653SHaojian Zhuang int result; 4149da7a653SHaojian Zhuang 4159da7a653SHaojian Zhuang assert(dev_con != NULL); 4169da7a653SHaojian Zhuang 4179da7a653SHaojian Zhuang /* 4189da7a653SHaojian Zhuang * Since dev_info isn't really used in io_register_device, always 4199da7a653SHaojian Zhuang * use the same device info at here instead. 4209da7a653SHaojian Zhuang */ 4219da7a653SHaojian Zhuang result = io_register_device(&dev_info_pool[0]); 4229da7a653SHaojian Zhuang if (result == 0) 4239da7a653SHaojian Zhuang *dev_con = &block_dev_connector; 4249da7a653SHaojian Zhuang return result; 4259da7a653SHaojian Zhuang } 426