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
mtd_part_alloc(rt_mtd_t * master,const struct mtd_part * part)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
rt_mtd_get(const char * name)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 */
rt_mtd_register(rt_mtd_t * master,const struct mtd_part * parts,int np)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
rt_mtd_block_erase(rt_mtd_t * mtd,uint32_t block)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
rt_mtd_block_isbad(rt_mtd_t * mtd,uint32_t block)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
rt_mtd_block_markbad(rt_mtd_t * mtd,uint32_t block)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
rt_mtd_erase(rt_mtd_t * mtd,loff_t addr,size_t size)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 */
rt_mtd_read(rt_mtd_t * mtd,loff_t from,uint8_t * buf,size_t len)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 */
rt_mtd_write(rt_mtd_t * mtd,loff_t to,const uint8_t * buf,size_t len)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 */
rt_mtd_read_oob(rt_mtd_t * mtd,loff_t from,struct mtd_io_desc * desc)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 */
rt_mtd_write_oob(rt_mtd_t * mtd,loff_t to,struct mtd_io_desc * desc)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