2 * Copyright (c) 2012 Mike Frysinger <vapier@gentoo.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include <linux/ioctl.h>
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)
36 # include <mtd/mtd-abi.h>
39 #include "xlat/mtd_mode_options.h"
40 #include "xlat/mtd_file_mode_options.h"
41 #include "xlat/mtd_type_options.h"
42 #include "xlat/mtd_flags_options.h"
43 #include "xlat/mtd_otp_options.h"
44 #include "xlat/mtd_nandecc_options.h"
47 decode_erase_info_user(struct tcb *tcp, const long addr)
49 struct erase_info_user einfo;
52 if (umove_or_printaddr(tcp, addr, &einfo))
55 tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length);
59 decode_erase_info_user64(struct tcb *tcp, const long addr)
61 struct erase_info_user64 einfo64;
64 if (umove_or_printaddr(tcp, addr, &einfo64))
67 tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
68 (uint64_t) einfo64.start, (uint64_t) einfo64.length);
72 decode_mtd_oob_buf(struct tcb *tcp, const long addr)
74 struct mtd_oob_buf mbuf;
77 if (umove_or_printaddr(tcp, addr, &mbuf))
80 tprintf("{start=%#x, length=%#x, ptr=%#lx}",
81 mbuf.start, mbuf.length, (unsigned long) mbuf.ptr);
85 decode_mtd_oob_buf64(struct tcb *tcp, const long addr)
87 struct mtd_oob_buf64 mbuf64;
90 if (umove_or_printaddr(tcp, addr, &mbuf64))
93 tprintf("{start=%#" PRIx64 ", length=%#x, usr_ptr=%#" PRIx64 "}",
94 (uint64_t) mbuf64.start, mbuf64.length,
95 (uint64_t) mbuf64.usr_ptr);
99 decode_otp_info(struct tcb *tcp, const long addr)
101 struct otp_info oinfo;
104 if (umove_or_printaddr(tcp, addr, &oinfo))
107 tprintf("{start=%#x, length=%#x, locked=%u}",
108 oinfo.start, oinfo.length, oinfo.locked);
112 decode_otp_select(struct tcb *tcp, const long addr)
117 if (umove_or_printaddr(tcp, addr, &i))
121 printxval(mtd_otp_options, i, "MTD_OTP_???");
126 decode_mtd_write_req(struct tcb *tcp, const long addr)
128 struct mtd_write_req mreq;
131 if (umove_or_printaddr(tcp, addr, &mreq))
134 tprintf("{start=%#" PRIx64 ", len=%#" PRIx64
135 ", ooblen=%#" PRIx64 ", usr_data=%#" PRIx64
136 ", usr_oob=%#" PRIx64 ", mode=",
137 (uint64_t) mreq.start, (uint64_t) mreq.len,
138 (uint64_t) mreq.ooblen, (uint64_t) mreq.usr_data,
139 (uint64_t) mreq.usr_oob);
140 printxval(mtd_mode_options, mreq.mode, "MTD_OPS_???");
145 decode_mtd_info_user(struct tcb *tcp, const long addr)
147 struct mtd_info_user minfo;
150 if (umove_or_printaddr(tcp, addr, &minfo))
154 printxval(mtd_type_options, minfo.type, "MTD_???");
156 printflags(mtd_flags_options, minfo.flags, "MTD_???");
157 tprintf(", size=%#x, erasesize=%#x, writesize=%#x, oobsize=%#x"
158 ", padding=%#" PRIx64 "}",
159 minfo.size, minfo.erasesize, minfo.writesize, minfo.oobsize,
160 (uint64_t) minfo.padding);
164 decode_nand_oobinfo(struct tcb *tcp, const long addr)
166 struct nand_oobinfo ninfo;
170 if (umove_or_printaddr(tcp, addr, &ninfo))
174 printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
175 tprintf(", eccbytes=%#x", ninfo.eccbytes);
177 tprints(", oobfree={");
178 for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
182 for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
185 tprintf("%#x", ninfo.oobfree[i][j]);
189 tprints("}}, eccpos={");
190 for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
193 tprintf("%#x", ninfo.eccpos[i]);
200 decode_nand_ecclayout_user(struct tcb *tcp, const long addr)
202 struct nand_ecclayout_user nlay;
206 if (umove_or_printaddr(tcp, addr, &nlay))
209 tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes);
210 for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
213 tprintf("%#x", nlay.eccpos[i]);
215 tprintf("}, oobavail=%#x, oobfree={", nlay.oobavail);
216 for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
219 tprintf("{offset=%#x, length=%#x}",
220 nlay.oobfree[i].offset, nlay.oobfree[i].length);
226 decode_mtd_ecc_stats(struct tcb *tcp, const long addr)
228 struct mtd_ecc_stats es;
231 if (umove_or_printaddr(tcp, addr, &es))
234 tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}",
235 es.corrected, es.failed, es.badblocks, es.bbtblocks);
239 mtd_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
246 decode_erase_info_user(tcp, arg);
250 decode_erase_info_user64(tcp, arg);
255 decode_mtd_oob_buf(tcp, arg);
260 decode_mtd_oob_buf64(tcp, arg);
264 decode_mtd_write_req(tcp, arg);
267 case OTPGETREGIONINFO:
272 decode_otp_info(tcp, arg);
276 decode_otp_select(tcp, arg);
281 printxval_long(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
287 printnum_int64(tcp, arg, "%" PRIu64);
293 decode_mtd_info_user(tcp, arg);
299 decode_nand_oobinfo(tcp, arg);
305 decode_nand_ecclayout_user(tcp, arg);
311 decode_mtd_ecc_stats(tcp, arg);
314 case OTPGETREGIONCOUNT:
318 printnum_int(tcp, arg, "%u");
321 case MEMGETREGIONCOUNT:
325 printnum_int(tcp, arg, "%d");
328 case MEMGETREGIONINFO:
330 struct region_info_user rinfo;
333 if (umove_or_printaddr(tcp, arg, &rinfo))
335 tprintf("{regionindex=%#x", rinfo.regionindex);
338 struct region_info_user rinfo;
340 if (!syserror(tcp) && !umove(tcp, arg, &rinfo))
341 tprintf(", offset=%#x"
355 return RVAL_DECODED | 1;