* [patch 1/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
2006-01-31 20:16 ` [patch 2/6] " Carlos Aguiar
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: linux, David Brownell, Tony Lindgren, Russell King,
Aguiar Carlos (EXT-INdT/Manaus),
Lizardo Anderson (EXT-INdT/Manaus), Anderson Briglia
[-- Attachment #1: mmc_ignore_locked.diff --]
[-- Type: text/plain, Size: 4809 bytes --]
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 block driver from trying to run privileged class
commands on locked MMC cards, which will fail anyway.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Signed-off-by: David Brownell <david-b@pacbell.net>
Index: linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc_sysfs.c 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c 2006-01-31 15:22:07.000000000 -0400
@@ -16,6 +16,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/protocol.h>
#include "mmc.h"
@@ -69,13 +70,22 @@ static void mmc_release_card(struct devi
}
/*
- * This currently matches any MMC driver to any MMC card - drivers
- * themselves make the decision whether to drive this card in their
- * probe method. However, we force "bad" cards to fail.
+ * This currently matches any MMC driver to any MMC card - drivers themselves
+ * make the decision whether to drive this card in their probe method.
+ * However, we force "bad" cards to fail.
+ *
+ * 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_lockable(card) && mmc_card_locked(card)) {
+ dev_dbg(&card->dev, "card is locked; binding is deferred\n");
+ return 0;
+ }
return !mmc_card_bad(card);
}
Index: linux-omap-2.6.git/include/linux/mmc/card.h
===================================================================
--- linux-omap-2.6.git.orig/include/linux/mmc/card.h 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/include/linux/mmc/card.h 2006-01-31 15:22:07.000000000 -0400
@@ -61,6 +61,7 @@ struct mmc_card {
#define MMC_STATE_BAD (1<<2) /* unrecognised device */
#define MMC_STATE_SDCARD (1<<3) /* is an SD card */
#define MMC_STATE_READONLY (1<<4) /* card is read-only */
+#define MMC_STATE_LOCKED (1<<5) /* card is currently locked */
u32 raw_cid[4]; /* raw card CID */
u32 raw_csd[4]; /* raw card CSD */
u32 raw_scr[2]; /* raw card SCR */
@@ -74,12 +75,18 @@ struct mmc_card {
#define mmc_card_bad(c) ((c)->state & MMC_STATE_BAD)
#define mmc_card_sd(c) ((c)->state & MMC_STATE_SDCARD)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
+#define mmc_card_locked(c) ((c)->state & MMC_STATE_LOCKED)
+#define mmc_card_clear_locked(c) ((c)->state &= ~MMC_STATE_LOCKED)
+
+#define mmc_card_lockable(c) (((c)->csd.cmdclass & CCC_LOCK_CARD) && \
+ ((c)->host->caps & MMC_CAP_LOCK_UNLOCK))
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_dead(c) ((c)->state |= MMC_STATE_DEAD)
#define mmc_card_set_bad(c) ((c)->state |= MMC_STATE_BAD)
#define mmc_card_set_sd(c) ((c)->state |= MMC_STATE_SDCARD)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
+#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)
Index: linux-omap-2.6.git/include/linux/mmc/host.h
===================================================================
--- linux-omap-2.6.git.orig/include/linux/mmc/host.h 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/include/linux/mmc/host.h 2006-01-31 15:22:07.000000000 -0400
@@ -85,6 +85,8 @@ struct mmc_host {
unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_LOCK_UNLOCK (1 << 1) /* Host password support capability */
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
Index: linux-omap-2.6.git/drivers/mmc/mmc.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc.c 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc.c 2006-01-31 15:22:07.000000000 -0400
@@ -828,6 +828,11 @@ static void mmc_discover_cards(struct mm
list_add(&card->node, &host->cards);
}
+ if (cmd.resp[0] & R1_CARD_IS_LOCKED)
+ mmc_card_set_locked(card);
+ else
+ mmc_card_clear_locked(card);
+
card->state &= ~MMC_STATE_DEAD;
if (host->mode == MMC_MODE_SD) {
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [patch 2/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
2006-01-31 20:16 ` [patch 1/6] " Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
2006-01-31 20:16 ` [patch 3/6] " Carlos Aguiar
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: linux, David Brownell, Tony Lindgren, Russell King,
Aguiar Carlos (EXT-INdT/Manaus),
Lizardo Anderson (EXT-INdT/Manaus), Anderson Briglia
[-- Attachment #1: mmc_lock_unlock.diff --]
[-- Type: text/plain, Size: 6166 bytes --]
Implement card lock/unlock operation, using the MMC_LOCK_UNLOCK command.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-omap-2.6.git/drivers/mmc/mmc.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc.c 2006-01-31 15:22:07.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc.c 2006-01-31 15:22:21.000000000 -0400
@@ -4,6 +4,8 @@
* Copyright (C) 2003-2004 Russell King, All Rights Reserved.
* SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
* SD support Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
+ * MMC password protection (C) 2005 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 version 2 as
@@ -20,6 +22,7 @@
#include <linux/err.h>
#include <asm/scatterlist.h>
#include <linux/scatterlist.h>
+#include <linux/key.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -1011,10 +1014,14 @@ static void mmc_check_cards(struct mmc_h
cmd.flags = MMC_RSP_R1;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
- if (err == MMC_ERR_NONE)
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
continue;
-
- mmc_card_set_dead(card);
+ }
+ if (cmd.resp[0] & R1_CARD_IS_LOCKED)
+ mmc_card_set_locked(card);
+ else
+ mmc_card_clear_locked(card);
}
}
@@ -1108,6 +1115,135 @@ static void mmc_setup(struct mmc_host *h
mmc_read_scrs(host);
}
+/* Calculate the minimal blksz_bits to hold x bytes. */
+static inline int blksz_bits(unsigned x)
+{
+ return fls(x-1);
+}
+
+/**
+ * mmc_lock_unlock - send LOCK_UNLOCK command to a specific card.
+ * @card: card to which the LOCK_UNLOCK command should be sent
+ * @key: key containing the MMC password
+ * @mode: LOCK_UNLOCK mode
+ *
+ */
+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 = kmalloc(data_size, GFP_KERNEL);
+ if (!data_buf)
+ return -ENOMEM;
+ memset(data_buf, 0, data_size);
+
+ data_buf[0] = mode;
+ if (mode != MMC_LOCK_MODE_ERASE) {
+ data_buf[1] = mpayload->datalen;
+ memcpy(data_buf + 2, mpayload->data, mpayload->datalen);
+ }
+
+ err = mmc_card_claim_host(card);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ goto out;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SET_BLOCKLEN;
+ cmd.arg = data_size;
+ cmd.flags = MMC_RSP_R1;
+ err = mmc_wait_for_cmd(card->host, &cmd, CMD_RETRIES);
+ if (err != MMC_ERR_NONE) {
+ mmc_card_set_dead(card);
+ goto error;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_LOCK_UNLOCK;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1B;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 10;
+ data.timeout_clks = card->csd.tacc_clks * 10;
+ data.blksz_bits = blksz_bits(data_size);
+ data.blocks = 1;
+ data.flags = MMC_DATA_WRITE;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, data_buf, data_size);
+ err = mmc_wait_for_req(card->host, &mrq);
+ if (err != MMC_ERR_NONE) {
+ if(err != MMC_ERR_INVALID)
+ mmc_card_set_dead(card);
+ goto error;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1;
+
+ /* 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 != MMC_ERR_NONE)
+ 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 = MMC_ERR_TIMEOUT;
+ 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 = MMC_ERR_FAILED;
+ }
+
+error:
+ mmc_check_cards(card->host);
+ mmc_deselect_cards(card->host);
+ mmc_card_release_host(card);
+out:
+ kfree(data_buf);
+
+ return err;
+}
+
+EXPORT_SYMBOL(mmc_lock_unlock);
+
/**
* mmc_detect_change - process change of state on a MMC socket
Index: linux-omap-2.6.git/include/linux/mmc/card.h
===================================================================
--- linux-omap-2.6.git.orig/include/linux/mmc/card.h 2006-01-31 15:22:07.000000000 -0400
+++ linux-omap-2.6.git/include/linux/mmc/card.h 2006-01-31 15:22:21.000000000 -0400
@@ -116,4 +116,8 @@ static inline int mmc_card_claim_host(st
#define mmc_card_release_host(c) mmc_release_host((c)->host)
+struct key;
+
+extern int mmc_lock_unlock(struct mmc_card *card, struct key *key, int mode);
+
#endif
Index: linux-omap-2.6.git/include/linux/mmc/protocol.h
===================================================================
--- linux-omap-2.6.git.orig/include/linux/mmc/protocol.h 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/include/linux/mmc/protocol.h 2006-01-31 15:22:21.000000000 -0400
@@ -243,5 +243,13 @@ struct _mmc_csd {
#define SD_BUS_WIDTH_1 0
#define SD_BUS_WIDTH_4 2
+/*
+ * MMC_LOCK_UNLOCK modes
+ */
+#define MMC_LOCK_MODE_ERASE (1<<3)
+#define MMC_LOCK_MODE_UNLOCK (0<<2)
+#define MMC_LOCK_MODE_CLR_PWD (1<<1)
+#define MMC_LOCK_MODE_SET_PWD (1<<0)
+
#endif /* MMC_MMC_PROTOCOL_H */
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [patch 3/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
2006-01-31 20:16 ` [patch 1/6] " Carlos Aguiar
2006-01-31 20:16 ` [patch 2/6] " Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
2006-01-31 20:16 ` [patch 4/6] " Carlos Aguiar
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: Russell King, linux, Lizardo Anderson (EXT-INdT/Manaus)
[-- Attachment #1: mmc_key_retention.diff --]
[-- Type: text/plain, Size: 4916 bytes --]
Implement key retention operations.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-omap-2.6.git/drivers/mmc/Kconfig
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/Kconfig 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/Kconfig 2006-01-31 15:22:25.000000000 -0400
@@ -19,6 +19,19 @@ config MMC_DEBUG
This is an option for use by developers; most people should
say N here. This enables MMC core and driver debugging.
+config MMC_PASSWORDS
+ boolean "MMC card lock/unlock passwords (EXPERIMENTAL)"
+ depends on MMC && 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.
+
config MMC_BLOCK
tristate "MMC block device driver"
depends on MMC
Index: linux-omap-2.6.git/drivers/mmc/mmc.h
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc.h 2006-01-31 15:17:45.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc.h 2006-01-31 15:22:25.000000000 -0400
@@ -18,4 +18,12 @@ struct mmc_host *mmc_alloc_host_sysfs(in
int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host);
+
+/* core-internal data */
+extern struct key_type mmc_key_type;
+struct mmc_key_payload {
+ struct rcu_head rcu; /* RCU destructor */
+ unsigned short datalen; /* length of this data */
+ char data[0]; /* actual data */
+};
#endif
Index: linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc_sysfs.c 2006-01-31 15:22:07.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c 2006-01-31 15:22:25.000000000 -0400
@@ -2,6 +2,8 @@
* linux/drivers/mmc/mmc_sysfs.c
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
+ * MMC password protection (C) 2005 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 version 2 as
@@ -13,6 +15,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/idr.h>
+#include <linux/key.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -265,6 +268,71 @@ static struct class mmc_host_class = {
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
+#ifdef CONFIG_MMC_PASSWORDS
+
+#define MMC_KEYLEN_MAXBYTES 32
+
+int mmc_key_instantiate(struct key *key, const void *data, size_t datalen)
+{
+ struct mmc_key_payload *mpayload, *zap;
+ int ret;
+
+ zap = NULL;
+ ret = -EINVAL;
+ if (datalen <= 0 || datalen > MMC_KEYLEN_MAXBYTES || !data) {
+ DBG("Invalid data\n");
+ goto error;
+ }
+
+ ret = key_payload_reserve(key, datalen);
+ if (ret < 0) {
+ DBG("ret = %d\n", ret);
+ goto error;
+ }
+
+ ret = -ENOMEM;
+ mpayload = kmalloc(sizeof(*mpayload) + datalen, GFP_KERNEL);
+ if (!mpayload) {
+ DBG("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;
+}
+
+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
+ */
+void mmc_key_destroy(struct key *key)
+{
+ struct mmc_key_payload *mpayload = key->payload.data;
+
+ kfree(mpayload);
+}
+
+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,
+};
+
+#endif
+
/*
* Internal function. Allocate a new MMC host.
*/
@@ -335,6 +403,15 @@ static int __init mmc_init(void)
ret = class_register(&mmc_host_class);
if (ret)
bus_unregister(&mmc_bus_type);
+#ifdef CONFIG_MMC_PASSWORDS
+ else {
+ ret = register_key_type(&mmc_key_type);
+ if (ret) {
+ class_unregister(&mmc_host_class);
+ bus_unregister(&mmc_bus_type);
+ }
+ }
+#endif
}
return ret;
}
@@ -343,6 +420,9 @@ static void __exit mmc_exit(void)
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
+#ifdef CONFIG_MMC_PASSWORDS
+ unregister_key_type(&mmc_key_type);
+#endif
}
module_init(mmc_init);
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [patch 4/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
` (2 preceding siblings ...)
2006-01-31 20:16 ` [patch 3/6] " Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
2006-01-31 20:16 ` [patch 5/6] " Carlos Aguiar
2006-01-31 20:16 ` [patch 6/6] " Carlos Aguiar
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: Russell King, linux, Lizardo Anderson (EXT-INdT/Manaus)
[-- Attachment #1: mmc_sysfs.diff --]
[-- Type: text/plain, Size: 4720 bytes --]
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: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/mmc_sysfs.c 2006-01-31 15:22:25.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/mmc_sysfs.c 2006-01-31 15:22:29.000000000 -0400
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/idr.h>
#include <linux/key.h>
+#include <linux/err.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -23,6 +24,12 @@
#include "mmc.h"
+#ifdef CONFIG_MMC_DEBUG
+#define DBG(x...) printk(KERN_DEBUG x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
#define dev_to_mmc_card(d) container_of(d, struct mmc_card, dev)
#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
@@ -64,6 +71,101 @@ static struct device_attribute mmc_dev_a
static struct device_attribute mmc_dev_attr_scr = MMC_ATTR_RO(scr);
+#ifdef CONFIG_MMC_PASSWORDS
+
+static ssize_t
+mmc_lockable_show(struct device *dev, struct device_attribute *att, char *buf)
+{
+ struct mmc_card *card = dev_to_mmc_card(dev);
+
+ if (!mmc_card_lockable(card))
+ return sprintf(buf, "unsupported\n");
+ else
+ 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);
+
+ if (!mmc_card_lockable(card))
+ return -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);
+ return len;
+ } else if (!mmc_card_locked(card) && !strncmp(data, "remove", 6)) {
+ /* remove password only works while card is unlocked */
+ struct key *mmc_key = request_key(&mmc_key_type, "mmc:key",
+ "remove");
+
+ if (!IS_ERR(mmc_key)) {
+ int err = mmc_lock_unlock(card, mmc_key,
+ MMC_LOCK_MODE_CLR_PWD);
+ if (!err)
+ return len;
+ } else
+ DBG("request_key returned error %ld\n",
+ PTR_ERR(mmc_key));
+ } else if (!mmc_card_locked(card) && !strncmp(data, "change", 6)) {
+ /* change */
+ struct key *mmc_key = request_key(&mmc_key_type,
+ "mmc:key", "change");
+ if (!IS_ERR(mmc_key)) {
+ int err = mmc_lock_unlock(card, mmc_key,
+ MMC_LOCK_MODE_SET_PWD);
+ if (!err)
+ return len;
+ } else
+ DBG("request_key returned error %ld\n",
+ PTR_ERR(mmc_key));
+ } else if (mmc_card_locked(card) && !strncmp(data, "unlock", 6)) {
+ /* unlock */
+ struct key *mmc_key = request_key(&mmc_key_type,
+ "mmc:key", "unlock");
+ if (!IS_ERR(mmc_key)) {
+ int err = mmc_lock_unlock(card, mmc_key,
+ MMC_LOCK_MODE_UNLOCK);
+ if (err)
+ DBG("Wrong password\n");
+ device_release_driver(dev);
+ device_attach(dev);
+ if (!err)
+ return len;
+ } else
+ DBG("request_key returned error %ld\n",
+ PTR_ERR(mmc_key));
+ } else if (!mmc_card_locked(card) && !strncmp(data, "assign", 6)) {
+ /* assign */
+ struct key *mmc_key = request_key(&mmc_key_type,
+ "mmc:key", "assign");
+ if (!IS_ERR(mmc_key)) {
+ int err = mmc_lock_unlock(card, mmc_key,
+ MMC_LOCK_MODE_SET_PWD);
+ if (!err)
+ return len;
+ } else
+ DBG("request_key returned error %ld\n",
+ PTR_ERR(mmc_key));
+ }
+
+ return -EINVAL;
+}
+
+static struct device_attribute mmc_dev_attr_lockable =
+ __ATTR(lockable, S_IWUSR | S_IRUGO,
+ mmc_lockable_show, mmc_lockable_store);
+
+#endif
+
static void mmc_release_card(struct device *dev)
{
@@ -233,6 +335,11 @@ int mmc_register_card(struct mmc_card *c
if (ret)
device_del(&card->dev);
}
+#ifdef CONFIG_MMC_PASSWORDS
+ ret = device_create_file(&card->dev, &mmc_dev_attr_lockable);
+ if (ret)
+ device_del(&card->dev);
+#endif
}
return ret;
}
@@ -246,7 +353,9 @@ void mmc_remove_card(struct mmc_card *ca
if (mmc_card_present(card)) {
if (mmc_card_sd(card))
device_remove_file(&card->dev, &mmc_dev_attr_scr);
-
+#ifdef CONFIG_MMC_PASSWORDS
+ device_remove_file(&card->dev, &mmc_dev_attr_lockable);
+#endif
device_del(&card->dev);
}
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [patch 5/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
` (3 preceding siblings ...)
2006-01-31 20:16 ` [patch 4/6] " Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
2006-01-31 20:16 ` [patch 6/6] " Carlos Aguiar
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: Russell King, linux, Lizardo Anderson (EXT-INdT/Manaus)
[-- Attachment #1: mmc_omap_blklen.diff --]
[-- Type: text/plain, Size: 1192 bytes --]
The MMC_LOCK_UNLOCK command requires the block length to be exactly the
password length + 2 bytes, but hardware-specific drivers force a "power of 2"
block size.
This patch sends the exact block size (password + 2 bytes) to the host. OMAP
specific.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-omap-2.6.git/drivers/mmc/omap.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/omap.c 2006-01-31 15:17:44.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/omap.c 2006-01-31 15:22:33.000000000 -0400
@@ -888,8 +888,12 @@ mmc_omap_prepare_data(struct mmc_omap_ho
return;
}
-
- block_size = 1 << data->blksz_bits;
+ /* password protection: we need to send the exact block size to the
+ * card (password + 2), not a 2-exponent. */
+ if (req->cmd->opcode == MMC_LOCK_UNLOCK)
+ block_size = data->sg[0].length;
+ else
+ block_size = 1 << data->blksz_bits;
OMAP_MMC_WRITE(host->base, NBLK, data->blocks - 1);
OMAP_MMC_WRITE(host->base, BLEN, block_size - 1);
--
^ permalink raw reply [flat|nested] 7+ messages in thread* [patch 6/6] Add MMC password protection (lock/unlock) support V4
2006-01-31 20:16 [patch 0/6] Add MMC password protection (lock/unlock) support V4 Carlos Aguiar
` (4 preceding siblings ...)
2006-01-31 20:16 ` [patch 5/6] " Carlos Aguiar
@ 2006-01-31 20:16 ` Carlos Aguiar
5 siblings, 0 replies; 7+ messages in thread
From: Carlos Aguiar @ 2006-01-31 20:16 UTC (permalink / raw)
To: linux-kernel, Linux-omap-open-source@linux.omap.com
Cc: linux, David Brownell, Tony Lindgren, Russell King,
Aguiar Carlos (EXT-INdT/Manaus),
Lizardo Anderson (EXT-INdT/Manaus), Anderson Briglia
[-- Attachment #1: mmc_omap_cap.diff --]
[-- Type: text/plain, Size: 808 bytes --]
Patch to add the host MMC lock/unlock capability support for OMAP platform.
Signed-off-by: Anderson Briglia <anderson.briglia@indt.org.br>
Signed-off-by: Anderson Lizardo <anderson.lizardo@indt.org.br>
Signed-off-by: Carlos Eduardo Aguiar <carlos.aguiar@indt.org.br>
Index: linux-omap-2.6.git/drivers/mmc/omap.c
===================================================================
--- linux-omap-2.6.git.orig/drivers/mmc/omap.c 2006-01-31 15:22:33.000000000 -0400
+++ linux-omap-2.6.git/drivers/mmc/omap.c 2006-01-31 15:22:36.000000000 -0400
@@ -1235,6 +1235,9 @@ static int __init mmc_omap_probe(struct
if (minfo->wire4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
+
+ /* Sets the lock/unlock capability */
+ host->mmc->caps |= MMC_CAP_LOCK_UNLOCK;
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
--
^ permalink raw reply [flat|nested] 7+ messages in thread