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