xref: /nrf52832-nimble/rt-thread/components/drivers/mtd/mtd.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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