blob: 976024ef7473c590058c404e9c6c76cbd1de2b15 [file] [log] [blame]
Mike Frysinger0cbed352012-04-04 22:22:01 -04001/*
2 * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "defs.h"
28
29#include <sys/ioctl.h>
30
31/* The mtd api changes quickly, so we have to keep a local copy */
32#include <linux/version.h>
33#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
34# include "mtd-abi.h"
35#else
36# include <mtd/mtd-abi.h>
37#endif
38
39static const struct xlat mtd_mode_options[] = {
40 { MTD_OPS_PLACE_OOB, "MTD_OPS_PLACE_OOB" },
41 { MTD_OPS_AUTO_OOB, "MTD_OPS_AUTO_OOB" },
42 { MTD_OPS_RAW, "MTD_OPS_RAW" },
43 { 0, NULL },
44};
45
46static const struct xlat mtd_type_options[] = {
47 { MTD_ABSENT, "MTD_ABSENT" },
48 { MTD_RAM, "MTD_RAM" },
49 { MTD_ROM, "MTD_ROM" },
50 { MTD_NORFLASH, "MTD_NORFLASH" },
51 { MTD_NANDFLASH, "MTD_NANDFLASH" },
52 { MTD_DATAFLASH, "MTD_DATAFLASH" },
53 { MTD_UBIVOLUME, "MTD_UBIVOLUME" },
54 { MTD_MLCNANDFLASH, "MTD_MLCNANDFLASH" },
55 { 0, NULL },
56};
57
58static const struct xlat mtd_flags_options[] = {
59 { MTD_WRITEABLE, "MTD_WRITEABLE" },
60 { MTD_BIT_WRITEABLE, "MTD_BIT_WRITEABLE" },
61 { MTD_NO_ERASE, "MTD_NO_ERASE" },
62 { MTD_POWERUP_LOCK, "MTD_POWERUP_LOCK" },
63 { 0, NULL },
64};
65
66static const struct xlat mtd_otp_options[] = {
67 { MTD_OTP_OFF, "MTD_OTP_OFF" },
68 { MTD_OTP_FACTORY, "MTD_OTP_FACTORY" },
69 { MTD_OTP_USER, "MTD_OTP_USER" },
70 { 0, NULL },
71};
72
73static const struct xlat mtd_nandecc_options[] = {
74 { MTD_NANDECC_OFF, "MTD_NANDECC_OFF" },
75 { MTD_NANDECC_PLACE, "MTD_NANDECC_PLACE" },
76 { MTD_NANDECC_AUTOPLACE, "MTD_NANDECC_AUTOPLACE" },
77 { MTD_NANDECC_PLACEONLY, "MTD_NANDECC_PLACEONLY" },
78 { MTD_NANDECC_AUTOPL_USR, "MTD_NANDECC_AUTOPL_USR" },
79 { 0, NULL },
80};
81
82int mtd_ioctl(struct tcb *tcp, long code, long arg)
83{
84 struct mtd_info_user minfo;
85 struct erase_info_user einfo;
86 struct erase_info_user64 einfo64;
87 struct mtd_oob_buf mbuf;
88 struct mtd_oob_buf64 mbuf64;
89 struct region_info_user rinfo;
90 struct otp_info oinfo;
91 struct mtd_ecc_stats estat;
92 struct mtd_write_req mreq;
93 struct nand_oobinfo ninfo;
94 struct nand_ecclayout_user nlay;
95 int i, j;
96
97 if (entering(tcp))
98 return 0;
99
100 switch (code) {
101
102 case MEMGETINFO:
103 if (!verbose(tcp) || umove(tcp, arg, &minfo) < 0)
104 return 0;
105
106 tprints(", {type=");
107 printxval(mtd_type_options, minfo.type, "MTD_???");
108 tprints(", flags=");
109 printflags(mtd_flags_options, minfo.flags, "MTD_???");
110 tprintf(", size=%#" PRIx32 ", erasesize=%#" PRIx32,
111 minfo.size, minfo.erasesize);
112 tprintf(", writesize=%#" PRIx32 ", oobsize=%#" PRIx32,
113 minfo.writesize, minfo.oobsize);
114 tprintf(", padding=%#" PRIx64 "}",
115 (uint64_t) minfo.padding);
116 return 1;
117
118 case MEMERASE:
119 case MEMLOCK:
120 case MEMUNLOCK:
121 case MEMISLOCKED:
122 if (!verbose(tcp) || umove(tcp, arg, &einfo) < 0)
123 return 0;
124
125 tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 "}",
126 einfo.start, einfo.length);
127 return 1;
128
129 case MEMERASE64:
130 if (!verbose(tcp) || umove(tcp, arg, &einfo64) < 0)
131 return 0;
132
133 tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 "}",
134 (uint64_t) einfo64.start, (uint64_t) einfo64.length);
135 return 1;
136
137 case MEMWRITEOOB:
138 case MEMREADOOB:
139 if (!verbose(tcp) || umove(tcp, arg, &mbuf) < 0)
140 return 0;
141
142 tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", ptr=...}",
143 mbuf.start, mbuf.length);
144 return 1;
145
146 case MEMWRITEOOB64:
147 case MEMREADOOB64:
148 if (!verbose(tcp) || umove(tcp, arg, &mbuf64) < 0)
149 return 0;
150
151 tprintf(", {start=%#" PRIx64 ", length=%#" PRIx64 ", ptr=...}",
152 (uint64_t) mbuf64.start, (uint64_t) mbuf64.length);
153 return 1;
154
155 case MEMGETREGIONINFO:
156 if (!verbose(tcp) || umove(tcp, arg, &rinfo) < 0)
157 return 0;
158
159 tprintf(", {offset=%#" PRIx32 ", erasesize=%#" PRIx32,
160 rinfo.offset, rinfo.erasesize);
161 tprintf(", numblocks=%#" PRIx32 ", regionindex=%#" PRIx32 "}",
162 rinfo.numblocks, rinfo.regionindex);
163 return 1;
164
165 case MEMGETOOBSEL:
166 if (!verbose(tcp) || umove(tcp, arg, &ninfo) < 0)
167 return 0;
168
169 tprints(", {useecc=");
170 printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
171 tprintf(", eccbytes=%#" PRIx32, ninfo.eccbytes);
172
173 tprints(", oobfree={");
174 for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
175 if (i)
176 tprints("}, ");
177 tprints("{");
178 for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
179 if (j)
180 tprints(", ");
181 tprintf("%#" PRIx32, ninfo.oobfree[i][j]);
182 }
183 }
184
185 tprints("}}, eccpos={");
186 for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
187 if (i)
188 tprints(", ");
189 tprintf("%#" PRIx32, ninfo.eccpos[i]);
190 }
191
192 tprints("}");
193 return 1;
194
195 case OTPGETREGIONINFO:
196 case OTPLOCK:
197 if (!verbose(tcp) || umove(tcp, arg, &oinfo) < 0)
198 return 0;
199
200 tprintf(", {start=%#" PRIx32 ", length=%#" PRIx32 ", locked=%" PRIu32 "}",
201 oinfo.start, oinfo.length, oinfo.locked);
202 return 1;
203
204 case ECCGETLAYOUT:
205 if (!verbose(tcp) || umove(tcp, arg, &nlay) < 0)
206 return 0;
207
208 tprintf(", {eccbytes=%#" PRIx32 ", eccpos={", nlay.eccbytes);
209 for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
210 if (i)
211 tprints(", ");
212 tprintf("%#" PRIx32, nlay.eccpos[i]);
213 }
214 tprintf("}, oobavail=%#" PRIx32 ", oobfree={", nlay.oobavail);
215 for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
216 if (i)
217 tprints(", ");
218 tprintf("{offset=%#" PRIx32 ", length=%#" PRIx32 "}",
219 nlay.oobfree[i].offset, nlay.oobfree[i].length);
220 }
221 tprints("}");
222 return 1;
223
224 case ECCGETSTATS:
225 if (!verbose(tcp) || umove(tcp, arg, &estat) < 0)
226 return 0;
227
228 tprintf(", {corrected=%#" PRIx32 ", failed=%#" PRIx32,
229 estat.corrected, estat.failed);
230 tprintf(", badblocks=%#" PRIx32 ", bbtblocks=%#" PRIx32 "}",
231 estat.badblocks, estat.bbtblocks);
232 return 1;
233
234 case MEMWRITE:
235 if (!verbose(tcp) || umove(tcp, arg, &mreq) < 0)
236 return 0;
237
238 tprintf(", {start=%#" PRIx64 ", len=%#" PRIx64,
239 (uint64_t) mreq.start, (uint64_t) mreq.len);
240 tprintf(", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64,
241 (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data);
242 tprintf(", usr_oob=%#" PRIx64 ", mode=",
243 (uint64_t) mreq.usr_oob);
244 printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
245 tprints(", padding=...}");
246 return 1;
247
248 case OTPSELECT:
249 if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
250 return 0;
251
252 tprints(", [");
253 printxval(mtd_otp_options, i, "MTD_OTP_???");
254 tprints("]");
255 return 1;
256
257 case MEMGETBADBLOCK:
258 case MEMSETBADBLOCK:
259 if (!verbose(tcp))
260 return 0;
261
262 tprints(", ");
263 print_loff_t(tcp, arg);
264 return 1;
265
266 case OTPGETREGIONCOUNT:
267 if (!verbose(tcp) || umove(tcp, arg, &i) < 0)
268 return 0;
269
270 tprintf(", [%i]", i);
271 return 1;
272
273 case MTDFILEMODE:
274 /* XXX: process return value as enum mtd_file_modes */
275
276 case MEMGETREGIONCOUNT:
277 /* These ones take simple args, so let default printer handle it */
278
279 default:
280 return 0;
281 }
282}