]> granicus.if.org Git - strace/blob - mtd.c
mtd.c: refactor
[strace] / mtd.c
1 /*
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 <linux/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
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"
45
46 static void
47 decode_erase_info_user(struct tcb *tcp, const long addr)
48 {
49         struct erase_info_user einfo;
50
51         tprints(", ");
52         if (umove_or_printaddr(tcp, addr, &einfo))
53                 return;
54
55         tprintf("{start=%#x, length=%#x}", einfo.start, einfo.length);
56 }
57
58 static void
59 decode_erase_info_user64(struct tcb *tcp, const long addr)
60 {
61         struct erase_info_user64 einfo64;
62
63         tprints(", ");
64         if (umove_or_printaddr(tcp, addr, &einfo64))
65                 return;
66
67         tprintf("{start=%#" PRIx64 ", length=%#" PRIx64 "}",
68                 (uint64_t) einfo64.start, (uint64_t) einfo64.length);
69 }
70
71 static void
72 decode_mtd_oob_buf(struct tcb *tcp, const long addr)
73 {
74         struct mtd_oob_buf mbuf;
75
76         tprints(", ");
77         if (umove_or_printaddr(tcp, addr, &mbuf))
78                 return;
79
80         tprintf("{start=%#x, length=%#x, ptr=%#lx}",
81                 mbuf.start, mbuf.length, (unsigned long) mbuf.ptr);
82 }
83
84 static void
85 decode_mtd_oob_buf64(struct tcb *tcp, const long addr)
86 {
87         struct mtd_oob_buf64 mbuf64;
88
89         tprints(", ");
90         if (umove_or_printaddr(tcp, addr, &mbuf64))
91                 return;
92
93         tprintf("{start=%#" PRIx64 ", length=%#x, usr_ptr=%#" PRIx64 "}",
94                 (uint64_t) mbuf64.start, mbuf64.length,
95                 (uint64_t) mbuf64.usr_ptr);
96 }
97
98 static void
99 decode_otp_info(struct tcb *tcp, const long addr)
100 {
101         struct otp_info oinfo;
102
103         tprints(", ");
104         if (umove_or_printaddr(tcp, addr, &oinfo))
105                 return;
106
107         tprintf("{start=%#x, length=%#x, locked=%u}",
108                 oinfo.start, oinfo.length, oinfo.locked);
109 }
110
111 static void
112 decode_otp_select(struct tcb *tcp, const long addr)
113 {
114         unsigned int i;
115
116         tprints(", ");
117         if (umove_or_printaddr(tcp, addr, &i))
118                 return;
119
120         tprints("[");
121         printxval(mtd_otp_options, i, "MTD_OTP_???");
122         tprints("]");
123 }
124
125 static void
126 decode_mtd_write_req(struct tcb *tcp, const long addr)
127 {
128         struct mtd_write_req mreq;
129
130         tprints(", ");
131         if (umove_or_printaddr(tcp, addr, &mreq))
132                 return;
133
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_???");
141         tprints("}");
142 }
143
144 static void
145 decode_mtd_info_user(struct tcb *tcp, const long addr)
146 {
147         struct mtd_info_user minfo;
148
149         tprints(", ");
150         if (umove_or_printaddr(tcp, addr, &minfo))
151                 return;
152
153         tprints("{type=");
154         printxval(mtd_type_options, minfo.type, "MTD_???");
155         tprints(", flags=");
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);
161 }
162
163 static void
164 decode_nand_oobinfo(struct tcb *tcp, const long addr)
165 {
166         struct nand_oobinfo ninfo;
167         unsigned int i, j;
168
169         tprints(", ");
170         if (umove_or_printaddr(tcp, addr, &ninfo))
171                 return;
172
173         tprints("{useecc=");
174         printxval(mtd_nandecc_options, ninfo.useecc, "MTD_NANDECC_???");
175         tprintf(", eccbytes=%#x", ninfo.eccbytes);
176
177         tprints(", oobfree={");
178         for (i = 0; i < ARRAY_SIZE(ninfo.oobfree); ++i) {
179                 if (i)
180                         tprints("}, ");
181                 tprints("{");
182                 for (j = 0; j < ARRAY_SIZE(ninfo.oobfree[0]); ++j) {
183                         if (j)
184                                 tprints(", ");
185                         tprintf("%#x", ninfo.oobfree[i][j]);
186                 }
187         }
188
189         tprints("}}, eccpos={");
190         for (i = 0; i < ARRAY_SIZE(ninfo.eccpos); ++i) {
191                 if (i)
192                         tprints(", ");
193                 tprintf("%#x", ninfo.eccpos[i]);
194         }
195
196         tprints("}");
197 }
198
199 static void
200 decode_nand_ecclayout_user(struct tcb *tcp, const long addr)
201 {
202         struct nand_ecclayout_user nlay;
203         unsigned int i;
204
205         tprints(", ");
206         if (umove_or_printaddr(tcp, addr, &nlay))
207                 return;
208
209         tprintf("{eccbytes=%#x, eccpos={", nlay.eccbytes);
210         for (i = 0; i < ARRAY_SIZE(nlay.eccpos); ++i) {
211                 if (i)
212                         tprints(", ");
213                 tprintf("%#x", nlay.eccpos[i]);
214         }
215         tprintf("}, oobavail=%#x, oobfree={", nlay.oobavail);
216         for (i = 0; i < ARRAY_SIZE(nlay.oobfree); ++i) {
217                 if (i)
218                         tprints(", ");
219                 tprintf("{offset=%#x, length=%#x}",
220                         nlay.oobfree[i].offset, nlay.oobfree[i].length);
221         }
222         tprints("}");
223 }
224
225 static void
226 decode_mtd_ecc_stats(struct tcb *tcp, const long addr)
227 {
228         struct mtd_ecc_stats es;
229
230         tprints(", ");
231         if (umove_or_printaddr(tcp, addr, &es))
232                 return;
233
234         tprintf("{corrected=%#x, failed=%#x, badblocks=%#x, bbtblocks=%#x}",
235                 es.corrected, es.failed, es.badblocks, es.bbtblocks);
236 }
237
238 int
239 mtd_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
240 {
241         switch (code) {
242         case MEMERASE:
243         case MEMLOCK:
244         case MEMUNLOCK:
245         case MEMISLOCKED:
246                 decode_erase_info_user(tcp, arg);
247                 break;
248
249         case MEMERASE64:
250                 decode_erase_info_user64(tcp, arg);
251                 break;
252
253         case MEMWRITEOOB:
254         case MEMREADOOB:
255                 decode_mtd_oob_buf(tcp, arg);
256                 break;
257
258         case MEMWRITEOOB64:
259         case MEMREADOOB64:
260                 decode_mtd_oob_buf64(tcp, arg);
261                 break;
262
263         case MEMWRITE:
264                 decode_mtd_write_req(tcp, arg);
265                 break;
266
267         case OTPGETREGIONINFO:
268                 if (entering(tcp))
269                         return 0;
270                 /* fall through */
271         case OTPLOCK:
272                 decode_otp_info(tcp, arg);
273                 break;
274
275         case OTPSELECT:
276                 decode_otp_select(tcp, arg);
277                 break;
278
279         case MTDFILEMODE:
280                 tprints(", ");
281                 printxval_long(mtd_file_mode_options, arg, "MTD_FILE_MODE_???");
282                 break;
283
284         case MEMGETBADBLOCK:
285         case MEMSETBADBLOCK:
286                 tprints(", ");
287                 printnum_int64(tcp, arg, "%" PRIu64);
288                 break;
289
290         case MEMGETINFO:
291                 if (entering(tcp))
292                         return 0;
293                 decode_mtd_info_user(tcp, arg);
294                 break;
295
296         case MEMGETOOBSEL:
297                 if (entering(tcp))
298                         return 0;
299                 decode_nand_oobinfo(tcp, arg);
300                 break;
301
302         case ECCGETLAYOUT:
303                 if (entering(tcp))
304                         return 0;
305                 decode_nand_ecclayout_user(tcp, arg);
306                 break;
307
308         case ECCGETSTATS:
309                 if (entering(tcp))
310                         return 0;
311                 decode_mtd_ecc_stats(tcp, arg);
312                 break;
313
314         case OTPGETREGIONCOUNT:
315                 if (entering(tcp))
316                         return 0;
317                 tprints(", ");
318                 printnum_int(tcp, arg, "%u");
319                 break;
320
321         case MEMGETREGIONCOUNT:
322                 if (entering(tcp))
323                         return 0;
324                 tprints(", ");
325                 printnum_int(tcp, arg, "%d");
326                 break;
327
328         case MEMGETREGIONINFO:
329                 if (entering(tcp)) {
330                         struct region_info_user rinfo;
331
332                         tprints(", ");
333                         if (umove_or_printaddr(tcp, arg, &rinfo))
334                                 break;
335                         tprintf("{regionindex=%#x", rinfo.regionindex);
336                         return 0;
337                 } else {
338                         struct region_info_user rinfo;
339
340                         if (!syserror(tcp) && !umove(tcp, arg, &rinfo))
341                                 tprintf(", offset=%#x"
342                                         ", erasesize=%#x"
343                                         ", numblocks=%#x}",
344                                         rinfo.offset,
345                                         rinfo.erasesize,
346                                         rinfo.numblocks);
347                         tprints("}");
348                         break;
349                 }
350
351         default:
352                 return RVAL_DECODED;
353         }
354
355         return RVAL_DECODED | 1;
356 }