diff options
author | Johan RUDHOLM <johan.rudholm@stericsson.com> | 2012-02-12 11:46:44 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-02-12 11:52:25 -0500 |
commit | a8bfde77e0e275070791138d60b75d1cc293daf0 (patch) | |
tree | a54356dd7f5595b8203b8624531a71edd39690d5 | |
parent | 80d2660fa95615f3bc77a9b258414f2c533175c7 (diff) | |
download | mmc-utils-a8bfde77e0e275070791138d60b75d1cc293daf0.tar.gz |
Add extcsd write-protect read/write code
This was posted to linux-mmc@ by Johan Rudholm.
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | mmc.h | 61 | ||||
-rw-r--r-- | mmc_cmds.c | 158 | ||||
-rw-r--r-- | mmc_cmds.h | 19 |
4 files changed, 239 insertions, 1 deletions
@@ -1,7 +1,7 @@ CC = gcc AM_CFLAGS = -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 CFLAGS = -g -O0 -objects = mmc.o +objects = mmc.o mmc_cmds.h CHECKFLAGS= -Wall -Werror -Wuninitialized -Wundef @@ -0,0 +1,61 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <asm-generic/int-ll64.h> +#include <linux/mmc/ioctl.h> +#include <linux/major.h> +#include <stdio.h> + +#define CHECK(expr, msg, err_stmt) { if (expr) { fprintf(stderr, msg); err_stmt; } } + +/* From kernel linux/mmc/mmc.h */ +#define MMC_SWITCH 6 /* ac [31:0] See below R1b */ +#define MMC_SEND_EXT_CSD 8 /* adtc R1 */ +#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ + +/* + * EXT_CSD fields + */ +#define EXT_CSD_BOOT_WP 173 /* R/W */ +#define EXT_CSD_PART_SWITCH_TIME 199 /* RO */ + +/* + * EXT_CSD field definitions + */ +#define EXT_CSD_CMD_SET_NORMAL (1<<0) +#define EXT_CSD_BOOT_WP_B_PWR_WP_DIS (0x40) +#define EXT_CSD_BOOT_WP_B_PERM_WP_DIS (0x10) +#define EXT_CSD_BOOT_WP_B_PERM_WP_EN (0x04) +#define EXT_CSD_BOOT_WP_B_PWR_WP_EN (0x01) + +/* From kernel linux/mmc/core.h */ +#define MMC_RSP_PRESENT (1 << 0) +#define MMC_RSP_136 (1 << 1) /* 136 bit response */ +#define MMC_RSP_CRC (1 << 2) /* expect valid crc */ +#define MMC_RSP_BUSY (1 << 3) /* card may send busy */ +#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */ + +#define MMC_CMD_AC (0 << 5) +#define MMC_CMD_ADTC (1 << 5) + +#define MMC_RSP_SPI_S1 (1 << 7) /* one status byte */ +#define MMC_RSP_SPI_BUSY (1 << 10) /* card may send busy */ + +#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1) +#define MMC_RSP_SPI_R1B (MMC_RSP_SPI_S1|MMC_RSP_SPI_BUSY) + +#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE) +#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY) diff --git a/mmc_cmds.c b/mmc_cmds.c new file mode 100644 index 0000000..82fd016 --- /dev/null +++ b/mmc_cmds.c @@ -0,0 +1,158 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <uuid/uuid.h> +#include <ctype.h> + +#include "mmc.h" +#include "mmc_cmds.h" + +int read_extcsd(int fd, __u8 *ext_csd) +{ + int ret = 0; + struct mmc_ioc_cmd idata; + memset(&idata, 0, sizeof(idata)); + memset(ext_csd, 0, sizeof(__u8) * 512); + idata.write_flag = 0; + idata.opcode = MMC_SEND_EXT_CSD; + idata.arg = 0; + idata.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; + idata.blksz = 512; + idata.blocks = 1; + mmc_ioc_cmd_set_data(idata, ext_csd); + + ret = ioctl(fd, MMC_IOC_CMD, &idata); + if (ret) + perror("ioctl"); + + return ret; +} + +int write_extcsd_value(int fd, __u8 index, __u8 value) +{ + int ret = 0; + struct mmc_ioc_cmd idata; + + memset(&idata, 0, sizeof(idata)); + idata.write_flag = 1; + idata.opcode = MMC_SWITCH; + idata.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | + (index << 16) | + (value << 8) | + EXT_CSD_CMD_SET_NORMAL; + idata.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; + + ret = ioctl(fd, MMC_IOC_CMD, &idata); + if (ret) + perror("ioctl"); + + return ret; +} + +int do_read_extcsd(int nargs, char **argv) +{ + __u8 ext_csd[512]; + int fd, ret; + char *device; + + CHECK(nargs != 2, "Usage: mmc </path/to/mmcblkX>\n", exit(1)); + + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + perror("open"); + exit(1); + } + + ret = read_extcsd(fd, ext_csd); + if (ret) { + fprintf(stderr, "Could not read EXT_CSD from %s\n", device); + exit(1); + } + + printf("Power ro locking: "); + if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) + printf("not possible\n"); + else + printf("possible\n"); + + printf("Permanent ro locking: "); + if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PERM_WP_DIS) + printf("not possible\n"); + else + printf("possible\n"); + + printf("ro lock status: "); + if (ext_csd[EXT_CSD_BOOT_WP] & EXT_CSD_BOOT_WP_B_PWR_WP_EN) + printf("locked until next power on\n"); + else if (ext_csd[EXT_CSD_BOOT_WP] & + EXT_CSD_BOOT_WP_B_PERM_WP_EN) + printf("locked permanently\n"); + else + printf("not locked\n"); + + return ret; +} + +int do_write_extcsd(int nargs, char **argv) +{ + __u8 ext_csd[512], value; + int fd, ret; + char *device; + + if (nargs != 2) { + fprintf (stderr, "Usage: %s </path/to/mmcblkX>\n", + argv[0]); + exit (1); + } + device = argv[1]; + + fd = open(device, O_RDWR); + if (fd < 0) { + perror("open"); + exit(1); + } + + ret = read_extcsd(fd, ext_csd); + if (ret) { + fprintf(stderr, "Could not read EXT_CSD from %s\n", device); + exit(1); + } + + value = ext_csd[EXT_CSD_BOOT_WP] | + EXT_CSD_BOOT_WP_B_PWR_WP_EN; + ret = write_extcsd_value(fd, EXT_CSD_BOOT_WP, value); + if (ret) { + fprintf(stderr, "Could not write 0x%02x to " + "EXT_CSD[%d] in %s\n", + value, EXT_CSD_BOOT_WP, device); + exit(1); + } + + return ret; +} diff --git a/mmc_cmds.h b/mmc_cmds.h new file mode 100644 index 0000000..1b28051 --- /dev/null +++ b/mmc_cmds.h @@ -0,0 +1,19 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + +/* mmc_cmds.c */ +int do_read_extcsd(int nargs, char **argv); +int do_write_extcsd(int nargs, char **argv); |