GIT 1e404acc96ffa9e9d4f52d185b98333ca230d90a git+ssh://master.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc.git#for-andrew commit e5b01117dd3e20a1b955b442b5a3488803d975d5 Author: Mariusz Kozlowski Date: Fri Aug 10 14:00:51 2007 -0700 drivers/mmc/core/mmc_ops.c: kmalloc + memset conversion to kzalloc drivers/mmc/core/mmc_ops.c | 7957 -> 7924 (-33 bytes) drivers/mmc/core/mmc_ops.o | 101732 -> 101744 (+12 bytes) Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Pierre Ossman commit 1763538bb8a661b78bb8c33f7b217acfe9804794 Author: Anderson Briglia Date: Sat Jan 6 22:57:35 2007 +0100 mmc: Lock sysfs interface Implement MMC password force erase, remove password, change password, unlock card and assign password operations. It uses the sysfs mechanism to send commands to the MMC subsystem. Signed-off-by: Carlos Eduardo Aguiar Signed-off-by: Anderson Lizardo Signed-off-by: Anderson Briglia Signed-off-by: Pierre Ossman commit 0c49a9801ce78a1166f8931113fa907a1ff5dce1 Author: Anderson Briglia Date: Fri May 18 13:32:40 2007 +0200 mmc: Implement card lock/unlock operation, using the MMC_LOCK_UNLOCK command. Signed-off-by: Carlos Eduardo Aguiar Signed-off-by: Anderson Lizardo Signed-off-by: Anderson Briglia Signed-off-by: Pierre Ossman commit 895036a6b58b0785dcc0fe12674d4737d2123582 Author: Anderson Briglia Date: Fri May 18 13:22:13 2007 +0200 mmc: Implement key retention operations. Signed-off-by: Carlos Eduardo Aguiar Signed-off-by: Anderson Lizardo Signed-off-by: Anderson Briglia Signed-off-by: Pierre Ossman commit 2735ce9d853d6ef6d8b3dfffd5b825ade807dd37 Author: Anderson Briglia Date: Fri May 18 13:15:46 2007 +0200 mmc: Lockable card state When a card is locked, only commands from the "basic" and "lock card" classes are accepted. To be able to use the other commands, the card must be unlocked first. This patch prevents the device drivers from probing the locked cards. Device probing must be triggered sometime later to make the card available to the block driver. Signed-off-by: Carlos Eduardo Aguiar Signed-off-by: Anderson Lizardo Signed-off-by: Anderson Briglia Signed-off-by: David Brownell Signed-off-by: Pierre Ossman drivers/mmc/core/Kconfig | 12 +++ drivers/mmc/core/Makefile | 1 + drivers/mmc/core/bus.c | 12 +++ drivers/mmc/core/core.c | 8 ++ drivers/mmc/core/lock.c | 207 ++++++++++++++++++++++++++++++++++++++++++++ drivers/mmc/core/lock.h | 51 +++++++++++ drivers/mmc/core/mmc.c | 20 ++++- drivers/mmc/core/mmc_ops.c | 117 +++++++++++++++++++++++++ drivers/mmc/core/mmc_ops.h | 3 + drivers/mmc/core/sd.c | 20 ++++- include/linux/mmc/card.h | 3 + include/linux/mmc/mmc.h | 8 ++ 12 files changed, 460 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index ab37a6d..f0ae75e 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -14,3 +14,15 @@ config MMC_UNSAFE_RESUME This option is usually just for embedded systems which use a MMC/SD card for rootfs. Most people should say N here. +config MMC_PASSWORDS + boolean "MMC card lock/unlock passwords (EXPERIMENTAL)" + depends on EXPERIMENTAL + select KEYS + help + Say Y here to enable the use of passwords to lock and unlock + MMC cards. This uses the access key retention support, using + request_key to look up the key associated with each card. + + For example, if you have an MMC card that was locked using + Symbian OS on your cell phone, you won't be able to read it + on Linux without this support. diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 4985807..d507c56 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -11,4 +11,5 @@ mmc_core-y := core.o sysfs.o bus.o host.o \ mmc.o mmc_ops.o sd.o sd_ops.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o +mmc_core-$(CONFIG_MMC_PASSWORDS) += lock.o diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index b0c22ca..c7dc520 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -51,9 +51,21 @@ static struct device_attribute mmc_dev_attrs[] = { * This currently matches any MMC driver to any MMC card - drivers * themselves make the decision whether to drive this card in their * probe method. + * + * We also fail for all locked cards; drivers expect to be able to do block + * I/O still on probe(), which is not possible while the card is locked. + * Device probing must be triggered sometime later to make the card available + * to the block driver. */ static int mmc_bus_match(struct device *dev, struct device_driver *drv) { + struct mmc_card *card = dev_to_mmc_card(dev); + + if (mmc_card_locked(card)) { + dev_dbg(&card->dev, "card is locked; binding is deferred\n"); + return 0; + } + return 1; } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b966674..a157c8c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -30,6 +30,7 @@ #include "bus.h" #include "host.h" #include "sdio_bus.h" +#include "lock.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -802,8 +803,14 @@ static int __init mmc_init(void) if (ret) goto unregister_host_class; + ret = mmc_register_key_type(); + if (ret) + goto unregister_sdio; + return 0; +unregister_sdio: + sdio_unregister_bus(); unregister_host_class: mmc_unregister_host_class(); unregister_bus: @@ -816,6 +823,7 @@ destroy_workqueue: static void __exit mmc_exit(void) { + mmc_unregister_key_type(); sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); diff --git a/drivers/mmc/core/lock.c b/drivers/mmc/core/lock.c new file mode 100644 index 0000000..869b97c --- /dev/null +++ b/drivers/mmc/core/lock.c @@ -0,0 +1,207 @@ +/* + * linux/drivers/mmc/core/lock.h + * + * Copyright 2006 Instituto Nokia de Tecnologia (INdT), All Rights Reserved. + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * MMC password key handling. + */ + +#include +#include +#include + +#include +#include +#include + +#include "sysfs.h" +#include "mmc_ops.h" +#include "lock.h" + +#define MMC_KEYLEN_MAXBYTES 32 + +#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev) + +static int mmc_key_instantiate(struct key *key, const void *data, size_t datalen) +{ + struct mmc_key_payload *mpayload; + int ret; + + ret = -EINVAL; + if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data) { + pr_debug("Invalid data\n"); + goto error; + } + + ret = key_payload_reserve(key, datalen); + if (ret < 0) { + pr_debug("ret = %d\n", ret); + goto error; + } + + ret = -ENOMEM; + mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL); + if (!mpayload) { + pr_debug("Unable to allocate mpayload structure\n"); + goto error; + } + mpayload->datalen = datalen; + memcpy(mpayload->data, data, datalen); + + rcu_assign_pointer(key->payload.data, mpayload); + + /* ret = 0 if there is no error */ + ret = 0; + +error: + return ret; +} + +static int mmc_key_match(const struct key *key, const void *description) +{ + return strcmp(key->description, description) == 0; +} + +/* + * dispose of the data dangling from the corpse of a mmc key + */ +static void mmc_key_destroy(struct key *key) +{ + struct mmc_key_payload *mpayload = key->payload.data; + + kfree(mpayload); +} + +static struct key_type mmc_key_type = { + .name = "mmc", + .def_datalen = MMC_KEYLEN_MAXBYTES, + .instantiate = mmc_key_instantiate, + .match = mmc_key_match, + .destroy = mmc_key_destroy, +}; + +int mmc_register_key_type(void) +{ + return register_key_type(&mmc_key_type); +} + +void mmc_unregister_key_type(void) +{ + unregister_key_type(&mmc_key_type); +} + +static ssize_t +mmc_lockable_show(struct device *dev, struct device_attribute *att, char *buf) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + + return sprintf(buf, "%slocked\n", mmc_card_locked(card) ? "" : "un"); +} + +/* + * implement MMC password functions: force erase, remove password, change + * password, unlock card and assign password. + */ +static ssize_t +mmc_lockable_store(struct device *dev, struct device_attribute *att, + const char *data, size_t len) +{ + struct mmc_card *card = dev_to_mmc_card(dev); + int ret; + struct key *mmc_key; + + WARN_ON(card->type != MMC_TYPE_MMC); + WARN_ON(!(card->csd.cmdclass & CCC_LOCK_CARD)); + + if(card->type != MMC_TYPE_MMC) + return -EINVAL; + if(!(card->csd.cmdclass & CCC_LOCK_CARD)) + return -EINVAL; + + mmc_claim_host(card->host); + + ret = -EINVAL; + if (mmc_card_locked(card) && !strncmp(data, "erase", 5)) { + /* forced erase only works while card is locked */ + mmc_lock_unlock(card, NULL, MMC_LOCK_MODE_ERASE); + ret = len; + } else if (!mmc_card_locked(card) && !strncmp(data, "remove", 6)) { + /* remove password only works while card is unlocked */ + mmc_key = request_key(&mmc_key_type, "mmc:key", "remove"); + + if (!IS_ERR(mmc_key)) { + ret = mmc_lock_unlock(card, mmc_key, MMC_LOCK_MODE_CLR_PWD); + if (!ret) + ret = len; + } else + dev_dbg(&card->dev, "request_key returned error %ld\n", PTR_ERR(mmc_key)); + } else if (!mmc_card_locked(card) && ((!strncmp(data, "assign", 6)) || + (!strncmp(data, "change", 6)))) { + /* assign or change */ + if(!(strncmp(data, "assign", 6))) + mmc_key = request_key(&mmc_key_type, "mmc:key", "assign"); + else + mmc_key = request_key(&mmc_key_type, "mmc:key", "change"); + + if (!IS_ERR(mmc_key)) { + ret = mmc_lock_unlock(card, mmc_key, MMC_LOCK_MODE_SET_PWD); + if (!ret) + ret = len; + } else + dev_dbg(&card->dev, "request_key returned error %ld\n", PTR_ERR(mmc_key)); + } else if (mmc_card_locked(card) && !strncmp(data, "unlock", 6)) { + /* unlock */ + mmc_key = request_key(&mmc_key_type, "mmc:key", "unlock"); + if (!IS_ERR(mmc_key)) { + ret = mmc_lock_unlock(card, mmc_key, MMC_LOCK_MODE_UNLOCK); + if (ret) { + dev_dbg(&card->dev, "Wrong password\n"); + ret = -EINVAL; + } + else { + mmc_release_host(card->host); + device_release_driver(dev); + ret = device_attach(dev); + if(!ret) + return -EINVAL; + else + return len; + } + } else + dev_dbg(&card->dev, "request_key returned error %ld\n", PTR_ERR(mmc_key)); + } + + mmc_release_host(card->host); + return ret; +} + +static struct device_attribute mmc_dev_attr_lockable[] = { + __ATTR(lockable, S_IWUSR | S_IRUGO, + mmc_lockable_show, mmc_lockable_store), + __ATTR_NULL, +}; + +int mmc_lock_add_sysfs(struct mmc_card *card) +{ + if(card->type != MMC_TYPE_MMC) + return 0; + if(!(card->csd.cmdclass & CCC_LOCK_CARD)) + return 0; + + return mmc_add_attrs(card, mmc_dev_attr_lockable); +} + +void mmc_lock_remove_sysfs(struct mmc_card *card) +{ + if(card->type != MMC_TYPE_MMC) + return; + if(!(card->csd.cmdclass & CCC_LOCK_CARD)) + return; + + mmc_remove_attrs(card, mmc_dev_attr_lockable); +} diff --git a/drivers/mmc/core/lock.h b/drivers/mmc/core/lock.h new file mode 100644 index 0000000..32a0314 --- /dev/null +++ b/drivers/mmc/core/lock.h @@ -0,0 +1,51 @@ +/* + * linux/drivers/mmc/core/lock.h + * + * Copyright 2006 Instituto Nokia de Tecnologia (INdT), All Rights Reserved. + * Copyright 2007 Pierre Ossman + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _MMC_CORE_LOCK_H +#define _MMC_CORE_LOCK_H + +#ifdef CONFIG_MMC_PASSWORDS + +/* core-internal data */ +struct mmc_key_payload { + struct rcu_head rcu; /* RCU destructor */ + unsigned short datalen; /* length of this data */ + char data[0]; /* actual data */ +}; + +int mmc_register_key_type(void); +void mmc_unregister_key_type(void); + +int mmc_lock_add_sysfs(struct mmc_card *card); +void mmc_lock_remove_sysfs(struct mmc_card *card); + +#else + +static inline int mmc_register_key_type(void) +{ + return 0; +} + +static inline void mmc_unregister_key_type(void) +{ +} + +static inline int mmc_lock_add_sysfs(struct mmc_card *card) +{ + return 0; +} + +static inline void mmc_lock_remove_sysfs(struct mmc_card *card) +{ +} + +#endif + +#endif diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 68c0e3b..cb11fcd 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -19,6 +19,7 @@ #include "core.h" #include "sysfs.h" #include "bus.h" +#include "lock.h" #include "mmc_ops.h" static const unsigned int tran_exp[] = { @@ -261,6 +262,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, int err; u32 cid[4]; unsigned int max_dtr; + u32 status; BUG_ON(!host); WARN_ON(!host->claimed); @@ -330,6 +332,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } + /* + * Check if card is locked. + */ + err = mmc_send_status(card, &status); + if (err) + goto free_card; + if (status & R1_CARD_IS_LOCKED) + mmc_card_set_locked(card); + if (!oldcard) { /* * Fetch CSD from card. @@ -495,6 +506,12 @@ static int mmc_sysfs_add(struct mmc_host *host, struct mmc_card *card) if (ret < 0) return ret; + ret = mmc_lock_add_sysfs(card); + if (ret < 0) { + mmc_remove_attrs(card, mmc_dev_attrs); + return ret; + } + return 0; } @@ -503,6 +520,7 @@ static int mmc_sysfs_add(struct mmc_host *host, struct mmc_card *card) */ static void mmc_sysfs_remove(struct mmc_host *host, struct mmc_card *card) { + mmc_lock_remove_sysfs(card); mmc_remove_attrs(card, mmc_dev_attrs); } @@ -519,7 +537,7 @@ static void mmc_suspend(struct mmc_host *host) mmc_claim_host(host); if (!mmc_host_is_spi(host)) mmc_deselect_cards(host); - host->card->state &= ~MMC_STATE_HIGHSPEED; + host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_LOCKED); mmc_release_host(host); } diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 64b05c6..e6703e5 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -2,6 +2,8 @@ * linux/drivers/mmc/core/mmc_ops.h * * Copyright 2006-2007 Pierre Ossman + * MMC password protection (C) 2006 Instituto Nokia de Tecnologia (INdT), + * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,12 +13,14 @@ #include #include +#include #include #include #include #include "core.h" +#include "lock.h" #include "mmc_ops.h" static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) @@ -395,3 +399,116 @@ int mmc_send_status(struct mmc_card *card, u32 *status) return 0; } +#ifdef CONFIG_MMC_PASSWORDS + +int mmc_lock_unlock(struct mmc_card *card, struct key *key, int mode) +{ + struct mmc_request mrq; + struct mmc_command cmd; + struct mmc_data data; + struct scatterlist sg; + struct mmc_key_payload *mpayload; + unsigned long erase_timeout; + int err, data_size; + u8 *data_buf; + + mpayload = NULL; + data_size = 1; + if (!(mode & MMC_LOCK_MODE_ERASE)) { + mpayload = rcu_dereference(key->payload.data); + data_size = 2 + mpayload->datalen; + } + + data_buf = kzalloc(data_size, GFP_KERNEL); + if (!data_buf) + return -ENOMEM; + + data_buf[0] |= mode; + if (mode & MMC_LOCK_MODE_UNLOCK) + data_buf[0] &= ~MMC_LOCK_MODE_UNLOCK; + + if (!(mode & MMC_LOCK_MODE_ERASE)) { + data_buf[1] = mpayload->datalen; + memcpy(data_buf + 2, mpayload->data, mpayload->datalen); + } + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SET_BLOCKLEN; + cmd.arg = data_size; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); + if (err) + goto out; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_LOCK_UNLOCK; + cmd.arg = 0; + cmd.flags = MMC_RSP_R1B | MMC_CMD_ADTC; + + memset(&data, 0, sizeof(struct mmc_data)); + + data.blksz = data_size; + data.blocks = 1; + data.flags = MMC_DATA_WRITE; + data.sg = &sg; + data.sg_len = 1; + + mmc_set_data_timeout(&data, card); + + memset(&mrq, 0, sizeof(struct mmc_request)); + + mrq.cmd = &cmd; + mrq.data = &data; + + sg_init_one(&sg, data_buf, data_size); + mmc_wait_for_req(card->host, &mrq); + err = cmd.error; + if (err) + goto out; + err = data.error; + if (err) + goto out; + + memset(&cmd, 0, sizeof(struct mmc_command)); + + cmd.opcode = MMC_SEND_STATUS; + cmd.arg = card->rca << 16; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + + /* set timeout for forced erase operation to 3 min. (see MMC spec) */ + erase_timeout = jiffies + 180 * HZ; + do { + /* we cannot use "retries" here because the + * R1_LOCK_UNLOCK_FAILED bit is cleared by subsequent reads to + * the status register, hiding the error condition */ + err = mmc_wait_for_cmd(card->host, &cmd, 0); + if (err) + break; + /* the other modes don't need timeout checking */ + if (!(mode & MMC_LOCK_MODE_ERASE)) + continue; + if (time_after(jiffies, erase_timeout)) { + dev_dbg(&card->dev, "forced erase timed out\n"); + err = -ETIMEDOUT; + break; + } + } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + if (cmd.resp[0] & R1_LOCK_UNLOCK_FAILED) { + dev_dbg(&card->dev, "LOCK_UNLOCK operation failed\n"); + err = -EIO; + } + + if (cmd.resp[0] & R1_CARD_IS_LOCKED) + mmc_card_set_locked(card); + else + card->state &= ~MMC_STATE_LOCKED; + +out: + kfree(data_buf); + + return err; +} + +#endif /* CONFIG_MMC_PASSWORDS */ diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h index 17854bf..15cd182 100644 --- a/drivers/mmc/core/mmc_ops.h +++ b/drivers/mmc/core/mmc_ops.h @@ -12,6 +12,8 @@ #ifndef _MMC_MMC_OPS_H #define _MMC_MMC_OPS_H +struct key; + int mmc_select_card(struct mmc_card *card); int mmc_deselect_cards(struct mmc_host *host); int mmc_go_idle(struct mmc_host *host); @@ -25,6 +27,7 @@ int mmc_send_status(struct mmc_card *card, u32 *status); int mmc_send_cid(struct mmc_host *host, u32 *cid); int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); int mmc_spi_set_crc(struct mmc_host *host, int use_crc); +int mmc_lock_unlock(struct mmc_card *card, struct key *key, int mode); #endif diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d1c1e0f..5d28960 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -20,6 +20,7 @@ #include "core.h" #include "sysfs.h" #include "bus.h" +#include "lock.h" #include "mmc_ops.h" #include "sd_ops.h" @@ -296,6 +297,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, int err; u32 cid[4]; unsigned int max_dtr; + u32 status; BUG_ON(!host); WARN_ON(!host->claimed); @@ -373,6 +375,15 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); } + /* + * Check if card is locked. + */ + err = mmc_send_status(card, &status); + if (err) + goto free_card; + if (status & R1_CARD_IS_LOCKED) + mmc_card_set_locked(card); + if (!oldcard) { /* * Fetch CSD from card. @@ -556,6 +567,12 @@ static int mmc_sd_sysfs_add(struct mmc_host *host, struct mmc_card *card) if (ret < 0) return ret; + ret = mmc_lock_add_sysfs(card); + if (ret < 0) { + mmc_remove_attrs(card, mmc_sd_dev_attrs); + return ret; + } + return 0; } @@ -564,6 +581,7 @@ static int mmc_sd_sysfs_add(struct mmc_host *host, struct mmc_card *card) */ static void mmc_sd_sysfs_remove(struct mmc_host *host, struct mmc_card *card) { + mmc_lock_remove_sysfs(card); mmc_remove_attrs(card, mmc_sd_dev_attrs); } @@ -580,7 +598,7 @@ static void mmc_sd_suspend(struct mmc_host *host) mmc_claim_host(host); if (!mmc_host_is_spi(host)) mmc_deselect_cards(host); - host->card->state &= ~MMC_STATE_HIGHSPEED; + host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_LOCKED); mmc_release_host(host); } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 0d508ac..85dda43 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -94,6 +94,7 @@ struct mmc_card { #define MMC_STATE_READONLY (1<<1) /* card is read-only */ #define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */ #define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */ +#define MMC_STATE_LOCKED (1<<4) /* card is currently locked */ u32 raw_cid[4]; /* raw card CID */ u32 raw_csd[4]; /* raw card CSD */ @@ -121,11 +122,13 @@ struct mmc_card { #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED) #define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) +#define mmc_card_locked(c) ((c)->state & MMC_STATE_LOCKED) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED) #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) +#define mmc_card_set_locked(c) ((c)->state |= MMC_STATE_LOCKED) #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) ((c)->dev.bus_id) diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index 4236fbf..58e3ec7 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -280,5 +280,13 @@ struct _mmc_csd { #define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */ #define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */ +/* + * MMC_LOCK_UNLOCK modes + */ +#define MMC_LOCK_MODE_ERASE (1<<3) +#define MMC_LOCK_MODE_UNLOCK (1<<2) +#define MMC_LOCK_MODE_CLR_PWD (1<<1) +#define MMC_LOCK_MODE_SET_PWD (1<<0) + #endif /* MMC_MMC_PROTOCOL_H */