1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 2018-09-10 heyuanjie87 first version 9 10 */ 11 12 #include <drivers/mtd.h> 13 14 static rt_mtd_t* mtd_part_alloc(rt_mtd_t *master, const struct mtd_part *part) 15 { 16 rt_mtd_t *slave; 17 18 slave = rt_malloc(sizeof(rt_mtd_t)); 19 if (slave == RT_NULL) 20 goto out; 21 22 slave->master = master; 23 24 *slave = *master; 25 slave->size = part->size; 26 slave->offset = part->offset; 27 28 out: 29 30 return slave; 31 } 32 33 rt_mtd_t* rt_mtd_get(const char *name) 34 { 35 rt_mtd_t *mtd; 36 37 mtd = (rt_mtd_t *)rt_device_find(name); 38 if (mtd == RT_NULL) 39 return RT_NULL; 40 41 if (mtd->parent.type != RT_Device_Class_MTD) 42 return RT_NULL; 43 44 return mtd; 45 } 46 47 /* 48 * Register MTD driver 49 * 50 * @parts partion description 51 * @np number of partitions 52 * @return number of unregistered partitions 53 * 54 */ 55 int rt_mtd_register(rt_mtd_t *master, const struct mtd_part *parts, int np) 56 { 57 int ret; 58 rt_mtd_t *slave; 59 60 master->master = master; 61 master->parent.type = RT_Device_Class_MTD; 62 63 if (np > 0) 64 { 65 master->offset = parts->offset; 66 master->size = parts->size; 67 68 ret = rt_device_register((rt_device_t)master, parts->name, 0); 69 if (ret != 0) 70 goto _out; 71 72 np --; 73 parts ++; 74 } 75 76 while (np > 0) 77 { 78 slave = mtd_part_alloc(master, parts); 79 if (!slave) 80 break; 81 ret = rt_device_register((rt_device_t)slave, parts->name, 0); 82 if (ret) 83 break; 84 parts ++; 85 np --; 86 } 87 88 _out: 89 return np; 90 } 91 92 int rt_mtd_block_erase(rt_mtd_t *mtd, uint32_t block) 93 { 94 uint32_t total_blks; 95 loff_t addr; 96 97 total_blks = mtd->size/mtd->block_size; 98 if (block >= total_blks) 99 return -EINVAL; 100 addr = mtd->offset + mtd->block_size * block; 101 102 return mtd->ops->erase(mtd->master, addr, mtd->block_size); 103 } 104 105 int rt_mtd_block_isbad(rt_mtd_t *mtd, uint32_t block) 106 { 107 uint32_t total_blks, offset_blk; 108 109 if (!mtd->ops->isbad) 110 return 0; 111 112 total_blks = mtd->size / mtd->block_size; 113 if (block >= total_blks) 114 return -EINVAL; 115 offset_blk = mtd->offset / mtd->block_size; 116 117 return mtd->ops->isbad(mtd->master, block + offset_blk); 118 } 119 120 int rt_mtd_block_markbad(rt_mtd_t *mtd, uint32_t block) 121 { 122 uint32_t total_blks, offset_blk; 123 124 if (!mtd->ops->markbad) 125 return -EOPNOTSUPP; 126 127 total_blks = mtd->size / mtd->block_size; 128 if (block >= total_blks) 129 return -EINVAL; 130 offset_blk = mtd->offset / mtd->block_size; 131 132 return mtd->ops->markbad(mtd->master, block + offset_blk); 133 } 134 135 int rt_mtd_erase(rt_mtd_t *mtd, loff_t addr, size_t size) 136 { 137 if (addr > mtd->size || (addr + size) > mtd->size) 138 return -EINVAL; 139 addr += mtd->offset; 140 141 return mtd->ops->erase(mtd->master, addr, size); 142 } 143 144 /* 145 * Read data only 146 * 147 * @from offset to read from 148 * @return success size or error code 149 */ 150 int rt_mtd_read(rt_mtd_t *mtd, loff_t from, uint8_t *buf, size_t len) 151 { 152 int ret; 153 struct mtd_io_desc desc = {0}; 154 155 if (from < 0 || from >= (loff_t)mtd->size || len > mtd->size - from) 156 return -EINVAL; 157 if (!len) 158 return 0; 159 160 desc.datbuf = buf; 161 desc.datlen = len; 162 ret = mtd->ops->read(mtd->master, from + mtd->offset, &desc); 163 if (ret) 164 return ret; 165 166 return desc.datretlen; 167 } 168 169 /** 170 * Write data only 171 * 172 * @to offset to write from 173 * @return success size or error code 174 */ 175 int rt_mtd_write(rt_mtd_t *mtd, loff_t to, const uint8_t *buf, size_t len) 176 { 177 int ret; 178 struct mtd_io_desc desc = {0}; 179 180 if (to < 0 || to >= (loff_t)mtd->size || len > mtd->size - to) 181 return -EINVAL; 182 if (!mtd->ops->write) 183 return -EROFS; 184 if (!len) 185 return 0; 186 187 desc.datbuf = (uint8_t*)buf; 188 desc.datlen = len; 189 ret = mtd->ops->write(mtd->master, to + mtd->offset, &desc); 190 if (ret) 191 return ret; 192 193 return desc.datretlen; 194 } 195 196 /** 197 * Read data and/or out-of-band 198 * 199 * @from offset to read from 200 * @desc sector operation description structure 201 * @return error code, 0 success 202 */ 203 int rt_mtd_read_oob(rt_mtd_t *mtd, loff_t from, struct mtd_io_desc *desc) 204 { 205 desc->datretlen = 0; 206 desc->oobretlen = 0; 207 208 if (from < 0 || from >= (loff_t)mtd->size) 209 return -EINVAL; 210 211 if (desc->datbuf && (desc->datlen > (mtd->size - from))) 212 return -EINVAL; 213 214 return mtd->ops->read(mtd->master, from + mtd->offset, desc); 215 } 216 217 /** 218 * Write data and/or out-of-band 219 * 220 * @to offset to read from 221 * @desc sector operation description structure 222 * @return error code, 0 success 223 */ 224 int rt_mtd_write_oob(rt_mtd_t *mtd, loff_t to, struct mtd_io_desc *desc) 225 { 226 desc->datretlen = 0; 227 desc->oobretlen = 0; 228 229 if (to < 0 || to >= (loff_t)mtd->size) 230 return -EINVAL; 231 232 if (desc->datbuf && (desc->datlen >(mtd->size - to))) 233 return -EINVAL; 234 235 return mtd->ops->write(mtd->master, to + mtd->offset, desc); 236 } 237