aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/card/cprmdrv_samsung.c
diff options
context:
space:
mode:
authorcodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
committercodeworkx <daniel.hillenbrand@codeworkx.de>2012-06-02 13:09:29 +0200
commitc6da2cfeb05178a11c6d062a06f8078150ee492f (patch)
treef3b4021d252c52d6463a9b3c1bb7245e399b009c /drivers/mmc/card/cprmdrv_samsung.c
parentc6d7c4dbff353eac7919342ae6b3299a378160a6 (diff)
downloadkernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz
kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2
samsung update 1
Diffstat (limited to 'drivers/mmc/card/cprmdrv_samsung.c')
-rw-r--r--drivers/mmc/card/cprmdrv_samsung.c450
1 files changed, 450 insertions, 0 deletions
diff --git a/drivers/mmc/card/cprmdrv_samsung.c b/drivers/mmc/card/cprmdrv_samsung.c
new file mode 100644
index 0000000..6f64a7f
--- /dev/null
+++ b/drivers/mmc/card/cprmdrv_samsung.c
@@ -0,0 +1,450 @@
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+
+#include <linux/scatterlist.h>
+#include <linux/uaccess.h>
+
+#include "cprmdrv_samsung.h"
+#include <linux/slab.h>
+
+
+static int mmc_wait_busy(struct mmc_card *card)
+{
+ int ret, busy;
+ struct mmc_command cmd;
+
+ busy = 0;
+ do {
+ 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;
+
+ ret = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (ret)
+ break;
+
+ if (!busy && !(cmd.resp[0] & R1_READY_FOR_DATA)) {
+ busy = 1;
+ printk(KERN_INFO "%s: Warning: Host did not "
+ "wait for busy state to end.\n",
+ mmc_hostname(card->host));
+ }
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+
+ return ret;
+}
+
+static int CPRM_CMD_SecureRW(struct mmc_card *card,
+ unsigned int command,
+ unsigned int dir,
+ unsigned long arg,
+ unsigned char *buff,
+ unsigned int length) {
+
+ int err;
+ int i = 0;
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_data data;
+ unsigned int timeout_us;
+
+ struct scatterlist sg;
+
+ if (command == SD_ACMD25_SECURE_WRITE_MULTI_BLOCK ||
+ command == SD_ACMD18_SECURE_READ_MULTI_BLOCK) {
+ return -EINVAL;
+ }
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err)
+ return (u32)-1;
+
+ if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
+ return (u32)-1;
+
+ printk("CPRM_CMD_SecureRW: 1, command : %d\n", command);
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = command;
+
+ if (command == SD_ACMD43_GET_MKB)
+ cmd.arg = arg;
+ else
+ cmd.arg = 0;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 100;
+ data.timeout_clks = card->csd.tacc_clks * 100;
+
+ timeout_us = data.timeout_ns / 1000;
+ timeout_us += data.timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (timeout_us > 100000) {
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+ }
+
+#if defined(CONFIG_TARGET_LOCALE_NTT)
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+#endif
+
+ data.blksz = length;
+ data.blocks = 1;
+ data.flags = dir;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ if (data.blocks == 1)
+ mrq.stop = NULL;
+ else
+ mrq.stop = &stop;
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 2\n");
+
+ sg_init_one(&sg, buff, length);
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 3\n");
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 4\n");
+
+ i = 0;
+ do {
+ printk(KERN_DEBUG "%x", buff[i++]);
+ if (i > 10)
+ break;
+ } while (i < length);
+ printk(KERN_DEBUG "\n");
+
+ if (cmd.error) {
+ printk(KERN_DEBUG "%s]cmd.error=%d\n ", __func__, cmd.error);
+ return cmd.error;
+ }
+
+ if (data.error) {
+ printk(KERN_DEBUG "%s]data.error=%d\n ", __func__, data.error);
+ return data.error;
+ }
+
+ err = mmc_wait_busy(card);
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 5\n");
+
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int CPRM_CMD_SecureMultiRW(struct mmc_card *card,
+ unsigned int command,
+ unsigned int dir,
+ unsigned long arg,
+ unsigned char *buff,
+ unsigned int length) {
+
+ int err;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_command stop;
+ struct mmc_data data;
+ unsigned int timeout_us;
+ unsigned long flags;
+
+ struct scatterlist sg;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+ memset(&stop, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if (err)
+ return (u32)-1;
+
+ if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
+ return (u32)-1;
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 1\n");
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = command;
+
+ if (command == SD_ACMD43_GET_MKB)
+ cmd.arg = arg;
+ else
+ cmd.arg = 0;
+
+ cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 100;
+ data.timeout_clks = card->csd.tacc_clks * 100;
+
+ timeout_us = data.timeout_ns / 1000;
+ timeout_us += data.timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (timeout_us > 100000) {
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+ }
+
+#if defined(CONFIG_TARGET_LOCALE_NTT)
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+#endif
+
+ data.blksz = 512;
+ data.blocks = (length + 511) / 512;
+
+ data.flags = dir;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ stop.opcode = MMC_STOP_TRANSMISSION;
+ stop.arg = 0;
+ stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+ mrq.stop = &stop;
+
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 2\n");
+
+ sg_init_one(&sg, buff, length);
+
+ if (dir == MMC_DATA_WRITE) {
+ local_irq_save(flags);
+ sg_copy_from_buffer(&sg, data.sg_len, buff, length);
+ local_irq_restore(flags);
+ }
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 3\n");
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 4\n");
+
+ if (cmd.error) {
+ printk(KERN_DEBUG "%s]cmd.error=%d\n", __func__, cmd.error);
+ return cmd.error;
+ }
+
+ if (data.error) {
+ printk(KERN_DEBUG "%s]data.error=%d\n", __func__, data.error);
+ return data.error;
+ }
+
+ err = mmc_wait_busy(card);
+ printk(KERN_DEBUG "CPRM_CMD_SecureRW: 5\n");
+
+ if (dir == MMC_DATA_READ) {
+ local_irq_save(flags);
+ sg_copy_to_buffer(&sg, data.sg_len, buff, length);
+ local_irq_restore(flags);
+ }
+
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+int stub_sendcmd(struct mmc_card *card,
+ unsigned int cmd,
+ unsigned long arg,
+ unsigned int len,
+ unsigned char *buff) {
+
+ int returnVal = -1;
+ unsigned char *kbuffer = NULL;
+ int direction = 0;
+ int result = 0;
+
+ if (card == NULL) {
+ printk(KERN_DEBUG "stub_sendcmd: card is null error\n");
+ return -ENXIO;
+ }
+
+ kbuffer = kmalloc(len, GFP_KERNEL);
+ if (kbuffer == NULL) {
+ printk(KERN_DEBUG "malloc failed\n");
+ return -ENOMEM;
+ }
+
+ memset(kbuffer, 0x00, len);
+
+ printk(KERN_DEBUG "%s]cmd=0x%x,len=%d\n ", __func__, cmd, len);
+
+ mmc_claim_host(card->host);
+
+ switch (cmd) {
+
+ case ACMD43:
+ direction = MMC_DATA_READ;
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD43_GET_MKB,
+ direction,
+ arg,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD43_GET_MKB:0x%x\n", returnVal);
+ break;
+
+ case ACMD44:
+ direction = MMC_DATA_READ;
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD44_GET_MID,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD44_GET_MID:0x%x\n", returnVal);
+ break;
+
+ case ACMD45:
+ direction = MMC_DATA_WRITE;
+ result = copy_from_user((void *)kbuffer, (void *)buff, len);
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD45_SET_CER_RN1,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD45_SET_CER_RN1:0x%x\n",
+ returnVal);
+ break;
+
+ case ACMD46:
+ direction = MMC_DATA_READ;
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD46_GET_CER_RN2,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD46_GET_CER_RN2:0x%x\n",
+ returnVal);
+ break;
+
+ case ACMD47:
+ direction = MMC_DATA_WRITE;
+ result = copy_from_user((void *)kbuffer, (void *)buff, len);
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD47_SET_CER_RES2,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD47_SET_CER_RES2:0x%x\n",
+ returnVal);
+ break;
+
+ case ACMD48:
+ direction = MMC_DATA_READ;
+ returnVal = CPRM_CMD_SecureRW(card,
+ SD_ACMD48_GET_CER_RES1,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD48_GET_CER_RES1:0x%x\n",
+ returnVal);
+ break;
+
+ case ACMD25:
+ direction = MMC_DATA_WRITE;
+ result = copy_from_user((void *)kbuffer, (void *)buff, len);
+ returnVal = CPRM_CMD_SecureMultiRW(card,
+ SD_ACMD25_SECURE_WRITE_MULTI_BLOCK,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD25_SECURE_WRITE_MULTI_BLOCK[%d]=%d\n",
+ len, returnVal);
+ break;
+
+ case ACMD18:
+ direction = MMC_DATA_READ;
+ returnVal = CPRM_CMD_SecureMultiRW(card,
+ SD_ACMD18_SECURE_READ_MULTI_BLOCK,
+ direction,
+ 0,
+ kbuffer,
+ len);
+
+ printk(KERN_DEBUG "SD_ACMD18_SECURE_READ_MULTI_BLOCK [%d]=%d\n",
+ len, returnVal);
+ break;
+
+ case ACMD13:
+ break;
+
+ default:
+ printk(KERN_DEBUG " %s ] : CMD [ %x ] ERROR", __func__, cmd);
+ break;
+ }
+
+ if (returnVal == 0) {
+ if (direction == MMC_DATA_READ)
+ result = copy_to_user((void *)buff,
+ (void *)kbuffer,
+ len);
+
+ result = returnVal;
+ printk(KERN_DEBUG "stub_sendcmd SDAS_E_SUCCESS\n");
+ } else {
+ printk(KERN_DEBUG "stub_sendcmd SDAS_E_FAIL\n");
+ result = -EIO;
+ }
+
+ mmc_release_host(card->host);
+ kfree(kbuffer);
+ return result;
+}