block.c revision 17b0429dde9ab60f9cee8e07ab28c7dc6cfe6efd
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Block driver for media (i.e., flash cards) 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright 2002 Hewlett-Packard Company 598ac2162699f7e9880683cb954891817f20b607cPierre Ossman * Copyright 2005-2007 Pierre Ossman 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use consistent with the GNU GPL is permitted, 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * provided that this copyright notice is 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * preserved in its entirety in all copies and derived works. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FITNESS FOR ANY PARTICULAR PURPOSE. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Many thanks to Alessandro Rubini and Jonathan Corbet! 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Author: Andrew Christian 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28 May 2002 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fs.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kdev_t.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h> 30a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven#include <linux/mutex.h> 31ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman#include <linux/scatterlist.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mmc/card.h> 34385e3227d4d83ab13d7767c4bb3593b0256bf246Pierre Ossman#include <linux/mmc/host.h> 35da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/mmc.h> 36da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/sd.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4198ac2162699f7e9880683cb954891817f20b607cPierre Ossman#include "queue.h" 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * max 8 partitions per card 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MMC_SHIFT 3 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There is one mmc_blk_data per slot. 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mmc_blk_data { 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spinlock_t lock; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct gendisk *disk; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_queue queue; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int usage; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int block_bits; 58a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King unsigned int read_only; 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Venstatic DEFINE_MUTEX(open_lock); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven mutex_lock(&open_lock); 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = disk->private_data; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md && md->usage == 0) 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = NULL; 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->usage++; 73a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven mutex_unlock(&open_lock); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return md; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_blk_put(struct mmc_blk_data *md) 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 80a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven mutex_lock(&open_lock); 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->usage--; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->usage == 0) { 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds put_disk(md->disk); 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(md); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 86a621aaed690b9439141c555941b6af53873f6ff1Arjan van de Ven mutex_unlock(&open_lock); 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_open(struct inode *inode, struct file *filp) 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = -ENXIO; 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = mmc_blk_get(inode->i_bdev->bd_disk); 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md->usage == 2) 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds check_disk_change(inode->i_bdev); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = 0; 99a00fc09029f02ca833cf90e5d5625f08c4ac4f51Pierre Ossman 100a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if ((filp->f_mode & FMODE_WRITE) && md->read_only) 101a00fc09029f02ca833cf90e5d5625f08c4ac4f51Pierre Ossman ret = -EROFS; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_release(struct inode *inode, struct file *filp) 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data; 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_put(md); 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 116a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwigmmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo) 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 118a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16); 119a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->heads = 4; 120a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig geo->sectors = 16; 121a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig return 0; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct block_device_operations mmc_bdops = { 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = mmc_blk_open, 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = mmc_blk_release, 127a885c8c4316e1c1d2d2c8755da3f3d14f852528dChristoph Hellwig .getgeo = mmc_blk_getgeo, 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct mmc_blk_request { 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_request mrq; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command cmd; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command stop; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_data data; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 138ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossmanstatic u32 mmc_sd_num_wr_blocks(struct mmc_card *card) 139ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman{ 140ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman int err; 141ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman u32 blocks; 142ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 143ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman struct mmc_request mrq; 144ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman struct mmc_command cmd; 145ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman struct mmc_data data; 146ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman unsigned int timeout_us; 147ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 148ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman struct scatterlist sg; 149ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 150ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 151ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 152ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.opcode = MMC_APP_CMD; 153ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.arg = card->rca << 16; 154ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 155ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 156ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman err = mmc_wait_for_cmd(card->host, &cmd, 0); 15717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err || !(cmd.resp[0] & R1_APP_CMD)) 158ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman return (u32)-1; 159ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 160ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman memset(&cmd, 0, sizeof(struct mmc_command)); 161ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 162ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.opcode = SD_APP_SEND_NUM_WR_BLKS; 163ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.arg = 0; 164ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 165ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 166ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman memset(&data, 0, sizeof(struct mmc_data)); 167ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 168ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.timeout_ns = card->csd.tacc_ns * 100; 169ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.timeout_clks = card->csd.tacc_clks * 100; 170ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 171ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman timeout_us = data.timeout_ns / 1000; 172ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman timeout_us += data.timeout_clks * 1000 / 173ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman (card->host->ios.clock / 1000); 174ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 175ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman if (timeout_us > 100000) { 176ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.timeout_ns = 100000000; 177ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.timeout_clks = 0; 178ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman } 179ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 180ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.blksz = 4; 181ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.blocks = 1; 182ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.flags = MMC_DATA_READ; 183ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.sg = &sg; 184ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman data.sg_len = 1; 185ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 186ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman memset(&mrq, 0, sizeof(struct mmc_request)); 187ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 188ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman mrq.cmd = &cmd; 189ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman mrq.data = &data; 190ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 191ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman sg_init_one(&sg, &blocks, 4); 192ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 193ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman mmc_wait_for_req(card->host, &mrq); 194ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 19517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (cmd.error || data.error) 196ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman return (u32)-1; 197ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 198ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman blocks = ntohl(blocks); 199ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 200ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman return blocks; 201ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman} 202ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mq->data; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_card *card = md->queue.card; 207176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman struct mmc_blk_request brq; 20814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov int ret = 1, sg_pos, data_size; 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 210b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_claim_host(card->host); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command cmd; 214db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King u32 readcmd, writecmd; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(&brq, 0, sizeof(struct mmc_blk_request)); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.mrq.cmd = &brq.cmd; 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.mrq.data = &brq.data; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 220fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale brq.cmd.arg = req->sector; 221fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale if (!mmc_card_blockaddr(card)) 222fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale brq.cmd.arg <<= 9; 223e92251762d02a46177d4105d1744041e3f8bc465Russell King brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; 2242c171bf13423dc5293188cea7f6c2da1720926e2Pavel Pisa brq.data.blksz = 1 << md->block_bits; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.stop.opcode = MMC_STOP_TRANSMISSION; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.stop.arg = 0; 227e92251762d02a46177d4105d1744041e3f8bc465Russell King brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC; 22855db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); 22955db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman if (brq.data.blocks > card->host->max_blk_count) 23055db890a838c7b37256241b1fc53d6344aa79cc0Pierre Ossman brq.data.blocks = card->host->max_blk_count; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 232d773d7255199a6c8934e197756f54a1115dd127bRussell King mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ); 233385e3227d4d83ab13d7767c4bb3593b0256bf246Pierre Ossman 234db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King /* 235db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King * If the host doesn't support multiple block writes, force 236ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * block writes to single block. SD cards are excepted from 237ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * this rule as they support querying the number of 238ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * successfully written sectors. 239db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King */ 240db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King if (rq_data_dir(req) != READ && 241ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman !(card->host->caps & MMC_CAP_MULTIWRITE) && 242ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman !mmc_card_sd(card)) 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.data.blocks = 1; 244788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King 245788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King if (brq.data.blocks > 1) { 246788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King brq.data.flags |= MMC_DATA_MULTI; 247788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King brq.mrq.stop = &brq.stop; 248db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King readcmd = MMC_READ_MULTIPLE_BLOCK; 249db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King writecmd = MMC_WRITE_MULTIPLE_BLOCK; 250788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King } else { 251788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King brq.mrq.stop = NULL; 252db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King readcmd = MMC_READ_SINGLE_BLOCK; 253db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King writecmd = MMC_WRITE_BLOCK; 254db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King } 255db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King 256db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King if (rq_data_dir(req) == READ) { 257db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.cmd.opcode = readcmd; 258db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.data.flags |= MMC_DATA_READ; 259db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King } else { 260db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.cmd.opcode = writecmd; 261db53f28b3a6d9338cca1b7e917dc063ac99e1871Russell King brq.data.flags |= MMC_DATA_WRITE; 262788ee7b09883515f3a72a8f2a980df5e94f37e2cRussell King } 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brq.data.sg = mq->sg; 26598ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman brq.data.sg_len = mmc_queue_map_sg(mq); 26698ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 26798ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman mmc_queue_bounce_pre(mq); 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26914d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (brq.data.blocks != 27014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov (req->nr_sectors >> (md->block_bits - 9))) { 27114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov data_size = brq.data.blocks * brq.data.blksz; 27214d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) { 27314d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov data_size -= mq->sg[sg_pos].length; 27414d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov if (data_size <= 0) { 27514d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov mq->sg[sg_pos].length += data_size; 27614d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov sg_pos++; 27714d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov break; 27814d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov } 27914d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov } 28014d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov brq.data.sg_len = sg_pos; 28114d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov } 28214d836e7499c53a1f6a65086c3d11600e871a971Alex Dubov 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_wait_for_req(card->host, &brq.mrq); 28498ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 28598ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman mmc_queue_bounce_post(mq); 28698ccf14909ba02a41c5925b0b2c92aeeef23d3b9Pierre Ossman 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.cmd.error) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: error %d sending read/write command\n", 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->rq_disk->disk_name, brq.cmd.error); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cmd_err; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.data.error) { 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: error %d transferring data\n", 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->rq_disk->disk_name, brq.data.error); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cmd_err; 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (brq.stop.error) { 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: error %d sending stop command\n", 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->rq_disk->disk_name, brq.stop.error); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto cmd_err; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3052ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (rq_data_dir(req) != READ) { 3062ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King do { 3072ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King int err; 3082ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King 3092ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.opcode = MMC_SEND_STATUS; 3102ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.arg = card->rca << 16; 3112ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 3122ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King err = mmc_wait_for_cmd(card->host, &cmd, 5); 3132ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (err) { 3142ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King printk(KERN_ERR "%s: error %d requesting status\n", 3152ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King req->rq_disk->disk_name, err); 3162ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King goto cmd_err; 3172ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King } 3182ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 3212ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (cmd.resp[0] & ~0x00000900) 3222ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King printk(KERN_ERR "%s: status = %08x\n", 3232ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King req->rq_disk->disk_name, cmd.resp[0]); 3242ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King if (mmc_decode_status(cmd.resp)) 3252ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King goto cmd_err; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 3272ed6d22cec37d9a3df4c5bacf1160dee7700106eRussell King } 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A block was successfully transferred. 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&md->lock); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!ret) { 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The whole request completed successfully. 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk_randomness(req->rq_disk); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_dequeue_request(req); 3408ffdc6550c47f75ca4e6c9f30a2a89063e035cf2Tejun Heo end_that_request_last(req, 1); 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&md->lock); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (ret); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 345b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 1; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd_err: 350ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman /* 351ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * If this is an SD card and we're writing, we can first 352ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * mark the known good sectors as ok. 353ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * 354ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * If the card is not SD, we can still ok written sectors 355ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman * if the controller can do proper error reporting. 356176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman * 357176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman * For reads we just fail the entire chunk as that should 358176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman * be safe in all cases. 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 360ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman if (rq_data_dir(req) != READ && mmc_card_sd(card)) { 361ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman u32 blocks; 362ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman unsigned int bytes; 363ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 364ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman blocks = mmc_sd_num_wr_blocks(card); 365ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman if (blocks != (u32)-1) { 366ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman if (card->csd.write_partial) 367ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman bytes = blocks << md->block_bits; 368ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman else 369ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman bytes = blocks << 9; 370ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman spin_lock_irq(&md->lock); 371ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman ret = end_that_request_chunk(req, 1, bytes); 372ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman spin_unlock_irq(&md->lock); 373ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman } 374ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman } else if (rq_data_dir(req) != READ && 375ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman (card->host->caps & MMC_CAP_MULTIWRITE)) { 376176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman spin_lock_irq(&md->lock); 377176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered); 378176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman spin_unlock_irq(&md->lock); 379176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman } 380176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman 381b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 382ec5a19dd935eb3793e1f6ed491e8035b3d7b1df9Pierre Ossman 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&md->lock); 384176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman while (ret) { 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = end_that_request_chunk(req, 0, 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req->current_nr_sectors << 9); 387176f00ffed3ef94a198326fbf6a5db64f1cf73adPierre Ossman } 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk_randomness(req->rq_disk); 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds blkdev_dequeue_request(req); 3918ffdc6550c47f75ca4e6c9f30a2a89063e035cf2Tejun Heo end_that_request_last(req, 0); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&md->lock); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MMC_NUM_MINORS (256 >> MMC_SHIFT) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell Kingstatic inline int mmc_blk_readonly(struct mmc_card *card) 402a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King{ 403a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King return mmc_card_readonly(card) || 404a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King !(card->csd.cmdclass & CCC_BLOCK_WRITE); 405a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King} 406a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card) 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int devidx, ret; 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS); 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devidx >= MMC_NUM_MINORS) 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ERR_PTR(-ENOSPC); 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __set_bit(devidx, dev_use); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 417dd00cc486ab1c17049a535413d1751ef3482141cYoann Padioleau md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); 418a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (!md) { 419a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = -ENOMEM; 420a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto out; 421a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King } 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 424a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King /* 425a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * Set the read-only status based on the supported commands 426a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * and the write protect switch. 427a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King */ 428a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->read_only = mmc_blk_readonly(card); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 430a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King /* 4316fe9febb8af2f82f9caace1aa1c00cd8de7469acPierre Ossman * Both SD and MMC specifications state (although a bit 4326fe9febb8af2f82f9caace1aa1c00cd8de7469acPierre Ossman * unclearly in the MMC case) that a block size of 512 4336fe9febb8af2f82f9caace1aa1c00cd8de7469acPierre Ossman * bytes must always be supported by the card. 434a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King */ 4356fe9febb8af2f82f9caace1aa1c00cd8de7469acPierre Ossman md->block_bits = 9; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 437a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk = alloc_disk(1 << MMC_SHIFT); 438a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (md->disk == NULL) { 439a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = -ENOMEM; 440a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto err_kfree; 441a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King } 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 443a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King spin_lock_init(&md->lock); 444a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->usage = 1; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 446a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King ret = mmc_init_queue(&md->queue, card, &md->lock); 447a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King if (ret) 448a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King goto err_putdisk; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 450a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->queue.issue_fn = mmc_blk_issue_rq; 451a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->queue.data = md; 452d2b18394259ef621fd2a6322aa9934198fd87a6aRussell King 453fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman md->disk->major = MMC_BLOCK_MAJOR; 454a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->first_minor = devidx << MMC_SHIFT; 455a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->fops = &mmc_bdops; 456a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->private_data = md; 457a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->queue = md->queue.queue; 458a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King md->disk->driverfs_dev = &card->dev; 459a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 460a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King /* 461a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * As discussed on lkml, GENHD_FL_REMOVABLE should: 462a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * 463a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * - be set for removable media with permanent block devices 464a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * - be unset for removable block devices with permanent media 465a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * 466a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * Since MMC block devices clearly fall under the second 467a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * case, we do not set GENHD_FL_REMOVABLE. Userspace 468a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * should use the block device creation/destruction hotplug 469a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King * messages to tell when the card is present. 470a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King */ 471a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 472a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King sprintf(md->disk->disk_name, "mmcblk%d", devidx); 473a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 474a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); 475a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 47685a18ad93ec66888d85758630019b10a84257f3cPierre Ossman if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { 47785a18ad93ec66888d85758630019b10a84257f3cPierre Ossman /* 47885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * The EXT_CSD sector count is in number or 512 byte 47985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * sectors. 48085a18ad93ec66888d85758630019b10a84257f3cPierre Ossman */ 48185a18ad93ec66888d85758630019b10a84257f3cPierre Ossman set_capacity(md->disk, card->ext_csd.sectors); 48285a18ad93ec66888d85758630019b10a84257f3cPierre Ossman } else { 48385a18ad93ec66888d85758630019b10a84257f3cPierre Ossman /* 48485a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * The CSD capacity field is in units of read_blkbits. 48585a18ad93ec66888d85758630019b10a84257f3cPierre Ossman * set_capacity takes units of 512 bytes. 48685a18ad93ec66888d85758630019b10a84257f3cPierre Ossman */ 48785a18ad93ec66888d85758630019b10a84257f3cPierre Ossman set_capacity(md->disk, 48885a18ad93ec66888d85758630019b10a84257f3cPierre Ossman card->csd.capacity << (card->csd.read_blkbits - 9)); 48985a18ad93ec66888d85758630019b10a84257f3cPierre Ossman } 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return md; 491a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King 492a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_putdisk: 493a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King put_disk(md->disk); 494a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King err_kfree: 495a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King kfree(md); 496a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King out: 497a6f6c96b65d7f65a7a7bf5cbe874eda182a6b2ccRussell King return ERR_PTR(ret); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_command cmd; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 506fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */ 507fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale if (mmc_card_blockaddr(card)) 508fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale return 0; 509fba68bd2dab1ac99af3c5a963ec9581cfa9f1725Philip Langdale 510b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_claim_host(card->host); 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd.opcode = MMC_SET_BLOCKLEN; 512d2b18394259ef621fd2a6322aa9934198fd87a6aRussell King cmd.arg = 1 << md->block_bits; 513e92251762d02a46177d4105d1744041e3f8bc465Russell King cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = mmc_wait_for_cmd(card->host, &cmd, 5); 515b855885e3b60cf6f9452848712a62517b94583ebPierre Ossman mmc_release_host(card->host); 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) { 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_ERR "%s: unable to set block size to %d: %d\n", 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->disk->disk_name, cmd.arg, err); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_probe(struct mmc_card *card) 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman /* 532912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman * Check that the card supports the command class(es) we need. 533912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman */ 534912490db699d83cb3d03570b63df7448677a3f56Pierre Ossman if (!(card->csd.cmdclass & CCC_BLOCK_READ)) 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md = mmc_blk_alloc(card); 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (IS_ERR(md)) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return PTR_ERR(md); 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = mmc_blk_set_blksize(md, card); 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (err) 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54551828abc17a4ae0f7fb3879e00a30da7bdc7ca20Andrew Morton printk(KERN_INFO "%s: %s %s %lluKiB %s\n", 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), 54751828abc17a4ae0f7fb3879e00a30da7bdc7ca20Andrew Morton (unsigned long long)(get_capacity(md->disk) >> 1), 54851828abc17a4ae0f7fb3879e00a30da7bdc7ca20Andrew Morton md->read_only ? "(ro)" : ""); 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_set_drvdata(card, md); 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_disk(md->disk); 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_put(md); 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void mmc_blk_remove(struct mmc_card *card) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int devidx; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56789b4e133afea9fce333054b94d89953583a55c19Pierre Ossman /* Stop new requests from getting into the queue */ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds del_gendisk(md->disk); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57089b4e133afea9fce333054b94d89953583a55c19Pierre Ossman /* Then flush out any already in there */ 57189b4e133afea9fce333054b94d89953583a55c19Pierre Ossman mmc_cleanup_queue(&md->queue); 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devidx = md->disk->first_minor >> MMC_SHIFT; 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __clear_bit(devidx, dev_use); 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_put(md); 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_set_drvdata(card, NULL); 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PM 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_suspend(struct mmc_card *card, pm_message_t state) 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_queue_suspend(&md->queue); 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int mmc_blk_resume(struct mmc_card *card) 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct mmc_blk_data *md = mmc_get_drvdata(card); 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (md) { 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_blk_set_blksize(md, card); 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_queue_resume(&md->queue); 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmc_blk_suspend NULL 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define mmc_blk_resume NULL 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct mmc_driver mmc_driver = { 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .drv = { 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "mmcblk", 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }, 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = mmc_blk_probe, 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .remove = mmc_blk_remove, 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .suspend = mmc_blk_suspend, 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .resume = mmc_blk_resume, 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init mmc_blk_init(void) 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = -ENOMEM; 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); 622fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman if (res) 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return mmc_register_driver(&mmc_driver); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out: 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit mmc_blk_exit(void) 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmc_unregister_driver(&mmc_driver); 634fe6b4c8840c5e23fe9b8696450cee8f2e8cebffdPierre Ossman unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(mmc_blk_init); 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(mmc_blk_exit); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Multimedia Card (MMC) block device driver"); 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 643