2 * Copyright (C) 2009 Nokia Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Author: Artem Bityutskiy
20 * This file is part of the MTD library. Implements pre-2.6.30 kernels support,
21 * where MTD did not have sysfs interface. The main limitation of the old
22 * kernels was that the sub-page size was not exported to user-space, so it was
23 * not possible to get sub-page size.
26 /* Imported from mtd-utils by dehrenberg */
33 #include <sys/types.h>
35 #include <sys/ioctl.h>
36 #include <mtd/mtd-user.h>
39 #include "libmtd_int.h"
40 #include "libmtd_common.h"
42 #define MTD_PROC_FILE "/proc/mtd"
43 #define MTD_DEV_PATT "/dev/mtd%d"
44 #define MTD_DEV_MAJOR 90
46 #define PROC_MTD_FIRST "dev: size erasesize name\n"
47 #define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
48 #define PROC_MTD_MAX_LEN 4096
49 #define PROC_MTD_PATT "mtd%d: %llx %x"
52 * struct proc_parse_info - /proc/mtd parsing information.
53 * @mtd_num: MTD device number
55 * @eb_size: eraseblock size
57 * @buf: contents of /proc/mtd
58 * @data_size: how much data was read into @buf
59 * @pos: next string in @buf to parse
61 struct proc_parse_info
65 char name[MTD_NAME_MAX + 1];
72 static int proc_parse_start(struct proc_parse_info *pi)
76 fd = open(MTD_PROC_FILE, O_RDONLY);
80 pi->buf = xmalloc(PROC_MTD_MAX_LEN);
82 ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
84 sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
88 if (ret < PROC_MTD_FIRST_LEN ||
89 memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
90 errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
96 pi->next = pi->buf + PROC_MTD_FIRST_LEN;
107 static int proc_parse_next(struct proc_parse_info *pi)
109 int ret, len, pos = pi->next - pi->buf;
112 if (pos >= pi->data_size) {
117 ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
120 return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
122 p = memchr(pi->next, '\"', pi->data_size - pos);
124 return errmsg("opening \" not found");
127 if (pos >= pi->data_size)
128 return errmsg("opening \" not found");
130 p1 = memchr(p, '\"', pi->data_size - pos);
132 return errmsg("closing \" not found");
134 if (pos >= pi->data_size)
135 return errmsg("closing \" not found");
138 if (len > MTD_NAME_MAX)
139 return errmsg("too long mtd%d device name", pi->mtd_num);
141 memcpy(pi->name, p, len);
142 pi->name[len] = '\0';
145 return errmsg("opening \"\n\" not found");
151 * legacy_libmtd_open - legacy version of 'libmtd_open()'.
153 * This function is just checks that MTD is present in the system. Returns
154 * zero in case of success and %-1 in case of failure. In case of failure,
155 * errno contains zero if MTD is not present in the system, or contains the
156 * error code if a real error happened. This is similar to the 'libmtd_open()'
157 * return conventions.
159 int legacy_libmtd_open(void)
163 fd = open(MTD_PROC_FILE, O_RDONLY);
175 * legacy_dev_presentl - legacy version of 'mtd_dev_present()'.
176 * @info: the MTD device information is returned here
178 * When the kernel does not provide sysfs files for the MTD subsystem,
179 * fall-back to parsing the /proc/mtd file to determine whether an mtd device
180 * number @mtd_num is present.
182 int legacy_dev_present(int mtd_num)
185 struct proc_parse_info pi;
187 ret = proc_parse_start(&pi);
191 while (proc_parse_next(&pi)) {
192 if (pi.mtd_num == mtd_num)
200 * legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
201 * @info: the MTD device information is returned here
203 * This function is similar to 'mtd_get_info()' and has the same conventions.
205 int legacy_mtd_get_info(struct mtd_info *info)
208 struct proc_parse_info pi;
210 ret = proc_parse_start(&pi);
214 info->lowest_mtd_num = INT_MAX;
215 while (proc_parse_next(&pi)) {
216 info->mtd_dev_cnt += 1;
217 if (pi.mtd_num > info->highest_mtd_num)
218 info->highest_mtd_num = pi.mtd_num;
219 if (pi.mtd_num < info->lowest_mtd_num)
220 info->lowest_mtd_num = pi.mtd_num;
227 * legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
228 * @node: name of the MTD device node
229 * @mtd: the MTD device information is returned here
231 * This function is similar to 'mtd_get_dev_info()' and has the same
234 int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
237 struct mtd_info_user ui;
240 struct proc_parse_info pi;
242 if (stat(node, &st)) {
243 sys_errmsg("cannot open \"%s\"", node);
245 normsg("MTD subsystem is old and does not support "
246 "sysfs, so MTD character device nodes have "
250 if (!S_ISCHR(st.st_mode)) {
252 return errmsg("\"%s\" is not a character device", node);
255 memset(mtd, '\0', sizeof(struct mtd_dev_info));
256 mtd->major = major(st.st_rdev);
257 mtd->minor = minor(st.st_rdev);
259 if (mtd->major != MTD_DEV_MAJOR) {
261 return errmsg("\"%s\" has major number %d, MTD devices have "
262 "major %d", node, mtd->major, MTD_DEV_MAJOR);
265 mtd->mtd_num = mtd->minor / 2;
267 fd = open(node, O_RDONLY);
269 return sys_errmsg("cannot open \"%s\"", node);
271 if (ioctl(fd, MEMGETINFO, &ui)) {
272 sys_errmsg("MEMGETINFO ioctl request failed");
276 ret = ioctl(fd, MEMGETBADBLOCK, &offs);
278 if (errno != EOPNOTSUPP) {
279 sys_errmsg("MEMGETBADBLOCK ioctl failed");
289 mtd->eb_size = ui.erasesize;
290 mtd->min_io_size = ui.writesize;
291 mtd->oob_size = ui.oobsize;
293 if (mtd->min_io_size <= 0) {
294 errmsg("mtd%d (%s) has insane min. I/O unit size %d",
295 mtd->mtd_num, node, mtd->min_io_size);
298 if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
299 errmsg("mtd%d (%s) has insane eraseblock size %d",
300 mtd->mtd_num, node, mtd->eb_size);
303 if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
304 errmsg("mtd%d (%s) has insane size %lld",
305 mtd->mtd_num, node, mtd->size);
308 mtd->eb_cnt = mtd->size / mtd->eb_size;
312 errmsg("mtd%d (%s) is removable and is not present",
316 strcpy((char *)mtd->type_str, "ram");
319 strcpy((char *)mtd->type_str, "rom");
322 strcpy((char *)mtd->type_str, "nor");
325 strcpy((char *)mtd->type_str, "nand");
327 case MTD_MLCNANDFLASH:
328 strcpy((char *)mtd->type_str, "mlc-nand");
331 strcpy((char *)mtd->type_str, "dataflash");
334 strcpy((char *)mtd->type_str, "ubi");
340 if (ui.flags & MTD_WRITEABLE)
342 mtd->subpage_size = mtd->min_io_size;
347 * Unfortunately, the device name is not available via ioctl, and
348 * we have to parse /proc/mtd to get it.
350 ret = proc_parse_start(&pi);
354 while (proc_parse_next(&pi)) {
355 if (pi.mtd_num == mtd->mtd_num) {
356 strcpy((char *)mtd->name, pi.name);
361 errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
371 * legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
372 * @node: name of the MTD device node
373 * @mtd: the MTD device information is returned here
375 * This function is similar to 'mtd_get_dev_info1()' and has the same
378 int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
380 char node[sizeof(MTD_DEV_PATT) + 20];
382 sprintf(node, MTD_DEV_PATT, mtd_num);
383 return legacy_get_dev_info(node, mtd);