#include #include #include #include #include #include /* * erase a range of erase groups aligned to mtd->erase_size */ static int mmc_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mmc_card *card = mtd->priv; struct mmc_command cmd[3] = { { .opcode = MMC_ERASE_GROUP_START, .arg = instr->addr, .flags = MMC_RSP_R1 | MMC_CMD_AC, }, { .opcode = MMC_ERASE_GROUP_END, .arg = instr->addr + instr->len, .flags = MMC_RSP_R1 | MMC_CMD_AC, }, { .opcode = MMC_ERASE, .flags = MMC_RSP_R1B | MMC_CMD_AC, }, }; int err, i; dev_dbg(card->dev, "%s: from %ld len %ld\n", __FUNCTION__, from, len); instr->state = MTD_ERASING; err = mmc_card_claim_host(card); if (err) goto error; for (i=0; i<3; i++) { err = mmc_wait_for_cmd(card->host, cmd, 5); if (err) { dev_err(&card->dev, "%s: error %d in stage %d\n", __FUNCTION__, err, i); break; } } mmc_card_release_host(card); mtd_erase_callback(instr); error: instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE; return err; } /* * check if a write command was completed correctly */ static int mmc_mtd_get_status(struct mmc_card *card) { int err; struct mmc_command cmd; err = mmc_card_claim_host(card); if (err) goto error; do { cmd = (struct mmc_command) { .opcode = MMC_SEND_STATUS, .arg = card->rca << 16, .flags = MMC_RSP_R1 | MMC_CMD_AC, }; err = mmc_wait_for_cmd(card->host, &cmd, 5); if (err) { dev_err(&card->dev, "error %d requesting status\n", err); break; } } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); mmc_card_release_host(card); error: return err; } /* * transfer a block to/from the card. The block needs to be aligned * to mtd->writesize. If we want to implement an mtd_writev method, * this needs to use stream operations with an appropriate stop * command as well. */ static int mmc_mtd_transfer_low(struct mmc_card *card, loff_t off, size_t len, size_t *retlen, u_char *buf, int write) { struct scatterlist sg; struct mmc_data data = { .blksz = 1 << card->csd.read_blkbits, .blocks = len >> card->csd.read_blkbits, .flags = write ? MMC_DATA_WRITE : MMC_DATA_READ, .sg = &sg, .sg_len = 1, }; struct mmc_command cmd = { .arg = off, .flags = MMC_RSP_R1 | MMC_CMD_ADTC, .opcode = write ? MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK, }; struct mmc_request mrq = { .cmd = &cmd, .data = &data, }; int ret; dev_dbg(&card->dev, "%s off %ld, len %ld\n", write ? "write" : "read", off, len); sg_init_one(&sg, buf, len); mmc_set_data_timeout(&data, card, write); mmc_wait_for_req(card->host, &mrq); if (cmd.error || data.error) { dev_err(&card->dev, "error %d/%d sending read/write command\n", cmd.error, data.error); ret = -EIO; } /* copied from the block driver, don't understand why this is needed */ if (write) ret = mmc_mtd_get_status(card); if (!ret) *retlen = len; return ret; } /* * do some common sanity checks and locking for the actual transfer * function. */ static int mmc_mtd_transfer(struct mmc_card *card, loff_t off, size_t len, size_t *retlen, u_char *buf, int write) { int ret; if (from > mtd->size) return -EINVAL; if (from + len > mtd->size) len = mtd->size - from; if (retlen) *retlen = 0; ret = mmc_card_claim_host(card); if (ret) { dev_warn(&card->dev, "%s: mmc_card_claim_host returned %d\n", __FUNCTION__, ret); ret = -EIO; goto error; } ret = mmc_mtd_transfer_low(card, from, len, retlen, buf, write); mmc_card_release_host(card); error: return ret; } static int mmc_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { return mmc_mtd_transfer(mtd->priv, from, len, retlen, buf, 0); } static int mmc_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { return mmc_mtd_transfer(mtd->priv, to, len, retlen, (u_char *)buf, 1); } /* * Initialize an mmc card. We create a new MTD device for each * MMC card we find. The operations are rather straightforward, * so we don't even need our own data structure to contain the * mtd_info. */ static int mmc_mtd_probe(struct mmc_card *card) { struct mtd_info *mtd; int ret; if (!(card->csd.cmdclass & CCC_ERASE)) return -ENODEV; dev_info(&card->dev, "mmc card %s found\n", card->dev.bus_id); mtd = kzalloc(GFP_KERNEL, sizeof *mtd); if (!mtd) return -ENOMEM; sprintf(mtd->name, "mmc: %s", card->dev.bus_id); /* Don't know if these computations are correct */ mtd->size = card->csd.capacity << (card->csd.read_blkbits - 9); mtd->writesize = 1 << card->csd.write_blkbits; mtd->erasesize = mtd->writesize * card->csd.erase_blksize; dev_info(&card->dev, "size %d bytes, writesize %d, readsize %d\n", mtd->size, mtd->writesize, mtd->erasesize); /* * NAND is a relatively good approximation, but with the current * MTD scheme, we might need to get our own type */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; /* * operations that may be worthwhile implementing: * writev, sync, lock, unlock, suspend, resume * In the mean time, these should be sufficient. */ mtd->erase = mmc_mtd_erase; mtd->write = mmc_mtd_write; mtd->writev = default_mtd_writev; mtd->read = mmc_mtd_read; mtd->owner = THIS_MODULE; mtd->priv = card; mmc_set_drvdata(card, mtd); ret = add_mtd_device(mtd); if (ret) kfree(mtd); return ret; } /* * Not sure if this is safe. Can we call del_mtd_device while * the device is still in use? Do we have a choice? */ static void mmc_mtd_remove(struct mmc_card *card) { struct mtd_info *mtd; mtd = mmc_get_drvdata(card); mmc_mtd_sync(mtd); del_mtd_device(mtd); kfree(mtd); } /* * This driver will match any card, so it conflicts with the * mmc block driver. It's only possible to load one of them * at a time. */ static struct mmc_driver mmc_mtd_driver = { .drv = { .name = "mmcmtd", }, .probe = mmc_mtd_probe, .remove = mmc_mtd_remove, }; static int __init mmc_blk_init(void) { return mmc_register_driver(&mmc_mtd_driver); } module_init(mmc_blk_init); static void __exit mmc_blk_exit(void) { mmc_unregister_driver(&mmc_mtd_driver); } module_exit(mmc_blk_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Multimedia Card (MMC) MTD device driver"); MODULE_AUTHOR("Arnd Bergmann ");