diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libmtd.c | 58 | ||||
| -rw-r--r-- | lib/libmtd_int.h | 18 | 
2 files changed, 70 insertions, 6 deletions
diff --git a/lib/libmtd.c b/lib/libmtd.c index 3ff031c..a976679 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -560,6 +560,8 @@ libmtd_t libmtd_open(void)  	if (!lib)  		return NULL; +	lib->offs64_ioctls = OFFS64_IOCTLS_UNKNOWN; +  	lib->sysfs_mtd = mkpath("/sys", SYSFS_MTD);  	if (!lib->sysfs_mtd)  		goto out_error; @@ -789,13 +791,57 @@ int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd)  	return mtd_get_dev_info1(desc, mtd_num, mtd);  } -int mtd_erase(const struct mtd_dev_info *mtd, int fd, int eb) +int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)  { +	int ret; +	struct libmtd *lib = (struct libmtd *)desc; +	struct erase_info_user64 ei64;  	struct erase_info_user ei; -	ei.start = eb * mtd->eb_size;; -	ei.length = mtd->eb_size; -	return ioctl(fd, MEMERASE, &ei); +	if (eb < 0 || eb >= mtd->eb_cnt) { +		errmsg("bad eraseblock number %d, mtd%d has %d eraseblocks", +		       eb, mtd->mtd_num, mtd->eb_cnt); +		errno = EINVAL; +		return -1; +	} + +	ei64.start = (__u64)eb * mtd->eb_size; +	ei64.length = mtd->eb_size; + +	if (lib->offs64_ioctls == OFFS64_IOCTLS_SUPPORTED || +	    lib->offs64_ioctls == OFFS64_IOCTLS_UNKNOWN) { +		ret = ioctl(fd, MEMERASE64, &ei64); +		if (ret == 0) +			return ret; + +		if (errno != ENOTTY || +		    lib->offs64_ioctls != OFFS64_IOCTLS_UNKNOWN) +			return sys_errmsg("MEMERASE64 ioctl failed for " +					  "eraseblock %d (mtd%d)", +					  eb, mtd->mtd_num); + +		/* +		 * MEMERASE64 support was added in kernel version 2.6.31, so +		 * probably we are working with older kernel and this ioctl is +		 * not supported. +		 */ +		lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; +	} + +	if (ei64.start + ei64.length > 0xFFFFFFFF) { +		errmsg("this system can address only %u eraseblocks", +		       0xFFFFFFFFU / mtd->eb_size); +		errno = EINVAL; +		return -1; +	} + +	ei.start = ei64.start; +	ei.length = ei64.length; +	ret = ioctl(fd, MEMERASE, &ei); +	if (ret < 0) +		return sys_errmsg("MEMERASE ioctl failed for eraseblock %d " +				  "(mtd%d)", eb, mtd->mtd_num); +	return 0;  }  /* Patterns to write to a physical eraseblock when torturing it */ @@ -820,7 +866,7 @@ static int check_pattern(const void *buf, uint8_t patt, int size)  	return 1;  } -int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb) +int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb)  {  	int err, i, patt_count;  	void *buf; @@ -835,7 +881,7 @@ int mtd_torture(const struct mtd_dev_info *mtd, int fd, int eb)  	}  	for (i = 0; i < patt_count; i++) { -		err = mtd_erase(mtd, fd, eb); +		err = mtd_erase(desc, mtd, fd, eb);  		if (err)  			goto out; diff --git a/lib/libmtd_int.h b/lib/libmtd_int.h index 7de4b42..bb48d35 100644 --- a/lib/libmtd_int.h +++ b/lib/libmtd_int.h @@ -43,6 +43,10 @@ extern "C" {  #define MTD_REGION_CNT   "numeraseregions"  #define MTD_FLAGS        "flags" +#define OFFS64_IOCTLS_UNKNOWN       0 +#define OFFS64_IOCTLS_NOT_SUPPORTED 1 +#define OFFS64_IOCTLS_SUPPORTED     2 +  /**   * libmtd - MTD library description data structure.   * @sysfs_mtd: MTD directory in sysfs @@ -58,6 +62,19 @@ extern "C" {   * @mtd_region_cnt: count of additional erase regions file pattern   * @mtd_flags: MTD device flags file pattern   * @sysfs_supported: non-zero if sysfs is supported by MTD + * @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64, + *                 %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are + *                 supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and + *                 %OFFS64_IOCTLS_UNKNOWN if it is not known yet; + * + *  Note, we cannot find out whether 64-bit ioctls are supported by MTD when we + *  are initializing the library, because this requires an MTD device node. + *  Indeed, we have to actually call the ioctl and check for %ENOTTY to find + *  out whether it is supported or not. + * + *  Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and + *  initialize it later, when corresponding libmtd function is used, and when + *  we actually have a device node and can invoke an ioctl command on it.   */  struct libmtd  { @@ -74,6 +91,7 @@ struct libmtd  	char *mtd_region_cnt;  	char *mtd_flags;  	unsigned int sysfs_supported:1; +	unsigned int offs64_ioctls:2;  };  int legacy_libmtd_open(void);  | 
